OSDN Git Service

Modified: Upload, Command execution
[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         __webpack_require__(23);
67         __webpack_require__(24);
68
69
70 /***/ },
71 /* 1 */
72 /***/ function(module, exports, __webpack_require__) {
73
74         __webpack_require__(2);
75         module.exports = angular;
76
77
78 /***/ },
79 /* 2 */
80 /***/ function(module, exports) {
81
82         /**
83          * @license AngularJS v1.4.8
84          * (c) 2010-2015 Google, Inc. http://angularjs.org
85          * License: MIT
86          */
87         (function(window, document, undefined) {'use strict';
88
89         /**
90          * @description
91          *
92          * This object provides a utility for producing rich Error messages within
93          * Angular. It can be called as follows:
94          *
95          * var exampleMinErr = minErr('example');
96          * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
97          *
98          * The above creates an instance of minErr in the example namespace. The
99          * resulting error will have a namespaced error code of example.one.  The
100          * resulting error will replace {0} with the value of foo, and {1} with the
101          * value of bar. The object is not restricted in the number of arguments it can
102          * take.
103          *
104          * If fewer arguments are specified than necessary for interpolation, the extra
105          * interpolation markers will be preserved in the final string.
106          *
107          * Since data will be parsed statically during a build step, some restrictions
108          * are applied with respect to how minErr instances are created and called.
109          * Instances should have names of the form namespaceMinErr for a minErr created
110          * using minErr('namespace') . Error codes, namespaces and template strings
111          * should all be static strings, not variables or general expressions.
112          *
113          * @param {string} module The namespace to use for the new minErr instance.
114          * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
115          *   error from returned function, for cases when a particular type of error is useful.
116          * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
117          */
118
119         function minErr(module, ErrorConstructor) {
120           ErrorConstructor = ErrorConstructor || Error;
121           return function() {
122             var SKIP_INDEXES = 2;
123
124             var templateArgs = arguments,
125               code = templateArgs[0],
126               message = '[' + (module ? module + ':' : '') + code + '] ',
127               template = templateArgs[1],
128               paramPrefix, i;
129
130             message += template.replace(/\{\d+\}/g, function(match) {
131               var index = +match.slice(1, -1),
132                 shiftedIndex = index + SKIP_INDEXES;
133
134               if (shiftedIndex < templateArgs.length) {
135                 return toDebugString(templateArgs[shiftedIndex]);
136               }
137
138               return match;
139             });
140
141             message += '\nhttp://errors.angularjs.org/1.4.8/' +
142               (module ? module + '/' : '') + code;
143
144             for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
145               message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
146                 encodeURIComponent(toDebugString(templateArgs[i]));
147             }
148
149             return new ErrorConstructor(message);
150           };
151         }
152
153         /* We need to tell jshint what variables are being exported */
154         /* global angular: true,
155           msie: true,
156           jqLite: true,
157           jQuery: true,
158           slice: true,
159           splice: true,
160           push: true,
161           toString: true,
162           ngMinErr: true,
163           angularModule: true,
164           uid: true,
165           REGEX_STRING_REGEXP: true,
166           VALIDITY_STATE_PROPERTY: true,
167
168           lowercase: true,
169           uppercase: true,
170           manualLowercase: true,
171           manualUppercase: true,
172           nodeName_: true,
173           isArrayLike: true,
174           forEach: true,
175           forEachSorted: true,
176           reverseParams: true,
177           nextUid: true,
178           setHashKey: true,
179           extend: true,
180           toInt: true,
181           inherit: true,
182           merge: true,
183           noop: true,
184           identity: true,
185           valueFn: true,
186           isUndefined: true,
187           isDefined: true,
188           isObject: true,
189           isBlankObject: true,
190           isString: true,
191           isNumber: true,
192           isDate: true,
193           isArray: true,
194           isFunction: true,
195           isRegExp: true,
196           isWindow: true,
197           isScope: true,
198           isFile: true,
199           isFormData: true,
200           isBlob: true,
201           isBoolean: true,
202           isPromiseLike: true,
203           trim: true,
204           escapeForRegexp: true,
205           isElement: true,
206           makeMap: true,
207           includes: true,
208           arrayRemove: true,
209           copy: true,
210           shallowCopy: true,
211           equals: true,
212           csp: true,
213           jq: true,
214           concat: true,
215           sliceArgs: true,
216           bind: true,
217           toJsonReplacer: true,
218           toJson: true,
219           fromJson: true,
220           convertTimezoneToLocal: true,
221           timezoneToOffset: true,
222           startingTag: true,
223           tryDecodeURIComponent: true,
224           parseKeyValue: true,
225           toKeyValue: true,
226           encodeUriSegment: true,
227           encodeUriQuery: true,
228           angularInit: true,
229           bootstrap: true,
230           getTestability: true,
231           snake_case: true,
232           bindJQuery: true,
233           assertArg: true,
234           assertArgFn: true,
235           assertNotHasOwnProperty: true,
236           getter: true,
237           getBlockNodes: true,
238           hasOwnProperty: true,
239           createMap: true,
240
241           NODE_TYPE_ELEMENT: true,
242           NODE_TYPE_ATTRIBUTE: true,
243           NODE_TYPE_TEXT: true,
244           NODE_TYPE_COMMENT: true,
245           NODE_TYPE_DOCUMENT: true,
246           NODE_TYPE_DOCUMENT_FRAGMENT: true,
247         */
248
249         ////////////////////////////////////
250
251         /**
252          * @ngdoc module
253          * @name ng
254          * @module ng
255          * @description
256          *
257          * # ng (core module)
258          * The ng module is loaded by default when an AngularJS application is started. The module itself
259          * contains the essential components for an AngularJS application to function. The table below
260          * lists a high level breakdown of each of the services/factories, filters, directives and testing
261          * components available within this core module.
262          *
263          * <div doc-module-components="ng"></div>
264          */
265
266         var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
267
268         // The name of a form control's ValidityState property.
269         // This is used so that it's possible for internal tests to create mock ValidityStates.
270         var VALIDITY_STATE_PROPERTY = 'validity';
271
272         /**
273          * @ngdoc function
274          * @name angular.lowercase
275          * @module ng
276          * @kind function
277          *
278          * @description Converts the specified string to lowercase.
279          * @param {string} string String to be converted to lowercase.
280          * @returns {string} Lowercased string.
281          */
282         var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
283         var hasOwnProperty = Object.prototype.hasOwnProperty;
284
285         /**
286          * @ngdoc function
287          * @name angular.uppercase
288          * @module ng
289          * @kind function
290          *
291          * @description Converts the specified string to uppercase.
292          * @param {string} string String to be converted to uppercase.
293          * @returns {string} Uppercased string.
294          */
295         var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
296
297
298         var manualLowercase = function(s) {
299           /* jshint bitwise: false */
300           return isString(s)
301               ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
302               : s;
303         };
304         var manualUppercase = function(s) {
305           /* jshint bitwise: false */
306           return isString(s)
307               ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
308               : s;
309         };
310
311
312         // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
313         // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
314         // with correct but slower alternatives.
315         if ('i' !== 'I'.toLowerCase()) {
316           lowercase = manualLowercase;
317           uppercase = manualUppercase;
318         }
319
320
321         var
322             msie,             // holds major version number for IE, or NaN if UA is not IE.
323             jqLite,           // delay binding since jQuery could be loaded after us.
324             jQuery,           // delay binding
325             slice             = [].slice,
326             splice            = [].splice,
327             push              = [].push,
328             toString          = Object.prototype.toString,
329             getPrototypeOf    = Object.getPrototypeOf,
330             ngMinErr          = minErr('ng'),
331
332             /** @name angular */
333             angular           = window.angular || (window.angular = {}),
334             angularModule,
335             uid               = 0;
336
337         /**
338          * documentMode is an IE-only property
339          * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
340          */
341         msie = document.documentMode;
342
343
344         /**
345          * @private
346          * @param {*} obj
347          * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
348          *                   String ...)
349          */
350         function isArrayLike(obj) {
351
352           // `null`, `undefined` and `window` are not array-like
353           if (obj == null || isWindow(obj)) return false;
354
355           // arrays, strings and jQuery/jqLite objects are array like
356           // * jqLite is either the jQuery or jqLite constructor function
357           // * we have to check the existance of jqLite first as this method is called
358           //   via the forEach method when constructing the jqLite object in the first place
359           if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
360
361           // Support: iOS 8.2 (not reproducible in simulator)
362           // "length" in obj used to prevent JIT error (gh-11508)
363           var length = "length" in Object(obj) && obj.length;
364
365           // NodeList objects (with `item` method) and
366           // other objects with suitable length characteristics are array-like
367           return isNumber(length) &&
368             (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
369         }
370
371         /**
372          * @ngdoc function
373          * @name angular.forEach
374          * @module ng
375          * @kind function
376          *
377          * @description
378          * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
379          * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
380          * is the value of an object property or an array element, `key` is the object property key or
381          * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
382          *
383          * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
384          * using the `hasOwnProperty` method.
385          *
386          * Unlike ES262's
387          * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
388          * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
389          * return the value provided.
390          *
391            ```js
392              var values = {name: 'misko', gender: 'male'};
393              var log = [];
394              angular.forEach(values, function(value, key) {
395                this.push(key + ': ' + value);
396              }, log);
397              expect(log).toEqual(['name: misko', 'gender: male']);
398            ```
399          *
400          * @param {Object|Array} obj Object to iterate over.
401          * @param {Function} iterator Iterator function.
402          * @param {Object=} context Object to become context (`this`) for the iterator function.
403          * @returns {Object|Array} Reference to `obj`.
404          */
405
406         function forEach(obj, iterator, context) {
407           var key, length;
408           if (obj) {
409             if (isFunction(obj)) {
410               for (key in obj) {
411                 // Need to check if hasOwnProperty exists,
412                 // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
413                 if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
414                   iterator.call(context, obj[key], key, obj);
415                 }
416               }
417             } else if (isArray(obj) || isArrayLike(obj)) {
418               var isPrimitive = typeof obj !== 'object';
419               for (key = 0, length = obj.length; key < length; key++) {
420                 if (isPrimitive || key in obj) {
421                   iterator.call(context, obj[key], key, obj);
422                 }
423               }
424             } else if (obj.forEach && obj.forEach !== forEach) {
425                 obj.forEach(iterator, context, obj);
426             } else if (isBlankObject(obj)) {
427               // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
428               for (key in obj) {
429                 iterator.call(context, obj[key], key, obj);
430               }
431             } else if (typeof obj.hasOwnProperty === 'function') {
432               // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
433               for (key in obj) {
434                 if (obj.hasOwnProperty(key)) {
435                   iterator.call(context, obj[key], key, obj);
436                 }
437               }
438             } else {
439               // Slow path for objects which do not have a method `hasOwnProperty`
440               for (key in obj) {
441                 if (hasOwnProperty.call(obj, key)) {
442                   iterator.call(context, obj[key], key, obj);
443                 }
444               }
445             }
446           }
447           return obj;
448         }
449
450         function forEachSorted(obj, iterator, context) {
451           var keys = Object.keys(obj).sort();
452           for (var i = 0; i < keys.length; i++) {
453             iterator.call(context, obj[keys[i]], keys[i]);
454           }
455           return keys;
456         }
457
458
459         /**
460          * when using forEach the params are value, key, but it is often useful to have key, value.
461          * @param {function(string, *)} iteratorFn
462          * @returns {function(*, string)}
463          */
464         function reverseParams(iteratorFn) {
465           return function(value, key) { iteratorFn(key, value); };
466         }
467
468         /**
469          * A consistent way of creating unique IDs in angular.
470          *
471          * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
472          * we hit number precision issues in JavaScript.
473          *
474          * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
475          *
476          * @returns {number} an unique alpha-numeric string
477          */
478         function nextUid() {
479           return ++uid;
480         }
481
482
483         /**
484          * Set or clear the hashkey for an object.
485          * @param obj object
486          * @param h the hashkey (!truthy to delete the hashkey)
487          */
488         function setHashKey(obj, h) {
489           if (h) {
490             obj.$$hashKey = h;
491           } else {
492             delete obj.$$hashKey;
493           }
494         }
495
496
497         function baseExtend(dst, objs, deep) {
498           var h = dst.$$hashKey;
499
500           for (var i = 0, ii = objs.length; i < ii; ++i) {
501             var obj = objs[i];
502             if (!isObject(obj) && !isFunction(obj)) continue;
503             var keys = Object.keys(obj);
504             for (var j = 0, jj = keys.length; j < jj; j++) {
505               var key = keys[j];
506               var src = obj[key];
507
508               if (deep && isObject(src)) {
509                 if (isDate(src)) {
510                   dst[key] = new Date(src.valueOf());
511                 } else if (isRegExp(src)) {
512                   dst[key] = new RegExp(src);
513                 } else if (src.nodeName) {
514                   dst[key] = src.cloneNode(true);
515                 } else if (isElement(src)) {
516                   dst[key] = src.clone();
517                 } else {
518                   if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
519                   baseExtend(dst[key], [src], true);
520                 }
521               } else {
522                 dst[key] = src;
523               }
524             }
525           }
526
527           setHashKey(dst, h);
528           return dst;
529         }
530
531         /**
532          * @ngdoc function
533          * @name angular.extend
534          * @module ng
535          * @kind function
536          *
537          * @description
538          * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
539          * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
540          * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
541          *
542          * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
543          * {@link angular.merge} for this.
544          *
545          * @param {Object} dst Destination object.
546          * @param {...Object} src Source object(s).
547          * @returns {Object} Reference to `dst`.
548          */
549         function extend(dst) {
550           return baseExtend(dst, slice.call(arguments, 1), false);
551         }
552
553
554         /**
555         * @ngdoc function
556         * @name angular.merge
557         * @module ng
558         * @kind function
559         *
560         * @description
561         * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
562         * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
563         * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
564         *
565         * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
566         * objects, performing a deep copy.
567         *
568         * @param {Object} dst Destination object.
569         * @param {...Object} src Source object(s).
570         * @returns {Object} Reference to `dst`.
571         */
572         function merge(dst) {
573           return baseExtend(dst, slice.call(arguments, 1), true);
574         }
575
576
577
578         function toInt(str) {
579           return parseInt(str, 10);
580         }
581
582
583         function inherit(parent, extra) {
584           return extend(Object.create(parent), extra);
585         }
586
587         /**
588          * @ngdoc function
589          * @name angular.noop
590          * @module ng
591          * @kind function
592          *
593          * @description
594          * A function that performs no operations. This function can be useful when writing code in the
595          * functional style.
596            ```js
597              function foo(callback) {
598                var result = calculateResult();
599                (callback || angular.noop)(result);
600              }
601            ```
602          */
603         function noop() {}
604         noop.$inject = [];
605
606
607         /**
608          * @ngdoc function
609          * @name angular.identity
610          * @module ng
611          * @kind function
612          *
613          * @description
614          * A function that returns its first argument. This function is useful when writing code in the
615          * functional style.
616          *
617            ```js
618              function transformer(transformationFn, value) {
619                return (transformationFn || angular.identity)(value);
620              };
621            ```
622           * @param {*} value to be returned.
623           * @returns {*} the value passed in.
624          */
625         function identity($) {return $;}
626         identity.$inject = [];
627
628
629         function valueFn(value) {return function() {return value;};}
630
631         function hasCustomToString(obj) {
632           return isFunction(obj.toString) && obj.toString !== toString;
633         }
634
635
636         /**
637          * @ngdoc function
638          * @name angular.isUndefined
639          * @module ng
640          * @kind function
641          *
642          * @description
643          * Determines if a reference is undefined.
644          *
645          * @param {*} value Reference to check.
646          * @returns {boolean} True if `value` is undefined.
647          */
648         function isUndefined(value) {return typeof value === 'undefined';}
649
650
651         /**
652          * @ngdoc function
653          * @name angular.isDefined
654          * @module ng
655          * @kind function
656          *
657          * @description
658          * Determines if a reference is defined.
659          *
660          * @param {*} value Reference to check.
661          * @returns {boolean} True if `value` is defined.
662          */
663         function isDefined(value) {return typeof value !== 'undefined';}
664
665
666         /**
667          * @ngdoc function
668          * @name angular.isObject
669          * @module ng
670          * @kind function
671          *
672          * @description
673          * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
674          * considered to be objects. Note that JavaScript arrays are objects.
675          *
676          * @param {*} value Reference to check.
677          * @returns {boolean} True if `value` is an `Object` but not `null`.
678          */
679         function isObject(value) {
680           // http://jsperf.com/isobject4
681           return value !== null && typeof value === 'object';
682         }
683
684
685         /**
686          * Determine if a value is an object with a null prototype
687          *
688          * @returns {boolean} True if `value` is an `Object` with a null prototype
689          */
690         function isBlankObject(value) {
691           return value !== null && typeof value === 'object' && !getPrototypeOf(value);
692         }
693
694
695         /**
696          * @ngdoc function
697          * @name angular.isString
698          * @module ng
699          * @kind function
700          *
701          * @description
702          * Determines if a reference is a `String`.
703          *
704          * @param {*} value Reference to check.
705          * @returns {boolean} True if `value` is a `String`.
706          */
707         function isString(value) {return typeof value === 'string';}
708
709
710         /**
711          * @ngdoc function
712          * @name angular.isNumber
713          * @module ng
714          * @kind function
715          *
716          * @description
717          * Determines if a reference is a `Number`.
718          *
719          * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
720          *
721          * If you wish to exclude these then you can use the native
722          * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
723          * method.
724          *
725          * @param {*} value Reference to check.
726          * @returns {boolean} True if `value` is a `Number`.
727          */
728         function isNumber(value) {return typeof value === 'number';}
729
730
731         /**
732          * @ngdoc function
733          * @name angular.isDate
734          * @module ng
735          * @kind function
736          *
737          * @description
738          * Determines if a value is a date.
739          *
740          * @param {*} value Reference to check.
741          * @returns {boolean} True if `value` is a `Date`.
742          */
743         function isDate(value) {
744           return toString.call(value) === '[object Date]';
745         }
746
747
748         /**
749          * @ngdoc function
750          * @name angular.isArray
751          * @module ng
752          * @kind function
753          *
754          * @description
755          * Determines if a reference is an `Array`.
756          *
757          * @param {*} value Reference to check.
758          * @returns {boolean} True if `value` is an `Array`.
759          */
760         var isArray = Array.isArray;
761
762         /**
763          * @ngdoc function
764          * @name angular.isFunction
765          * @module ng
766          * @kind function
767          *
768          * @description
769          * Determines if a reference is a `Function`.
770          *
771          * @param {*} value Reference to check.
772          * @returns {boolean} True if `value` is a `Function`.
773          */
774         function isFunction(value) {return typeof value === 'function';}
775
776
777         /**
778          * Determines if a value is a regular expression object.
779          *
780          * @private
781          * @param {*} value Reference to check.
782          * @returns {boolean} True if `value` is a `RegExp`.
783          */
784         function isRegExp(value) {
785           return toString.call(value) === '[object RegExp]';
786         }
787
788
789         /**
790          * Checks if `obj` is a window object.
791          *
792          * @private
793          * @param {*} obj Object to check
794          * @returns {boolean} True if `obj` is a window obj.
795          */
796         function isWindow(obj) {
797           return obj && obj.window === obj;
798         }
799
800
801         function isScope(obj) {
802           return obj && obj.$evalAsync && obj.$watch;
803         }
804
805
806         function isFile(obj) {
807           return toString.call(obj) === '[object File]';
808         }
809
810
811         function isFormData(obj) {
812           return toString.call(obj) === '[object FormData]';
813         }
814
815
816         function isBlob(obj) {
817           return toString.call(obj) === '[object Blob]';
818         }
819
820
821         function isBoolean(value) {
822           return typeof value === 'boolean';
823         }
824
825
826         function isPromiseLike(obj) {
827           return obj && isFunction(obj.then);
828         }
829
830
831         var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
832         function isTypedArray(value) {
833           return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
834         }
835
836
837         var trim = function(value) {
838           return isString(value) ? value.trim() : value;
839         };
840
841         // Copied from:
842         // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
843         // Prereq: s is a string.
844         var escapeForRegexp = function(s) {
845           return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
846                    replace(/\x08/g, '\\x08');
847         };
848
849
850         /**
851          * @ngdoc function
852          * @name angular.isElement
853          * @module ng
854          * @kind function
855          *
856          * @description
857          * Determines if a reference is a DOM element (or wrapped jQuery element).
858          *
859          * @param {*} value Reference to check.
860          * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
861          */
862         function isElement(node) {
863           return !!(node &&
864             (node.nodeName  // we are a direct element
865             || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
866         }
867
868         /**
869          * @param str 'key1,key2,...'
870          * @returns {object} in the form of {key1:true, key2:true, ...}
871          */
872         function makeMap(str) {
873           var obj = {}, items = str.split(","), i;
874           for (i = 0; i < items.length; i++) {
875             obj[items[i]] = true;
876           }
877           return obj;
878         }
879
880
881         function nodeName_(element) {
882           return lowercase(element.nodeName || (element[0] && element[0].nodeName));
883         }
884
885         function includes(array, obj) {
886           return Array.prototype.indexOf.call(array, obj) != -1;
887         }
888
889         function arrayRemove(array, value) {
890           var index = array.indexOf(value);
891           if (index >= 0) {
892             array.splice(index, 1);
893           }
894           return index;
895         }
896
897         /**
898          * @ngdoc function
899          * @name angular.copy
900          * @module ng
901          * @kind function
902          *
903          * @description
904          * Creates a deep copy of `source`, which should be an object or an array.
905          *
906          * * If no destination is supplied, a copy of the object or array is created.
907          * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
908          *   are deleted and then all elements/properties from the source are copied to it.
909          * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
910          * * If `source` is identical to 'destination' an exception will be thrown.
911          *
912          * @param {*} source The source that will be used to make a copy.
913          *                   Can be any type, including primitives, `null`, and `undefined`.
914          * @param {(Object|Array)=} destination Destination into which the source is copied. If
915          *     provided, must be of the same type as `source`.
916          * @returns {*} The copy or updated `destination`, if `destination` was specified.
917          *
918          * @example
919          <example module="copyExample">
920          <file name="index.html">
921          <div ng-controller="ExampleController">
922          <form novalidate class="simple-form">
923          Name: <input type="text" ng-model="user.name" /><br />
924          E-mail: <input type="email" ng-model="user.email" /><br />
925          Gender: <input type="radio" ng-model="user.gender" value="male" />male
926          <input type="radio" ng-model="user.gender" value="female" />female<br />
927          <button ng-click="reset()">RESET</button>
928          <button ng-click="update(user)">SAVE</button>
929          </form>
930          <pre>form = {{user | json}}</pre>
931          <pre>master = {{master | json}}</pre>
932          </div>
933
934          <script>
935           angular.module('copyExample', [])
936             .controller('ExampleController', ['$scope', function($scope) {
937               $scope.master= {};
938
939               $scope.update = function(user) {
940                 // Example with 1 argument
941                 $scope.master= angular.copy(user);
942               };
943
944               $scope.reset = function() {
945                 // Example with 2 arguments
946                 angular.copy($scope.master, $scope.user);
947               };
948
949               $scope.reset();
950             }]);
951          </script>
952          </file>
953          </example>
954          */
955         function copy(source, destination) {
956           var stackSource = [];
957           var stackDest = [];
958
959           if (destination) {
960             if (isTypedArray(destination)) {
961               throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
962             }
963             if (source === destination) {
964               throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
965             }
966
967             // Empty the destination object
968             if (isArray(destination)) {
969               destination.length = 0;
970             } else {
971               forEach(destination, function(value, key) {
972                 if (key !== '$$hashKey') {
973                   delete destination[key];
974                 }
975               });
976             }
977
978             stackSource.push(source);
979             stackDest.push(destination);
980             return copyRecurse(source, destination);
981           }
982
983           return copyElement(source);
984
985           function copyRecurse(source, destination) {
986             var h = destination.$$hashKey;
987             var result, key;
988             if (isArray(source)) {
989               for (var i = 0, ii = source.length; i < ii; i++) {
990                 destination.push(copyElement(source[i]));
991               }
992             } else if (isBlankObject(source)) {
993               // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
994               for (key in source) {
995                 destination[key] = copyElement(source[key]);
996               }
997             } else if (source && typeof source.hasOwnProperty === 'function') {
998               // Slow path, which must rely on hasOwnProperty
999               for (key in source) {
1000                 if (source.hasOwnProperty(key)) {
1001                   destination[key] = copyElement(source[key]);
1002                 }
1003               }
1004             } else {
1005               // Slowest path --- hasOwnProperty can't be called as a method
1006               for (key in source) {
1007                 if (hasOwnProperty.call(source, key)) {
1008                   destination[key] = copyElement(source[key]);
1009                 }
1010               }
1011             }
1012             setHashKey(destination, h);
1013             return destination;
1014           }
1015
1016           function copyElement(source) {
1017             // Simple values
1018             if (!isObject(source)) {
1019               return source;
1020             }
1021
1022             // Already copied values
1023             var index = stackSource.indexOf(source);
1024             if (index !== -1) {
1025               return stackDest[index];
1026             }
1027
1028             if (isWindow(source) || isScope(source)) {
1029               throw ngMinErr('cpws',
1030                 "Can't copy! Making copies of Window or Scope instances is not supported.");
1031             }
1032
1033             var needsRecurse = false;
1034             var destination;
1035
1036             if (isArray(source)) {
1037               destination = [];
1038               needsRecurse = true;
1039             } else if (isTypedArray(source)) {
1040               destination = new source.constructor(source);
1041             } else if (isDate(source)) {
1042               destination = new Date(source.getTime());
1043             } else if (isRegExp(source)) {
1044               destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
1045               destination.lastIndex = source.lastIndex;
1046             } else if (isFunction(source.cloneNode)) {
1047                 destination = source.cloneNode(true);
1048             } else {
1049               destination = Object.create(getPrototypeOf(source));
1050               needsRecurse = true;
1051             }
1052
1053             stackSource.push(source);
1054             stackDest.push(destination);
1055
1056             return needsRecurse
1057               ? copyRecurse(source, destination)
1058               : destination;
1059           }
1060         }
1061
1062         /**
1063          * Creates a shallow copy of an object, an array or a primitive.
1064          *
1065          * Assumes that there are no proto properties for objects.
1066          */
1067         function shallowCopy(src, dst) {
1068           if (isArray(src)) {
1069             dst = dst || [];
1070
1071             for (var i = 0, ii = src.length; i < ii; i++) {
1072               dst[i] = src[i];
1073             }
1074           } else if (isObject(src)) {
1075             dst = dst || {};
1076
1077             for (var key in src) {
1078               if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
1079                 dst[key] = src[key];
1080               }
1081             }
1082           }
1083
1084           return dst || src;
1085         }
1086
1087
1088         /**
1089          * @ngdoc function
1090          * @name angular.equals
1091          * @module ng
1092          * @kind function
1093          *
1094          * @description
1095          * Determines if two objects or two values are equivalent. Supports value types, regular
1096          * expressions, arrays and objects.
1097          *
1098          * Two objects or values are considered equivalent if at least one of the following is true:
1099          *
1100          * * Both objects or values pass `===` comparison.
1101          * * Both objects or values are of the same type and all of their properties are equal by
1102          *   comparing them with `angular.equals`.
1103          * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1104          * * Both values represent the same regular expression (In JavaScript,
1105          *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1106          *   representation matches).
1107          *
1108          * During a property comparison, properties of `function` type and properties with names
1109          * that begin with `$` are ignored.
1110          *
1111          * Scope and DOMWindow objects are being compared only by identify (`===`).
1112          *
1113          * @param {*} o1 Object or value to compare.
1114          * @param {*} o2 Object or value to compare.
1115          * @returns {boolean} True if arguments are equal.
1116          */
1117         function equals(o1, o2) {
1118           if (o1 === o2) return true;
1119           if (o1 === null || o2 === null) return false;
1120           if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1121           var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1122           if (t1 == t2) {
1123             if (t1 == 'object') {
1124               if (isArray(o1)) {
1125                 if (!isArray(o2)) return false;
1126                 if ((length = o1.length) == o2.length) {
1127                   for (key = 0; key < length; key++) {
1128                     if (!equals(o1[key], o2[key])) return false;
1129                   }
1130                   return true;
1131                 }
1132               } else if (isDate(o1)) {
1133                 if (!isDate(o2)) return false;
1134                 return equals(o1.getTime(), o2.getTime());
1135               } else if (isRegExp(o1)) {
1136                 return isRegExp(o2) ? o1.toString() == o2.toString() : false;
1137               } else {
1138                 if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1139                   isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1140                 keySet = createMap();
1141                 for (key in o1) {
1142                   if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1143                   if (!equals(o1[key], o2[key])) return false;
1144                   keySet[key] = true;
1145                 }
1146                 for (key in o2) {
1147                   if (!(key in keySet) &&
1148                       key.charAt(0) !== '$' &&
1149                       isDefined(o2[key]) &&
1150                       !isFunction(o2[key])) return false;
1151                 }
1152                 return true;
1153               }
1154             }
1155           }
1156           return false;
1157         }
1158
1159         var csp = function() {
1160           if (!isDefined(csp.rules)) {
1161
1162
1163             var ngCspElement = (document.querySelector('[ng-csp]') ||
1164                             document.querySelector('[data-ng-csp]'));
1165
1166             if (ngCspElement) {
1167               var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1168                             ngCspElement.getAttribute('data-ng-csp');
1169               csp.rules = {
1170                 noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1171                 noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1172               };
1173             } else {
1174               csp.rules = {
1175                 noUnsafeEval: noUnsafeEval(),
1176                 noInlineStyle: false
1177               };
1178             }
1179           }
1180
1181           return csp.rules;
1182
1183           function noUnsafeEval() {
1184             try {
1185               /* jshint -W031, -W054 */
1186               new Function('');
1187               /* jshint +W031, +W054 */
1188               return false;
1189             } catch (e) {
1190               return true;
1191             }
1192           }
1193         };
1194
1195         /**
1196          * @ngdoc directive
1197          * @module ng
1198          * @name ngJq
1199          *
1200          * @element ANY
1201          * @param {string=} ngJq the name of the library available under `window`
1202          * to be used for angular.element
1203          * @description
1204          * Use this directive to force the angular.element library.  This should be
1205          * used to force either jqLite by leaving ng-jq blank or setting the name of
1206          * the jquery variable under window (eg. jQuery).
1207          *
1208          * Since angular looks for this directive when it is loaded (doesn't wait for the
1209          * DOMContentLoaded event), it must be placed on an element that comes before the script
1210          * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1211          * others ignored.
1212          *
1213          * @example
1214          * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1215          ```html
1216          <!doctype html>
1217          <html ng-app ng-jq>
1218          ...
1219          ...
1220          </html>
1221          ```
1222          * @example
1223          * This example shows how to use a jQuery based library of a different name.
1224          * The library name must be available at the top most 'window'.
1225          ```html
1226          <!doctype html>
1227          <html ng-app ng-jq="jQueryLib">
1228          ...
1229          ...
1230          </html>
1231          ```
1232          */
1233         var jq = function() {
1234           if (isDefined(jq.name_)) return jq.name_;
1235           var el;
1236           var i, ii = ngAttrPrefixes.length, prefix, name;
1237           for (i = 0; i < ii; ++i) {
1238             prefix = ngAttrPrefixes[i];
1239             if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1240               name = el.getAttribute(prefix + 'jq');
1241               break;
1242             }
1243           }
1244
1245           return (jq.name_ = name);
1246         };
1247
1248         function concat(array1, array2, index) {
1249           return array1.concat(slice.call(array2, index));
1250         }
1251
1252         function sliceArgs(args, startIndex) {
1253           return slice.call(args, startIndex || 0);
1254         }
1255
1256
1257         /* jshint -W101 */
1258         /**
1259          * @ngdoc function
1260          * @name angular.bind
1261          * @module ng
1262          * @kind function
1263          *
1264          * @description
1265          * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1266          * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1267          * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1268          * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1269          *
1270          * @param {Object} self Context which `fn` should be evaluated in.
1271          * @param {function()} fn Function to be bound.
1272          * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1273          * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1274          */
1275         /* jshint +W101 */
1276         function bind(self, fn) {
1277           var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1278           if (isFunction(fn) && !(fn instanceof RegExp)) {
1279             return curryArgs.length
1280               ? function() {
1281                   return arguments.length
1282                     ? fn.apply(self, concat(curryArgs, arguments, 0))
1283                     : fn.apply(self, curryArgs);
1284                 }
1285               : function() {
1286                   return arguments.length
1287                     ? fn.apply(self, arguments)
1288                     : fn.call(self);
1289                 };
1290           } else {
1291             // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1292             return fn;
1293           }
1294         }
1295
1296
1297         function toJsonReplacer(key, value) {
1298           var val = value;
1299
1300           if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1301             val = undefined;
1302           } else if (isWindow(value)) {
1303             val = '$WINDOW';
1304           } else if (value &&  document === value) {
1305             val = '$DOCUMENT';
1306           } else if (isScope(value)) {
1307             val = '$SCOPE';
1308           }
1309
1310           return val;
1311         }
1312
1313
1314         /**
1315          * @ngdoc function
1316          * @name angular.toJson
1317          * @module ng
1318          * @kind function
1319          *
1320          * @description
1321          * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1322          * stripped since angular uses this notation internally.
1323          *
1324          * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1325          * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1326          *    If set to an integer, the JSON output will contain that many spaces per indentation.
1327          * @returns {string|undefined} JSON-ified string representing `obj`.
1328          */
1329         function toJson(obj, pretty) {
1330           if (typeof obj === 'undefined') return undefined;
1331           if (!isNumber(pretty)) {
1332             pretty = pretty ? 2 : null;
1333           }
1334           return JSON.stringify(obj, toJsonReplacer, pretty);
1335         }
1336
1337
1338         /**
1339          * @ngdoc function
1340          * @name angular.fromJson
1341          * @module ng
1342          * @kind function
1343          *
1344          * @description
1345          * Deserializes a JSON string.
1346          *
1347          * @param {string} json JSON string to deserialize.
1348          * @returns {Object|Array|string|number} Deserialized JSON string.
1349          */
1350         function fromJson(json) {
1351           return isString(json)
1352               ? JSON.parse(json)
1353               : json;
1354         }
1355
1356
1357         function timezoneToOffset(timezone, fallback) {
1358           var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1359           return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1360         }
1361
1362
1363         function addDateMinutes(date, minutes) {
1364           date = new Date(date.getTime());
1365           date.setMinutes(date.getMinutes() + minutes);
1366           return date;
1367         }
1368
1369
1370         function convertTimezoneToLocal(date, timezone, reverse) {
1371           reverse = reverse ? -1 : 1;
1372           var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
1373           return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
1374         }
1375
1376
1377         /**
1378          * @returns {string} Returns the string representation of the element.
1379          */
1380         function startingTag(element) {
1381           element = jqLite(element).clone();
1382           try {
1383             // turns out IE does not let you set .html() on elements which
1384             // are not allowed to have children. So we just ignore it.
1385             element.empty();
1386           } catch (e) {}
1387           var elemHtml = jqLite('<div>').append(element).html();
1388           try {
1389             return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1390                 elemHtml.
1391                   match(/^(<[^>]+>)/)[1].
1392                   replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1393           } catch (e) {
1394             return lowercase(elemHtml);
1395           }
1396
1397         }
1398
1399
1400         /////////////////////////////////////////////////
1401
1402         /**
1403          * Tries to decode the URI component without throwing an exception.
1404          *
1405          * @private
1406          * @param str value potential URI component to check.
1407          * @returns {boolean} True if `value` can be decoded
1408          * with the decodeURIComponent function.
1409          */
1410         function tryDecodeURIComponent(value) {
1411           try {
1412             return decodeURIComponent(value);
1413           } catch (e) {
1414             // Ignore any invalid uri component
1415           }
1416         }
1417
1418
1419         /**
1420          * Parses an escaped url query string into key-value pairs.
1421          * @returns {Object.<string,boolean|Array>}
1422          */
1423         function parseKeyValue(/**string*/keyValue) {
1424           var obj = {};
1425           forEach((keyValue || "").split('&'), function(keyValue) {
1426             var splitPoint, key, val;
1427             if (keyValue) {
1428               key = keyValue = keyValue.replace(/\+/g,'%20');
1429               splitPoint = keyValue.indexOf('=');
1430               if (splitPoint !== -1) {
1431                 key = keyValue.substring(0, splitPoint);
1432                 val = keyValue.substring(splitPoint + 1);
1433               }
1434               key = tryDecodeURIComponent(key);
1435               if (isDefined(key)) {
1436                 val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1437                 if (!hasOwnProperty.call(obj, key)) {
1438                   obj[key] = val;
1439                 } else if (isArray(obj[key])) {
1440                   obj[key].push(val);
1441                 } else {
1442                   obj[key] = [obj[key],val];
1443                 }
1444               }
1445             }
1446           });
1447           return obj;
1448         }
1449
1450         function toKeyValue(obj) {
1451           var parts = [];
1452           forEach(obj, function(value, key) {
1453             if (isArray(value)) {
1454               forEach(value, function(arrayValue) {
1455                 parts.push(encodeUriQuery(key, true) +
1456                            (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1457               });
1458             } else {
1459             parts.push(encodeUriQuery(key, true) +
1460                        (value === true ? '' : '=' + encodeUriQuery(value, true)));
1461             }
1462           });
1463           return parts.length ? parts.join('&') : '';
1464         }
1465
1466
1467         /**
1468          * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1469          * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1470          * segments:
1471          *    segment       = *pchar
1472          *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1473          *    pct-encoded   = "%" HEXDIG HEXDIG
1474          *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1475          *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1476          *                     / "*" / "+" / "," / ";" / "="
1477          */
1478         function encodeUriSegment(val) {
1479           return encodeUriQuery(val, true).
1480                      replace(/%26/gi, '&').
1481                      replace(/%3D/gi, '=').
1482                      replace(/%2B/gi, '+');
1483         }
1484
1485
1486         /**
1487          * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1488          * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1489          * encoded per http://tools.ietf.org/html/rfc3986:
1490          *    query       = *( pchar / "/" / "?" )
1491          *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1492          *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1493          *    pct-encoded   = "%" HEXDIG HEXDIG
1494          *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1495          *                     / "*" / "+" / "," / ";" / "="
1496          */
1497         function encodeUriQuery(val, pctEncodeSpaces) {
1498           return encodeURIComponent(val).
1499                      replace(/%40/gi, '@').
1500                      replace(/%3A/gi, ':').
1501                      replace(/%24/g, '$').
1502                      replace(/%2C/gi, ',').
1503                      replace(/%3B/gi, ';').
1504                      replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1505         }
1506
1507         var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1508
1509         function getNgAttribute(element, ngAttr) {
1510           var attr, i, ii = ngAttrPrefixes.length;
1511           for (i = 0; i < ii; ++i) {
1512             attr = ngAttrPrefixes[i] + ngAttr;
1513             if (isString(attr = element.getAttribute(attr))) {
1514               return attr;
1515             }
1516           }
1517           return null;
1518         }
1519
1520         /**
1521          * @ngdoc directive
1522          * @name ngApp
1523          * @module ng
1524          *
1525          * @element ANY
1526          * @param {angular.Module} ngApp an optional application
1527          *   {@link angular.module module} name to load.
1528          * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1529          *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1530          *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1531          *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1532          *   tracking down the root of these bugs.
1533          *
1534          * @description
1535          *
1536          * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1537          * designates the **root element** of the application and is typically placed near the root element
1538          * of the page - e.g. on the `<body>` or `<html>` tags.
1539          *
1540          * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1541          * found in the document will be used to define the root element to auto-bootstrap as an
1542          * application. To run multiple applications in an HTML document you must manually bootstrap them using
1543          * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1544          *
1545          * You can specify an **AngularJS module** to be used as the root module for the application.  This
1546          * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1547          * should contain the application code needed or have dependencies on other modules that will
1548          * contain the code. See {@link angular.module} for more information.
1549          *
1550          * In the example below if the `ngApp` directive were not placed on the `html` element then the
1551          * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1552          * would not be resolved to `3`.
1553          *
1554          * `ngApp` is the easiest, and most common way to bootstrap an application.
1555          *
1556          <example module="ngAppDemo">
1557            <file name="index.html">
1558            <div ng-controller="ngAppDemoController">
1559              I can add: {{a}} + {{b}} =  {{ a+b }}
1560            </div>
1561            </file>
1562            <file name="script.js">
1563            angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1564              $scope.a = 1;
1565              $scope.b = 2;
1566            });
1567            </file>
1568          </example>
1569          *
1570          * Using `ngStrictDi`, you would see something like this:
1571          *
1572          <example ng-app-included="true">
1573            <file name="index.html">
1574            <div ng-app="ngAppStrictDemo" ng-strict-di>
1575                <div ng-controller="GoodController1">
1576                    I can add: {{a}} + {{b}} =  {{ a+b }}
1577
1578                    <p>This renders because the controller does not fail to
1579                       instantiate, by using explicit annotation style (see
1580                       script.js for details)
1581                    </p>
1582                </div>
1583
1584                <div ng-controller="GoodController2">
1585                    Name: <input ng-model="name"><br />
1586                    Hello, {{name}}!
1587
1588                    <p>This renders because the controller does not fail to
1589                       instantiate, by using explicit annotation style
1590                       (see script.js for details)
1591                    </p>
1592                </div>
1593
1594                <div ng-controller="BadController">
1595                    I can add: {{a}} + {{b}} =  {{ a+b }}
1596
1597                    <p>The controller could not be instantiated, due to relying
1598                       on automatic function annotations (which are disabled in
1599                       strict mode). As such, the content of this section is not
1600                       interpolated, and there should be an error in your web console.
1601                    </p>
1602                </div>
1603            </div>
1604            </file>
1605            <file name="script.js">
1606            angular.module('ngAppStrictDemo', [])
1607              // BadController will fail to instantiate, due to relying on automatic function annotation,
1608              // rather than an explicit annotation
1609              .controller('BadController', function($scope) {
1610                $scope.a = 1;
1611                $scope.b = 2;
1612              })
1613              // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1614              // due to using explicit annotations using the array style and $inject property, respectively.
1615              .controller('GoodController1', ['$scope', function($scope) {
1616                $scope.a = 1;
1617                $scope.b = 2;
1618              }])
1619              .controller('GoodController2', GoodController2);
1620              function GoodController2($scope) {
1621                $scope.name = "World";
1622              }
1623              GoodController2.$inject = ['$scope'];
1624            </file>
1625            <file name="style.css">
1626            div[ng-controller] {
1627                margin-bottom: 1em;
1628                -webkit-border-radius: 4px;
1629                border-radius: 4px;
1630                border: 1px solid;
1631                padding: .5em;
1632            }
1633            div[ng-controller^=Good] {
1634                border-color: #d6e9c6;
1635                background-color: #dff0d8;
1636                color: #3c763d;
1637            }
1638            div[ng-controller^=Bad] {
1639                border-color: #ebccd1;
1640                background-color: #f2dede;
1641                color: #a94442;
1642                margin-bottom: 0;
1643            }
1644            </file>
1645          </example>
1646          */
1647         function angularInit(element, bootstrap) {
1648           var appElement,
1649               module,
1650               config = {};
1651
1652           // The element `element` has priority over any other element
1653           forEach(ngAttrPrefixes, function(prefix) {
1654             var name = prefix + 'app';
1655
1656             if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1657               appElement = element;
1658               module = element.getAttribute(name);
1659             }
1660           });
1661           forEach(ngAttrPrefixes, function(prefix) {
1662             var name = prefix + 'app';
1663             var candidate;
1664
1665             if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1666               appElement = candidate;
1667               module = candidate.getAttribute(name);
1668             }
1669           });
1670           if (appElement) {
1671             config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1672             bootstrap(appElement, module ? [module] : [], config);
1673           }
1674         }
1675
1676         /**
1677          * @ngdoc function
1678          * @name angular.bootstrap
1679          * @module ng
1680          * @description
1681          * Use this function to manually start up angular application.
1682          *
1683          * See: {@link guide/bootstrap Bootstrap}
1684          *
1685          * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1686          * They must use {@link ng.directive:ngApp ngApp}.
1687          *
1688          * Angular will detect if it has been loaded into the browser more than once and only allow the
1689          * first loaded script to be bootstrapped and will report a warning to the browser console for
1690          * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1691          * multiple instances of Angular try to work on the DOM.
1692          *
1693          * ```html
1694          * <!doctype html>
1695          * <html>
1696          * <body>
1697          * <div ng-controller="WelcomeController">
1698          *   {{greeting}}
1699          * </div>
1700          *
1701          * <script src="angular.js"></script>
1702          * <script>
1703          *   var app = angular.module('demo', [])
1704          *   .controller('WelcomeController', function($scope) {
1705          *       $scope.greeting = 'Welcome!';
1706          *   });
1707          *   angular.bootstrap(document, ['demo']);
1708          * </script>
1709          * </body>
1710          * </html>
1711          * ```
1712          *
1713          * @param {DOMElement} element DOM element which is the root of angular application.
1714          * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1715          *     Each item in the array should be the name of a predefined module or a (DI annotated)
1716          *     function that will be invoked by the injector as a `config` block.
1717          *     See: {@link angular.module modules}
1718          * @param {Object=} config an object for defining configuration options for the application. The
1719          *     following keys are supported:
1720          *
1721          * * `strictDi` - disable automatic function annotation for the application. This is meant to
1722          *   assist in finding bugs which break minified code. Defaults to `false`.
1723          *
1724          * @returns {auto.$injector} Returns the newly created injector for this app.
1725          */
1726         function bootstrap(element, modules, config) {
1727           if (!isObject(config)) config = {};
1728           var defaultConfig = {
1729             strictDi: false
1730           };
1731           config = extend(defaultConfig, config);
1732           var doBootstrap = function() {
1733             element = jqLite(element);
1734
1735             if (element.injector()) {
1736               var tag = (element[0] === document) ? 'document' : startingTag(element);
1737               //Encode angle brackets to prevent input from being sanitized to empty string #8683
1738               throw ngMinErr(
1739                   'btstrpd',
1740                   "App Already Bootstrapped with this Element '{0}'",
1741                   tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1742             }
1743
1744             modules = modules || [];
1745             modules.unshift(['$provide', function($provide) {
1746               $provide.value('$rootElement', element);
1747             }]);
1748
1749             if (config.debugInfoEnabled) {
1750               // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1751               modules.push(['$compileProvider', function($compileProvider) {
1752                 $compileProvider.debugInfoEnabled(true);
1753               }]);
1754             }
1755
1756             modules.unshift('ng');
1757             var injector = createInjector(modules, config.strictDi);
1758             injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1759                function bootstrapApply(scope, element, compile, injector) {
1760                 scope.$apply(function() {
1761                   element.data('$injector', injector);
1762                   compile(element)(scope);
1763                 });
1764               }]
1765             );
1766             return injector;
1767           };
1768
1769           var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1770           var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1771
1772           if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1773             config.debugInfoEnabled = true;
1774             window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1775           }
1776
1777           if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1778             return doBootstrap();
1779           }
1780
1781           window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1782           angular.resumeBootstrap = function(extraModules) {
1783             forEach(extraModules, function(module) {
1784               modules.push(module);
1785             });
1786             return doBootstrap();
1787           };
1788
1789           if (isFunction(angular.resumeDeferredBootstrap)) {
1790             angular.resumeDeferredBootstrap();
1791           }
1792         }
1793
1794         /**
1795          * @ngdoc function
1796          * @name angular.reloadWithDebugInfo
1797          * @module ng
1798          * @description
1799          * Use this function to reload the current application with debug information turned on.
1800          * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1801          *
1802          * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1803          */
1804         function reloadWithDebugInfo() {
1805           window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1806           window.location.reload();
1807         }
1808
1809         /**
1810          * @name angular.getTestability
1811          * @module ng
1812          * @description
1813          * Get the testability service for the instance of Angular on the given
1814          * element.
1815          * @param {DOMElement} element DOM element which is the root of angular application.
1816          */
1817         function getTestability(rootElement) {
1818           var injector = angular.element(rootElement).injector();
1819           if (!injector) {
1820             throw ngMinErr('test',
1821               'no injector found for element argument to getTestability');
1822           }
1823           return injector.get('$$testability');
1824         }
1825
1826         var SNAKE_CASE_REGEXP = /[A-Z]/g;
1827         function snake_case(name, separator) {
1828           separator = separator || '_';
1829           return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1830             return (pos ? separator : '') + letter.toLowerCase();
1831           });
1832         }
1833
1834         var bindJQueryFired = false;
1835         var skipDestroyOnNextJQueryCleanData;
1836         function bindJQuery() {
1837           var originalCleanData;
1838
1839           if (bindJQueryFired) {
1840             return;
1841           }
1842
1843           // bind to jQuery if present;
1844           var jqName = jq();
1845           jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
1846                    !jqName             ? undefined     :   // use jqLite
1847                                          window[jqName];   // use jQuery specified by `ngJq`
1848
1849           // Use jQuery if it exists with proper functionality, otherwise default to us.
1850           // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1851           // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1852           // versions. It will not work for sure with jQuery <1.7, though.
1853           if (jQuery && jQuery.fn.on) {
1854             jqLite = jQuery;
1855             extend(jQuery.fn, {
1856               scope: JQLitePrototype.scope,
1857               isolateScope: JQLitePrototype.isolateScope,
1858               controller: JQLitePrototype.controller,
1859               injector: JQLitePrototype.injector,
1860               inheritedData: JQLitePrototype.inheritedData
1861             });
1862
1863             // All nodes removed from the DOM via various jQuery APIs like .remove()
1864             // are passed through jQuery.cleanData. Monkey-patch this method to fire
1865             // the $destroy event on all removed nodes.
1866             originalCleanData = jQuery.cleanData;
1867             jQuery.cleanData = function(elems) {
1868               var events;
1869               if (!skipDestroyOnNextJQueryCleanData) {
1870                 for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1871                   events = jQuery._data(elem, "events");
1872                   if (events && events.$destroy) {
1873                     jQuery(elem).triggerHandler('$destroy');
1874                   }
1875                 }
1876               } else {
1877                 skipDestroyOnNextJQueryCleanData = false;
1878               }
1879               originalCleanData(elems);
1880             };
1881           } else {
1882             jqLite = JQLite;
1883           }
1884
1885           angular.element = jqLite;
1886
1887           // Prevent double-proxying.
1888           bindJQueryFired = true;
1889         }
1890
1891         /**
1892          * throw error if the argument is falsy.
1893          */
1894         function assertArg(arg, name, reason) {
1895           if (!arg) {
1896             throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1897           }
1898           return arg;
1899         }
1900
1901         function assertArgFn(arg, name, acceptArrayAnnotation) {
1902           if (acceptArrayAnnotation && isArray(arg)) {
1903               arg = arg[arg.length - 1];
1904           }
1905
1906           assertArg(isFunction(arg), name, 'not a function, got ' +
1907               (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1908           return arg;
1909         }
1910
1911         /**
1912          * throw error if the name given is hasOwnProperty
1913          * @param  {String} name    the name to test
1914          * @param  {String} context the context in which the name is used, such as module or directive
1915          */
1916         function assertNotHasOwnProperty(name, context) {
1917           if (name === 'hasOwnProperty') {
1918             throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1919           }
1920         }
1921
1922         /**
1923          * Return the value accessible from the object by path. Any undefined traversals are ignored
1924          * @param {Object} obj starting object
1925          * @param {String} path path to traverse
1926          * @param {boolean} [bindFnToScope=true]
1927          * @returns {Object} value as accessible by path
1928          */
1929         //TODO(misko): this function needs to be removed
1930         function getter(obj, path, bindFnToScope) {
1931           if (!path) return obj;
1932           var keys = path.split('.');
1933           var key;
1934           var lastInstance = obj;
1935           var len = keys.length;
1936
1937           for (var i = 0; i < len; i++) {
1938             key = keys[i];
1939             if (obj) {
1940               obj = (lastInstance = obj)[key];
1941             }
1942           }
1943           if (!bindFnToScope && isFunction(obj)) {
1944             return bind(lastInstance, obj);
1945           }
1946           return obj;
1947         }
1948
1949         /**
1950          * Return the DOM siblings between the first and last node in the given array.
1951          * @param {Array} array like object
1952          * @returns {Array} the inputted object or a jqLite collection containing the nodes
1953          */
1954         function getBlockNodes(nodes) {
1955           // TODO(perf): update `nodes` instead of creating a new object?
1956           var node = nodes[0];
1957           var endNode = nodes[nodes.length - 1];
1958           var blockNodes;
1959
1960           for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
1961             if (blockNodes || nodes[i] !== node) {
1962               if (!blockNodes) {
1963                 blockNodes = jqLite(slice.call(nodes, 0, i));
1964               }
1965               blockNodes.push(node);
1966             }
1967           }
1968
1969           return blockNodes || nodes;
1970         }
1971
1972
1973         /**
1974          * Creates a new object without a prototype. This object is useful for lookup without having to
1975          * guard against prototypically inherited properties via hasOwnProperty.
1976          *
1977          * Related micro-benchmarks:
1978          * - http://jsperf.com/object-create2
1979          * - http://jsperf.com/proto-map-lookup/2
1980          * - http://jsperf.com/for-in-vs-object-keys2
1981          *
1982          * @returns {Object}
1983          */
1984         function createMap() {
1985           return Object.create(null);
1986         }
1987
1988         var NODE_TYPE_ELEMENT = 1;
1989         var NODE_TYPE_ATTRIBUTE = 2;
1990         var NODE_TYPE_TEXT = 3;
1991         var NODE_TYPE_COMMENT = 8;
1992         var NODE_TYPE_DOCUMENT = 9;
1993         var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1994
1995         /**
1996          * @ngdoc type
1997          * @name angular.Module
1998          * @module ng
1999          * @description
2000          *
2001          * Interface for configuring angular {@link angular.module modules}.
2002          */
2003
2004         function setupModuleLoader(window) {
2005
2006           var $injectorMinErr = minErr('$injector');
2007           var ngMinErr = minErr('ng');
2008
2009           function ensure(obj, name, factory) {
2010             return obj[name] || (obj[name] = factory());
2011           }
2012
2013           var angular = ensure(window, 'angular', Object);
2014
2015           // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
2016           angular.$$minErr = angular.$$minErr || minErr;
2017
2018           return ensure(angular, 'module', function() {
2019             /** @type {Object.<string, angular.Module>} */
2020             var modules = {};
2021
2022             /**
2023              * @ngdoc function
2024              * @name angular.module
2025              * @module ng
2026              * @description
2027              *
2028              * The `angular.module` is a global place for creating, registering and retrieving Angular
2029              * modules.
2030              * All modules (angular core or 3rd party) that should be available to an application must be
2031              * registered using this mechanism.
2032              *
2033              * Passing one argument retrieves an existing {@link angular.Module},
2034              * whereas passing more than one argument creates a new {@link angular.Module}
2035              *
2036              *
2037              * # Module
2038              *
2039              * A module is a collection of services, directives, controllers, filters, and configuration information.
2040              * `angular.module` is used to configure the {@link auto.$injector $injector}.
2041              *
2042              * ```js
2043              * // Create a new module
2044              * var myModule = angular.module('myModule', []);
2045              *
2046              * // register a new service
2047              * myModule.value('appName', 'MyCoolApp');
2048              *
2049              * // configure existing services inside initialization blocks.
2050              * myModule.config(['$locationProvider', function($locationProvider) {
2051              *   // Configure existing providers
2052              *   $locationProvider.hashPrefix('!');
2053              * }]);
2054              * ```
2055              *
2056              * Then you can create an injector and load your modules like this:
2057              *
2058              * ```js
2059              * var injector = angular.injector(['ng', 'myModule'])
2060              * ```
2061              *
2062              * However it's more likely that you'll just use
2063              * {@link ng.directive:ngApp ngApp} or
2064              * {@link angular.bootstrap} to simplify this process for you.
2065              *
2066              * @param {!string} name The name of the module to create or retrieve.
2067              * @param {!Array.<string>=} requires If specified then new module is being created. If
2068              *        unspecified then the module is being retrieved for further configuration.
2069              * @param {Function=} configFn Optional configuration function for the module. Same as
2070              *        {@link angular.Module#config Module#config()}.
2071              * @returns {module} new module with the {@link angular.Module} api.
2072              */
2073             return function module(name, requires, configFn) {
2074               var assertNotHasOwnProperty = function(name, context) {
2075                 if (name === 'hasOwnProperty') {
2076                   throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2077                 }
2078               };
2079
2080               assertNotHasOwnProperty(name, 'module');
2081               if (requires && modules.hasOwnProperty(name)) {
2082                 modules[name] = null;
2083               }
2084               return ensure(modules, name, function() {
2085                 if (!requires) {
2086                   throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
2087                      "the module name or forgot to load it. If registering a module ensure that you " +
2088                      "specify the dependencies as the second argument.", name);
2089                 }
2090
2091                 /** @type {!Array.<Array.<*>>} */
2092                 var invokeQueue = [];
2093
2094                 /** @type {!Array.<Function>} */
2095                 var configBlocks = [];
2096
2097                 /** @type {!Array.<Function>} */
2098                 var runBlocks = [];
2099
2100                 var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2101
2102                 /** @type {angular.Module} */
2103                 var moduleInstance = {
2104                   // Private state
2105                   _invokeQueue: invokeQueue,
2106                   _configBlocks: configBlocks,
2107                   _runBlocks: runBlocks,
2108
2109                   /**
2110                    * @ngdoc property
2111                    * @name angular.Module#requires
2112                    * @module ng
2113                    *
2114                    * @description
2115                    * Holds the list of modules which the injector will load before the current module is
2116                    * loaded.
2117                    */
2118                   requires: requires,
2119
2120                   /**
2121                    * @ngdoc property
2122                    * @name angular.Module#name
2123                    * @module ng
2124                    *
2125                    * @description
2126                    * Name of the module.
2127                    */
2128                   name: name,
2129
2130
2131                   /**
2132                    * @ngdoc method
2133                    * @name angular.Module#provider
2134                    * @module ng
2135                    * @param {string} name service name
2136                    * @param {Function} providerType Construction function for creating new instance of the
2137                    *                                service.
2138                    * @description
2139                    * See {@link auto.$provide#provider $provide.provider()}.
2140                    */
2141                   provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2142
2143                   /**
2144                    * @ngdoc method
2145                    * @name angular.Module#factory
2146                    * @module ng
2147                    * @param {string} name service name
2148                    * @param {Function} providerFunction Function for creating new instance of the service.
2149                    * @description
2150                    * See {@link auto.$provide#factory $provide.factory()}.
2151                    */
2152                   factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2153
2154                   /**
2155                    * @ngdoc method
2156                    * @name angular.Module#service
2157                    * @module ng
2158                    * @param {string} name service name
2159                    * @param {Function} constructor A constructor function that will be instantiated.
2160                    * @description
2161                    * See {@link auto.$provide#service $provide.service()}.
2162                    */
2163                   service: invokeLaterAndSetModuleName('$provide', 'service'),
2164
2165                   /**
2166                    * @ngdoc method
2167                    * @name angular.Module#value
2168                    * @module ng
2169                    * @param {string} name service name
2170                    * @param {*} object Service instance object.
2171                    * @description
2172                    * See {@link auto.$provide#value $provide.value()}.
2173                    */
2174                   value: invokeLater('$provide', 'value'),
2175
2176                   /**
2177                    * @ngdoc method
2178                    * @name angular.Module#constant
2179                    * @module ng
2180                    * @param {string} name constant name
2181                    * @param {*} object Constant value.
2182                    * @description
2183                    * Because the constants are fixed, they get applied before other provide methods.
2184                    * See {@link auto.$provide#constant $provide.constant()}.
2185                    */
2186                   constant: invokeLater('$provide', 'constant', 'unshift'),
2187
2188                    /**
2189                    * @ngdoc method
2190                    * @name angular.Module#decorator
2191                    * @module ng
2192                    * @param {string} The name of the service to decorate.
2193                    * @param {Function} This function will be invoked when the service needs to be
2194                    *                                    instantiated and should return the decorated service instance.
2195                    * @description
2196                    * See {@link auto.$provide#decorator $provide.decorator()}.
2197                    */
2198                   decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
2199
2200                   /**
2201                    * @ngdoc method
2202                    * @name angular.Module#animation
2203                    * @module ng
2204                    * @param {string} name animation name
2205                    * @param {Function} animationFactory Factory function for creating new instance of an
2206                    *                                    animation.
2207                    * @description
2208                    *
2209                    * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2210                    *
2211                    *
2212                    * Defines an animation hook that can be later used with
2213                    * {@link $animate $animate} service and directives that use this service.
2214                    *
2215                    * ```js
2216                    * module.animation('.animation-name', function($inject1, $inject2) {
2217                    *   return {
2218                    *     eventName : function(element, done) {
2219                    *       //code to run the animation
2220                    *       //once complete, then run done()
2221                    *       return function cancellationFunction(element) {
2222                    *         //code to cancel the animation
2223                    *       }
2224                    *     }
2225                    *   }
2226                    * })
2227                    * ```
2228                    *
2229                    * See {@link ng.$animateProvider#register $animateProvider.register()} and
2230                    * {@link ngAnimate ngAnimate module} for more information.
2231                    */
2232                   animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2233
2234                   /**
2235                    * @ngdoc method
2236                    * @name angular.Module#filter
2237                    * @module ng
2238                    * @param {string} name Filter name - this must be a valid angular expression identifier
2239                    * @param {Function} filterFactory Factory function for creating new instance of filter.
2240                    * @description
2241                    * See {@link ng.$filterProvider#register $filterProvider.register()}.
2242                    *
2243                    * <div class="alert alert-warning">
2244                    * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2245                    * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2246                    * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2247                    * (`myapp_subsection_filterx`).
2248                    * </div>
2249                    */
2250                   filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2251
2252                   /**
2253                    * @ngdoc method
2254                    * @name angular.Module#controller
2255                    * @module ng
2256                    * @param {string|Object} name Controller name, or an object map of controllers where the
2257                    *    keys are the names and the values are the constructors.
2258                    * @param {Function} constructor Controller constructor function.
2259                    * @description
2260                    * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2261                    */
2262                   controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2263
2264                   /**
2265                    * @ngdoc method
2266                    * @name angular.Module#directive
2267                    * @module ng
2268                    * @param {string|Object} name Directive name, or an object map of directives where the
2269                    *    keys are the names and the values are the factories.
2270                    * @param {Function} directiveFactory Factory function for creating new instance of
2271                    * directives.
2272                    * @description
2273                    * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2274                    */
2275                   directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2276
2277                   /**
2278                    * @ngdoc method
2279                    * @name angular.Module#config
2280                    * @module ng
2281                    * @param {Function} configFn Execute this function on module load. Useful for service
2282                    *    configuration.
2283                    * @description
2284                    * Use this method to register work which needs to be performed on module loading.
2285                    * For more about how to configure services, see
2286                    * {@link providers#provider-recipe Provider Recipe}.
2287                    */
2288                   config: config,
2289
2290                   /**
2291                    * @ngdoc method
2292                    * @name angular.Module#run
2293                    * @module ng
2294                    * @param {Function} initializationFn Execute this function after injector creation.
2295                    *    Useful for application initialization.
2296                    * @description
2297                    * Use this method to register work which should be performed when the injector is done
2298                    * loading all modules.
2299                    */
2300                   run: function(block) {
2301                     runBlocks.push(block);
2302                     return this;
2303                   }
2304                 };
2305
2306                 if (configFn) {
2307                   config(configFn);
2308                 }
2309
2310                 return moduleInstance;
2311
2312                 /**
2313                  * @param {string} provider
2314                  * @param {string} method
2315                  * @param {String=} insertMethod
2316                  * @returns {angular.Module}
2317                  */
2318                 function invokeLater(provider, method, insertMethod, queue) {
2319                   if (!queue) queue = invokeQueue;
2320                   return function() {
2321                     queue[insertMethod || 'push']([provider, method, arguments]);
2322                     return moduleInstance;
2323                   };
2324                 }
2325
2326                 /**
2327                  * @param {string} provider
2328                  * @param {string} method
2329                  * @returns {angular.Module}
2330                  */
2331                 function invokeLaterAndSetModuleName(provider, method) {
2332                   return function(recipeName, factoryFunction) {
2333                     if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2334                     invokeQueue.push([provider, method, arguments]);
2335                     return moduleInstance;
2336                   };
2337                 }
2338               });
2339             };
2340           });
2341
2342         }
2343
2344         /* global: toDebugString: true */
2345
2346         function serializeObject(obj) {
2347           var seen = [];
2348
2349           return JSON.stringify(obj, function(key, val) {
2350             val = toJsonReplacer(key, val);
2351             if (isObject(val)) {
2352
2353               if (seen.indexOf(val) >= 0) return '...';
2354
2355               seen.push(val);
2356             }
2357             return val;
2358           });
2359         }
2360
2361         function toDebugString(obj) {
2362           if (typeof obj === 'function') {
2363             return obj.toString().replace(/ \{[\s\S]*$/, '');
2364           } else if (isUndefined(obj)) {
2365             return 'undefined';
2366           } else if (typeof obj !== 'string') {
2367             return serializeObject(obj);
2368           }
2369           return obj;
2370         }
2371
2372         /* global angularModule: true,
2373           version: true,
2374
2375           $CompileProvider,
2376
2377           htmlAnchorDirective,
2378           inputDirective,
2379           inputDirective,
2380           formDirective,
2381           scriptDirective,
2382           selectDirective,
2383           styleDirective,
2384           optionDirective,
2385           ngBindDirective,
2386           ngBindHtmlDirective,
2387           ngBindTemplateDirective,
2388           ngClassDirective,
2389           ngClassEvenDirective,
2390           ngClassOddDirective,
2391           ngCloakDirective,
2392           ngControllerDirective,
2393           ngFormDirective,
2394           ngHideDirective,
2395           ngIfDirective,
2396           ngIncludeDirective,
2397           ngIncludeFillContentDirective,
2398           ngInitDirective,
2399           ngNonBindableDirective,
2400           ngPluralizeDirective,
2401           ngRepeatDirective,
2402           ngShowDirective,
2403           ngStyleDirective,
2404           ngSwitchDirective,
2405           ngSwitchWhenDirective,
2406           ngSwitchDefaultDirective,
2407           ngOptionsDirective,
2408           ngTranscludeDirective,
2409           ngModelDirective,
2410           ngListDirective,
2411           ngChangeDirective,
2412           patternDirective,
2413           patternDirective,
2414           requiredDirective,
2415           requiredDirective,
2416           minlengthDirective,
2417           minlengthDirective,
2418           maxlengthDirective,
2419           maxlengthDirective,
2420           ngValueDirective,
2421           ngModelOptionsDirective,
2422           ngAttributeAliasDirectives,
2423           ngEventDirectives,
2424
2425           $AnchorScrollProvider,
2426           $AnimateProvider,
2427           $CoreAnimateCssProvider,
2428           $$CoreAnimateQueueProvider,
2429           $$CoreAnimateRunnerProvider,
2430           $BrowserProvider,
2431           $CacheFactoryProvider,
2432           $ControllerProvider,
2433           $DocumentProvider,
2434           $ExceptionHandlerProvider,
2435           $FilterProvider,
2436           $$ForceReflowProvider,
2437           $InterpolateProvider,
2438           $IntervalProvider,
2439           $$HashMapProvider,
2440           $HttpProvider,
2441           $HttpParamSerializerProvider,
2442           $HttpParamSerializerJQLikeProvider,
2443           $HttpBackendProvider,
2444           $xhrFactoryProvider,
2445           $LocationProvider,
2446           $LogProvider,
2447           $ParseProvider,
2448           $RootScopeProvider,
2449           $QProvider,
2450           $$QProvider,
2451           $$SanitizeUriProvider,
2452           $SceProvider,
2453           $SceDelegateProvider,
2454           $SnifferProvider,
2455           $TemplateCacheProvider,
2456           $TemplateRequestProvider,
2457           $$TestabilityProvider,
2458           $TimeoutProvider,
2459           $$RAFProvider,
2460           $WindowProvider,
2461           $$jqLiteProvider,
2462           $$CookieReaderProvider
2463         */
2464
2465
2466         /**
2467          * @ngdoc object
2468          * @name angular.version
2469          * @module ng
2470          * @description
2471          * An object that contains information about the current AngularJS version.
2472          *
2473          * This object has the following properties:
2474          *
2475          * - `full` – `{string}` – Full version string, such as "0.9.18".
2476          * - `major` – `{number}` – Major version number, such as "0".
2477          * - `minor` – `{number}` – Minor version number, such as "9".
2478          * - `dot` – `{number}` – Dot version number, such as "18".
2479          * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2480          */
2481         var version = {
2482           full: '1.4.8',    // all of these placeholder strings will be replaced by grunt's
2483           major: 1,    // package task
2484           minor: 4,
2485           dot: 8,
2486           codeName: 'ice-manipulation'
2487         };
2488
2489
2490         function publishExternalAPI(angular) {
2491           extend(angular, {
2492             'bootstrap': bootstrap,
2493             'copy': copy,
2494             'extend': extend,
2495             'merge': merge,
2496             'equals': equals,
2497             'element': jqLite,
2498             'forEach': forEach,
2499             'injector': createInjector,
2500             'noop': noop,
2501             'bind': bind,
2502             'toJson': toJson,
2503             'fromJson': fromJson,
2504             'identity': identity,
2505             'isUndefined': isUndefined,
2506             'isDefined': isDefined,
2507             'isString': isString,
2508             'isFunction': isFunction,
2509             'isObject': isObject,
2510             'isNumber': isNumber,
2511             'isElement': isElement,
2512             'isArray': isArray,
2513             'version': version,
2514             'isDate': isDate,
2515             'lowercase': lowercase,
2516             'uppercase': uppercase,
2517             'callbacks': {counter: 0},
2518             'getTestability': getTestability,
2519             '$$minErr': minErr,
2520             '$$csp': csp,
2521             'reloadWithDebugInfo': reloadWithDebugInfo
2522           });
2523
2524           angularModule = setupModuleLoader(window);
2525
2526           angularModule('ng', ['ngLocale'], ['$provide',
2527             function ngModule($provide) {
2528               // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2529               $provide.provider({
2530                 $$sanitizeUri: $$SanitizeUriProvider
2531               });
2532               $provide.provider('$compile', $CompileProvider).
2533                 directive({
2534                     a: htmlAnchorDirective,
2535                     input: inputDirective,
2536                     textarea: inputDirective,
2537                     form: formDirective,
2538                     script: scriptDirective,
2539                     select: selectDirective,
2540                     style: styleDirective,
2541                     option: optionDirective,
2542                     ngBind: ngBindDirective,
2543                     ngBindHtml: ngBindHtmlDirective,
2544                     ngBindTemplate: ngBindTemplateDirective,
2545                     ngClass: ngClassDirective,
2546                     ngClassEven: ngClassEvenDirective,
2547                     ngClassOdd: ngClassOddDirective,
2548                     ngCloak: ngCloakDirective,
2549                     ngController: ngControllerDirective,
2550                     ngForm: ngFormDirective,
2551                     ngHide: ngHideDirective,
2552                     ngIf: ngIfDirective,
2553                     ngInclude: ngIncludeDirective,
2554                     ngInit: ngInitDirective,
2555                     ngNonBindable: ngNonBindableDirective,
2556                     ngPluralize: ngPluralizeDirective,
2557                     ngRepeat: ngRepeatDirective,
2558                     ngShow: ngShowDirective,
2559                     ngStyle: ngStyleDirective,
2560                     ngSwitch: ngSwitchDirective,
2561                     ngSwitchWhen: ngSwitchWhenDirective,
2562                     ngSwitchDefault: ngSwitchDefaultDirective,
2563                     ngOptions: ngOptionsDirective,
2564                     ngTransclude: ngTranscludeDirective,
2565                     ngModel: ngModelDirective,
2566                     ngList: ngListDirective,
2567                     ngChange: ngChangeDirective,
2568                     pattern: patternDirective,
2569                     ngPattern: patternDirective,
2570                     required: requiredDirective,
2571                     ngRequired: requiredDirective,
2572                     minlength: minlengthDirective,
2573                     ngMinlength: minlengthDirective,
2574                     maxlength: maxlengthDirective,
2575                     ngMaxlength: maxlengthDirective,
2576                     ngValue: ngValueDirective,
2577                     ngModelOptions: ngModelOptionsDirective
2578                 }).
2579                 directive({
2580                   ngInclude: ngIncludeFillContentDirective
2581                 }).
2582                 directive(ngAttributeAliasDirectives).
2583                 directive(ngEventDirectives);
2584               $provide.provider({
2585                 $anchorScroll: $AnchorScrollProvider,
2586                 $animate: $AnimateProvider,
2587                 $animateCss: $CoreAnimateCssProvider,
2588                 $$animateQueue: $$CoreAnimateQueueProvider,
2589                 $$AnimateRunner: $$CoreAnimateRunnerProvider,
2590                 $browser: $BrowserProvider,
2591                 $cacheFactory: $CacheFactoryProvider,
2592                 $controller: $ControllerProvider,
2593                 $document: $DocumentProvider,
2594                 $exceptionHandler: $ExceptionHandlerProvider,
2595                 $filter: $FilterProvider,
2596                 $$forceReflow: $$ForceReflowProvider,
2597                 $interpolate: $InterpolateProvider,
2598                 $interval: $IntervalProvider,
2599                 $http: $HttpProvider,
2600                 $httpParamSerializer: $HttpParamSerializerProvider,
2601                 $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2602                 $httpBackend: $HttpBackendProvider,
2603                 $xhrFactory: $xhrFactoryProvider,
2604                 $location: $LocationProvider,
2605                 $log: $LogProvider,
2606                 $parse: $ParseProvider,
2607                 $rootScope: $RootScopeProvider,
2608                 $q: $QProvider,
2609                 $$q: $$QProvider,
2610                 $sce: $SceProvider,
2611                 $sceDelegate: $SceDelegateProvider,
2612                 $sniffer: $SnifferProvider,
2613                 $templateCache: $TemplateCacheProvider,
2614                 $templateRequest: $TemplateRequestProvider,
2615                 $$testability: $$TestabilityProvider,
2616                 $timeout: $TimeoutProvider,
2617                 $window: $WindowProvider,
2618                 $$rAF: $$RAFProvider,
2619                 $$jqLite: $$jqLiteProvider,
2620                 $$HashMap: $$HashMapProvider,
2621                 $$cookieReader: $$CookieReaderProvider
2622               });
2623             }
2624           ]);
2625         }
2626
2627         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2628          *     Any commits to this file should be reviewed with security in mind.  *
2629          *   Changes to this file can potentially create security vulnerabilities. *
2630          *          An approval from 2 Core members with history of modifying      *
2631          *                         this file is required.                          *
2632          *                                                                         *
2633          *  Does the change somehow allow for arbitrary javascript to be executed? *
2634          *    Or allows for someone to change the prototype of built-in objects?   *
2635          *     Or gives undesired access to variables likes document or window?    *
2636          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2637
2638         /* global JQLitePrototype: true,
2639           addEventListenerFn: true,
2640           removeEventListenerFn: true,
2641           BOOLEAN_ATTR: true,
2642           ALIASED_ATTR: true,
2643         */
2644
2645         //////////////////////////////////
2646         //JQLite
2647         //////////////////////////////////
2648
2649         /**
2650          * @ngdoc function
2651          * @name angular.element
2652          * @module ng
2653          * @kind function
2654          *
2655          * @description
2656          * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2657          *
2658          * If jQuery is available, `angular.element` is an alias for the
2659          * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2660          * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2661          *
2662          * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2663          * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2664          * commonly needed functionality with the goal of having a very small footprint.</div>
2665          *
2666          * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2667          *
2668          * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2669          * jqLite; they are never raw DOM references.</div>
2670          *
2671          * ## Angular's jqLite
2672          * jqLite provides only the following jQuery methods:
2673          *
2674          * - [`addClass()`](http://api.jquery.com/addClass/)
2675          * - [`after()`](http://api.jquery.com/after/)
2676          * - [`append()`](http://api.jquery.com/append/)
2677          * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2678          * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2679          * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2680          * - [`clone()`](http://api.jquery.com/clone/)
2681          * - [`contents()`](http://api.jquery.com/contents/)
2682          * - [`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'.
2683          * - [`data()`](http://api.jquery.com/data/)
2684          * - [`detach()`](http://api.jquery.com/detach/)
2685          * - [`empty()`](http://api.jquery.com/empty/)
2686          * - [`eq()`](http://api.jquery.com/eq/)
2687          * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2688          * - [`hasClass()`](http://api.jquery.com/hasClass/)
2689          * - [`html()`](http://api.jquery.com/html/)
2690          * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2691          * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2692          * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
2693          * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2694          * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2695          * - [`prepend()`](http://api.jquery.com/prepend/)
2696          * - [`prop()`](http://api.jquery.com/prop/)
2697          * - [`ready()`](http://api.jquery.com/ready/)
2698          * - [`remove()`](http://api.jquery.com/remove/)
2699          * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2700          * - [`removeClass()`](http://api.jquery.com/removeClass/)
2701          * - [`removeData()`](http://api.jquery.com/removeData/)
2702          * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2703          * - [`text()`](http://api.jquery.com/text/)
2704          * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2705          * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2706          * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
2707          * - [`val()`](http://api.jquery.com/val/)
2708          * - [`wrap()`](http://api.jquery.com/wrap/)
2709          *
2710          * ## jQuery/jqLite Extras
2711          * Angular also provides the following additional methods and events to both jQuery and jqLite:
2712          *
2713          * ### Events
2714          * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2715          *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2716          *    element before it is removed.
2717          *
2718          * ### Methods
2719          * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2720          *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2721          *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2722          *   `'ngModel'`).
2723          * - `injector()` - retrieves the injector of the current element or its parent.
2724          * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2725          *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2726          *   be enabled.
2727          * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2728          *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2729          *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2730          *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2731          * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2732          *   parent element is reached.
2733          *
2734          * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2735          * @returns {Object} jQuery object.
2736          */
2737
2738         JQLite.expando = 'ng339';
2739
2740         var jqCache = JQLite.cache = {},
2741             jqId = 1,
2742             addEventListenerFn = function(element, type, fn) {
2743               element.addEventListener(type, fn, false);
2744             },
2745             removeEventListenerFn = function(element, type, fn) {
2746               element.removeEventListener(type, fn, false);
2747             };
2748
2749         /*
2750          * !!! This is an undocumented "private" function !!!
2751          */
2752         JQLite._data = function(node) {
2753           //jQuery always returns an object on cache miss
2754           return this.cache[node[this.expando]] || {};
2755         };
2756
2757         function jqNextId() { return ++jqId; }
2758
2759
2760         var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2761         var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2762         var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2763         var jqLiteMinErr = minErr('jqLite');
2764
2765         /**
2766          * Converts snake_case to camelCase.
2767          * Also there is special case for Moz prefix starting with upper case letter.
2768          * @param name Name to normalize
2769          */
2770         function camelCase(name) {
2771           return name.
2772             replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2773               return offset ? letter.toUpperCase() : letter;
2774             }).
2775             replace(MOZ_HACK_REGEXP, 'Moz$1');
2776         }
2777
2778         var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
2779         var HTML_REGEXP = /<|&#?\w+;/;
2780         var TAG_NAME_REGEXP = /<([\w:-]+)/;
2781         var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
2782
2783         var wrapMap = {
2784           'option': [1, '<select multiple="multiple">', '</select>'],
2785
2786           'thead': [1, '<table>', '</table>'],
2787           'col': [2, '<table><colgroup>', '</colgroup></table>'],
2788           'tr': [2, '<table><tbody>', '</tbody></table>'],
2789           'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2790           '_default': [0, "", ""]
2791         };
2792
2793         wrapMap.optgroup = wrapMap.option;
2794         wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2795         wrapMap.th = wrapMap.td;
2796
2797
2798         function jqLiteIsTextNode(html) {
2799           return !HTML_REGEXP.test(html);
2800         }
2801
2802         function jqLiteAcceptsData(node) {
2803           // The window object can accept data but has no nodeType
2804           // Otherwise we are only interested in elements (1) and documents (9)
2805           var nodeType = node.nodeType;
2806           return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2807         }
2808
2809         function jqLiteHasData(node) {
2810           for (var key in jqCache[node.ng339]) {
2811             return true;
2812           }
2813           return false;
2814         }
2815
2816         function jqLiteBuildFragment(html, context) {
2817           var tmp, tag, wrap,
2818               fragment = context.createDocumentFragment(),
2819               nodes = [], i;
2820
2821           if (jqLiteIsTextNode(html)) {
2822             // Convert non-html into a text node
2823             nodes.push(context.createTextNode(html));
2824           } else {
2825             // Convert html into DOM nodes
2826             tmp = tmp || fragment.appendChild(context.createElement("div"));
2827             tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2828             wrap = wrapMap[tag] || wrapMap._default;
2829             tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2830
2831             // Descend through wrappers to the right content
2832             i = wrap[0];
2833             while (i--) {
2834               tmp = tmp.lastChild;
2835             }
2836
2837             nodes = concat(nodes, tmp.childNodes);
2838
2839             tmp = fragment.firstChild;
2840             tmp.textContent = "";
2841           }
2842
2843           // Remove wrapper from fragment
2844           fragment.textContent = "";
2845           fragment.innerHTML = ""; // Clear inner HTML
2846           forEach(nodes, function(node) {
2847             fragment.appendChild(node);
2848           });
2849
2850           return fragment;
2851         }
2852
2853         function jqLiteParseHTML(html, context) {
2854           context = context || document;
2855           var parsed;
2856
2857           if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2858             return [context.createElement(parsed[1])];
2859           }
2860
2861           if ((parsed = jqLiteBuildFragment(html, context))) {
2862             return parsed.childNodes;
2863           }
2864
2865           return [];
2866         }
2867
2868
2869         // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2870         var jqLiteContains = Node.prototype.contains || function(arg) {
2871           // jshint bitwise: false
2872           return !!(this.compareDocumentPosition(arg) & 16);
2873           // jshint bitwise: true
2874         };
2875
2876         /////////////////////////////////////////////
2877         function JQLite(element) {
2878           if (element instanceof JQLite) {
2879             return element;
2880           }
2881
2882           var argIsString;
2883
2884           if (isString(element)) {
2885             element = trim(element);
2886             argIsString = true;
2887           }
2888           if (!(this instanceof JQLite)) {
2889             if (argIsString && element.charAt(0) != '<') {
2890               throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2891             }
2892             return new JQLite(element);
2893           }
2894
2895           if (argIsString) {
2896             jqLiteAddNodes(this, jqLiteParseHTML(element));
2897           } else {
2898             jqLiteAddNodes(this, element);
2899           }
2900         }
2901
2902         function jqLiteClone(element) {
2903           return element.cloneNode(true);
2904         }
2905
2906         function jqLiteDealoc(element, onlyDescendants) {
2907           if (!onlyDescendants) jqLiteRemoveData(element);
2908
2909           if (element.querySelectorAll) {
2910             var descendants = element.querySelectorAll('*');
2911             for (var i = 0, l = descendants.length; i < l; i++) {
2912               jqLiteRemoveData(descendants[i]);
2913             }
2914           }
2915         }
2916
2917         function jqLiteOff(element, type, fn, unsupported) {
2918           if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2919
2920           var expandoStore = jqLiteExpandoStore(element);
2921           var events = expandoStore && expandoStore.events;
2922           var handle = expandoStore && expandoStore.handle;
2923
2924           if (!handle) return; //no listeners registered
2925
2926           if (!type) {
2927             for (type in events) {
2928               if (type !== '$destroy') {
2929                 removeEventListenerFn(element, type, handle);
2930               }
2931               delete events[type];
2932             }
2933           } else {
2934
2935             var removeHandler = function(type) {
2936               var listenerFns = events[type];
2937               if (isDefined(fn)) {
2938                 arrayRemove(listenerFns || [], fn);
2939               }
2940               if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
2941                 removeEventListenerFn(element, type, handle);
2942                 delete events[type];
2943               }
2944             };
2945
2946             forEach(type.split(' '), function(type) {
2947               removeHandler(type);
2948               if (MOUSE_EVENT_MAP[type]) {
2949                 removeHandler(MOUSE_EVENT_MAP[type]);
2950               }
2951             });
2952           }
2953         }
2954
2955         function jqLiteRemoveData(element, name) {
2956           var expandoId = element.ng339;
2957           var expandoStore = expandoId && jqCache[expandoId];
2958
2959           if (expandoStore) {
2960             if (name) {
2961               delete expandoStore.data[name];
2962               return;
2963             }
2964
2965             if (expandoStore.handle) {
2966               if (expandoStore.events.$destroy) {
2967                 expandoStore.handle({}, '$destroy');
2968               }
2969               jqLiteOff(element);
2970             }
2971             delete jqCache[expandoId];
2972             element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2973           }
2974         }
2975
2976
2977         function jqLiteExpandoStore(element, createIfNecessary) {
2978           var expandoId = element.ng339,
2979               expandoStore = expandoId && jqCache[expandoId];
2980
2981           if (createIfNecessary && !expandoStore) {
2982             element.ng339 = expandoId = jqNextId();
2983             expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2984           }
2985
2986           return expandoStore;
2987         }
2988
2989
2990         function jqLiteData(element, key, value) {
2991           if (jqLiteAcceptsData(element)) {
2992
2993             var isSimpleSetter = isDefined(value);
2994             var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2995             var massGetter = !key;
2996             var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2997             var data = expandoStore && expandoStore.data;
2998
2999             if (isSimpleSetter) { // data('key', value)
3000               data[key] = value;
3001             } else {
3002               if (massGetter) {  // data()
3003                 return data;
3004               } else {
3005                 if (isSimpleGetter) { // data('key')
3006                   // don't force creation of expandoStore if it doesn't exist yet
3007                   return data && data[key];
3008                 } else { // mass-setter: data({key1: val1, key2: val2})
3009                   extend(data, key);
3010                 }
3011               }
3012             }
3013           }
3014         }
3015
3016         function jqLiteHasClass(element, selector) {
3017           if (!element.getAttribute) return false;
3018           return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
3019               indexOf(" " + selector + " ") > -1);
3020         }
3021
3022         function jqLiteRemoveClass(element, cssClasses) {
3023           if (cssClasses && element.setAttribute) {
3024             forEach(cssClasses.split(' '), function(cssClass) {
3025               element.setAttribute('class', trim(
3026                   (" " + (element.getAttribute('class') || '') + " ")
3027                   .replace(/[\n\t]/g, " ")
3028                   .replace(" " + trim(cssClass) + " ", " "))
3029               );
3030             });
3031           }
3032         }
3033
3034         function jqLiteAddClass(element, cssClasses) {
3035           if (cssClasses && element.setAttribute) {
3036             var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3037                                     .replace(/[\n\t]/g, " ");
3038
3039             forEach(cssClasses.split(' '), function(cssClass) {
3040               cssClass = trim(cssClass);
3041               if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
3042                 existingClasses += cssClass + ' ';
3043               }
3044             });
3045
3046             element.setAttribute('class', trim(existingClasses));
3047           }
3048         }
3049
3050
3051         function jqLiteAddNodes(root, elements) {
3052           // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
3053
3054           if (elements) {
3055
3056             // if a Node (the most common case)
3057             if (elements.nodeType) {
3058               root[root.length++] = elements;
3059             } else {
3060               var length = elements.length;
3061
3062               // if an Array or NodeList and not a Window
3063               if (typeof length === 'number' && elements.window !== elements) {
3064                 if (length) {
3065                   for (var i = 0; i < length; i++) {
3066                     root[root.length++] = elements[i];
3067                   }
3068                 }
3069               } else {
3070                 root[root.length++] = elements;
3071               }
3072             }
3073           }
3074         }
3075
3076
3077         function jqLiteController(element, name) {
3078           return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
3079         }
3080
3081         function jqLiteInheritedData(element, name, value) {
3082           // if element is the document object work with the html element instead
3083           // this makes $(document).scope() possible
3084           if (element.nodeType == NODE_TYPE_DOCUMENT) {
3085             element = element.documentElement;
3086           }
3087           var names = isArray(name) ? name : [name];
3088
3089           while (element) {
3090             for (var i = 0, ii = names.length; i < ii; i++) {
3091               if (isDefined(value = jqLite.data(element, names[i]))) return value;
3092             }
3093
3094             // If dealing with a document fragment node with a host element, and no parent, use the host
3095             // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3096             // to lookup parent controllers.
3097             element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3098           }
3099         }
3100
3101         function jqLiteEmpty(element) {
3102           jqLiteDealoc(element, true);
3103           while (element.firstChild) {
3104             element.removeChild(element.firstChild);
3105           }
3106         }
3107
3108         function jqLiteRemove(element, keepData) {
3109           if (!keepData) jqLiteDealoc(element);
3110           var parent = element.parentNode;
3111           if (parent) parent.removeChild(element);
3112         }
3113
3114
3115         function jqLiteDocumentLoaded(action, win) {
3116           win = win || window;
3117           if (win.document.readyState === 'complete') {
3118             // Force the action to be run async for consistent behaviour
3119             // from the action's point of view
3120             // i.e. it will definitely not be in a $apply
3121             win.setTimeout(action);
3122           } else {
3123             // No need to unbind this handler as load is only ever called once
3124             jqLite(win).on('load', action);
3125           }
3126         }
3127
3128         //////////////////////////////////////////
3129         // Functions which are declared directly.
3130         //////////////////////////////////////////
3131         var JQLitePrototype = JQLite.prototype = {
3132           ready: function(fn) {
3133             var fired = false;
3134
3135             function trigger() {
3136               if (fired) return;
3137               fired = true;
3138               fn();
3139             }
3140
3141             // check if document is already loaded
3142             if (document.readyState === 'complete') {
3143               setTimeout(trigger);
3144             } else {
3145               this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3146               // we can not use jqLite since we are not done loading and jQuery could be loaded later.
3147               // jshint -W064
3148               JQLite(window).on('load', trigger); // fallback to window.onload for others
3149               // jshint +W064
3150             }
3151           },
3152           toString: function() {
3153             var value = [];
3154             forEach(this, function(e) { value.push('' + e);});
3155             return '[' + value.join(', ') + ']';
3156           },
3157
3158           eq: function(index) {
3159               return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3160           },
3161
3162           length: 0,
3163           push: push,
3164           sort: [].sort,
3165           splice: [].splice
3166         };
3167
3168         //////////////////////////////////////////
3169         // Functions iterating getter/setters.
3170         // these functions return self on setter and
3171         // value on get.
3172         //////////////////////////////////////////
3173         var BOOLEAN_ATTR = {};
3174         forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3175           BOOLEAN_ATTR[lowercase(value)] = value;
3176         });
3177         var BOOLEAN_ELEMENTS = {};
3178         forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3179           BOOLEAN_ELEMENTS[value] = true;
3180         });
3181         var ALIASED_ATTR = {
3182           'ngMinlength': 'minlength',
3183           'ngMaxlength': 'maxlength',
3184           'ngMin': 'min',
3185           'ngMax': 'max',
3186           'ngPattern': 'pattern'
3187         };
3188
3189         function getBooleanAttrName(element, name) {
3190           // check dom last since we will most likely fail on name
3191           var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3192
3193           // booleanAttr is here twice to minimize DOM access
3194           return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3195         }
3196
3197         function getAliasedAttrName(name) {
3198           return ALIASED_ATTR[name];
3199         }
3200
3201         forEach({
3202           data: jqLiteData,
3203           removeData: jqLiteRemoveData,
3204           hasData: jqLiteHasData
3205         }, function(fn, name) {
3206           JQLite[name] = fn;
3207         });
3208
3209         forEach({
3210           data: jqLiteData,
3211           inheritedData: jqLiteInheritedData,
3212
3213           scope: function(element) {
3214             // Can't use jqLiteData here directly so we stay compatible with jQuery!
3215             return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3216           },
3217
3218           isolateScope: function(element) {
3219             // Can't use jqLiteData here directly so we stay compatible with jQuery!
3220             return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3221           },
3222
3223           controller: jqLiteController,
3224
3225           injector: function(element) {
3226             return jqLiteInheritedData(element, '$injector');
3227           },
3228
3229           removeAttr: function(element, name) {
3230             element.removeAttribute(name);
3231           },
3232
3233           hasClass: jqLiteHasClass,
3234
3235           css: function(element, name, value) {
3236             name = camelCase(name);
3237
3238             if (isDefined(value)) {
3239               element.style[name] = value;
3240             } else {
3241               return element.style[name];
3242             }
3243           },
3244
3245           attr: function(element, name, value) {
3246             var nodeType = element.nodeType;
3247             if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3248               return;
3249             }
3250             var lowercasedName = lowercase(name);
3251             if (BOOLEAN_ATTR[lowercasedName]) {
3252               if (isDefined(value)) {
3253                 if (!!value) {
3254                   element[name] = true;
3255                   element.setAttribute(name, lowercasedName);
3256                 } else {
3257                   element[name] = false;
3258                   element.removeAttribute(lowercasedName);
3259                 }
3260               } else {
3261                 return (element[name] ||
3262                          (element.attributes.getNamedItem(name) || noop).specified)
3263                        ? lowercasedName
3264                        : undefined;
3265               }
3266             } else if (isDefined(value)) {
3267               element.setAttribute(name, value);
3268             } else if (element.getAttribute) {
3269               // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3270               // some elements (e.g. Document) don't have get attribute, so return undefined
3271               var ret = element.getAttribute(name, 2);
3272               // normalize non-existing attributes to undefined (as jQuery)
3273               return ret === null ? undefined : ret;
3274             }
3275           },
3276
3277           prop: function(element, name, value) {
3278             if (isDefined(value)) {
3279               element[name] = value;
3280             } else {
3281               return element[name];
3282             }
3283           },
3284
3285           text: (function() {
3286             getText.$dv = '';
3287             return getText;
3288
3289             function getText(element, value) {
3290               if (isUndefined(value)) {
3291                 var nodeType = element.nodeType;
3292                 return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3293               }
3294               element.textContent = value;
3295             }
3296           })(),
3297
3298           val: function(element, value) {
3299             if (isUndefined(value)) {
3300               if (element.multiple && nodeName_(element) === 'select') {
3301                 var result = [];
3302                 forEach(element.options, function(option) {
3303                   if (option.selected) {
3304                     result.push(option.value || option.text);
3305                   }
3306                 });
3307                 return result.length === 0 ? null : result;
3308               }
3309               return element.value;
3310             }
3311             element.value = value;
3312           },
3313
3314           html: function(element, value) {
3315             if (isUndefined(value)) {
3316               return element.innerHTML;
3317             }
3318             jqLiteDealoc(element, true);
3319             element.innerHTML = value;
3320           },
3321
3322           empty: jqLiteEmpty
3323         }, function(fn, name) {
3324           /**
3325            * Properties: writes return selection, reads return first value
3326            */
3327           JQLite.prototype[name] = function(arg1, arg2) {
3328             var i, key;
3329             var nodeCount = this.length;
3330
3331             // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3332             // in a way that survives minification.
3333             // jqLiteEmpty takes no arguments but is a setter.
3334             if (fn !== jqLiteEmpty &&
3335                 (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3336               if (isObject(arg1)) {
3337
3338                 // we are a write, but the object properties are the key/values
3339                 for (i = 0; i < nodeCount; i++) {
3340                   if (fn === jqLiteData) {
3341                     // data() takes the whole object in jQuery
3342                     fn(this[i], arg1);
3343                   } else {
3344                     for (key in arg1) {
3345                       fn(this[i], key, arg1[key]);
3346                     }
3347                   }
3348                 }
3349                 // return self for chaining
3350                 return this;
3351               } else {
3352                 // we are a read, so read the first child.
3353                 // TODO: do we still need this?
3354                 var value = fn.$dv;
3355                 // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3356                 var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3357                 for (var j = 0; j < jj; j++) {
3358                   var nodeValue = fn(this[j], arg1, arg2);
3359                   value = value ? value + nodeValue : nodeValue;
3360                 }
3361                 return value;
3362               }
3363             } else {
3364               // we are a write, so apply to all children
3365               for (i = 0; i < nodeCount; i++) {
3366                 fn(this[i], arg1, arg2);
3367               }
3368               // return self for chaining
3369               return this;
3370             }
3371           };
3372         });
3373
3374         function createEventHandler(element, events) {
3375           var eventHandler = function(event, type) {
3376             // jQuery specific api
3377             event.isDefaultPrevented = function() {
3378               return event.defaultPrevented;
3379             };
3380
3381             var eventFns = events[type || event.type];
3382             var eventFnsLength = eventFns ? eventFns.length : 0;
3383
3384             if (!eventFnsLength) return;
3385
3386             if (isUndefined(event.immediatePropagationStopped)) {
3387               var originalStopImmediatePropagation = event.stopImmediatePropagation;
3388               event.stopImmediatePropagation = function() {
3389                 event.immediatePropagationStopped = true;
3390
3391                 if (event.stopPropagation) {
3392                   event.stopPropagation();
3393                 }
3394
3395                 if (originalStopImmediatePropagation) {
3396                   originalStopImmediatePropagation.call(event);
3397                 }
3398               };
3399             }
3400
3401             event.isImmediatePropagationStopped = function() {
3402               return event.immediatePropagationStopped === true;
3403             };
3404
3405             // Some events have special handlers that wrap the real handler
3406             var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3407
3408             // Copy event handlers in case event handlers array is modified during execution.
3409             if ((eventFnsLength > 1)) {
3410               eventFns = shallowCopy(eventFns);
3411             }
3412
3413             for (var i = 0; i < eventFnsLength; i++) {
3414               if (!event.isImmediatePropagationStopped()) {
3415                 handlerWrapper(element, event, eventFns[i]);
3416               }
3417             }
3418           };
3419
3420           // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3421           //       events on `element`
3422           eventHandler.elem = element;
3423           return eventHandler;
3424         }
3425
3426         function defaultHandlerWrapper(element, event, handler) {
3427           handler.call(element, event);
3428         }
3429
3430         function specialMouseHandlerWrapper(target, event, handler) {
3431           // Refer to jQuery's implementation of mouseenter & mouseleave
3432           // Read about mouseenter and mouseleave:
3433           // http://www.quirksmode.org/js/events_mouse.html#link8
3434           var related = event.relatedTarget;
3435           // For mousenter/leave call the handler if related is outside the target.
3436           // NB: No relatedTarget if the mouse left/entered the browser window
3437           if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3438             handler.call(target, event);
3439           }
3440         }
3441
3442         //////////////////////////////////////////
3443         // Functions iterating traversal.
3444         // These functions chain results into a single
3445         // selector.
3446         //////////////////////////////////////////
3447         forEach({
3448           removeData: jqLiteRemoveData,
3449
3450           on: function jqLiteOn(element, type, fn, unsupported) {
3451             if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3452
3453             // Do not add event handlers to non-elements because they will not be cleaned up.
3454             if (!jqLiteAcceptsData(element)) {
3455               return;
3456             }
3457
3458             var expandoStore = jqLiteExpandoStore(element, true);
3459             var events = expandoStore.events;
3460             var handle = expandoStore.handle;
3461
3462             if (!handle) {
3463               handle = expandoStore.handle = createEventHandler(element, events);
3464             }
3465
3466             // http://jsperf.com/string-indexof-vs-split
3467             var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3468             var i = types.length;
3469
3470             var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3471               var eventFns = events[type];
3472
3473               if (!eventFns) {
3474                 eventFns = events[type] = [];
3475                 eventFns.specialHandlerWrapper = specialHandlerWrapper;
3476                 if (type !== '$destroy' && !noEventListener) {
3477                   addEventListenerFn(element, type, handle);
3478                 }
3479               }
3480
3481               eventFns.push(fn);
3482             };
3483
3484             while (i--) {
3485               type = types[i];
3486               if (MOUSE_EVENT_MAP[type]) {
3487                 addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3488                 addHandler(type, undefined, true);
3489               } else {
3490                 addHandler(type);
3491               }
3492             }
3493           },
3494
3495           off: jqLiteOff,
3496
3497           one: function(element, type, fn) {
3498             element = jqLite(element);
3499
3500             //add the listener twice so that when it is called
3501             //you can remove the original function and still be
3502             //able to call element.off(ev, fn) normally
3503             element.on(type, function onFn() {
3504               element.off(type, fn);
3505               element.off(type, onFn);
3506             });
3507             element.on(type, fn);
3508           },
3509
3510           replaceWith: function(element, replaceNode) {
3511             var index, parent = element.parentNode;
3512             jqLiteDealoc(element);
3513             forEach(new JQLite(replaceNode), function(node) {
3514               if (index) {
3515                 parent.insertBefore(node, index.nextSibling);
3516               } else {
3517                 parent.replaceChild(node, element);
3518               }
3519               index = node;
3520             });
3521           },
3522
3523           children: function(element) {
3524             var children = [];
3525             forEach(element.childNodes, function(element) {
3526               if (element.nodeType === NODE_TYPE_ELEMENT) {
3527                 children.push(element);
3528               }
3529             });
3530             return children;
3531           },
3532
3533           contents: function(element) {
3534             return element.contentDocument || element.childNodes || [];
3535           },
3536
3537           append: function(element, node) {
3538             var nodeType = element.nodeType;
3539             if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3540
3541             node = new JQLite(node);
3542
3543             for (var i = 0, ii = node.length; i < ii; i++) {
3544               var child = node[i];
3545               element.appendChild(child);
3546             }
3547           },
3548
3549           prepend: function(element, node) {
3550             if (element.nodeType === NODE_TYPE_ELEMENT) {
3551               var index = element.firstChild;
3552               forEach(new JQLite(node), function(child) {
3553                 element.insertBefore(child, index);
3554               });
3555             }
3556           },
3557
3558           wrap: function(element, wrapNode) {
3559             wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3560             var parent = element.parentNode;
3561             if (parent) {
3562               parent.replaceChild(wrapNode, element);
3563             }
3564             wrapNode.appendChild(element);
3565           },
3566
3567           remove: jqLiteRemove,
3568
3569           detach: function(element) {
3570             jqLiteRemove(element, true);
3571           },
3572
3573           after: function(element, newElement) {
3574             var index = element, parent = element.parentNode;
3575             newElement = new JQLite(newElement);
3576
3577             for (var i = 0, ii = newElement.length; i < ii; i++) {
3578               var node = newElement[i];
3579               parent.insertBefore(node, index.nextSibling);
3580               index = node;
3581             }
3582           },
3583
3584           addClass: jqLiteAddClass,
3585           removeClass: jqLiteRemoveClass,
3586
3587           toggleClass: function(element, selector, condition) {
3588             if (selector) {
3589               forEach(selector.split(' '), function(className) {
3590                 var classCondition = condition;
3591                 if (isUndefined(classCondition)) {
3592                   classCondition = !jqLiteHasClass(element, className);
3593                 }
3594                 (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3595               });
3596             }
3597           },
3598
3599           parent: function(element) {
3600             var parent = element.parentNode;
3601             return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3602           },
3603
3604           next: function(element) {
3605             return element.nextElementSibling;
3606           },
3607
3608           find: function(element, selector) {
3609             if (element.getElementsByTagName) {
3610               return element.getElementsByTagName(selector);
3611             } else {
3612               return [];
3613             }
3614           },
3615
3616           clone: jqLiteClone,
3617
3618           triggerHandler: function(element, event, extraParameters) {
3619
3620             var dummyEvent, eventFnsCopy, handlerArgs;
3621             var eventName = event.type || event;
3622             var expandoStore = jqLiteExpandoStore(element);
3623             var events = expandoStore && expandoStore.events;
3624             var eventFns = events && events[eventName];
3625
3626             if (eventFns) {
3627               // Create a dummy event to pass to the handlers
3628               dummyEvent = {
3629                 preventDefault: function() { this.defaultPrevented = true; },
3630                 isDefaultPrevented: function() { return this.defaultPrevented === true; },
3631                 stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3632                 isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3633                 stopPropagation: noop,
3634                 type: eventName,
3635                 target: element
3636               };
3637
3638               // If a custom event was provided then extend our dummy event with it
3639               if (event.type) {
3640                 dummyEvent = extend(dummyEvent, event);
3641               }
3642
3643               // Copy event handlers in case event handlers array is modified during execution.
3644               eventFnsCopy = shallowCopy(eventFns);
3645               handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3646
3647               forEach(eventFnsCopy, function(fn) {
3648                 if (!dummyEvent.isImmediatePropagationStopped()) {
3649                   fn.apply(element, handlerArgs);
3650                 }
3651               });
3652             }
3653           }
3654         }, function(fn, name) {
3655           /**
3656            * chaining functions
3657            */
3658           JQLite.prototype[name] = function(arg1, arg2, arg3) {
3659             var value;
3660
3661             for (var i = 0, ii = this.length; i < ii; i++) {
3662               if (isUndefined(value)) {
3663                 value = fn(this[i], arg1, arg2, arg3);
3664                 if (isDefined(value)) {
3665                   // any function which returns a value needs to be wrapped
3666                   value = jqLite(value);
3667                 }
3668               } else {
3669                 jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3670               }
3671             }
3672             return isDefined(value) ? value : this;
3673           };
3674
3675           // bind legacy bind/unbind to on/off
3676           JQLite.prototype.bind = JQLite.prototype.on;
3677           JQLite.prototype.unbind = JQLite.prototype.off;
3678         });
3679
3680
3681         // Provider for private $$jqLite service
3682         function $$jqLiteProvider() {
3683           this.$get = function $$jqLite() {
3684             return extend(JQLite, {
3685               hasClass: function(node, classes) {
3686                 if (node.attr) node = node[0];
3687                 return jqLiteHasClass(node, classes);
3688               },
3689               addClass: function(node, classes) {
3690                 if (node.attr) node = node[0];
3691                 return jqLiteAddClass(node, classes);
3692               },
3693               removeClass: function(node, classes) {
3694                 if (node.attr) node = node[0];
3695                 return jqLiteRemoveClass(node, classes);
3696               }
3697             });
3698           };
3699         }
3700
3701         /**
3702          * Computes a hash of an 'obj'.
3703          * Hash of a:
3704          *  string is string
3705          *  number is number as string
3706          *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3707          *         that is also assigned to the $$hashKey property of the object.
3708          *
3709          * @param obj
3710          * @returns {string} hash string such that the same input will have the same hash string.
3711          *         The resulting string key is in 'type:hashKey' format.
3712          */
3713         function hashKey(obj, nextUidFn) {
3714           var key = obj && obj.$$hashKey;
3715
3716           if (key) {
3717             if (typeof key === 'function') {
3718               key = obj.$$hashKey();
3719             }
3720             return key;
3721           }
3722
3723           var objType = typeof obj;
3724           if (objType == 'function' || (objType == 'object' && obj !== null)) {
3725             key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3726           } else {
3727             key = objType + ':' + obj;
3728           }
3729
3730           return key;
3731         }
3732
3733         /**
3734          * HashMap which can use objects as keys
3735          */
3736         function HashMap(array, isolatedUid) {
3737           if (isolatedUid) {
3738             var uid = 0;
3739             this.nextUid = function() {
3740               return ++uid;
3741             };
3742           }
3743           forEach(array, this.put, this);
3744         }
3745         HashMap.prototype = {
3746           /**
3747            * Store key value pair
3748            * @param key key to store can be any type
3749            * @param value value to store can be any type
3750            */
3751           put: function(key, value) {
3752             this[hashKey(key, this.nextUid)] = value;
3753           },
3754
3755           /**
3756            * @param key
3757            * @returns {Object} the value for the key
3758            */
3759           get: function(key) {
3760             return this[hashKey(key, this.nextUid)];
3761           },
3762
3763           /**
3764            * Remove the key/value pair
3765            * @param key
3766            */
3767           remove: function(key) {
3768             var value = this[key = hashKey(key, this.nextUid)];
3769             delete this[key];
3770             return value;
3771           }
3772         };
3773
3774         var $$HashMapProvider = [function() {
3775           this.$get = [function() {
3776             return HashMap;
3777           }];
3778         }];
3779
3780         /**
3781          * @ngdoc function
3782          * @module ng
3783          * @name angular.injector
3784          * @kind function
3785          *
3786          * @description
3787          * Creates an injector object that can be used for retrieving services as well as for
3788          * dependency injection (see {@link guide/di dependency injection}).
3789          *
3790          * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3791          *     {@link angular.module}. The `ng` module must be explicitly added.
3792          * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3793          *     disallows argument name annotation inference.
3794          * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3795          *
3796          * @example
3797          * Typical usage
3798          * ```js
3799          *   // create an injector
3800          *   var $injector = angular.injector(['ng']);
3801          *
3802          *   // use the injector to kick off your application
3803          *   // use the type inference to auto inject arguments, or use implicit injection
3804          *   $injector.invoke(function($rootScope, $compile, $document) {
3805          *     $compile($document)($rootScope);
3806          *     $rootScope.$digest();
3807          *   });
3808          * ```
3809          *
3810          * Sometimes you want to get access to the injector of a currently running Angular app
3811          * from outside Angular. Perhaps, you want to inject and compile some markup after the
3812          * application has been bootstrapped. You can do this using the extra `injector()` added
3813          * to JQuery/jqLite elements. See {@link angular.element}.
3814          *
3815          * *This is fairly rare but could be the case if a third party library is injecting the
3816          * markup.*
3817          *
3818          * In the following example a new block of HTML containing a `ng-controller`
3819          * directive is added to the end of the document body by JQuery. We then compile and link
3820          * it into the current AngularJS scope.
3821          *
3822          * ```js
3823          * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3824          * $(document.body).append($div);
3825          *
3826          * angular.element(document).injector().invoke(function($compile) {
3827          *   var scope = angular.element($div).scope();
3828          *   $compile($div)(scope);
3829          * });
3830          * ```
3831          */
3832
3833
3834         /**
3835          * @ngdoc module
3836          * @name auto
3837          * @description
3838          *
3839          * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3840          */
3841
3842         var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
3843         var FN_ARG_SPLIT = /,/;
3844         var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3845         var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3846         var $injectorMinErr = minErr('$injector');
3847
3848         function anonFn(fn) {
3849           // For anonymous functions, showing at the very least the function signature can help in
3850           // debugging.
3851           var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3852               args = fnText.match(FN_ARGS);
3853           if (args) {
3854             return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3855           }
3856           return 'fn';
3857         }
3858
3859         function annotate(fn, strictDi, name) {
3860           var $inject,
3861               fnText,
3862               argDecl,
3863               last;
3864
3865           if (typeof fn === 'function') {
3866             if (!($inject = fn.$inject)) {
3867               $inject = [];
3868               if (fn.length) {
3869                 if (strictDi) {
3870                   if (!isString(name) || !name) {
3871                     name = fn.name || anonFn(fn);
3872                   }
3873                   throw $injectorMinErr('strictdi',
3874                     '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3875                 }
3876                 fnText = fn.toString().replace(STRIP_COMMENTS, '');
3877                 argDecl = fnText.match(FN_ARGS);
3878                 forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3879                   arg.replace(FN_ARG, function(all, underscore, name) {
3880                     $inject.push(name);
3881                   });
3882                 });
3883               }
3884               fn.$inject = $inject;
3885             }
3886           } else if (isArray(fn)) {
3887             last = fn.length - 1;
3888             assertArgFn(fn[last], 'fn');
3889             $inject = fn.slice(0, last);
3890           } else {
3891             assertArgFn(fn, 'fn', true);
3892           }
3893           return $inject;
3894         }
3895
3896         ///////////////////////////////////////
3897
3898         /**
3899          * @ngdoc service
3900          * @name $injector
3901          *
3902          * @description
3903          *
3904          * `$injector` is used to retrieve object instances as defined by
3905          * {@link auto.$provide provider}, instantiate types, invoke methods,
3906          * and load modules.
3907          *
3908          * The following always holds true:
3909          *
3910          * ```js
3911          *   var $injector = angular.injector();
3912          *   expect($injector.get('$injector')).toBe($injector);
3913          *   expect($injector.invoke(function($injector) {
3914          *     return $injector;
3915          *   })).toBe($injector);
3916          * ```
3917          *
3918          * # Injection Function Annotation
3919          *
3920          * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3921          * following are all valid ways of annotating function with injection arguments and are equivalent.
3922          *
3923          * ```js
3924          *   // inferred (only works if code not minified/obfuscated)
3925          *   $injector.invoke(function(serviceA){});
3926          *
3927          *   // annotated
3928          *   function explicit(serviceA) {};
3929          *   explicit.$inject = ['serviceA'];
3930          *   $injector.invoke(explicit);
3931          *
3932          *   // inline
3933          *   $injector.invoke(['serviceA', function(serviceA){}]);
3934          * ```
3935          *
3936          * ## Inference
3937          *
3938          * In JavaScript calling `toString()` on a function returns the function definition. The definition
3939          * can then be parsed and the function arguments can be extracted. This method of discovering
3940          * annotations is disallowed when the injector is in strict mode.
3941          * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3942          * argument names.
3943          *
3944          * ## `$inject` Annotation
3945          * By adding an `$inject` property onto a function the injection parameters can be specified.
3946          *
3947          * ## Inline
3948          * As an array of injection names, where the last item in the array is the function to call.
3949          */
3950
3951         /**
3952          * @ngdoc method
3953          * @name $injector#get
3954          *
3955          * @description
3956          * Return an instance of the service.
3957          *
3958          * @param {string} name The name of the instance to retrieve.
3959          * @param {string=} caller An optional string to provide the origin of the function call for error messages.
3960          * @return {*} The instance.
3961          */
3962
3963         /**
3964          * @ngdoc method
3965          * @name $injector#invoke
3966          *
3967          * @description
3968          * Invoke the method and supply the method arguments from the `$injector`.
3969          *
3970          * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
3971          *   injected according to the {@link guide/di $inject Annotation} rules.
3972          * @param {Object=} self The `this` for the invoked method.
3973          * @param {Object=} locals Optional object. If preset then any argument names are read from this
3974          *                         object first, before the `$injector` is consulted.
3975          * @returns {*} the value returned by the invoked `fn` function.
3976          */
3977
3978         /**
3979          * @ngdoc method
3980          * @name $injector#has
3981          *
3982          * @description
3983          * Allows the user to query if the particular service exists.
3984          *
3985          * @param {string} name Name of the service to query.
3986          * @returns {boolean} `true` if injector has given service.
3987          */
3988
3989         /**
3990          * @ngdoc method
3991          * @name $injector#instantiate
3992          * @description
3993          * Create a new instance of JS type. The method takes a constructor function, invokes the new
3994          * operator, and supplies all of the arguments to the constructor function as specified by the
3995          * constructor annotation.
3996          *
3997          * @param {Function} Type Annotated constructor function.
3998          * @param {Object=} locals Optional object. If preset then any argument names are read from this
3999          * object first, before the `$injector` is consulted.
4000          * @returns {Object} new instance of `Type`.
4001          */
4002
4003         /**
4004          * @ngdoc method
4005          * @name $injector#annotate
4006          *
4007          * @description
4008          * Returns an array of service names which the function is requesting for injection. This API is
4009          * used by the injector to determine which services need to be injected into the function when the
4010          * function is invoked. There are three ways in which the function can be annotated with the needed
4011          * dependencies.
4012          *
4013          * # Argument names
4014          *
4015          * The simplest form is to extract the dependencies from the arguments of the function. This is done
4016          * by converting the function into a string using `toString()` method and extracting the argument
4017          * names.
4018          * ```js
4019          *   // Given
4020          *   function MyController($scope, $route) {
4021          *     // ...
4022          *   }
4023          *
4024          *   // Then
4025          *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4026          * ```
4027          *
4028          * You can disallow this method by using strict injection mode.
4029          *
4030          * This method does not work with code minification / obfuscation. For this reason the following
4031          * annotation strategies are supported.
4032          *
4033          * # The `$inject` property
4034          *
4035          * If a function has an `$inject` property and its value is an array of strings, then the strings
4036          * represent names of services to be injected into the function.
4037          * ```js
4038          *   // Given
4039          *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
4040          *     // ...
4041          *   }
4042          *   // Define function dependencies
4043          *   MyController['$inject'] = ['$scope', '$route'];
4044          *
4045          *   // Then
4046          *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4047          * ```
4048          *
4049          * # The array notation
4050          *
4051          * It is often desirable to inline Injected functions and that's when setting the `$inject` property
4052          * is very inconvenient. In these situations using the array notation to specify the dependencies in
4053          * a way that survives minification is a better choice:
4054          *
4055          * ```js
4056          *   // We wish to write this (not minification / obfuscation safe)
4057          *   injector.invoke(function($compile, $rootScope) {
4058          *     // ...
4059          *   });
4060          *
4061          *   // We are forced to write break inlining
4062          *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
4063          *     // ...
4064          *   };
4065          *   tmpFn.$inject = ['$compile', '$rootScope'];
4066          *   injector.invoke(tmpFn);
4067          *
4068          *   // To better support inline function the inline annotation is supported
4069          *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
4070          *     // ...
4071          *   }]);
4072          *
4073          *   // Therefore
4074          *   expect(injector.annotate(
4075          *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
4076          *    ).toEqual(['$compile', '$rootScope']);
4077          * ```
4078          *
4079          * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
4080          * be retrieved as described above.
4081          *
4082          * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4083          *
4084          * @returns {Array.<string>} The names of the services which the function requires.
4085          */
4086
4087
4088
4089
4090         /**
4091          * @ngdoc service
4092          * @name $provide
4093          *
4094          * @description
4095          *
4096          * The {@link auto.$provide $provide} service has a number of methods for registering components
4097          * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4098          * {@link angular.Module}.
4099          *
4100          * An Angular **service** is a singleton object created by a **service factory**.  These **service
4101          * factories** are functions which, in turn, are created by a **service provider**.
4102          * The **service providers** are constructor functions. When instantiated they must contain a
4103          * property called `$get`, which holds the **service factory** function.
4104          *
4105          * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4106          * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4107          * function to get the instance of the **service**.
4108          *
4109          * Often services have no configuration options and there is no need to add methods to the service
4110          * provider.  The provider will be no more than a constructor function with a `$get` property. For
4111          * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4112          * services without specifying a provider.
4113          *
4114          * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
4115          *     {@link auto.$injector $injector}
4116          * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
4117          *     providers and services.
4118          * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
4119          *     services, not providers.
4120          * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
4121          *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
4122          *     given factory function.
4123          * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
4124          *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4125          *      a new object using the given constructor function.
4126          *
4127          * See the individual methods for more information and examples.
4128          */
4129
4130         /**
4131          * @ngdoc method
4132          * @name $provide#provider
4133          * @description
4134          *
4135          * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4136          * are constructor functions, whose instances are responsible for "providing" a factory for a
4137          * service.
4138          *
4139          * Service provider names start with the name of the service they provide followed by `Provider`.
4140          * For example, the {@link ng.$log $log} service has a provider called
4141          * {@link ng.$logProvider $logProvider}.
4142          *
4143          * Service provider objects can have additional methods which allow configuration of the provider
4144          * and its service. Importantly, you can configure what kind of service is created by the `$get`
4145          * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4146          * method {@link ng.$logProvider#debugEnabled debugEnabled}
4147          * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4148          * console or not.
4149          *
4150          * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4151                                 'Provider'` key.
4152          * @param {(Object|function())} provider If the provider is:
4153          *
4154          *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4155          *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4156          *   - `Constructor`: a new instance of the provider will be created using
4157          *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4158          *
4159          * @returns {Object} registered provider instance
4160
4161          * @example
4162          *
4163          * The following example shows how to create a simple event tracking service and register it using
4164          * {@link auto.$provide#provider $provide.provider()}.
4165          *
4166          * ```js
4167          *  // Define the eventTracker provider
4168          *  function EventTrackerProvider() {
4169          *    var trackingUrl = '/track';
4170          *
4171          *    // A provider method for configuring where the tracked events should been saved
4172          *    this.setTrackingUrl = function(url) {
4173          *      trackingUrl = url;
4174          *    };
4175          *
4176          *    // The service factory function
4177          *    this.$get = ['$http', function($http) {
4178          *      var trackedEvents = {};
4179          *      return {
4180          *        // Call this to track an event
4181          *        event: function(event) {
4182          *          var count = trackedEvents[event] || 0;
4183          *          count += 1;
4184          *          trackedEvents[event] = count;
4185          *          return count;
4186          *        },
4187          *        // Call this to save the tracked events to the trackingUrl
4188          *        save: function() {
4189          *          $http.post(trackingUrl, trackedEvents);
4190          *        }
4191          *      };
4192          *    }];
4193          *  }
4194          *
4195          *  describe('eventTracker', function() {
4196          *    var postSpy;
4197          *
4198          *    beforeEach(module(function($provide) {
4199          *      // Register the eventTracker provider
4200          *      $provide.provider('eventTracker', EventTrackerProvider);
4201          *    }));
4202          *
4203          *    beforeEach(module(function(eventTrackerProvider) {
4204          *      // Configure eventTracker provider
4205          *      eventTrackerProvider.setTrackingUrl('/custom-track');
4206          *    }));
4207          *
4208          *    it('tracks events', inject(function(eventTracker) {
4209          *      expect(eventTracker.event('login')).toEqual(1);
4210          *      expect(eventTracker.event('login')).toEqual(2);
4211          *    }));
4212          *
4213          *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4214          *      postSpy = spyOn($http, 'post');
4215          *      eventTracker.event('login');
4216          *      eventTracker.save();
4217          *      expect(postSpy).toHaveBeenCalled();
4218          *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4219          *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4220          *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4221          *    }));
4222          *  });
4223          * ```
4224          */
4225
4226         /**
4227          * @ngdoc method
4228          * @name $provide#factory
4229          * @description
4230          *
4231          * Register a **service factory**, which will be called to return the service instance.
4232          * This is short for registering a service where its provider consists of only a `$get` property,
4233          * which is the given service factory function.
4234          * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4235          * configure your service in a provider.
4236          *
4237          * @param {string} name The name of the instance.
4238          * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4239          *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4240          * @returns {Object} registered provider instance
4241          *
4242          * @example
4243          * Here is an example of registering a service
4244          * ```js
4245          *   $provide.factory('ping', ['$http', function($http) {
4246          *     return function ping() {
4247          *       return $http.send('/ping');
4248          *     };
4249          *   }]);
4250          * ```
4251          * You would then inject and use this service like this:
4252          * ```js
4253          *   someModule.controller('Ctrl', ['ping', function(ping) {
4254          *     ping();
4255          *   }]);
4256          * ```
4257          */
4258
4259
4260         /**
4261          * @ngdoc method
4262          * @name $provide#service
4263          * @description
4264          *
4265          * Register a **service constructor**, which will be invoked with `new` to create the service
4266          * instance.
4267          * This is short for registering a service where its provider's `$get` property is the service
4268          * constructor function that will be used to instantiate the service instance.
4269          *
4270          * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4271          * as a type/class.
4272          *
4273          * @param {string} name The name of the instance.
4274          * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4275          *     that will be instantiated.
4276          * @returns {Object} registered provider instance
4277          *
4278          * @example
4279          * Here is an example of registering a service using
4280          * {@link auto.$provide#service $provide.service(class)}.
4281          * ```js
4282          *   var Ping = function($http) {
4283          *     this.$http = $http;
4284          *   };
4285          *
4286          *   Ping.$inject = ['$http'];
4287          *
4288          *   Ping.prototype.send = function() {
4289          *     return this.$http.get('/ping');
4290          *   };
4291          *   $provide.service('ping', Ping);
4292          * ```
4293          * You would then inject and use this service like this:
4294          * ```js
4295          *   someModule.controller('Ctrl', ['ping', function(ping) {
4296          *     ping.send();
4297          *   }]);
4298          * ```
4299          */
4300
4301
4302         /**
4303          * @ngdoc method
4304          * @name $provide#value
4305          * @description
4306          *
4307          * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4308          * number, an array, an object or a function.  This is short for registering a service where its
4309          * provider's `$get` property is a factory function that takes no arguments and returns the **value
4310          * service**.
4311          *
4312          * Value services are similar to constant services, except that they cannot be injected into a
4313          * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4314          * an Angular
4315          * {@link auto.$provide#decorator decorator}.
4316          *
4317          * @param {string} name The name of the instance.
4318          * @param {*} value The value.
4319          * @returns {Object} registered provider instance
4320          *
4321          * @example
4322          * Here are some examples of creating value services.
4323          * ```js
4324          *   $provide.value('ADMIN_USER', 'admin');
4325          *
4326          *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4327          *
4328          *   $provide.value('halfOf', function(value) {
4329          *     return value / 2;
4330          *   });
4331          * ```
4332          */
4333
4334
4335         /**
4336          * @ngdoc method
4337          * @name $provide#constant
4338          * @description
4339          *
4340          * Register a **constant service**, such as a string, a number, an array, an object or a function,
4341          * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
4342          * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4343          * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4344          *
4345          * @param {string} name The name of the constant.
4346          * @param {*} value The constant value.
4347          * @returns {Object} registered instance
4348          *
4349          * @example
4350          * Here a some examples of creating constants:
4351          * ```js
4352          *   $provide.constant('SHARD_HEIGHT', 306);
4353          *
4354          *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4355          *
4356          *   $provide.constant('double', function(value) {
4357          *     return value * 2;
4358          *   });
4359          * ```
4360          */
4361
4362
4363         /**
4364          * @ngdoc method
4365          * @name $provide#decorator
4366          * @description
4367          *
4368          * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
4369          * intercepts the creation of a service, allowing it to override or modify the behaviour of the
4370          * service. The object returned by the decorator may be the original service, or a new service
4371          * object which replaces or wraps and delegates to the original service.
4372          *
4373          * @param {string} name The name of the service to decorate.
4374          * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4375          *    instantiated and should return the decorated service instance. The function is called using
4376          *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4377          *    Local injection arguments:
4378          *
4379          *    * `$delegate` - The original service instance, which can be monkey patched, configured,
4380          *      decorated or delegated to.
4381          *
4382          * @example
4383          * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4384          * calls to {@link ng.$log#error $log.warn()}.
4385          * ```js
4386          *   $provide.decorator('$log', ['$delegate', function($delegate) {
4387          *     $delegate.warn = $delegate.error;
4388          *     return $delegate;
4389          *   }]);
4390          * ```
4391          */
4392
4393
4394         function createInjector(modulesToLoad, strictDi) {
4395           strictDi = (strictDi === true);
4396           var INSTANTIATING = {},
4397               providerSuffix = 'Provider',
4398               path = [],
4399               loadedModules = new HashMap([], true),
4400               providerCache = {
4401                 $provide: {
4402                     provider: supportObject(provider),
4403                     factory: supportObject(factory),
4404                     service: supportObject(service),
4405                     value: supportObject(value),
4406                     constant: supportObject(constant),
4407                     decorator: decorator
4408                   }
4409               },
4410               providerInjector = (providerCache.$injector =
4411                   createInternalInjector(providerCache, function(serviceName, caller) {
4412                     if (angular.isString(caller)) {
4413                       path.push(caller);
4414                     }
4415                     throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4416                   })),
4417               instanceCache = {},
4418               instanceInjector = (instanceCache.$injector =
4419                   createInternalInjector(instanceCache, function(serviceName, caller) {
4420                     var provider = providerInjector.get(serviceName + providerSuffix, caller);
4421                     return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4422                   }));
4423
4424
4425           forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
4426
4427           return instanceInjector;
4428
4429           ////////////////////////////////////
4430           // $provider
4431           ////////////////////////////////////
4432
4433           function supportObject(delegate) {
4434             return function(key, value) {
4435               if (isObject(key)) {
4436                 forEach(key, reverseParams(delegate));
4437               } else {
4438                 return delegate(key, value);
4439               }
4440             };
4441           }
4442
4443           function provider(name, provider_) {
4444             assertNotHasOwnProperty(name, 'service');
4445             if (isFunction(provider_) || isArray(provider_)) {
4446               provider_ = providerInjector.instantiate(provider_);
4447             }
4448             if (!provider_.$get) {
4449               throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4450             }
4451             return providerCache[name + providerSuffix] = provider_;
4452           }
4453
4454           function enforceReturnValue(name, factory) {
4455             return function enforcedReturnValue() {
4456               var result = instanceInjector.invoke(factory, this);
4457               if (isUndefined(result)) {
4458                 throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4459               }
4460               return result;
4461             };
4462           }
4463
4464           function factory(name, factoryFn, enforce) {
4465             return provider(name, {
4466               $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4467             });
4468           }
4469
4470           function service(name, constructor) {
4471             return factory(name, ['$injector', function($injector) {
4472               return $injector.instantiate(constructor);
4473             }]);
4474           }
4475
4476           function value(name, val) { return factory(name, valueFn(val), false); }
4477
4478           function constant(name, value) {
4479             assertNotHasOwnProperty(name, 'constant');
4480             providerCache[name] = value;
4481             instanceCache[name] = value;
4482           }
4483
4484           function decorator(serviceName, decorFn) {
4485             var origProvider = providerInjector.get(serviceName + providerSuffix),
4486                 orig$get = origProvider.$get;
4487
4488             origProvider.$get = function() {
4489               var origInstance = instanceInjector.invoke(orig$get, origProvider);
4490               return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4491             };
4492           }
4493
4494           ////////////////////////////////////
4495           // Module Loading
4496           ////////////////////////////////////
4497           function loadModules(modulesToLoad) {
4498             assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
4499             var runBlocks = [], moduleFn;
4500             forEach(modulesToLoad, function(module) {
4501               if (loadedModules.get(module)) return;
4502               loadedModules.put(module, true);
4503
4504               function runInvokeQueue(queue) {
4505                 var i, ii;
4506                 for (i = 0, ii = queue.length; i < ii; i++) {
4507                   var invokeArgs = queue[i],
4508                       provider = providerInjector.get(invokeArgs[0]);
4509
4510                   provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4511                 }
4512               }
4513
4514               try {
4515                 if (isString(module)) {
4516                   moduleFn = angularModule(module);
4517                   runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4518                   runInvokeQueue(moduleFn._invokeQueue);
4519                   runInvokeQueue(moduleFn._configBlocks);
4520                 } else if (isFunction(module)) {
4521                     runBlocks.push(providerInjector.invoke(module));
4522                 } else if (isArray(module)) {
4523                     runBlocks.push(providerInjector.invoke(module));
4524                 } else {
4525                   assertArgFn(module, 'module');
4526                 }
4527               } catch (e) {
4528                 if (isArray(module)) {
4529                   module = module[module.length - 1];
4530                 }
4531                 if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4532                   // Safari & FF's stack traces don't contain error.message content
4533                   // unlike those of Chrome and IE
4534                   // So if stack doesn't contain message, we create a new string that contains both.
4535                   // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4536                   /* jshint -W022 */
4537                   e = e.message + '\n' + e.stack;
4538                 }
4539                 throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4540                           module, e.stack || e.message || e);
4541               }
4542             });
4543             return runBlocks;
4544           }
4545
4546           ////////////////////////////////////
4547           // internal Injector
4548           ////////////////////////////////////
4549
4550           function createInternalInjector(cache, factory) {
4551
4552             function getService(serviceName, caller) {
4553               if (cache.hasOwnProperty(serviceName)) {
4554                 if (cache[serviceName] === INSTANTIATING) {
4555                   throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4556                             serviceName + ' <- ' + path.join(' <- '));
4557                 }
4558                 return cache[serviceName];
4559               } else {
4560                 try {
4561                   path.unshift(serviceName);
4562                   cache[serviceName] = INSTANTIATING;
4563                   return cache[serviceName] = factory(serviceName, caller);
4564                 } catch (err) {
4565                   if (cache[serviceName] === INSTANTIATING) {
4566                     delete cache[serviceName];
4567                   }
4568                   throw err;
4569                 } finally {
4570                   path.shift();
4571                 }
4572               }
4573             }
4574
4575             function invoke(fn, self, locals, serviceName) {
4576               if (typeof locals === 'string') {
4577                 serviceName = locals;
4578                 locals = null;
4579               }
4580
4581               var args = [],
4582                   $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4583                   length, i,
4584                   key;
4585
4586               for (i = 0, length = $inject.length; i < length; i++) {
4587                 key = $inject[i];
4588                 if (typeof key !== 'string') {
4589                   throw $injectorMinErr('itkn',
4590                           'Incorrect injection token! Expected service name as string, got {0}', key);
4591                 }
4592                 args.push(
4593                   locals && locals.hasOwnProperty(key)
4594                   ? locals[key]
4595                   : getService(key, serviceName)
4596                 );
4597               }
4598               if (isArray(fn)) {
4599                 fn = fn[length];
4600               }
4601
4602               // http://jsperf.com/angularjs-invoke-apply-vs-switch
4603               // #5388
4604               return fn.apply(self, args);
4605             }
4606
4607             function instantiate(Type, locals, serviceName) {
4608               // Check if Type is annotated and use just the given function at n-1 as parameter
4609               // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4610               // Object creation: http://jsperf.com/create-constructor/2
4611               var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4612               var returnedValue = invoke(Type, instance, locals, serviceName);
4613
4614               return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4615             }
4616
4617             return {
4618               invoke: invoke,
4619               instantiate: instantiate,
4620               get: getService,
4621               annotate: createInjector.$$annotate,
4622               has: function(name) {
4623                 return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4624               }
4625             };
4626           }
4627         }
4628
4629         createInjector.$$annotate = annotate;
4630
4631         /**
4632          * @ngdoc provider
4633          * @name $anchorScrollProvider
4634          *
4635          * @description
4636          * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4637          * {@link ng.$location#hash $location.hash()} changes.
4638          */
4639         function $AnchorScrollProvider() {
4640
4641           var autoScrollingEnabled = true;
4642
4643           /**
4644            * @ngdoc method
4645            * @name $anchorScrollProvider#disableAutoScrolling
4646            *
4647            * @description
4648            * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4649            * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4650            * Use this method to disable automatic scrolling.
4651            *
4652            * If automatic scrolling is disabled, one must explicitly call
4653            * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4654            * current hash.
4655            */
4656           this.disableAutoScrolling = function() {
4657             autoScrollingEnabled = false;
4658           };
4659
4660           /**
4661            * @ngdoc service
4662            * @name $anchorScroll
4663            * @kind function
4664            * @requires $window
4665            * @requires $location
4666            * @requires $rootScope
4667            *
4668            * @description
4669            * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4670            * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4671            * in the
4672            * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
4673            *
4674            * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4675            * match any anchor whenever it changes. This can be disabled by calling
4676            * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4677            *
4678            * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4679            * vertical scroll-offset (either fixed or dynamic).
4680            *
4681            * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4682            *                       {@link ng.$location#hash $location.hash()} will be used.
4683            *
4684            * @property {(number|function|jqLite)} yOffset
4685            * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4686            * positioned elements at the top of the page, such as navbars, headers etc.
4687            *
4688            * `yOffset` can be specified in various ways:
4689            * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4690            * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4691            *   a number representing the offset (in pixels).<br /><br />
4692            * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4693            *   the top of the page to the element's bottom will be used as offset.<br />
4694            *   **Note**: The element will be taken into account only as long as its `position` is set to
4695            *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4696            *   their height and/or positioning according to the viewport's size.
4697            *
4698            * <br />
4699            * <div class="alert alert-warning">
4700            * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4701            * not some child element.
4702            * </div>
4703            *
4704            * @example
4705              <example module="anchorScrollExample">
4706                <file name="index.html">
4707                  <div id="scrollArea" ng-controller="ScrollController">
4708                    <a ng-click="gotoBottom()">Go to bottom</a>
4709                    <a id="bottom"></a> You're at the bottom!
4710                  </div>
4711                </file>
4712                <file name="script.js">
4713                  angular.module('anchorScrollExample', [])
4714                    .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4715                      function ($scope, $location, $anchorScroll) {
4716                        $scope.gotoBottom = function() {
4717                          // set the location.hash to the id of
4718                          // the element you wish to scroll to.
4719                          $location.hash('bottom');
4720
4721                          // call $anchorScroll()
4722                          $anchorScroll();
4723                        };
4724                      }]);
4725                </file>
4726                <file name="style.css">
4727                  #scrollArea {
4728                    height: 280px;
4729                    overflow: auto;
4730                  }
4731
4732                  #bottom {
4733                    display: block;
4734                    margin-top: 2000px;
4735                  }
4736                </file>
4737              </example>
4738            *
4739            * <hr />
4740            * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4741            * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4742            *
4743            * @example
4744              <example module="anchorScrollOffsetExample">
4745                <file name="index.html">
4746                  <div class="fixed-header" ng-controller="headerCtrl">
4747                    <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4748                      Go to anchor {{x}}
4749                    </a>
4750                  </div>
4751                  <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4752                    Anchor {{x}} of 5
4753                  </div>
4754                </file>
4755                <file name="script.js">
4756                  angular.module('anchorScrollOffsetExample', [])
4757                    .run(['$anchorScroll', function($anchorScroll) {
4758                      $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4759                    }])
4760                    .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4761                      function ($anchorScroll, $location, $scope) {
4762                        $scope.gotoAnchor = function(x) {
4763                          var newHash = 'anchor' + x;
4764                          if ($location.hash() !== newHash) {
4765                            // set the $location.hash to `newHash` and
4766                            // $anchorScroll will automatically scroll to it
4767                            $location.hash('anchor' + x);
4768                          } else {
4769                            // call $anchorScroll() explicitly,
4770                            // since $location.hash hasn't changed
4771                            $anchorScroll();
4772                          }
4773                        };
4774                      }
4775                    ]);
4776                </file>
4777                <file name="style.css">
4778                  body {
4779                    padding-top: 50px;
4780                  }
4781
4782                  .anchor {
4783                    border: 2px dashed DarkOrchid;
4784                    padding: 10px 10px 200px 10px;
4785                  }
4786
4787                  .fixed-header {
4788                    background-color: rgba(0, 0, 0, 0.2);
4789                    height: 50px;
4790                    position: fixed;
4791                    top: 0; left: 0; right: 0;
4792                  }
4793
4794                  .fixed-header > a {
4795                    display: inline-block;
4796                    margin: 5px 15px;
4797                  }
4798                </file>
4799              </example>
4800            */
4801           this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4802             var document = $window.document;
4803
4804             // Helper function to get first anchor from a NodeList
4805             // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4806             //  and working in all supported browsers.)
4807             function getFirstAnchor(list) {
4808               var result = null;
4809               Array.prototype.some.call(list, function(element) {
4810                 if (nodeName_(element) === 'a') {
4811                   result = element;
4812                   return true;
4813                 }
4814               });
4815               return result;
4816             }
4817
4818             function getYOffset() {
4819
4820               var offset = scroll.yOffset;
4821
4822               if (isFunction(offset)) {
4823                 offset = offset();
4824               } else if (isElement(offset)) {
4825                 var elem = offset[0];
4826                 var style = $window.getComputedStyle(elem);
4827                 if (style.position !== 'fixed') {
4828                   offset = 0;
4829                 } else {
4830                   offset = elem.getBoundingClientRect().bottom;
4831                 }
4832               } else if (!isNumber(offset)) {
4833                 offset = 0;
4834               }
4835
4836               return offset;
4837             }
4838
4839             function scrollTo(elem) {
4840               if (elem) {
4841                 elem.scrollIntoView();
4842
4843                 var offset = getYOffset();
4844
4845                 if (offset) {
4846                   // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4847                   // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4848                   // top of the viewport.
4849                   //
4850                   // IF the number of pixels from the top of `elem` to the end of the page's content is less
4851                   // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4852                   // way down the page.
4853                   //
4854                   // This is often the case for elements near the bottom of the page.
4855                   //
4856                   // In such cases we do not need to scroll the whole `offset` up, just the difference between
4857                   // the top of the element and the offset, which is enough to align the top of `elem` at the
4858                   // desired position.
4859                   var elemTop = elem.getBoundingClientRect().top;
4860                   $window.scrollBy(0, elemTop - offset);
4861                 }
4862               } else {
4863                 $window.scrollTo(0, 0);
4864               }
4865             }
4866
4867             function scroll(hash) {
4868               hash = isString(hash) ? hash : $location.hash();
4869               var elm;
4870
4871               // empty hash, scroll to the top of the page
4872               if (!hash) scrollTo(null);
4873
4874               // element with given id
4875               else if ((elm = document.getElementById(hash))) scrollTo(elm);
4876
4877               // first anchor with given name :-D
4878               else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4879
4880               // no element and hash == 'top', scroll to the top of the page
4881               else if (hash === 'top') scrollTo(null);
4882             }
4883
4884             // does not scroll when user clicks on anchor link that is currently on
4885             // (no url change, no $location.hash() change), browser native does scroll
4886             if (autoScrollingEnabled) {
4887               $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4888                 function autoScrollWatchAction(newVal, oldVal) {
4889                   // skip the initial scroll if $location.hash is empty
4890                   if (newVal === oldVal && newVal === '') return;
4891
4892                   jqLiteDocumentLoaded(function() {
4893                     $rootScope.$evalAsync(scroll);
4894                   });
4895                 });
4896             }
4897
4898             return scroll;
4899           }];
4900         }
4901
4902         var $animateMinErr = minErr('$animate');
4903         var ELEMENT_NODE = 1;
4904         var NG_ANIMATE_CLASSNAME = 'ng-animate';
4905
4906         function mergeClasses(a,b) {
4907           if (!a && !b) return '';
4908           if (!a) return b;
4909           if (!b) return a;
4910           if (isArray(a)) a = a.join(' ');
4911           if (isArray(b)) b = b.join(' ');
4912           return a + ' ' + b;
4913         }
4914
4915         function extractElementNode(element) {
4916           for (var i = 0; i < element.length; i++) {
4917             var elm = element[i];
4918             if (elm.nodeType === ELEMENT_NODE) {
4919               return elm;
4920             }
4921           }
4922         }
4923
4924         function splitClasses(classes) {
4925           if (isString(classes)) {
4926             classes = classes.split(' ');
4927           }
4928
4929           // Use createMap() to prevent class assumptions involving property names in
4930           // Object.prototype
4931           var obj = createMap();
4932           forEach(classes, function(klass) {
4933             // sometimes the split leaves empty string values
4934             // incase extra spaces were applied to the options
4935             if (klass.length) {
4936               obj[klass] = true;
4937             }
4938           });
4939           return obj;
4940         }
4941
4942         // if any other type of options value besides an Object value is
4943         // passed into the $animate.method() animation then this helper code
4944         // will be run which will ignore it. While this patch is not the
4945         // greatest solution to this, a lot of existing plugins depend on
4946         // $animate to either call the callback (< 1.2) or return a promise
4947         // that can be changed. This helper function ensures that the options
4948         // are wiped clean incase a callback function is provided.
4949         function prepareAnimateOptions(options) {
4950           return isObject(options)
4951               ? options
4952               : {};
4953         }
4954
4955         var $$CoreAnimateRunnerProvider = function() {
4956           this.$get = ['$q', '$$rAF', function($q, $$rAF) {
4957             function AnimateRunner() {}
4958             AnimateRunner.all = noop;
4959             AnimateRunner.chain = noop;
4960             AnimateRunner.prototype = {
4961               end: noop,
4962               cancel: noop,
4963               resume: noop,
4964               pause: noop,
4965               complete: noop,
4966               then: function(pass, fail) {
4967                 return $q(function(resolve) {
4968                   $$rAF(function() {
4969                     resolve();
4970                   });
4971                 }).then(pass, fail);
4972               }
4973             };
4974             return AnimateRunner;
4975           }];
4976         };
4977
4978         // this is prefixed with Core since it conflicts with
4979         // the animateQueueProvider defined in ngAnimate/animateQueue.js
4980         var $$CoreAnimateQueueProvider = function() {
4981           var postDigestQueue = new HashMap();
4982           var postDigestElements = [];
4983
4984           this.$get = ['$$AnimateRunner', '$rootScope',
4985                function($$AnimateRunner,   $rootScope) {
4986             return {
4987               enabled: noop,
4988               on: noop,
4989               off: noop,
4990               pin: noop,
4991
4992               push: function(element, event, options, domOperation) {
4993                 domOperation        && domOperation();
4994
4995                 options = options || {};
4996                 options.from        && element.css(options.from);
4997                 options.to          && element.css(options.to);
4998
4999                 if (options.addClass || options.removeClass) {
5000                   addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
5001                 }
5002
5003                 return new $$AnimateRunner(); // jshint ignore:line
5004               }
5005             };
5006
5007
5008             function updateData(data, classes, value) {
5009               var changed = false;
5010               if (classes) {
5011                 classes = isString(classes) ? classes.split(' ') :
5012                           isArray(classes) ? classes : [];
5013                 forEach(classes, function(className) {
5014                   if (className) {
5015                     changed = true;
5016                     data[className] = value;
5017                   }
5018                 });
5019               }
5020               return changed;
5021             }
5022
5023             function handleCSSClassChanges() {
5024               forEach(postDigestElements, function(element) {
5025                 var data = postDigestQueue.get(element);
5026                 if (data) {
5027                   var existing = splitClasses(element.attr('class'));
5028                   var toAdd = '';
5029                   var toRemove = '';
5030                   forEach(data, function(status, className) {
5031                     var hasClass = !!existing[className];
5032                     if (status !== hasClass) {
5033                       if (status) {
5034                         toAdd += (toAdd.length ? ' ' : '') + className;
5035                       } else {
5036                         toRemove += (toRemove.length ? ' ' : '') + className;
5037                       }
5038                     }
5039                   });
5040
5041                   forEach(element, function(elm) {
5042                     toAdd    && jqLiteAddClass(elm, toAdd);
5043                     toRemove && jqLiteRemoveClass(elm, toRemove);
5044                   });
5045                   postDigestQueue.remove(element);
5046                 }
5047               });
5048               postDigestElements.length = 0;
5049             }
5050
5051
5052             function addRemoveClassesPostDigest(element, add, remove) {
5053               var data = postDigestQueue.get(element) || {};
5054
5055               var classesAdded = updateData(data, add, true);
5056               var classesRemoved = updateData(data, remove, false);
5057
5058               if (classesAdded || classesRemoved) {
5059
5060                 postDigestQueue.put(element, data);
5061                 postDigestElements.push(element);
5062
5063                 if (postDigestElements.length === 1) {
5064                   $rootScope.$$postDigest(handleCSSClassChanges);
5065                 }
5066               }
5067             }
5068           }];
5069         };
5070
5071         /**
5072          * @ngdoc provider
5073          * @name $animateProvider
5074          *
5075          * @description
5076          * Default implementation of $animate that doesn't perform any animations, instead just
5077          * synchronously performs DOM updates and resolves the returned runner promise.
5078          *
5079          * In order to enable animations the `ngAnimate` module has to be loaded.
5080          *
5081          * To see the functional implementation check out `src/ngAnimate/animate.js`.
5082          */
5083         var $AnimateProvider = ['$provide', function($provide) {
5084           var provider = this;
5085
5086           this.$$registeredAnimations = Object.create(null);
5087
5088            /**
5089            * @ngdoc method
5090            * @name $animateProvider#register
5091            *
5092            * @description
5093            * Registers a new injectable animation factory function. The factory function produces the
5094            * animation object which contains callback functions for each event that is expected to be
5095            * animated.
5096            *
5097            *   * `eventFn`: `function(element, ... , doneFunction, options)`
5098            *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
5099            *   on the type of animation additional arguments will be injected into the animation function. The
5100            *   list below explains the function signatures for the different animation methods:
5101            *
5102            *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
5103            *   - addClass: function(element, addedClasses, doneFunction, options)
5104            *   - removeClass: function(element, removedClasses, doneFunction, options)
5105            *   - enter, leave, move: function(element, doneFunction, options)
5106            *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
5107            *
5108            *   Make sure to trigger the `doneFunction` once the animation is fully complete.
5109            *
5110            * ```js
5111            *   return {
5112            *     //enter, leave, move signature
5113            *     eventFn : function(element, done, options) {
5114            *       //code to run the animation
5115            *       //once complete, then run done()
5116            *       return function endFunction(wasCancelled) {
5117            *         //code to cancel the animation
5118            *       }
5119            *     }
5120            *   }
5121            * ```
5122            *
5123            * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
5124            * @param {Function} factory The factory function that will be executed to return the animation
5125            *                           object.
5126            */
5127           this.register = function(name, factory) {
5128             if (name && name.charAt(0) !== '.') {
5129               throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
5130             }
5131
5132             var key = name + '-animation';
5133             provider.$$registeredAnimations[name.substr(1)] = key;
5134             $provide.factory(key, factory);
5135           };
5136
5137           /**
5138            * @ngdoc method
5139            * @name $animateProvider#classNameFilter
5140            *
5141            * @description
5142            * Sets and/or returns the CSS class regular expression that is checked when performing
5143            * an animation. Upon bootstrap the classNameFilter value is not set at all and will
5144            * therefore enable $animate to attempt to perform an animation on any element that is triggered.
5145            * When setting the `classNameFilter` value, animations will only be performed on elements
5146            * that successfully match the filter expression. This in turn can boost performance
5147            * for low-powered devices as well as applications containing a lot of structural operations.
5148            * @param {RegExp=} expression The className expression which will be checked against all animations
5149            * @return {RegExp} The current CSS className expression value. If null then there is no expression value
5150            */
5151           this.classNameFilter = function(expression) {
5152             if (arguments.length === 1) {
5153               this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
5154               if (this.$$classNameFilter) {
5155                 var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
5156                 if (reservedRegex.test(this.$$classNameFilter.toString())) {
5157                   throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
5158
5159                 }
5160               }
5161             }
5162             return this.$$classNameFilter;
5163           };
5164
5165           this.$get = ['$$animateQueue', function($$animateQueue) {
5166             function domInsert(element, parentElement, afterElement) {
5167               // if for some reason the previous element was removed
5168               // from the dom sometime before this code runs then let's
5169               // just stick to using the parent element as the anchor
5170               if (afterElement) {
5171                 var afterNode = extractElementNode(afterElement);
5172                 if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
5173                   afterElement = null;
5174                 }
5175               }
5176               afterElement ? afterElement.after(element) : parentElement.prepend(element);
5177             }
5178
5179             /**
5180              * @ngdoc service
5181              * @name $animate
5182              * @description The $animate service exposes a series of DOM utility methods that provide support
5183              * for animation hooks. The default behavior is the application of DOM operations, however,
5184              * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5185              * to ensure that animation runs with the triggered DOM operation.
5186              *
5187              * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5188              * included and only when it is active then the animation hooks that `$animate` triggers will be
5189              * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5190              * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5191              * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5192              *
5193              * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5194              *
5195              * To learn more about enabling animation support, click here to visit the
5196              * {@link ngAnimate ngAnimate module page}.
5197              */
5198             return {
5199               // we don't call it directly since non-existant arguments may
5200               // be interpreted as null within the sub enabled function
5201
5202               /**
5203                *
5204                * @ngdoc method
5205                * @name $animate#on
5206                * @kind function
5207                * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5208                *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5209                *    is fired with the following params:
5210                *
5211                * ```js
5212                * $animate.on('enter', container,
5213                *    function callback(element, phase) {
5214                *      // cool we detected an enter animation within the container
5215                *    }
5216                * );
5217                * ```
5218                *
5219                * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5220                * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5221                *     as well as among its children
5222                * @param {Function} callback the callback function that will be fired when the listener is triggered
5223                *
5224                * The arguments present in the callback function are:
5225                * * `element` - The captured DOM element that the animation was fired on.
5226                * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5227                */
5228               on: $$animateQueue.on,
5229
5230               /**
5231                *
5232                * @ngdoc method
5233                * @name $animate#off
5234                * @kind function
5235                * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5236                * can be used in three different ways depending on the arguments:
5237                *
5238                * ```js
5239                * // remove all the animation event listeners listening for `enter`
5240                * $animate.off('enter');
5241                *
5242                * // remove all the animation event listeners listening for `enter` on the given element and its children
5243                * $animate.off('enter', container);
5244                *
5245                * // remove the event listener function provided by `listenerFn` that is set
5246                * // to listen for `enter` on the given `element` as well as its children
5247                * $animate.off('enter', container, callback);
5248                * ```
5249                *
5250                * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
5251                * @param {DOMElement=} container the container element the event listener was placed on
5252                * @param {Function=} callback the callback function that was registered as the listener
5253                */
5254               off: $$animateQueue.off,
5255
5256               /**
5257                * @ngdoc method
5258                * @name $animate#pin
5259                * @kind function
5260                * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5261                *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
5262                *    element despite being outside the realm of the application or within another application. Say for example if the application
5263                *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5264                *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5265                *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5266                *
5267                *    Note that this feature is only active when the `ngAnimate` module is used.
5268                *
5269                * @param {DOMElement} element the external element that will be pinned
5270                * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5271                */
5272               pin: $$animateQueue.pin,
5273
5274               /**
5275                *
5276                * @ngdoc method
5277                * @name $animate#enabled
5278                * @kind function
5279                * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5280                * function can be called in four ways:
5281                *
5282                * ```js
5283                * // returns true or false
5284                * $animate.enabled();
5285                *
5286                * // changes the enabled state for all animations
5287                * $animate.enabled(false);
5288                * $animate.enabled(true);
5289                *
5290                * // returns true or false if animations are enabled for an element
5291                * $animate.enabled(element);
5292                *
5293                * // changes the enabled state for an element and its children
5294                * $animate.enabled(element, true);
5295                * $animate.enabled(element, false);
5296                * ```
5297                *
5298                * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5299                * @param {boolean=} enabled whether or not the animations will be enabled for the element
5300                *
5301                * @return {boolean} whether or not animations are enabled
5302                */
5303               enabled: $$animateQueue.enabled,
5304
5305               /**
5306                * @ngdoc method
5307                * @name $animate#cancel
5308                * @kind function
5309                * @description Cancels the provided animation.
5310                *
5311                * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
5312                */
5313               cancel: function(runner) {
5314                 runner.end && runner.end();
5315               },
5316
5317               /**
5318                *
5319                * @ngdoc method
5320                * @name $animate#enter
5321                * @kind function
5322                * @description Inserts the element into the DOM either after the `after` element (if provided) or
5323                *   as the first child within the `parent` element and then triggers an animation.
5324                *   A promise is returned that will be resolved during the next digest once the animation
5325                *   has completed.
5326                *
5327                * @param {DOMElement} element the element which will be inserted into the DOM
5328                * @param {DOMElement} parent the parent element which will append the element as
5329                *   a child (so long as the after element is not present)
5330                * @param {DOMElement=} after the sibling element after which the element will be appended
5331                * @param {object=} options an optional collection of options/styles that will be applied to the element
5332                *
5333                * @return {Promise} the animation callback promise
5334                */
5335               enter: function(element, parent, after, options) {
5336                 parent = parent && jqLite(parent);
5337                 after = after && jqLite(after);
5338                 parent = parent || after.parent();
5339                 domInsert(element, parent, after);
5340                 return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
5341               },
5342
5343               /**
5344                *
5345                * @ngdoc method
5346                * @name $animate#move
5347                * @kind function
5348                * @description Inserts (moves) the element into its new position in the DOM either after
5349                *   the `after` element (if provided) or as the first child within the `parent` element
5350                *   and then triggers an animation. A promise is returned that will be resolved
5351                *   during the next digest once the animation has completed.
5352                *
5353                * @param {DOMElement} element the element which will be moved into the new DOM position
5354                * @param {DOMElement} parent the parent element which will append the element as
5355                *   a child (so long as the after element is not present)
5356                * @param {DOMElement=} after the sibling element after which the element will be appended
5357                * @param {object=} options an optional collection of options/styles that will be applied to the element
5358                *
5359                * @return {Promise} the animation callback promise
5360                */
5361               move: function(element, parent, after, options) {
5362                 parent = parent && jqLite(parent);
5363                 after = after && jqLite(after);
5364                 parent = parent || after.parent();
5365                 domInsert(element, parent, after);
5366                 return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
5367               },
5368
5369               /**
5370                * @ngdoc method
5371                * @name $animate#leave
5372                * @kind function
5373                * @description Triggers an animation and then removes the element from the DOM.
5374                * When the function is called a promise is returned that will be resolved during the next
5375                * digest once the animation has completed.
5376                *
5377                * @param {DOMElement} element the element which will be removed from the DOM
5378                * @param {object=} options an optional collection of options/styles that will be applied to the element
5379                *
5380                * @return {Promise} the animation callback promise
5381                */
5382               leave: function(element, options) {
5383                 return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
5384                   element.remove();
5385                 });
5386               },
5387
5388               /**
5389                * @ngdoc method
5390                * @name $animate#addClass
5391                * @kind function
5392                *
5393                * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
5394                *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
5395                *   animation if element already contains the CSS class or if the class is removed at a later step.
5396                *   Note that class-based animations are treated differently compared to structural animations
5397                *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5398                *   depending if CSS or JavaScript animations are used.
5399                *
5400                * @param {DOMElement} element the element which the CSS classes will be applied to
5401                * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
5402                * @param {object=} options an optional collection of options/styles that will be applied to the element
5403                *
5404                * @return {Promise} the animation callback promise
5405                */
5406               addClass: function(element, className, options) {
5407                 options = prepareAnimateOptions(options);
5408                 options.addClass = mergeClasses(options.addclass, className);
5409                 return $$animateQueue.push(element, 'addClass', options);
5410               },
5411
5412               /**
5413                * @ngdoc method
5414                * @name $animate#removeClass
5415                * @kind function
5416                *
5417                * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
5418                *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
5419                *   animation if element does not contain the CSS class or if the class is added at a later step.
5420                *   Note that class-based animations are treated differently compared to structural animations
5421                *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5422                *   depending if CSS or JavaScript animations are used.
5423                *
5424                * @param {DOMElement} element the element which the CSS classes will be applied to
5425                * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
5426                * @param {object=} options an optional collection of options/styles that will be applied to the element
5427                *
5428                * @return {Promise} the animation callback promise
5429                */
5430               removeClass: function(element, className, options) {
5431                 options = prepareAnimateOptions(options);
5432                 options.removeClass = mergeClasses(options.removeClass, className);
5433                 return $$animateQueue.push(element, 'removeClass', options);
5434               },
5435
5436               /**
5437                * @ngdoc method
5438                * @name $animate#setClass
5439                * @kind function
5440                *
5441                * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
5442                *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
5443                *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
5444                *    passed. Note that class-based animations are treated differently compared to structural animations
5445                *    (like enter, move and leave) since the CSS classes may be added/removed at different points
5446                *    depending if CSS or JavaScript animations are used.
5447                *
5448                * @param {DOMElement} element the element which the CSS classes will be applied to
5449                * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
5450                * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
5451                * @param {object=} options an optional collection of options/styles that will be applied to the element
5452                *
5453                * @return {Promise} the animation callback promise
5454                */
5455               setClass: function(element, add, remove, options) {
5456                 options = prepareAnimateOptions(options);
5457                 options.addClass = mergeClasses(options.addClass, add);
5458                 options.removeClass = mergeClasses(options.removeClass, remove);
5459                 return $$animateQueue.push(element, 'setClass', options);
5460               },
5461
5462               /**
5463                * @ngdoc method
5464                * @name $animate#animate
5465                * @kind function
5466                *
5467                * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5468                * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
5469                * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
5470                * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
5471                * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
5472                *
5473                * @param {DOMElement} element the element which the CSS styles will be applied to
5474                * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5475                * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5476                * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5477                *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5478                *    (Note that if no animation is detected then this value will not be appplied to the element.)
5479                * @param {object=} options an optional collection of options/styles that will be applied to the element
5480                *
5481                * @return {Promise} the animation callback promise
5482                */
5483               animate: function(element, from, to, className, options) {
5484                 options = prepareAnimateOptions(options);
5485                 options.from = options.from ? extend(options.from, from) : from;
5486                 options.to   = options.to   ? extend(options.to, to)     : to;
5487
5488                 className = className || 'ng-inline-animate';
5489                 options.tempClasses = mergeClasses(options.tempClasses, className);
5490                 return $$animateQueue.push(element, 'animate', options);
5491               }
5492             };
5493           }];
5494         }];
5495
5496         /**
5497          * @ngdoc service
5498          * @name $animateCss
5499          * @kind object
5500          *
5501          * @description
5502          * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
5503          * then the `$animateCss` service will actually perform animations.
5504          *
5505          * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
5506          */
5507         var $CoreAnimateCssProvider = function() {
5508           this.$get = ['$$rAF', '$q', function($$rAF, $q) {
5509
5510             var RAFPromise = function() {};
5511             RAFPromise.prototype = {
5512               done: function(cancel) {
5513                 this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
5514               },
5515               end: function() {
5516                 this.done();
5517               },
5518               cancel: function() {
5519                 this.done(true);
5520               },
5521               getPromise: function() {
5522                 if (!this.defer) {
5523                   this.defer = $q.defer();
5524                 }
5525                 return this.defer.promise;
5526               },
5527               then: function(f1,f2) {
5528                 return this.getPromise().then(f1,f2);
5529               },
5530               'catch': function(f1) {
5531                 return this.getPromise()['catch'](f1);
5532               },
5533               'finally': function(f1) {
5534                 return this.getPromise()['finally'](f1);
5535               }
5536             };
5537
5538             return function(element, options) {
5539               // there is no point in applying the styles since
5540               // there is no animation that goes on at all in
5541               // this version of $animateCss.
5542               if (options.cleanupStyles) {
5543                 options.from = options.to = null;
5544               }
5545
5546               if (options.from) {
5547                 element.css(options.from);
5548                 options.from = null;
5549               }
5550
5551               var closed, runner = new RAFPromise();
5552               return {
5553                 start: run,
5554                 end: run
5555               };
5556
5557               function run() {
5558                 $$rAF(function() {
5559                   close();
5560                   if (!closed) {
5561                     runner.done();
5562                   }
5563                   closed = true;
5564                 });
5565                 return runner;
5566               }
5567
5568               function close() {
5569                 if (options.addClass) {
5570                   element.addClass(options.addClass);
5571                   options.addClass = null;
5572                 }
5573                 if (options.removeClass) {
5574                   element.removeClass(options.removeClass);
5575                   options.removeClass = null;
5576                 }
5577                 if (options.to) {
5578                   element.css(options.to);
5579                   options.to = null;
5580                 }
5581               }
5582             };
5583           }];
5584         };
5585
5586         /* global stripHash: true */
5587
5588         /**
5589          * ! This is a private undocumented service !
5590          *
5591          * @name $browser
5592          * @requires $log
5593          * @description
5594          * This object has two goals:
5595          *
5596          * - hide all the global state in the browser caused by the window object
5597          * - abstract away all the browser specific features and inconsistencies
5598          *
5599          * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
5600          * service, which can be used for convenient testing of the application without the interaction with
5601          * the real browser apis.
5602          */
5603         /**
5604          * @param {object} window The global window object.
5605          * @param {object} document jQuery wrapped document.
5606          * @param {object} $log window.console or an object with the same interface.
5607          * @param {object} $sniffer $sniffer service
5608          */
5609         function Browser(window, document, $log, $sniffer) {
5610           var self = this,
5611               rawDocument = document[0],
5612               location = window.location,
5613               history = window.history,
5614               setTimeout = window.setTimeout,
5615               clearTimeout = window.clearTimeout,
5616               pendingDeferIds = {};
5617
5618           self.isMock = false;
5619
5620           var outstandingRequestCount = 0;
5621           var outstandingRequestCallbacks = [];
5622
5623           // TODO(vojta): remove this temporary api
5624           self.$$completeOutstandingRequest = completeOutstandingRequest;
5625           self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
5626
5627           /**
5628            * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
5629            * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
5630            */
5631           function completeOutstandingRequest(fn) {
5632             try {
5633               fn.apply(null, sliceArgs(arguments, 1));
5634             } finally {
5635               outstandingRequestCount--;
5636               if (outstandingRequestCount === 0) {
5637                 while (outstandingRequestCallbacks.length) {
5638                   try {
5639                     outstandingRequestCallbacks.pop()();
5640                   } catch (e) {
5641                     $log.error(e);
5642                   }
5643                 }
5644               }
5645             }
5646           }
5647
5648           function getHash(url) {
5649             var index = url.indexOf('#');
5650             return index === -1 ? '' : url.substr(index);
5651           }
5652
5653           /**
5654            * @private
5655            * Note: this method is used only by scenario runner
5656            * TODO(vojta): prefix this method with $$ ?
5657            * @param {function()} callback Function that will be called when no outstanding request
5658            */
5659           self.notifyWhenNoOutstandingRequests = function(callback) {
5660             if (outstandingRequestCount === 0) {
5661               callback();
5662             } else {
5663               outstandingRequestCallbacks.push(callback);
5664             }
5665           };
5666
5667           //////////////////////////////////////////////////////////////
5668           // URL API
5669           //////////////////////////////////////////////////////////////
5670
5671           var cachedState, lastHistoryState,
5672               lastBrowserUrl = location.href,
5673               baseElement = document.find('base'),
5674               pendingLocation = null;
5675
5676           cacheState();
5677           lastHistoryState = cachedState;
5678
5679           /**
5680            * @name $browser#url
5681            *
5682            * @description
5683            * GETTER:
5684            * Without any argument, this method just returns current value of location.href.
5685            *
5686            * SETTER:
5687            * With at least one argument, this method sets url to new value.
5688            * If html5 history api supported, pushState/replaceState is used, otherwise
5689            * location.href/location.replace is used.
5690            * Returns its own instance to allow chaining
5691            *
5692            * NOTE: this api is intended for use only by the $location service. Please use the
5693            * {@link ng.$location $location service} to change url.
5694            *
5695            * @param {string} url New url (when used as setter)
5696            * @param {boolean=} replace Should new url replace current history record?
5697            * @param {object=} state object to use with pushState/replaceState
5698            */
5699           self.url = function(url, replace, state) {
5700             // In modern browsers `history.state` is `null` by default; treating it separately
5701             // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5702             // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5703             if (isUndefined(state)) {
5704               state = null;
5705             }
5706
5707             // Android Browser BFCache causes location, history reference to become stale.
5708             if (location !== window.location) location = window.location;
5709             if (history !== window.history) history = window.history;
5710
5711             // setter
5712             if (url) {
5713               var sameState = lastHistoryState === state;
5714
5715               // Don't change anything if previous and current URLs and states match. This also prevents
5716               // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5717               // See https://github.com/angular/angular.js/commit/ffb2701
5718               if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5719                 return self;
5720               }
5721               var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5722               lastBrowserUrl = url;
5723               lastHistoryState = state;
5724               // Don't use history API if only the hash changed
5725               // due to a bug in IE10/IE11 which leads
5726               // to not firing a `hashchange` nor `popstate` event
5727               // in some cases (see #9143).
5728               if ($sniffer.history && (!sameBase || !sameState)) {
5729                 history[replace ? 'replaceState' : 'pushState'](state, '', url);
5730                 cacheState();
5731                 // Do the assignment again so that those two variables are referentially identical.
5732                 lastHistoryState = cachedState;
5733               } else {
5734                 if (!sameBase || pendingLocation) {
5735                   pendingLocation = url;
5736                 }
5737                 if (replace) {
5738                   location.replace(url);
5739                 } else if (!sameBase) {
5740                   location.href = url;
5741                 } else {
5742                   location.hash = getHash(url);
5743                 }
5744                 if (location.href !== url) {
5745                   pendingLocation = url;
5746                 }
5747               }
5748               return self;
5749             // getter
5750             } else {
5751               // - pendingLocation is needed as browsers don't allow to read out
5752               //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
5753               //   https://openradar.appspot.com/22186109).
5754               // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5755               return pendingLocation || location.href.replace(/%27/g,"'");
5756             }
5757           };
5758
5759           /**
5760            * @name $browser#state
5761            *
5762            * @description
5763            * This method is a getter.
5764            *
5765            * Return history.state or null if history.state is undefined.
5766            *
5767            * @returns {object} state
5768            */
5769           self.state = function() {
5770             return cachedState;
5771           };
5772
5773           var urlChangeListeners = [],
5774               urlChangeInit = false;
5775
5776           function cacheStateAndFireUrlChange() {
5777             pendingLocation = null;
5778             cacheState();
5779             fireUrlChange();
5780           }
5781
5782           function getCurrentState() {
5783             try {
5784               return history.state;
5785             } catch (e) {
5786               // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5787             }
5788           }
5789
5790           // This variable should be used *only* inside the cacheState function.
5791           var lastCachedState = null;
5792           function cacheState() {
5793             // This should be the only place in $browser where `history.state` is read.
5794             cachedState = getCurrentState();
5795             cachedState = isUndefined(cachedState) ? null : cachedState;
5796
5797             // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5798             if (equals(cachedState, lastCachedState)) {
5799               cachedState = lastCachedState;
5800             }
5801             lastCachedState = cachedState;
5802           }
5803
5804           function fireUrlChange() {
5805             if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5806               return;
5807             }
5808
5809             lastBrowserUrl = self.url();
5810             lastHistoryState = cachedState;
5811             forEach(urlChangeListeners, function(listener) {
5812               listener(self.url(), cachedState);
5813             });
5814           }
5815
5816           /**
5817            * @name $browser#onUrlChange
5818            *
5819            * @description
5820            * Register callback function that will be called, when url changes.
5821            *
5822            * It's only called when the url is changed from outside of angular:
5823            * - user types different url into address bar
5824            * - user clicks on history (forward/back) button
5825            * - user clicks on a link
5826            *
5827            * It's not called when url is changed by $browser.url() method
5828            *
5829            * The listener gets called with new url as parameter.
5830            *
5831            * NOTE: this api is intended for use only by the $location service. Please use the
5832            * {@link ng.$location $location service} to monitor url changes in angular apps.
5833            *
5834            * @param {function(string)} listener Listener function to be called when url changes.
5835            * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5836            */
5837           self.onUrlChange = function(callback) {
5838             // TODO(vojta): refactor to use node's syntax for events
5839             if (!urlChangeInit) {
5840               // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5841               // don't fire popstate when user change the address bar and don't fire hashchange when url
5842               // changed by push/replaceState
5843
5844               // html5 history api - popstate event
5845               if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5846               // hashchange event
5847               jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5848
5849               urlChangeInit = true;
5850             }
5851
5852             urlChangeListeners.push(callback);
5853             return callback;
5854           };
5855
5856           /**
5857            * @private
5858            * Remove popstate and hashchange handler from window.
5859            *
5860            * NOTE: this api is intended for use only by $rootScope.
5861            */
5862           self.$$applicationDestroyed = function() {
5863             jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
5864           };
5865
5866           /**
5867            * Checks whether the url has changed outside of Angular.
5868            * Needs to be exported to be able to check for changes that have been done in sync,
5869            * as hashchange/popstate events fire in async.
5870            */
5871           self.$$checkUrlChange = fireUrlChange;
5872
5873           //////////////////////////////////////////////////////////////
5874           // Misc API
5875           //////////////////////////////////////////////////////////////
5876
5877           /**
5878            * @name $browser#baseHref
5879            *
5880            * @description
5881            * Returns current <base href>
5882            * (always relative - without domain)
5883            *
5884            * @returns {string} The current base href
5885            */
5886           self.baseHref = function() {
5887             var href = baseElement.attr('href');
5888             return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5889           };
5890
5891           /**
5892            * @name $browser#defer
5893            * @param {function()} fn A function, who's execution should be deferred.
5894            * @param {number=} [delay=0] of milliseconds to defer the function execution.
5895            * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5896            *
5897            * @description
5898            * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5899            *
5900            * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5901            * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5902            * via `$browser.defer.flush()`.
5903            *
5904            */
5905           self.defer = function(fn, delay) {
5906             var timeoutId;
5907             outstandingRequestCount++;
5908             timeoutId = setTimeout(function() {
5909               delete pendingDeferIds[timeoutId];
5910               completeOutstandingRequest(fn);
5911             }, delay || 0);
5912             pendingDeferIds[timeoutId] = true;
5913             return timeoutId;
5914           };
5915
5916
5917           /**
5918            * @name $browser#defer.cancel
5919            *
5920            * @description
5921            * Cancels a deferred task identified with `deferId`.
5922            *
5923            * @param {*} deferId Token returned by the `$browser.defer` function.
5924            * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5925            *                    canceled.
5926            */
5927           self.defer.cancel = function(deferId) {
5928             if (pendingDeferIds[deferId]) {
5929               delete pendingDeferIds[deferId];
5930               clearTimeout(deferId);
5931               completeOutstandingRequest(noop);
5932               return true;
5933             }
5934             return false;
5935           };
5936
5937         }
5938
5939         function $BrowserProvider() {
5940           this.$get = ['$window', '$log', '$sniffer', '$document',
5941               function($window, $log, $sniffer, $document) {
5942                 return new Browser($window, $document, $log, $sniffer);
5943               }];
5944         }
5945
5946         /**
5947          * @ngdoc service
5948          * @name $cacheFactory
5949          *
5950          * @description
5951          * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5952          * them.
5953          *
5954          * ```js
5955          *
5956          *  var cache = $cacheFactory('cacheId');
5957          *  expect($cacheFactory.get('cacheId')).toBe(cache);
5958          *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5959          *
5960          *  cache.put("key", "value");
5961          *  cache.put("another key", "another value");
5962          *
5963          *  // We've specified no options on creation
5964          *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5965          *
5966          * ```
5967          *
5968          *
5969          * @param {string} cacheId Name or id of the newly created cache.
5970          * @param {object=} options Options object that specifies the cache behavior. Properties:
5971          *
5972          *   - `{number=}` `capacity` — turns the cache into LRU cache.
5973          *
5974          * @returns {object} Newly created cache object with the following set of methods:
5975          *
5976          * - `{object}` `info()` — Returns id, size, and options of cache.
5977          * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5978          *   it.
5979          * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5980          * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5981          * - `{void}` `removeAll()` — Removes all cached values.
5982          * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5983          *
5984          * @example
5985            <example module="cacheExampleApp">
5986              <file name="index.html">
5987                <div ng-controller="CacheController">
5988                  <input ng-model="newCacheKey" placeholder="Key">
5989                  <input ng-model="newCacheValue" placeholder="Value">
5990                  <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5991
5992                  <p ng-if="keys.length">Cached Values</p>
5993                  <div ng-repeat="key in keys">
5994                    <span ng-bind="key"></span>
5995                    <span>: </span>
5996                    <b ng-bind="cache.get(key)"></b>
5997                  </div>
5998
5999                  <p>Cache Info</p>
6000                  <div ng-repeat="(key, value) in cache.info()">
6001                    <span ng-bind="key"></span>
6002                    <span>: </span>
6003                    <b ng-bind="value"></b>
6004                  </div>
6005                </div>
6006              </file>
6007              <file name="script.js">
6008                angular.module('cacheExampleApp', []).
6009                  controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
6010                    $scope.keys = [];
6011                    $scope.cache = $cacheFactory('cacheId');
6012                    $scope.put = function(key, value) {
6013                      if (angular.isUndefined($scope.cache.get(key))) {
6014                        $scope.keys.push(key);
6015                      }
6016                      $scope.cache.put(key, angular.isUndefined(value) ? null : value);
6017                    };
6018                  }]);
6019              </file>
6020              <file name="style.css">
6021                p {
6022                  margin: 10px 0 3px;
6023                }
6024              </file>
6025            </example>
6026          */
6027         function $CacheFactoryProvider() {
6028
6029           this.$get = function() {
6030             var caches = {};
6031
6032             function cacheFactory(cacheId, options) {
6033               if (cacheId in caches) {
6034                 throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
6035               }
6036
6037               var size = 0,
6038                   stats = extend({}, options, {id: cacheId}),
6039                   data = createMap(),
6040                   capacity = (options && options.capacity) || Number.MAX_VALUE,
6041                   lruHash = createMap(),
6042                   freshEnd = null,
6043                   staleEnd = null;
6044
6045               /**
6046                * @ngdoc type
6047                * @name $cacheFactory.Cache
6048                *
6049                * @description
6050                * A cache object used to store and retrieve data, primarily used by
6051                * {@link $http $http} and the {@link ng.directive:script script} directive to cache
6052                * templates and other data.
6053                *
6054                * ```js
6055                *  angular.module('superCache')
6056                *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
6057                *      return $cacheFactory('super-cache');
6058                *    }]);
6059                * ```
6060                *
6061                * Example test:
6062                *
6063                * ```js
6064                *  it('should behave like a cache', inject(function(superCache) {
6065                *    superCache.put('key', 'value');
6066                *    superCache.put('another key', 'another value');
6067                *
6068                *    expect(superCache.info()).toEqual({
6069                *      id: 'super-cache',
6070                *      size: 2
6071                *    });
6072                *
6073                *    superCache.remove('another key');
6074                *    expect(superCache.get('another key')).toBeUndefined();
6075                *
6076                *    superCache.removeAll();
6077                *    expect(superCache.info()).toEqual({
6078                *      id: 'super-cache',
6079                *      size: 0
6080                *    });
6081                *  }));
6082                * ```
6083                */
6084               return caches[cacheId] = {
6085
6086                 /**
6087                  * @ngdoc method
6088                  * @name $cacheFactory.Cache#put
6089                  * @kind function
6090                  *
6091                  * @description
6092                  * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
6093                  * retrieved later, and incrementing the size of the cache if the key was not already
6094                  * present in the cache. If behaving like an LRU cache, it will also remove stale
6095                  * entries from the set.
6096                  *
6097                  * It will not insert undefined values into the cache.
6098                  *
6099                  * @param {string} key the key under which the cached data is stored.
6100                  * @param {*} value the value to store alongside the key. If it is undefined, the key
6101                  *    will not be stored.
6102                  * @returns {*} the value stored.
6103                  */
6104                 put: function(key, value) {
6105                   if (isUndefined(value)) return;
6106                   if (capacity < Number.MAX_VALUE) {
6107                     var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
6108
6109                     refresh(lruEntry);
6110                   }
6111
6112                   if (!(key in data)) size++;
6113                   data[key] = value;
6114
6115                   if (size > capacity) {
6116                     this.remove(staleEnd.key);
6117                   }
6118
6119                   return value;
6120                 },
6121
6122                 /**
6123                  * @ngdoc method
6124                  * @name $cacheFactory.Cache#get
6125                  * @kind function
6126                  *
6127                  * @description
6128                  * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
6129                  *
6130                  * @param {string} key the key of the data to be retrieved
6131                  * @returns {*} the value stored.
6132                  */
6133                 get: function(key) {
6134                   if (capacity < Number.MAX_VALUE) {
6135                     var lruEntry = lruHash[key];
6136
6137                     if (!lruEntry) return;
6138
6139                     refresh(lruEntry);
6140                   }
6141
6142                   return data[key];
6143                 },
6144
6145
6146                 /**
6147                  * @ngdoc method
6148                  * @name $cacheFactory.Cache#remove
6149                  * @kind function
6150                  *
6151                  * @description
6152                  * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
6153                  *
6154                  * @param {string} key the key of the entry to be removed
6155                  */
6156                 remove: function(key) {
6157                   if (capacity < Number.MAX_VALUE) {
6158                     var lruEntry = lruHash[key];
6159
6160                     if (!lruEntry) return;
6161
6162                     if (lruEntry == freshEnd) freshEnd = lruEntry.p;
6163                     if (lruEntry == staleEnd) staleEnd = lruEntry.n;
6164                     link(lruEntry.n,lruEntry.p);
6165
6166                     delete lruHash[key];
6167                   }
6168
6169                   if (!(key in data)) return;
6170
6171                   delete data[key];
6172                   size--;
6173                 },
6174
6175
6176                 /**
6177                  * @ngdoc method
6178                  * @name $cacheFactory.Cache#removeAll
6179                  * @kind function
6180                  *
6181                  * @description
6182                  * Clears the cache object of any entries.
6183                  */
6184                 removeAll: function() {
6185                   data = createMap();
6186                   size = 0;
6187                   lruHash = createMap();
6188                   freshEnd = staleEnd = null;
6189                 },
6190
6191
6192                 /**
6193                  * @ngdoc method
6194                  * @name $cacheFactory.Cache#destroy
6195                  * @kind function
6196                  *
6197                  * @description
6198                  * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
6199                  * removing it from the {@link $cacheFactory $cacheFactory} set.
6200                  */
6201                 destroy: function() {
6202                   data = null;
6203                   stats = null;
6204                   lruHash = null;
6205                   delete caches[cacheId];
6206                 },
6207
6208
6209                 /**
6210                  * @ngdoc method
6211                  * @name $cacheFactory.Cache#info
6212                  * @kind function
6213                  *
6214                  * @description
6215                  * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
6216                  *
6217                  * @returns {object} an object with the following properties:
6218                  *   <ul>
6219                  *     <li>**id**: the id of the cache instance</li>
6220                  *     <li>**size**: the number of entries kept in the cache instance</li>
6221                  *     <li>**...**: any additional properties from the options object when creating the
6222                  *       cache.</li>
6223                  *   </ul>
6224                  */
6225                 info: function() {
6226                   return extend({}, stats, {size: size});
6227                 }
6228               };
6229
6230
6231               /**
6232                * makes the `entry` the freshEnd of the LRU linked list
6233                */
6234               function refresh(entry) {
6235                 if (entry != freshEnd) {
6236                   if (!staleEnd) {
6237                     staleEnd = entry;
6238                   } else if (staleEnd == entry) {
6239                     staleEnd = entry.n;
6240                   }
6241
6242                   link(entry.n, entry.p);
6243                   link(entry, freshEnd);
6244                   freshEnd = entry;
6245                   freshEnd.n = null;
6246                 }
6247               }
6248
6249
6250               /**
6251                * bidirectionally links two entries of the LRU linked list
6252                */
6253               function link(nextEntry, prevEntry) {
6254                 if (nextEntry != prevEntry) {
6255                   if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
6256                   if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
6257                 }
6258               }
6259             }
6260
6261
6262           /**
6263            * @ngdoc method
6264            * @name $cacheFactory#info
6265            *
6266            * @description
6267            * Get information about all the caches that have been created
6268            *
6269            * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
6270            */
6271             cacheFactory.info = function() {
6272               var info = {};
6273               forEach(caches, function(cache, cacheId) {
6274                 info[cacheId] = cache.info();
6275               });
6276               return info;
6277             };
6278
6279
6280           /**
6281            * @ngdoc method
6282            * @name $cacheFactory#get
6283            *
6284            * @description
6285            * Get access to a cache object by the `cacheId` used when it was created.
6286            *
6287            * @param {string} cacheId Name or id of a cache to access.
6288            * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
6289            */
6290             cacheFactory.get = function(cacheId) {
6291               return caches[cacheId];
6292             };
6293
6294
6295             return cacheFactory;
6296           };
6297         }
6298
6299         /**
6300          * @ngdoc service
6301          * @name $templateCache
6302          *
6303          * @description
6304          * The first time a template is used, it is loaded in the template cache for quick retrieval. You
6305          * can load templates directly into the cache in a `script` tag, or by consuming the
6306          * `$templateCache` service directly.
6307          *
6308          * Adding via the `script` tag:
6309          *
6310          * ```html
6311          *   <script type="text/ng-template" id="templateId.html">
6312          *     <p>This is the content of the template</p>
6313          *   </script>
6314          * ```
6315          *
6316          * **Note:** the `script` tag containing the template does not need to be included in the `head` of
6317          * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
6318          * element with ng-app attribute), otherwise the template will be ignored.
6319          *
6320          * Adding via the `$templateCache` service:
6321          *
6322          * ```js
6323          * var myApp = angular.module('myApp', []);
6324          * myApp.run(function($templateCache) {
6325          *   $templateCache.put('templateId.html', 'This is the content of the template');
6326          * });
6327          * ```
6328          *
6329          * To retrieve the template later, simply use it in your HTML:
6330          * ```html
6331          * <div ng-include=" 'templateId.html' "></div>
6332          * ```
6333          *
6334          * or get it via Javascript:
6335          * ```js
6336          * $templateCache.get('templateId.html')
6337          * ```
6338          *
6339          * See {@link ng.$cacheFactory $cacheFactory}.
6340          *
6341          */
6342         function $TemplateCacheProvider() {
6343           this.$get = ['$cacheFactory', function($cacheFactory) {
6344             return $cacheFactory('templates');
6345           }];
6346         }
6347
6348         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6349          *     Any commits to this file should be reviewed with security in mind.  *
6350          *   Changes to this file can potentially create security vulnerabilities. *
6351          *          An approval from 2 Core members with history of modifying      *
6352          *                         this file is required.                          *
6353          *                                                                         *
6354          *  Does the change somehow allow for arbitrary javascript to be executed? *
6355          *    Or allows for someone to change the prototype of built-in objects?   *
6356          *     Or gives undesired access to variables likes document or window?    *
6357          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6358
6359         /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
6360          *
6361          * DOM-related variables:
6362          *
6363          * - "node" - DOM Node
6364          * - "element" - DOM Element or Node
6365          * - "$node" or "$element" - jqLite-wrapped node or element
6366          *
6367          *
6368          * Compiler related stuff:
6369          *
6370          * - "linkFn" - linking fn of a single directive
6371          * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
6372          * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
6373          * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
6374          */
6375
6376
6377         /**
6378          * @ngdoc service
6379          * @name $compile
6380          * @kind function
6381          *
6382          * @description
6383          * Compiles an HTML string or DOM into a template and produces a template function, which
6384          * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
6385          *
6386          * The compilation is a process of walking the DOM tree and matching DOM elements to
6387          * {@link ng.$compileProvider#directive directives}.
6388          *
6389          * <div class="alert alert-warning">
6390          * **Note:** This document is an in-depth reference of all directive options.
6391          * For a gentle introduction to directives with examples of common use cases,
6392          * see the {@link guide/directive directive guide}.
6393          * </div>
6394          *
6395          * ## Comprehensive Directive API
6396          *
6397          * There are many different options for a directive.
6398          *
6399          * The difference resides in the return value of the factory function.
6400          * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
6401          * or just the `postLink` function (all other properties will have the default values).
6402          *
6403          * <div class="alert alert-success">
6404          * **Best Practice:** It's recommended to use the "directive definition object" form.
6405          * </div>
6406          *
6407          * Here's an example directive declared with a Directive Definition Object:
6408          *
6409          * ```js
6410          *   var myModule = angular.module(...);
6411          *
6412          *   myModule.directive('directiveName', function factory(injectables) {
6413          *     var directiveDefinitionObject = {
6414          *       priority: 0,
6415          *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
6416          *       // or
6417          *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
6418          *       transclude: false,
6419          *       restrict: 'A',
6420          *       templateNamespace: 'html',
6421          *       scope: false,
6422          *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
6423          *       controllerAs: 'stringIdentifier',
6424          *       bindToController: false,
6425          *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
6426          *       compile: function compile(tElement, tAttrs, transclude) {
6427          *         return {
6428          *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6429          *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
6430          *         }
6431          *         // or
6432          *         // return function postLink( ... ) { ... }
6433          *       },
6434          *       // or
6435          *       // link: {
6436          *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6437          *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
6438          *       // }
6439          *       // or
6440          *       // link: function postLink( ... ) { ... }
6441          *     };
6442          *     return directiveDefinitionObject;
6443          *   });
6444          * ```
6445          *
6446          * <div class="alert alert-warning">
6447          * **Note:** Any unspecified options will use the default value. You can see the default values below.
6448          * </div>
6449          *
6450          * Therefore the above can be simplified as:
6451          *
6452          * ```js
6453          *   var myModule = angular.module(...);
6454          *
6455          *   myModule.directive('directiveName', function factory(injectables) {
6456          *     var directiveDefinitionObject = {
6457          *       link: function postLink(scope, iElement, iAttrs) { ... }
6458          *     };
6459          *     return directiveDefinitionObject;
6460          *     // or
6461          *     // return function postLink(scope, iElement, iAttrs) { ... }
6462          *   });
6463          * ```
6464          *
6465          *
6466          *
6467          * ### Directive Definition Object
6468          *
6469          * The directive definition object provides instructions to the {@link ng.$compile
6470          * compiler}. The attributes are:
6471          *
6472          * #### `multiElement`
6473          * When this property is set to true, the HTML compiler will collect DOM nodes between
6474          * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
6475          * together as the directive elements. It is recommended that this feature be used on directives
6476          * which are not strictly behavioural (such as {@link ngClick}), and which
6477          * do not manipulate or replace child nodes (such as {@link ngInclude}).
6478          *
6479          * #### `priority`
6480          * When there are multiple directives defined on a single DOM element, sometimes it
6481          * is necessary to specify the order in which the directives are applied. The `priority` is used
6482          * to sort the directives before their `compile` functions get called. Priority is defined as a
6483          * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
6484          * are also run in priority order, but post-link functions are run in reverse order. The order
6485          * of directives with the same priority is undefined. The default priority is `0`.
6486          *
6487          * #### `terminal`
6488          * If set to true then the current `priority` will be the last set of directives
6489          * which will execute (any directives at the current priority will still execute
6490          * as the order of execution on same `priority` is undefined). Note that expressions
6491          * and other directives used in the directive's template will also be excluded from execution.
6492          *
6493          * #### `scope`
6494          * The scope property can be `true`, an object or a falsy value:
6495          *
6496          * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
6497          *
6498          * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
6499          * the directive's element. If multiple directives on the same element request a new scope,
6500          * only one new scope is created. The new scope rule does not apply for the root of the template
6501          * since the root of the template always gets a new scope.
6502          *
6503          * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
6504          * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
6505          * scope. This is useful when creating reusable components, which should not accidentally read or modify
6506          * data in the parent scope.
6507          *
6508          * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
6509          * directive's element. These local properties are useful for aliasing values for templates. The keys in
6510          * the object hash map to the name of the property on the isolate scope; the values define how the property
6511          * is bound to the parent scope, via matching attributes on the directive's element:
6512          *
6513          * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
6514          *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
6515          *   attribute name is assumed to be the same as the local name.
6516          *   Given `<widget my-attr="hello {{name}}">` and widget definition
6517          *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
6518          *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
6519          *   `localName` property on the widget scope. The `name` is read from the parent scope (not
6520          *   component scope).
6521          *
6522          * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
6523          *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
6524          *   name is specified then the attribute name is assumed to be the same as the local name.
6525          *   Given `<widget my-attr="parentModel">` and widget definition of
6526          *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
6527          *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
6528          *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
6529          *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
6530          *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
6531          *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
6532          *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
6533          *
6534          * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
6535          *   If no `attr` name is specified then the attribute name is assumed to be the same as the
6536          *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
6537          *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
6538          *   a function wrapper for the `count = count + value` expression. Often it's desirable to
6539          *   pass data from the isolated scope via an expression to the parent scope, this can be
6540          *   done by passing a map of local variable names and values into the expression wrapper fn.
6541          *   For example, if the expression is `increment(amount)` then we can specify the amount value
6542          *   by calling the `localFn` as `localFn({amount: 22})`.
6543          *
6544          * In general it's possible to apply more than one directive to one element, but there might be limitations
6545          * depending on the type of scope required by the directives. The following points will help explain these limitations.
6546          * For simplicity only two directives are taken into account, but it is also applicable for several directives:
6547          *
6548          * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
6549          * * **child scope** + **no scope** =>  Both directives will share one single child scope
6550          * * **child scope** + **child scope** =>  Both directives will share one single child scope
6551          * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
6552          * its parent's scope
6553          * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
6554          * be applied to the same element.
6555          * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
6556          * cannot be applied to the same element.
6557          *
6558          *
6559          * #### `bindToController`
6560          * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
6561          * allow a component to have its properties bound to the controller, rather than to scope. When the controller
6562          * is instantiated, the initial values of the isolate scope bindings are already available.
6563          *
6564          * #### `controller`
6565          * Controller constructor function. The controller is instantiated before the
6566          * pre-linking phase and can be accessed by other directives (see
6567          * `require` attribute). This allows the directives to communicate with each other and augment
6568          * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
6569          *
6570          * * `$scope` - Current scope associated with the element
6571          * * `$element` - Current element
6572          * * `$attrs` - Current attributes object for the element
6573          * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
6574          *   `function([scope], cloneLinkingFn, futureParentElement)`.
6575          *    * `scope`: optional argument to override the scope.
6576          *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
6577          *    * `futureParentElement`:
6578          *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
6579          *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
6580          *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
6581          *          and when the `cloneLinkinFn` is passed,
6582          *          as those elements need to created and cloned in a special way when they are defined outside their
6583          *          usual containers (e.g. like `<svg>`).
6584          *        * See also the `directive.templateNamespace` property.
6585          *
6586          *
6587          * #### `require`
6588          * Require another directive and inject its controller as the fourth argument to the linking function. The
6589          * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
6590          * injected argument will be an array in corresponding order. If no such directive can be
6591          * found, or if the directive does not have a controller, then an error is raised (unless no link function
6592          * is specified, in which case error checking is skipped). The name can be prefixed with:
6593          *
6594          * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
6595          * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
6596          * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
6597          * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
6598          * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
6599          *   `null` to the `link` fn if not found.
6600          * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
6601          *   `null` to the `link` fn if not found.
6602          *
6603          *
6604          * #### `controllerAs`
6605          * Identifier name for a reference to the controller in the directive's scope.
6606          * This allows the controller to be referenced from the directive template. This is especially
6607          * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
6608          * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
6609          * `controllerAs` reference might overwrite a property that already exists on the parent scope.
6610          *
6611          *
6612          * #### `restrict`
6613          * String of subset of `EACM` which restricts the directive to a specific directive
6614          * declaration style. If omitted, the defaults (elements and attributes) are used.
6615          *
6616          * * `E` - Element name (default): `<my-directive></my-directive>`
6617          * * `A` - Attribute (default): `<div my-directive="exp"></div>`
6618          * * `C` - Class: `<div class="my-directive: exp;"></div>`
6619          * * `M` - Comment: `<!-- directive: my-directive exp -->`
6620          *
6621          *
6622          * #### `templateNamespace`
6623          * String representing the document type used by the markup in the template.
6624          * AngularJS needs this information as those elements need to be created and cloned
6625          * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6626          *
6627          * * `html` - All root nodes in the template are HTML. Root nodes may also be
6628          *   top-level elements such as `<svg>` or `<math>`.
6629          * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6630          * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6631          *
6632          * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6633          *
6634          * #### `template`
6635          * HTML markup that may:
6636          * * Replace the contents of the directive's element (default).
6637          * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6638          * * Wrap the contents of the directive's element (if `transclude` is true).
6639          *
6640          * Value may be:
6641          *
6642          * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6643          * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6644          *   function api below) and returns a string value.
6645          *
6646          *
6647          * #### `templateUrl`
6648          * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6649          *
6650          * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6651          * for later when the template has been resolved.  In the meantime it will continue to compile and link
6652          * sibling and parent elements as though this element had not contained any directives.
6653          *
6654          * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6655          * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6656          * case when only one deeply nested directive has `templateUrl`.
6657          *
6658          * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6659          *
6660          * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6661          * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6662          * a string value representing the url.  In either case, the template URL is passed through {@link
6663          * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6664          *
6665          *
6666          * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6667          * specify what the template should replace. Defaults to `false`.
6668          *
6669          * * `true` - the template will replace the directive's element.
6670          * * `false` - the template will replace the contents of the directive's element.
6671          *
6672          * The replacement process migrates all of the attributes / classes from the old element to the new
6673          * one. See the {@link guide/directive#template-expanding-directive
6674          * Directives Guide} for an example.
6675          *
6676          * There are very few scenarios where element replacement is required for the application function,
6677          * the main one being reusable custom components that are used within SVG contexts
6678          * (because SVG doesn't work with custom elements in the DOM tree).
6679          *
6680          * #### `transclude`
6681          * Extract the contents of the element where the directive appears and make it available to the directive.
6682          * The contents are compiled and provided to the directive as a **transclusion function**. See the
6683          * {@link $compile#transclusion Transclusion} section below.
6684          *
6685          * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6686          * directive's element or the entire element:
6687          *
6688          * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6689          * * `'element'` - transclude the whole of the directive's element including any directives on this
6690          *   element that defined at a lower priority than this directive. When used, the `template`
6691          *   property is ignored.
6692          *
6693          *
6694          * #### `compile`
6695          *
6696          * ```js
6697          *   function compile(tElement, tAttrs, transclude) { ... }
6698          * ```
6699          *
6700          * The compile function deals with transforming the template DOM. Since most directives do not do
6701          * template transformation, it is not used often. The compile function takes the following arguments:
6702          *
6703          *   * `tElement` - template element - The element where the directive has been declared. It is
6704          *     safe to do template transformation on the element and child elements only.
6705          *
6706          *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6707          *     between all directive compile functions.
6708          *
6709          *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6710          *
6711          * <div class="alert alert-warning">
6712          * **Note:** The template instance and the link instance may be different objects if the template has
6713          * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6714          * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6715          * should be done in a linking function rather than in a compile function.
6716          * </div>
6717
6718          * <div class="alert alert-warning">
6719          * **Note:** The compile function cannot handle directives that recursively use themselves in their
6720          * own templates or compile functions. Compiling these directives results in an infinite loop and a
6721          * stack overflow errors.
6722          *
6723          * This can be avoided by manually using $compile in the postLink function to imperatively compile
6724          * a directive's template instead of relying on automatic template compilation via `template` or
6725          * `templateUrl` declaration or manual compilation inside the compile function.
6726          * </div>
6727          *
6728          * <div class="alert alert-danger">
6729          * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6730          *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6731          *   to the link function instead.
6732          * </div>
6733
6734          * A compile function can have a return value which can be either a function or an object.
6735          *
6736          * * returning a (post-link) function - is equivalent to registering the linking function via the
6737          *   `link` property of the config object when the compile function is empty.
6738          *
6739          * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6740          *   control when a linking function should be called during the linking phase. See info about
6741          *   pre-linking and post-linking functions below.
6742          *
6743          *
6744          * #### `link`
6745          * This property is used only if the `compile` property is not defined.
6746          *
6747          * ```js
6748          *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6749          * ```
6750          *
6751          * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6752          * executed after the template has been cloned. This is where most of the directive logic will be
6753          * put.
6754          *
6755          *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6756          *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6757          *
6758          *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6759          *     manipulate the children of the element only in `postLink` function since the children have
6760          *     already been linked.
6761          *
6762          *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6763          *     between all directive linking functions.
6764          *
6765          *   * `controller` - the directive's required controller instance(s) - Instances are shared
6766          *     among all directives, which allows the directives to use the controllers as a communication
6767          *     channel. The exact value depends on the directive's `require` property:
6768          *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
6769          *       * `string`: the controller instance
6770          *       * `array`: array of controller instances
6771          *
6772          *     If a required controller cannot be found, and it is optional, the instance is `null`,
6773          *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
6774          *
6775          *     Note that you can also require the directive's own controller - it will be made available like
6776          *     any other controller.
6777          *
6778          *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6779          *     This is the same as the `$transclude`
6780          *     parameter of directive controllers, see there for details.
6781          *     `function([scope], cloneLinkingFn, futureParentElement)`.
6782          *
6783          * #### Pre-linking function
6784          *
6785          * Executed before the child elements are linked. Not safe to do DOM transformation since the
6786          * compiler linking function will fail to locate the correct elements for linking.
6787          *
6788          * #### Post-linking function
6789          *
6790          * Executed after the child elements are linked.
6791          *
6792          * Note that child elements that contain `templateUrl` directives will not have been compiled
6793          * and linked since they are waiting for their template to load asynchronously and their own
6794          * compilation and linking has been suspended until that occurs.
6795          *
6796          * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6797          * for their async templates to be resolved.
6798          *
6799          *
6800          * ### Transclusion
6801          *
6802          * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
6803          * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6804          * scope from where they were taken.
6805          *
6806          * Transclusion is used (often with {@link ngTransclude}) to insert the
6807          * original contents of a directive's element into a specified place in the template of the directive.
6808          * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6809          * content has access to the properties on the scope from which it was taken, even if the directive
6810          * has isolated scope.
6811          * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6812          *
6813          * This makes it possible for the widget to have private state for its template, while the transcluded
6814          * content has access to its originating scope.
6815          *
6816          * <div class="alert alert-warning">
6817          * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6818          * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6819          * Testing Transclusion Directives}.
6820          * </div>
6821          *
6822          * #### Transclusion Functions
6823          *
6824          * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6825          * function** to the directive's `link` function and `controller`. This transclusion function is a special
6826          * **linking function** that will return the compiled contents linked to a new transclusion scope.
6827          *
6828          * <div class="alert alert-info">
6829          * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6830          * ngTransclude will deal with it for us.
6831          * </div>
6832          *
6833          * If you want to manually control the insertion and removal of the transcluded content in your directive
6834          * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6835          * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6836          *
6837          * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6838          * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6839          * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6840          *
6841          * <div class="alert alert-info">
6842          * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6843          * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6844          * </div>
6845          *
6846          * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6847          * attach function**:
6848          *
6849          * ```js
6850          * var transcludedContent, transclusionScope;
6851          *
6852          * $transclude(function(clone, scope) {
6853          *   element.append(clone);
6854          *   transcludedContent = clone;
6855          *   transclusionScope = scope;
6856          * });
6857          * ```
6858          *
6859          * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6860          * associated transclusion scope:
6861          *
6862          * ```js
6863          * transcludedContent.remove();
6864          * transclusionScope.$destroy();
6865          * ```
6866          *
6867          * <div class="alert alert-info">
6868          * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6869          * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
6870          * then you are also responsible for calling `$destroy` on the transclusion scope.
6871          * </div>
6872          *
6873          * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6874          * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6875          * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6876          *
6877          *
6878          * #### Transclusion Scopes
6879          *
6880          * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6881          * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6882          * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6883          * was taken.
6884          *
6885          * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6886          * like this:
6887          *
6888          * ```html
6889          * <div ng-app>
6890          *   <div isolate>
6891          *     <div transclusion>
6892          *     </div>
6893          *   </div>
6894          * </div>
6895          * ```
6896          *
6897          * The `$parent` scope hierarchy will look like this:
6898          *
6899          * ```
6900          * - $rootScope
6901          *   - isolate
6902          *     - transclusion
6903          * ```
6904          *
6905          * but the scopes will inherit prototypically from different scopes to their `$parent`.
6906          *
6907          * ```
6908          * - $rootScope
6909          *   - transclusion
6910          * - isolate
6911          * ```
6912          *
6913          *
6914          * ### Attributes
6915          *
6916          * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6917          * `link()` or `compile()` functions. It has a variety of uses.
6918          *
6919          * accessing *Normalized attribute names:*
6920          * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6921          * the attributes object allows for normalized access to
6922          *   the attributes.
6923          *
6924          * * *Directive inter-communication:* All directives share the same instance of the attributes
6925          *   object which allows the directives to use the attributes object as inter directive
6926          *   communication.
6927          *
6928          * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6929          *   allowing other directives to read the interpolated value.
6930          *
6931          * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6932          *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6933          *   the only way to easily get the actual value because during the linking phase the interpolation
6934          *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6935          *
6936          * ```js
6937          * function linkingFn(scope, elm, attrs, ctrl) {
6938          *   // get the attribute value
6939          *   console.log(attrs.ngModel);
6940          *
6941          *   // change the attribute
6942          *   attrs.$set('ngModel', 'new value');
6943          *
6944          *   // observe changes to interpolated attribute
6945          *   attrs.$observe('ngModel', function(value) {
6946          *     console.log('ngModel has changed value to ' + value);
6947          *   });
6948          * }
6949          * ```
6950          *
6951          * ## Example
6952          *
6953          * <div class="alert alert-warning">
6954          * **Note**: Typically directives are registered with `module.directive`. The example below is
6955          * to illustrate how `$compile` works.
6956          * </div>
6957          *
6958          <example module="compileExample">
6959            <file name="index.html">
6960             <script>
6961               angular.module('compileExample', [], function($compileProvider) {
6962                 // configure new 'compile' directive by passing a directive
6963                 // factory function. The factory function injects the '$compile'
6964                 $compileProvider.directive('compile', function($compile) {
6965                   // directive factory creates a link function
6966                   return function(scope, element, attrs) {
6967                     scope.$watch(
6968                       function(scope) {
6969                          // watch the 'compile' expression for changes
6970                         return scope.$eval(attrs.compile);
6971                       },
6972                       function(value) {
6973                         // when the 'compile' expression changes
6974                         // assign it into the current DOM
6975                         element.html(value);
6976
6977                         // compile the new DOM and link it to the current
6978                         // scope.
6979                         // NOTE: we only compile .childNodes so that
6980                         // we don't get into infinite loop compiling ourselves
6981                         $compile(element.contents())(scope);
6982                       }
6983                     );
6984                   };
6985                 });
6986               })
6987               .controller('GreeterController', ['$scope', function($scope) {
6988                 $scope.name = 'Angular';
6989                 $scope.html = 'Hello {{name}}';
6990               }]);
6991             </script>
6992             <div ng-controller="GreeterController">
6993               <input ng-model="name"> <br/>
6994               <textarea ng-model="html"></textarea> <br/>
6995               <div compile="html"></div>
6996             </div>
6997            </file>
6998            <file name="protractor.js" type="protractor">
6999              it('should auto compile', function() {
7000                var textarea = $('textarea');
7001                var output = $('div[compile]');
7002                // The initial state reads 'Hello Angular'.
7003                expect(output.getText()).toBe('Hello Angular');
7004                textarea.clear();
7005                textarea.sendKeys('{{name}}!');
7006                expect(output.getText()).toBe('Angular!');
7007              });
7008            </file>
7009          </example>
7010
7011          *
7012          *
7013          * @param {string|DOMElement} element Element or HTML string to compile into a template function.
7014          * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
7015          *
7016          * <div class="alert alert-danger">
7017          * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
7018          *   e.g. will not use the right outer scope. Please pass the transclude function as a
7019          *   `parentBoundTranscludeFn` to the link function instead.
7020          * </div>
7021          *
7022          * @param {number} maxPriority only apply directives lower than given priority (Only effects the
7023          *                 root element(s), not their children)
7024          * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
7025          * (a DOM element/tree) to a scope. Where:
7026          *
7027          *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
7028          *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
7029          *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
7030          *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
7031          *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
7032          *
7033          *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
7034          *      * `scope` - is the current scope with which the linking function is working with.
7035          *
7036          *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
7037          *  keys may be used to control linking behavior:
7038          *
7039          *      * `parentBoundTranscludeFn` - the transclude function made available to
7040          *        directives; if given, it will be passed through to the link functions of
7041          *        directives found in `element` during compilation.
7042          *      * `transcludeControllers` - an object hash with keys that map controller names
7043          *        to controller instances; if given, it will make the controllers
7044          *        available to directives.
7045          *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
7046          *        the cloned elements; only needed for transcludes that are allowed to contain non html
7047          *        elements (e.g. SVG elements). See also the directive.controller property.
7048          *
7049          * Calling the linking function returns the element of the template. It is either the original
7050          * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
7051          *
7052          * After linking the view is not updated until after a call to $digest which typically is done by
7053          * Angular automatically.
7054          *
7055          * If you need access to the bound view, there are two ways to do it:
7056          *
7057          * - If you are not asking the linking function to clone the template, create the DOM element(s)
7058          *   before you send them to the compiler and keep this reference around.
7059          *   ```js
7060          *     var element = $compile('<p>{{total}}</p>')(scope);
7061          *   ```
7062          *
7063          * - if on the other hand, you need the element to be cloned, the view reference from the original
7064          *   example would not point to the clone, but rather to the original template that was cloned. In
7065          *   this case, you can access the clone via the cloneAttachFn:
7066          *   ```js
7067          *     var templateElement = angular.element('<p>{{total}}</p>'),
7068          *         scope = ....;
7069          *
7070          *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
7071          *       //attach the clone to DOM document at the right place
7072          *     });
7073          *
7074          *     //now we have reference to the cloned DOM via `clonedElement`
7075          *   ```
7076          *
7077          *
7078          * For information on how the compiler works, see the
7079          * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
7080          */
7081
7082         var $compileMinErr = minErr('$compile');
7083
7084         /**
7085          * @ngdoc provider
7086          * @name $compileProvider
7087          *
7088          * @description
7089          */
7090         $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
7091         function $CompileProvider($provide, $$sanitizeUriProvider) {
7092           var hasDirectives = {},
7093               Suffix = 'Directive',
7094               COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
7095               CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
7096               ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
7097               REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
7098
7099           // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
7100           // The assumption is that future DOM event attribute names will begin with
7101           // 'on' and be composed of only English letters.
7102           var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
7103
7104           function parseIsolateBindings(scope, directiveName, isController) {
7105             var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
7106
7107             var bindings = {};
7108
7109             forEach(scope, function(definition, scopeName) {
7110               var match = definition.match(LOCAL_REGEXP);
7111
7112               if (!match) {
7113                 throw $compileMinErr('iscp',
7114                     "Invalid {3} for directive '{0}'." +
7115                     " Definition: {... {1}: '{2}' ...}",
7116                     directiveName, scopeName, definition,
7117                     (isController ? "controller bindings definition" :
7118                     "isolate scope definition"));
7119               }
7120
7121               bindings[scopeName] = {
7122                 mode: match[1][0],
7123                 collection: match[2] === '*',
7124                 optional: match[3] === '?',
7125                 attrName: match[4] || scopeName
7126               };
7127             });
7128
7129             return bindings;
7130           }
7131
7132           function parseDirectiveBindings(directive, directiveName) {
7133             var bindings = {
7134               isolateScope: null,
7135               bindToController: null
7136             };
7137             if (isObject(directive.scope)) {
7138               if (directive.bindToController === true) {
7139                 bindings.bindToController = parseIsolateBindings(directive.scope,
7140                                                                  directiveName, true);
7141                 bindings.isolateScope = {};
7142               } else {
7143                 bindings.isolateScope = parseIsolateBindings(directive.scope,
7144                                                              directiveName, false);
7145               }
7146             }
7147             if (isObject(directive.bindToController)) {
7148               bindings.bindToController =
7149                   parseIsolateBindings(directive.bindToController, directiveName, true);
7150             }
7151             if (isObject(bindings.bindToController)) {
7152               var controller = directive.controller;
7153               var controllerAs = directive.controllerAs;
7154               if (!controller) {
7155                 // There is no controller, there may or may not be a controllerAs property
7156                 throw $compileMinErr('noctrl',
7157                       "Cannot bind to controller without directive '{0}'s controller.",
7158                       directiveName);
7159               } else if (!identifierForController(controller, controllerAs)) {
7160                 // There is a controller, but no identifier or controllerAs property
7161                 throw $compileMinErr('noident',
7162                       "Cannot bind to controller without identifier for directive '{0}'.",
7163                       directiveName);
7164               }
7165             }
7166             return bindings;
7167           }
7168
7169           function assertValidDirectiveName(name) {
7170             var letter = name.charAt(0);
7171             if (!letter || letter !== lowercase(letter)) {
7172               throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
7173             }
7174             if (name !== name.trim()) {
7175               throw $compileMinErr('baddir',
7176                     "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
7177                     name);
7178             }
7179           }
7180
7181           /**
7182            * @ngdoc method
7183            * @name $compileProvider#directive
7184            * @kind function
7185            *
7186            * @description
7187            * Register a new directive with the compiler.
7188            *
7189            * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
7190            *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
7191            *    names and the values are the factories.
7192            * @param {Function|Array} directiveFactory An injectable directive factory function. See
7193            *    {@link guide/directive} for more info.
7194            * @returns {ng.$compileProvider} Self for chaining.
7195            */
7196            this.directive = function registerDirective(name, directiveFactory) {
7197             assertNotHasOwnProperty(name, 'directive');
7198             if (isString(name)) {
7199               assertValidDirectiveName(name);
7200               assertArg(directiveFactory, 'directiveFactory');
7201               if (!hasDirectives.hasOwnProperty(name)) {
7202                 hasDirectives[name] = [];
7203                 $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
7204                   function($injector, $exceptionHandler) {
7205                     var directives = [];
7206                     forEach(hasDirectives[name], function(directiveFactory, index) {
7207                       try {
7208                         var directive = $injector.invoke(directiveFactory);
7209                         if (isFunction(directive)) {
7210                           directive = { compile: valueFn(directive) };
7211                         } else if (!directive.compile && directive.link) {
7212                           directive.compile = valueFn(directive.link);
7213                         }
7214                         directive.priority = directive.priority || 0;
7215                         directive.index = index;
7216                         directive.name = directive.name || name;
7217                         directive.require = directive.require || (directive.controller && directive.name);
7218                         directive.restrict = directive.restrict || 'EA';
7219                         var bindings = directive.$$bindings =
7220                             parseDirectiveBindings(directive, directive.name);
7221                         if (isObject(bindings.isolateScope)) {
7222                           directive.$$isolateBindings = bindings.isolateScope;
7223                         }
7224                         directive.$$moduleName = directiveFactory.$$moduleName;
7225                         directives.push(directive);
7226                       } catch (e) {
7227                         $exceptionHandler(e);
7228                       }
7229                     });
7230                     return directives;
7231                   }]);
7232               }
7233               hasDirectives[name].push(directiveFactory);
7234             } else {
7235               forEach(name, reverseParams(registerDirective));
7236             }
7237             return this;
7238           };
7239
7240
7241           /**
7242            * @ngdoc method
7243            * @name $compileProvider#aHrefSanitizationWhitelist
7244            * @kind function
7245            *
7246            * @description
7247            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7248            * urls during a[href] sanitization.
7249            *
7250            * The sanitization is a security measure aimed at preventing XSS attacks via html links.
7251            *
7252            * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
7253            * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
7254            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7255            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7256            *
7257            * @param {RegExp=} regexp New regexp to whitelist urls with.
7258            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7259            *    chaining otherwise.
7260            */
7261           this.aHrefSanitizationWhitelist = function(regexp) {
7262             if (isDefined(regexp)) {
7263               $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
7264               return this;
7265             } else {
7266               return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
7267             }
7268           };
7269
7270
7271           /**
7272            * @ngdoc method
7273            * @name $compileProvider#imgSrcSanitizationWhitelist
7274            * @kind function
7275            *
7276            * @description
7277            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
7278            * urls during img[src] sanitization.
7279            *
7280            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
7281            *
7282            * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
7283            * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
7284            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
7285            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
7286            *
7287            * @param {RegExp=} regexp New regexp to whitelist urls with.
7288            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
7289            *    chaining otherwise.
7290            */
7291           this.imgSrcSanitizationWhitelist = function(regexp) {
7292             if (isDefined(regexp)) {
7293               $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
7294               return this;
7295             } else {
7296               return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
7297             }
7298           };
7299
7300           /**
7301            * @ngdoc method
7302            * @name  $compileProvider#debugInfoEnabled
7303            *
7304            * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
7305            * current debugInfoEnabled state
7306            * @returns {*} current value if used as getter or itself (chaining) if used as setter
7307            *
7308            * @kind function
7309            *
7310            * @description
7311            * Call this method to enable/disable various debug runtime information in the compiler such as adding
7312            * binding information and a reference to the current scope on to DOM elements.
7313            * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
7314            * * `ng-binding` CSS class
7315            * * `$binding` data property containing an array of the binding expressions
7316            *
7317            * You may want to disable this in production for a significant performance boost. See
7318            * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
7319            *
7320            * The default value is true.
7321            */
7322           var debugInfoEnabled = true;
7323           this.debugInfoEnabled = function(enabled) {
7324             if (isDefined(enabled)) {
7325               debugInfoEnabled = enabled;
7326               return this;
7327             }
7328             return debugInfoEnabled;
7329           };
7330
7331           this.$get = [
7332                     '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7333                     '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
7334             function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
7335                      $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
7336
7337             var Attributes = function(element, attributesToCopy) {
7338               if (attributesToCopy) {
7339                 var keys = Object.keys(attributesToCopy);
7340                 var i, l, key;
7341
7342                 for (i = 0, l = keys.length; i < l; i++) {
7343                   key = keys[i];
7344                   this[key] = attributesToCopy[key];
7345                 }
7346               } else {
7347                 this.$attr = {};
7348               }
7349
7350               this.$$element = element;
7351             };
7352
7353             Attributes.prototype = {
7354               /**
7355                * @ngdoc method
7356                * @name $compile.directive.Attributes#$normalize
7357                * @kind function
7358                *
7359                * @description
7360                * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
7361                * `data-`) to its normalized, camelCase form.
7362                *
7363                * Also there is special case for Moz prefix starting with upper case letter.
7364                *
7365                * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7366                *
7367                * @param {string} name Name to normalize
7368                */
7369               $normalize: directiveNormalize,
7370
7371
7372               /**
7373                * @ngdoc method
7374                * @name $compile.directive.Attributes#$addClass
7375                * @kind function
7376                *
7377                * @description
7378                * Adds the CSS class value specified by the classVal parameter to the element. If animations
7379                * are enabled then an animation will be triggered for the class addition.
7380                *
7381                * @param {string} classVal The className value that will be added to the element
7382                */
7383               $addClass: function(classVal) {
7384                 if (classVal && classVal.length > 0) {
7385                   $animate.addClass(this.$$element, classVal);
7386                 }
7387               },
7388
7389               /**
7390                * @ngdoc method
7391                * @name $compile.directive.Attributes#$removeClass
7392                * @kind function
7393                *
7394                * @description
7395                * Removes the CSS class value specified by the classVal parameter from the element. If
7396                * animations are enabled then an animation will be triggered for the class removal.
7397                *
7398                * @param {string} classVal The className value that will be removed from the element
7399                */
7400               $removeClass: function(classVal) {
7401                 if (classVal && classVal.length > 0) {
7402                   $animate.removeClass(this.$$element, classVal);
7403                 }
7404               },
7405
7406               /**
7407                * @ngdoc method
7408                * @name $compile.directive.Attributes#$updateClass
7409                * @kind function
7410                *
7411                * @description
7412                * Adds and removes the appropriate CSS class values to the element based on the difference
7413                * between the new and old CSS class values (specified as newClasses and oldClasses).
7414                *
7415                * @param {string} newClasses The current CSS className value
7416                * @param {string} oldClasses The former CSS className value
7417                */
7418               $updateClass: function(newClasses, oldClasses) {
7419                 var toAdd = tokenDifference(newClasses, oldClasses);
7420                 if (toAdd && toAdd.length) {
7421                   $animate.addClass(this.$$element, toAdd);
7422                 }
7423
7424                 var toRemove = tokenDifference(oldClasses, newClasses);
7425                 if (toRemove && toRemove.length) {
7426                   $animate.removeClass(this.$$element, toRemove);
7427                 }
7428               },
7429
7430               /**
7431                * Set a normalized attribute on the element in a way such that all directives
7432                * can share the attribute. This function properly handles boolean attributes.
7433                * @param {string} key Normalized key. (ie ngAttribute)
7434                * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
7435                * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
7436                *     Defaults to true.
7437                * @param {string=} attrName Optional none normalized name. Defaults to key.
7438                */
7439               $set: function(key, value, writeAttr, attrName) {
7440                 // TODO: decide whether or not to throw an error if "class"
7441                 //is set through this function since it may cause $updateClass to
7442                 //become unstable.
7443
7444                 var node = this.$$element[0],
7445                     booleanKey = getBooleanAttrName(node, key),
7446                     aliasedKey = getAliasedAttrName(key),
7447                     observer = key,
7448                     nodeName;
7449
7450                 if (booleanKey) {
7451                   this.$$element.prop(key, value);
7452                   attrName = booleanKey;
7453                 } else if (aliasedKey) {
7454                   this[aliasedKey] = value;
7455                   observer = aliasedKey;
7456                 }
7457
7458                 this[key] = value;
7459
7460                 // translate normalized key to actual key
7461                 if (attrName) {
7462                   this.$attr[key] = attrName;
7463                 } else {
7464                   attrName = this.$attr[key];
7465                   if (!attrName) {
7466                     this.$attr[key] = attrName = snake_case(key, '-');
7467                   }
7468                 }
7469
7470                 nodeName = nodeName_(this.$$element);
7471
7472                 if ((nodeName === 'a' && key === 'href') ||
7473                     (nodeName === 'img' && key === 'src')) {
7474                   // sanitize a[href] and img[src] values
7475                   this[key] = value = $$sanitizeUri(value, key === 'src');
7476                 } else if (nodeName === 'img' && key === 'srcset') {
7477                   // sanitize img[srcset] values
7478                   var result = "";
7479
7480                   // first check if there are spaces because it's not the same pattern
7481                   var trimmedSrcset = trim(value);
7482                   //                (   999x   ,|   999w   ,|   ,|,   )
7483                   var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
7484                   var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
7485
7486                   // split srcset into tuple of uri and descriptor except for the last item
7487                   var rawUris = trimmedSrcset.split(pattern);
7488
7489                   // for each tuples
7490                   var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
7491                   for (var i = 0; i < nbrUrisWith2parts; i++) {
7492                     var innerIdx = i * 2;
7493                     // sanitize the uri
7494                     result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
7495                     // add the descriptor
7496                     result += (" " + trim(rawUris[innerIdx + 1]));
7497                   }
7498
7499                   // split the last item into uri and descriptor
7500                   var lastTuple = trim(rawUris[i * 2]).split(/\s/);
7501
7502                   // sanitize the last uri
7503                   result += $$sanitizeUri(trim(lastTuple[0]), true);
7504
7505                   // and add the last descriptor if any
7506                   if (lastTuple.length === 2) {
7507                     result += (" " + trim(lastTuple[1]));
7508                   }
7509                   this[key] = value = result;
7510                 }
7511
7512                 if (writeAttr !== false) {
7513                   if (value === null || isUndefined(value)) {
7514                     this.$$element.removeAttr(attrName);
7515                   } else {
7516                     this.$$element.attr(attrName, value);
7517                   }
7518                 }
7519
7520                 // fire observers
7521                 var $$observers = this.$$observers;
7522                 $$observers && forEach($$observers[observer], function(fn) {
7523                   try {
7524                     fn(value);
7525                   } catch (e) {
7526                     $exceptionHandler(e);
7527                   }
7528                 });
7529               },
7530
7531
7532               /**
7533                * @ngdoc method
7534                * @name $compile.directive.Attributes#$observe
7535                * @kind function
7536                *
7537                * @description
7538                * Observes an interpolated attribute.
7539                *
7540                * The observer function will be invoked once during the next `$digest` following
7541                * compilation. The observer is then invoked whenever the interpolated value
7542                * changes.
7543                *
7544                * @param {string} key Normalized key. (ie ngAttribute) .
7545                * @param {function(interpolatedValue)} fn Function that will be called whenever
7546                         the interpolated value of the attribute changes.
7547                *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
7548                * @returns {function()} Returns a deregistration function for this observer.
7549                */
7550               $observe: function(key, fn) {
7551                 var attrs = this,
7552                     $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
7553                     listeners = ($$observers[key] || ($$observers[key] = []));
7554
7555                 listeners.push(fn);
7556                 $rootScope.$evalAsync(function() {
7557                   if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
7558                     // no one registered attribute interpolation function, so lets call it manually
7559                     fn(attrs[key]);
7560                   }
7561                 });
7562
7563                 return function() {
7564                   arrayRemove(listeners, fn);
7565                 };
7566               }
7567             };
7568
7569
7570             function safeAddClass($element, className) {
7571               try {
7572                 $element.addClass(className);
7573               } catch (e) {
7574                 // ignore, since it means that we are trying to set class on
7575                 // SVG element, where class name is read-only.
7576               }
7577             }
7578
7579
7580             var startSymbol = $interpolate.startSymbol(),
7581                 endSymbol = $interpolate.endSymbol(),
7582                 denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
7583                     ? identity
7584                     : function denormalizeTemplate(template) {
7585                       return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
7586                 },
7587                 NG_ATTR_BINDING = /^ngAttr[A-Z]/;
7588             var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
7589
7590             compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
7591               var bindings = $element.data('$binding') || [];
7592
7593               if (isArray(binding)) {
7594                 bindings = bindings.concat(binding);
7595               } else {
7596                 bindings.push(binding);
7597               }
7598
7599               $element.data('$binding', bindings);
7600             } : noop;
7601
7602             compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
7603               safeAddClass($element, 'ng-binding');
7604             } : noop;
7605
7606             compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
7607               var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
7608               $element.data(dataName, scope);
7609             } : noop;
7610
7611             compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
7612               safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
7613             } : noop;
7614
7615             return compile;
7616
7617             //================================
7618
7619             function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
7620                                 previousCompileContext) {
7621               if (!($compileNodes instanceof jqLite)) {
7622                 // jquery always rewraps, whereas we need to preserve the original selector so that we can
7623                 // modify it.
7624                 $compileNodes = jqLite($compileNodes);
7625               }
7626               // We can not compile top level text elements since text nodes can be merged and we will
7627               // not be able to attach scope data to them, so we will wrap them in <span>
7628               forEach($compileNodes, function(node, index) {
7629                 if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
7630                   $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
7631                 }
7632               });
7633               var compositeLinkFn =
7634                       compileNodes($compileNodes, transcludeFn, $compileNodes,
7635                                    maxPriority, ignoreDirective, previousCompileContext);
7636               compile.$$addScopeClass($compileNodes);
7637               var namespace = null;
7638               return function publicLinkFn(scope, cloneConnectFn, options) {
7639                 assertArg(scope, 'scope');
7640
7641                 if (previousCompileContext && previousCompileContext.needsNewScope) {
7642                   // A parent directive did a replace and a directive on this element asked
7643                   // for transclusion, which caused us to lose a layer of element on which
7644                   // we could hold the new transclusion scope, so we will create it manually
7645                   // here.
7646                   scope = scope.$parent.$new();
7647                 }
7648
7649                 options = options || {};
7650                 var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
7651                   transcludeControllers = options.transcludeControllers,
7652                   futureParentElement = options.futureParentElement;
7653
7654                 // When `parentBoundTranscludeFn` is passed, it is a
7655                 // `controllersBoundTransclude` function (it was previously passed
7656                 // as `transclude` to directive.link) so we must unwrap it to get
7657                 // its `boundTranscludeFn`
7658                 if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
7659                   parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
7660                 }
7661
7662                 if (!namespace) {
7663                   namespace = detectNamespaceForChildElements(futureParentElement);
7664                 }
7665                 var $linkNode;
7666                 if (namespace !== 'html') {
7667                   // When using a directive with replace:true and templateUrl the $compileNodes
7668                   // (or a child element inside of them)
7669                   // might change, so we need to recreate the namespace adapted compileNodes
7670                   // for call to the link function.
7671                   // Note: This will already clone the nodes...
7672                   $linkNode = jqLite(
7673                     wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
7674                   );
7675                 } else if (cloneConnectFn) {
7676                   // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
7677                   // and sometimes changes the structure of the DOM.
7678                   $linkNode = JQLitePrototype.clone.call($compileNodes);
7679                 } else {
7680                   $linkNode = $compileNodes;
7681                 }
7682
7683                 if (transcludeControllers) {
7684                   for (var controllerName in transcludeControllers) {
7685                     $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
7686                   }
7687                 }
7688
7689                 compile.$$addScopeInfo($linkNode, scope);
7690
7691                 if (cloneConnectFn) cloneConnectFn($linkNode, scope);
7692                 if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
7693                 return $linkNode;
7694               };
7695             }
7696
7697             function detectNamespaceForChildElements(parentElement) {
7698               // TODO: Make this detect MathML as well...
7699               var node = parentElement && parentElement[0];
7700               if (!node) {
7701                 return 'html';
7702               } else {
7703                 return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7704               }
7705             }
7706
7707             /**
7708              * Compile function matches each node in nodeList against the directives. Once all directives
7709              * for a particular node are collected their compile functions are executed. The compile
7710              * functions return values - the linking functions - are combined into a composite linking
7711              * function, which is the a linking function for the node.
7712              *
7713              * @param {NodeList} nodeList an array of nodes or NodeList to compile
7714              * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7715              *        scope argument is auto-generated to the new child of the transcluded parent scope.
7716              * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7717              *        the rootElement must be set the jqLite collection of the compile root. This is
7718              *        needed so that the jqLite collection items can be replaced with widgets.
7719              * @param {number=} maxPriority Max directive priority.
7720              * @returns {Function} A composite linking function of all of the matched directives or null.
7721              */
7722             function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7723                                     previousCompileContext) {
7724               var linkFns = [],
7725                   attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7726
7727               for (var i = 0; i < nodeList.length; i++) {
7728                 attrs = new Attributes();
7729
7730                 // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7731                 directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7732                                                 ignoreDirective);
7733
7734                 nodeLinkFn = (directives.length)
7735                     ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7736                                               null, [], [], previousCompileContext)
7737                     : null;
7738
7739                 if (nodeLinkFn && nodeLinkFn.scope) {
7740                   compile.$$addScopeClass(attrs.$$element);
7741                 }
7742
7743                 childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7744                               !(childNodes = nodeList[i].childNodes) ||
7745                               !childNodes.length)
7746                     ? null
7747                     : compileNodes(childNodes,
7748                          nodeLinkFn ? (
7749                           (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7750                              && nodeLinkFn.transclude) : transcludeFn);
7751
7752                 if (nodeLinkFn || childLinkFn) {
7753                   linkFns.push(i, nodeLinkFn, childLinkFn);
7754                   linkFnFound = true;
7755                   nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7756                 }
7757
7758                 //use the previous context only for the first element in the virtual group
7759                 previousCompileContext = null;
7760               }
7761
7762               // return a linking function if we have found anything, null otherwise
7763               return linkFnFound ? compositeLinkFn : null;
7764
7765               function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7766                 var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7767                 var stableNodeList;
7768
7769
7770                 if (nodeLinkFnFound) {
7771                   // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7772                   // offsets don't get screwed up
7773                   var nodeListLength = nodeList.length;
7774                   stableNodeList = new Array(nodeListLength);
7775
7776                   // create a sparse array by only copying the elements which have a linkFn
7777                   for (i = 0; i < linkFns.length; i+=3) {
7778                     idx = linkFns[i];
7779                     stableNodeList[idx] = nodeList[idx];
7780                   }
7781                 } else {
7782                   stableNodeList = nodeList;
7783                 }
7784
7785                 for (i = 0, ii = linkFns.length; i < ii;) {
7786                   node = stableNodeList[linkFns[i++]];
7787                   nodeLinkFn = linkFns[i++];
7788                   childLinkFn = linkFns[i++];
7789
7790                   if (nodeLinkFn) {
7791                     if (nodeLinkFn.scope) {
7792                       childScope = scope.$new();
7793                       compile.$$addScopeInfo(jqLite(node), childScope);
7794                     } else {
7795                       childScope = scope;
7796                     }
7797
7798                     if (nodeLinkFn.transcludeOnThisElement) {
7799                       childBoundTranscludeFn = createBoundTranscludeFn(
7800                           scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
7801
7802                     } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7803                       childBoundTranscludeFn = parentBoundTranscludeFn;
7804
7805                     } else if (!parentBoundTranscludeFn && transcludeFn) {
7806                       childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7807
7808                     } else {
7809                       childBoundTranscludeFn = null;
7810                     }
7811
7812                     nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7813
7814                   } else if (childLinkFn) {
7815                     childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7816                   }
7817                 }
7818               }
7819             }
7820
7821             function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
7822
7823               var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7824
7825                 if (!transcludedScope) {
7826                   transcludedScope = scope.$new(false, containingScope);
7827                   transcludedScope.$$transcluded = true;
7828                 }
7829
7830                 return transcludeFn(transcludedScope, cloneFn, {
7831                   parentBoundTranscludeFn: previousBoundTranscludeFn,
7832                   transcludeControllers: controllers,
7833                   futureParentElement: futureParentElement
7834                 });
7835               };
7836
7837               return boundTranscludeFn;
7838             }
7839
7840             /**
7841              * Looks for directives on the given node and adds them to the directive collection which is
7842              * sorted.
7843              *
7844              * @param node Node to search.
7845              * @param directives An array to which the directives are added to. This array is sorted before
7846              *        the function returns.
7847              * @param attrs The shared attrs object which is used to populate the normalized attributes.
7848              * @param {number=} maxPriority Max directive priority.
7849              */
7850             function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7851               var nodeType = node.nodeType,
7852                   attrsMap = attrs.$attr,
7853                   match,
7854                   className;
7855
7856               switch (nodeType) {
7857                 case NODE_TYPE_ELEMENT: /* Element */
7858                   // use the node name: <directive>
7859                   addDirective(directives,
7860                       directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7861
7862                   // iterate over the attributes
7863                   for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7864                            j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7865                     var attrStartName = false;
7866                     var attrEndName = false;
7867
7868                     attr = nAttrs[j];
7869                     name = attr.name;
7870                     value = trim(attr.value);
7871
7872                     // support ngAttr attribute binding
7873                     ngAttrName = directiveNormalize(name);
7874                     if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7875                       name = name.replace(PREFIX_REGEXP, '')
7876                         .substr(8).replace(/_(.)/g, function(match, letter) {
7877                           return letter.toUpperCase();
7878                         });
7879                     }
7880
7881                     var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
7882                     if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
7883                       attrStartName = name;
7884                       attrEndName = name.substr(0, name.length - 5) + 'end';
7885                       name = name.substr(0, name.length - 6);
7886                     }
7887
7888                     nName = directiveNormalize(name.toLowerCase());
7889                     attrsMap[nName] = name;
7890                     if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7891                         attrs[nName] = value;
7892                         if (getBooleanAttrName(node, nName)) {
7893                           attrs[nName] = true; // presence means true
7894                         }
7895                     }
7896                     addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7897                     addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7898                                   attrEndName);
7899                   }
7900
7901                   // use class as directive
7902                   className = node.className;
7903                   if (isObject(className)) {
7904                       // Maybe SVGAnimatedString
7905                       className = className.animVal;
7906                   }
7907                   if (isString(className) && className !== '') {
7908                     while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7909                       nName = directiveNormalize(match[2]);
7910                       if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7911                         attrs[nName] = trim(match[3]);
7912                       }
7913                       className = className.substr(match.index + match[0].length);
7914                     }
7915                   }
7916                   break;
7917                 case NODE_TYPE_TEXT: /* Text Node */
7918                   if (msie === 11) {
7919                     // Workaround for #11781
7920                     while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
7921                       node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
7922                       node.parentNode.removeChild(node.nextSibling);
7923                     }
7924                   }
7925                   addTextInterpolateDirective(directives, node.nodeValue);
7926                   break;
7927                 case NODE_TYPE_COMMENT: /* Comment */
7928                   try {
7929                     match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7930                     if (match) {
7931                       nName = directiveNormalize(match[1]);
7932                       if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7933                         attrs[nName] = trim(match[2]);
7934                       }
7935                     }
7936                   } catch (e) {
7937                     // turns out that under some circumstances IE9 throws errors when one attempts to read
7938                     // comment's node value.
7939                     // Just ignore it and continue. (Can't seem to reproduce in test case.)
7940                   }
7941                   break;
7942               }
7943
7944               directives.sort(byPriority);
7945               return directives;
7946             }
7947
7948             /**
7949              * Given a node with an directive-start it collects all of the siblings until it finds
7950              * directive-end.
7951              * @param node
7952              * @param attrStart
7953              * @param attrEnd
7954              * @returns {*}
7955              */
7956             function groupScan(node, attrStart, attrEnd) {
7957               var nodes = [];
7958               var depth = 0;
7959               if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7960                 do {
7961                   if (!node) {
7962                     throw $compileMinErr('uterdir',
7963                               "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7964                               attrStart, attrEnd);
7965                   }
7966                   if (node.nodeType == NODE_TYPE_ELEMENT) {
7967                     if (node.hasAttribute(attrStart)) depth++;
7968                     if (node.hasAttribute(attrEnd)) depth--;
7969                   }
7970                   nodes.push(node);
7971                   node = node.nextSibling;
7972                 } while (depth > 0);
7973               } else {
7974                 nodes.push(node);
7975               }
7976
7977               return jqLite(nodes);
7978             }
7979
7980             /**
7981              * Wrapper for linking function which converts normal linking function into a grouped
7982              * linking function.
7983              * @param linkFn
7984              * @param attrStart
7985              * @param attrEnd
7986              * @returns {Function}
7987              */
7988             function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7989               return function(scope, element, attrs, controllers, transcludeFn) {
7990                 element = groupScan(element[0], attrStart, attrEnd);
7991                 return linkFn(scope, element, attrs, controllers, transcludeFn);
7992               };
7993             }
7994
7995             /**
7996              * Once the directives have been collected, their compile functions are executed. This method
7997              * is responsible for inlining directive templates as well as terminating the application
7998              * of the directives if the terminal directive has been reached.
7999              *
8000              * @param {Array} directives Array of collected directives to execute their compile function.
8001              *        this needs to be pre-sorted by priority order.
8002              * @param {Node} compileNode The raw DOM node to apply the compile functions to
8003              * @param {Object} templateAttrs The shared attribute function
8004              * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
8005              *                                                  scope argument is auto-generated to the new
8006              *                                                  child of the transcluded parent scope.
8007              * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
8008              *                              argument has the root jqLite array so that we can replace nodes
8009              *                              on it.
8010              * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
8011              *                                           compiling the transclusion.
8012              * @param {Array.<Function>} preLinkFns
8013              * @param {Array.<Function>} postLinkFns
8014              * @param {Object} previousCompileContext Context used for previous compilation of the current
8015              *                                        node
8016              * @returns {Function} linkFn
8017              */
8018             function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
8019                                            jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
8020                                            previousCompileContext) {
8021               previousCompileContext = previousCompileContext || {};
8022
8023               var terminalPriority = -Number.MAX_VALUE,
8024                   newScopeDirective = previousCompileContext.newScopeDirective,
8025                   controllerDirectives = previousCompileContext.controllerDirectives,
8026                   newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
8027                   templateDirective = previousCompileContext.templateDirective,
8028                   nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
8029                   hasTranscludeDirective = false,
8030                   hasTemplate = false,
8031                   hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
8032                   $compileNode = templateAttrs.$$element = jqLite(compileNode),
8033                   directive,
8034                   directiveName,
8035                   $template,
8036                   replaceDirective = originalReplaceDirective,
8037                   childTranscludeFn = transcludeFn,
8038                   linkFn,
8039                   directiveValue;
8040
8041               // executes all directives on the current element
8042               for (var i = 0, ii = directives.length; i < ii; i++) {
8043                 directive = directives[i];
8044                 var attrStart = directive.$$start;
8045                 var attrEnd = directive.$$end;
8046
8047                 // collect multiblock sections
8048                 if (attrStart) {
8049                   $compileNode = groupScan(compileNode, attrStart, attrEnd);
8050                 }
8051                 $template = undefined;
8052
8053                 if (terminalPriority > directive.priority) {
8054                   break; // prevent further processing of directives
8055                 }
8056
8057                 if (directiveValue = directive.scope) {
8058
8059                   // skip the check for directives with async templates, we'll check the derived sync
8060                   // directive when the template arrives
8061                   if (!directive.templateUrl) {
8062                     if (isObject(directiveValue)) {
8063                       // This directive is trying to add an isolated scope.
8064                       // Check that there is no scope of any kind already
8065                       assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
8066                                         directive, $compileNode);
8067                       newIsolateScopeDirective = directive;
8068                     } else {
8069                       // This directive is trying to add a child scope.
8070                       // Check that there is no isolated scope already
8071                       assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
8072                                         $compileNode);
8073                     }
8074                   }
8075
8076                   newScopeDirective = newScopeDirective || directive;
8077                 }
8078
8079                 directiveName = directive.name;
8080
8081                 if (!directive.templateUrl && directive.controller) {
8082                   directiveValue = directive.controller;
8083                   controllerDirectives = controllerDirectives || createMap();
8084                   assertNoDuplicate("'" + directiveName + "' controller",
8085                       controllerDirectives[directiveName], directive, $compileNode);
8086                   controllerDirectives[directiveName] = directive;
8087                 }
8088
8089                 if (directiveValue = directive.transclude) {
8090                   hasTranscludeDirective = true;
8091
8092                   // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
8093                   // This option should only be used by directives that know how to safely handle element transclusion,
8094                   // where the transcluded nodes are added or replaced after linking.
8095                   if (!directive.$$tlb) {
8096                     assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
8097                     nonTlbTranscludeDirective = directive;
8098                   }
8099
8100                   if (directiveValue == 'element') {
8101                     hasElementTranscludeDirective = true;
8102                     terminalPriority = directive.priority;
8103                     $template = $compileNode;
8104                     $compileNode = templateAttrs.$$element =
8105                         jqLite(document.createComment(' ' + directiveName + ': ' +
8106                                                       templateAttrs[directiveName] + ' '));
8107                     compileNode = $compileNode[0];
8108                     replaceWith(jqCollection, sliceArgs($template), compileNode);
8109
8110                     childTranscludeFn = compile($template, transcludeFn, terminalPriority,
8111                                                 replaceDirective && replaceDirective.name, {
8112                                                   // Don't pass in:
8113                                                   // - controllerDirectives - otherwise we'll create duplicates controllers
8114                                                   // - newIsolateScopeDirective or templateDirective - combining templates with
8115                                                   //   element transclusion doesn't make sense.
8116                                                   //
8117                                                   // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
8118                                                   // on the same element more than once.
8119                                                   nonTlbTranscludeDirective: nonTlbTranscludeDirective
8120                                                 });
8121                   } else {
8122                     $template = jqLite(jqLiteClone(compileNode)).contents();
8123                     $compileNode.empty(); // clear contents
8124                     childTranscludeFn = compile($template, transcludeFn, undefined,
8125                         undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
8126                   }
8127                 }
8128
8129                 if (directive.template) {
8130                   hasTemplate = true;
8131                   assertNoDuplicate('template', templateDirective, directive, $compileNode);
8132                   templateDirective = directive;
8133
8134                   directiveValue = (isFunction(directive.template))
8135                       ? directive.template($compileNode, templateAttrs)
8136                       : directive.template;
8137
8138                   directiveValue = denormalizeTemplate(directiveValue);
8139
8140                   if (directive.replace) {
8141                     replaceDirective = directive;
8142                     if (jqLiteIsTextNode(directiveValue)) {
8143                       $template = [];
8144                     } else {
8145                       $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
8146                     }
8147                     compileNode = $template[0];
8148
8149                     if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8150                       throw $compileMinErr('tplrt',
8151                           "Template for directive '{0}' must have exactly one root element. {1}",
8152                           directiveName, '');
8153                     }
8154
8155                     replaceWith(jqCollection, $compileNode, compileNode);
8156
8157                     var newTemplateAttrs = {$attr: {}};
8158
8159                     // combine directives from the original node and from the template:
8160                     // - take the array of directives for this element
8161                     // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
8162                     // - collect directives from the template and sort them by priority
8163                     // - combine directives as: processed + template + unprocessed
8164                     var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
8165                     var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
8166
8167                     if (newIsolateScopeDirective || newScopeDirective) {
8168                       // The original directive caused the current element to be replaced but this element
8169                       // also needs to have a new scope, so we need to tell the template directives
8170                       // that they would need to get their scope from further up, if they require transclusion
8171                       markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
8172                     }
8173                     directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
8174                     mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
8175
8176                     ii = directives.length;
8177                   } else {
8178                     $compileNode.html(directiveValue);
8179                   }
8180                 }
8181
8182                 if (directive.templateUrl) {
8183                   hasTemplate = true;
8184                   assertNoDuplicate('template', templateDirective, directive, $compileNode);
8185                   templateDirective = directive;
8186
8187                   if (directive.replace) {
8188                     replaceDirective = directive;
8189                   }
8190
8191                   nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
8192                       templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
8193                         controllerDirectives: controllerDirectives,
8194                         newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
8195                         newIsolateScopeDirective: newIsolateScopeDirective,
8196                         templateDirective: templateDirective,
8197                         nonTlbTranscludeDirective: nonTlbTranscludeDirective
8198                       });
8199                   ii = directives.length;
8200                 } else if (directive.compile) {
8201                   try {
8202                     linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
8203                     if (isFunction(linkFn)) {
8204                       addLinkFns(null, linkFn, attrStart, attrEnd);
8205                     } else if (linkFn) {
8206                       addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
8207                     }
8208                   } catch (e) {
8209                     $exceptionHandler(e, startingTag($compileNode));
8210                   }
8211                 }
8212
8213                 if (directive.terminal) {
8214                   nodeLinkFn.terminal = true;
8215                   terminalPriority = Math.max(terminalPriority, directive.priority);
8216                 }
8217
8218               }
8219
8220               nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
8221               nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
8222               nodeLinkFn.templateOnThisElement = hasTemplate;
8223               nodeLinkFn.transclude = childTranscludeFn;
8224
8225               previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
8226
8227               // might be normal or delayed nodeLinkFn depending on if templateUrl is present
8228               return nodeLinkFn;
8229
8230               ////////////////////
8231
8232               function addLinkFns(pre, post, attrStart, attrEnd) {
8233                 if (pre) {
8234                   if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
8235                   pre.require = directive.require;
8236                   pre.directiveName = directiveName;
8237                   if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8238                     pre = cloneAndAnnotateFn(pre, {isolateScope: true});
8239                   }
8240                   preLinkFns.push(pre);
8241                 }
8242                 if (post) {
8243                   if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
8244                   post.require = directive.require;
8245                   post.directiveName = directiveName;
8246                   if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
8247                     post = cloneAndAnnotateFn(post, {isolateScope: true});
8248                   }
8249                   postLinkFns.push(post);
8250                 }
8251               }
8252
8253
8254               function getControllers(directiveName, require, $element, elementControllers) {
8255                 var value;
8256
8257                 if (isString(require)) {
8258                   var match = require.match(REQUIRE_PREFIX_REGEXP);
8259                   var name = require.substring(match[0].length);
8260                   var inheritType = match[1] || match[3];
8261                   var optional = match[2] === '?';
8262
8263                   //If only parents then start at the parent element
8264                   if (inheritType === '^^') {
8265                     $element = $element.parent();
8266                   //Otherwise attempt getting the controller from elementControllers in case
8267                   //the element is transcluded (and has no data) and to avoid .data if possible
8268                   } else {
8269                     value = elementControllers && elementControllers[name];
8270                     value = value && value.instance;
8271                   }
8272
8273                   if (!value) {
8274                     var dataName = '$' + name + 'Controller';
8275                     value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
8276                   }
8277
8278                   if (!value && !optional) {
8279                     throw $compileMinErr('ctreq',
8280                         "Controller '{0}', required by directive '{1}', can't be found!",
8281                         name, directiveName);
8282                   }
8283                 } else if (isArray(require)) {
8284                   value = [];
8285                   for (var i = 0, ii = require.length; i < ii; i++) {
8286                     value[i] = getControllers(directiveName, require[i], $element, elementControllers);
8287                   }
8288                 }
8289
8290                 return value || null;
8291               }
8292
8293               function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
8294                 var elementControllers = createMap();
8295                 for (var controllerKey in controllerDirectives) {
8296                   var directive = controllerDirectives[controllerKey];
8297                   var locals = {
8298                     $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
8299                     $element: $element,
8300                     $attrs: attrs,
8301                     $transclude: transcludeFn
8302                   };
8303
8304                   var controller = directive.controller;
8305                   if (controller == '@') {
8306                     controller = attrs[directive.name];
8307                   }
8308
8309                   var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
8310
8311                   // For directives with element transclusion the element is a comment,
8312                   // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
8313                   // clean up (http://bugs.jquery.com/ticket/8335).
8314                   // Instead, we save the controllers for the element in a local hash and attach to .data
8315                   // later, once we have the actual element.
8316                   elementControllers[directive.name] = controllerInstance;
8317                   if (!hasElementTranscludeDirective) {
8318                     $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
8319                   }
8320                 }
8321                 return elementControllers;
8322               }
8323
8324               function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8325                 var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8326                     attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8327
8328                 if (compileNode === linkNode) {
8329                   attrs = templateAttrs;
8330                   $element = templateAttrs.$$element;
8331                 } else {
8332                   $element = jqLite(linkNode);
8333                   attrs = new Attributes($element, templateAttrs);
8334                 }
8335
8336                 controllerScope = scope;
8337                 if (newIsolateScopeDirective) {
8338                   isolateScope = scope.$new(true);
8339                 } else if (newScopeDirective) {
8340                   controllerScope = scope.$parent;
8341                 }
8342
8343                 if (boundTranscludeFn) {
8344                   // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
8345                   // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
8346                   transcludeFn = controllersBoundTransclude;
8347                   transcludeFn.$$boundTransclude = boundTranscludeFn;
8348                 }
8349
8350                 if (controllerDirectives) {
8351                   elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
8352                 }
8353
8354                 if (newIsolateScopeDirective) {
8355                   // Initialize isolate scope bindings for new isolate scope directive.
8356                   compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
8357                       templateDirective === newIsolateScopeDirective.$$originalDirective)));
8358                   compile.$$addScopeClass($element, true);
8359                   isolateScope.$$isolateBindings =
8360                       newIsolateScopeDirective.$$isolateBindings;
8361                   removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
8362                                                 isolateScope.$$isolateBindings,
8363                                                 newIsolateScopeDirective);
8364                   if (removeScopeBindingWatches) {
8365                     isolateScope.$on('$destroy', removeScopeBindingWatches);
8366                   }
8367                 }
8368
8369                 // Initialize bindToController bindings
8370                 for (var name in elementControllers) {
8371                   var controllerDirective = controllerDirectives[name];
8372                   var controller = elementControllers[name];
8373                   var bindings = controllerDirective.$$bindings.bindToController;
8374
8375                   if (controller.identifier && bindings) {
8376                     removeControllerBindingWatches =
8377                       initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8378                   }
8379
8380                   var controllerResult = controller();
8381                   if (controllerResult !== controller.instance) {
8382                     // If the controller constructor has a return value, overwrite the instance
8383                     // from setupControllers
8384                     controller.instance = controllerResult;
8385                     $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8386                     removeControllerBindingWatches && removeControllerBindingWatches();
8387                     removeControllerBindingWatches =
8388                       initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8389                   }
8390                 }
8391
8392                 // PRELINKING
8393                 for (i = 0, ii = preLinkFns.length; i < ii; i++) {
8394                   linkFn = preLinkFns[i];
8395                   invokeLinkFn(linkFn,
8396                       linkFn.isolateScope ? isolateScope : scope,
8397                       $element,
8398                       attrs,
8399                       linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8400                       transcludeFn
8401                   );
8402                 }
8403
8404                 // RECURSION
8405                 // We only pass the isolate scope, if the isolate directive has a template,
8406                 // otherwise the child elements do not belong to the isolate directive.
8407                 var scopeToChild = scope;
8408                 if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
8409                   scopeToChild = isolateScope;
8410                 }
8411                 childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
8412
8413                 // POSTLINKING
8414                 for (i = postLinkFns.length - 1; i >= 0; i--) {
8415                   linkFn = postLinkFns[i];
8416                   invokeLinkFn(linkFn,
8417                       linkFn.isolateScope ? isolateScope : scope,
8418                       $element,
8419                       attrs,
8420                       linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8421                       transcludeFn
8422                   );
8423                 }
8424
8425                 // This is the function that is injected as `$transclude`.
8426                 // Note: all arguments are optional!
8427                 function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
8428                   var transcludeControllers;
8429
8430                   // No scope passed in:
8431                   if (!isScope(scope)) {
8432                     futureParentElement = cloneAttachFn;
8433                     cloneAttachFn = scope;
8434                     scope = undefined;
8435                   }
8436
8437                   if (hasElementTranscludeDirective) {
8438                     transcludeControllers = elementControllers;
8439                   }
8440                   if (!futureParentElement) {
8441                     futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
8442                   }
8443                   return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
8444                 }
8445               }
8446             }
8447
8448             // Depending upon the context in which a directive finds itself it might need to have a new isolated
8449             // or child scope created. For instance:
8450             // * if the directive has been pulled into a template because another directive with a higher priority
8451             // asked for element transclusion
8452             // * if the directive itself asks for transclusion but it is at the root of a template and the original
8453             // element was replaced. See https://github.com/angular/angular.js/issues/12936
8454             function markDirectiveScope(directives, isolateScope, newScope) {
8455               for (var j = 0, jj = directives.length; j < jj; j++) {
8456                 directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
8457               }
8458             }
8459
8460             /**
8461              * looks up the directive and decorates it with exception handling and proper parameters. We
8462              * call this the boundDirective.
8463              *
8464              * @param {string} name name of the directive to look up.
8465              * @param {string} location The directive must be found in specific format.
8466              *   String containing any of theses characters:
8467              *
8468              *   * `E`: element name
8469              *   * `A': attribute
8470              *   * `C`: class
8471              *   * `M`: comment
8472              * @returns {boolean} true if directive was added.
8473              */
8474             function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
8475                                   endAttrName) {
8476               if (name === ignoreDirective) return null;
8477               var match = null;
8478               if (hasDirectives.hasOwnProperty(name)) {
8479                 for (var directive, directives = $injector.get(name + Suffix),
8480                     i = 0, ii = directives.length; i < ii; i++) {
8481                   try {
8482                     directive = directives[i];
8483                     if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
8484                          directive.restrict.indexOf(location) != -1) {
8485                       if (startAttrName) {
8486                         directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
8487                       }
8488                       tDirectives.push(directive);
8489                       match = directive;
8490                     }
8491                   } catch (e) { $exceptionHandler(e); }
8492                 }
8493               }
8494               return match;
8495             }
8496
8497
8498             /**
8499              * looks up the directive and returns true if it is a multi-element directive,
8500              * and therefore requires DOM nodes between -start and -end markers to be grouped
8501              * together.
8502              *
8503              * @param {string} name name of the directive to look up.
8504              * @returns true if directive was registered as multi-element.
8505              */
8506             function directiveIsMultiElement(name) {
8507               if (hasDirectives.hasOwnProperty(name)) {
8508                 for (var directive, directives = $injector.get(name + Suffix),
8509                     i = 0, ii = directives.length; i < ii; i++) {
8510                   directive = directives[i];
8511                   if (directive.multiElement) {
8512                     return true;
8513                   }
8514                 }
8515               }
8516               return false;
8517             }
8518
8519             /**
8520              * When the element is replaced with HTML template then the new attributes
8521              * on the template need to be merged with the existing attributes in the DOM.
8522              * The desired effect is to have both of the attributes present.
8523              *
8524              * @param {object} dst destination attributes (original DOM)
8525              * @param {object} src source attributes (from the directive template)
8526              */
8527             function mergeTemplateAttributes(dst, src) {
8528               var srcAttr = src.$attr,
8529                   dstAttr = dst.$attr,
8530                   $element = dst.$$element;
8531
8532               // reapply the old attributes to the new element
8533               forEach(dst, function(value, key) {
8534                 if (key.charAt(0) != '$') {
8535                   if (src[key] && src[key] !== value) {
8536                     value += (key === 'style' ? ';' : ' ') + src[key];
8537                   }
8538                   dst.$set(key, value, true, srcAttr[key]);
8539                 }
8540               });
8541
8542               // copy the new attributes on the old attrs object
8543               forEach(src, function(value, key) {
8544                 if (key == 'class') {
8545                   safeAddClass($element, value);
8546                   dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
8547                 } else if (key == 'style') {
8548                   $element.attr('style', $element.attr('style') + ';' + value);
8549                   dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
8550                   // `dst` will never contain hasOwnProperty as DOM parser won't let it.
8551                   // You will get an "InvalidCharacterError: DOM Exception 5" error if you
8552                   // have an attribute like "has-own-property" or "data-has-own-property", etc.
8553                 } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
8554                   dst[key] = value;
8555                   dstAttr[key] = srcAttr[key];
8556                 }
8557               });
8558             }
8559
8560
8561             function compileTemplateUrl(directives, $compileNode, tAttrs,
8562                 $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
8563               var linkQueue = [],
8564                   afterTemplateNodeLinkFn,
8565                   afterTemplateChildLinkFn,
8566                   beforeTemplateCompileNode = $compileNode[0],
8567                   origAsyncDirective = directives.shift(),
8568                   derivedSyncDirective = inherit(origAsyncDirective, {
8569                     templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
8570                   }),
8571                   templateUrl = (isFunction(origAsyncDirective.templateUrl))
8572                       ? origAsyncDirective.templateUrl($compileNode, tAttrs)
8573                       : origAsyncDirective.templateUrl,
8574                   templateNamespace = origAsyncDirective.templateNamespace;
8575
8576               $compileNode.empty();
8577
8578               $templateRequest(templateUrl)
8579                 .then(function(content) {
8580                   var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
8581
8582                   content = denormalizeTemplate(content);
8583
8584                   if (origAsyncDirective.replace) {
8585                     if (jqLiteIsTextNode(content)) {
8586                       $template = [];
8587                     } else {
8588                       $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
8589                     }
8590                     compileNode = $template[0];
8591
8592                     if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8593                       throw $compileMinErr('tplrt',
8594                           "Template for directive '{0}' must have exactly one root element. {1}",
8595                           origAsyncDirective.name, templateUrl);
8596                     }
8597
8598                     tempTemplateAttrs = {$attr: {}};
8599                     replaceWith($rootElement, $compileNode, compileNode);
8600                     var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
8601
8602                     if (isObject(origAsyncDirective.scope)) {
8603                       // the original directive that caused the template to be loaded async required
8604                       // an isolate scope
8605                       markDirectiveScope(templateDirectives, true);
8606                     }
8607                     directives = templateDirectives.concat(directives);
8608                     mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
8609                   } else {
8610                     compileNode = beforeTemplateCompileNode;
8611                     $compileNode.html(content);
8612                   }
8613
8614                   directives.unshift(derivedSyncDirective);
8615
8616                   afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
8617                       childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
8618                       previousCompileContext);
8619                   forEach($rootElement, function(node, i) {
8620                     if (node == compileNode) {
8621                       $rootElement[i] = $compileNode[0];
8622                     }
8623                   });
8624                   afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
8625
8626                   while (linkQueue.length) {
8627                     var scope = linkQueue.shift(),
8628                         beforeTemplateLinkNode = linkQueue.shift(),
8629                         linkRootElement = linkQueue.shift(),
8630                         boundTranscludeFn = linkQueue.shift(),
8631                         linkNode = $compileNode[0];
8632
8633                     if (scope.$$destroyed) continue;
8634
8635                     if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
8636                       var oldClasses = beforeTemplateLinkNode.className;
8637
8638                       if (!(previousCompileContext.hasElementTranscludeDirective &&
8639                           origAsyncDirective.replace)) {
8640                         // it was cloned therefore we have to clone as well.
8641                         linkNode = jqLiteClone(compileNode);
8642                       }
8643                       replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
8644
8645                       // Copy in CSS classes from original node
8646                       safeAddClass(jqLite(linkNode), oldClasses);
8647                     }
8648                     if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8649                       childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8650                     } else {
8651                       childBoundTranscludeFn = boundTranscludeFn;
8652                     }
8653                     afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8654                       childBoundTranscludeFn);
8655                   }
8656                   linkQueue = null;
8657                 });
8658
8659               return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8660                 var childBoundTranscludeFn = boundTranscludeFn;
8661                 if (scope.$$destroyed) return;
8662                 if (linkQueue) {
8663                   linkQueue.push(scope,
8664                                  node,
8665                                  rootElement,
8666                                  childBoundTranscludeFn);
8667                 } else {
8668                   if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8669                     childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8670                   }
8671                   afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8672                 }
8673               };
8674             }
8675
8676
8677             /**
8678              * Sorting function for bound directives.
8679              */
8680             function byPriority(a, b) {
8681               var diff = b.priority - a.priority;
8682               if (diff !== 0) return diff;
8683               if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8684               return a.index - b.index;
8685             }
8686
8687             function assertNoDuplicate(what, previousDirective, directive, element) {
8688
8689               function wrapModuleNameIfDefined(moduleName) {
8690                 return moduleName ?
8691                   (' (module: ' + moduleName + ')') :
8692                   '';
8693               }
8694
8695               if (previousDirective) {
8696                 throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
8697                     previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
8698                     directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
8699               }
8700             }
8701
8702
8703             function addTextInterpolateDirective(directives, text) {
8704               var interpolateFn = $interpolate(text, true);
8705               if (interpolateFn) {
8706                 directives.push({
8707                   priority: 0,
8708                   compile: function textInterpolateCompileFn(templateNode) {
8709                     var templateNodeParent = templateNode.parent(),
8710                         hasCompileParent = !!templateNodeParent.length;
8711
8712                     // When transcluding a template that has bindings in the root
8713                     // we don't have a parent and thus need to add the class during linking fn.
8714                     if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8715
8716                     return function textInterpolateLinkFn(scope, node) {
8717                       var parent = node.parent();
8718                       if (!hasCompileParent) compile.$$addBindingClass(parent);
8719                       compile.$$addBindingInfo(parent, interpolateFn.expressions);
8720                       scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8721                         node[0].nodeValue = value;
8722                       });
8723                     };
8724                   }
8725                 });
8726               }
8727             }
8728
8729
8730             function wrapTemplate(type, template) {
8731               type = lowercase(type || 'html');
8732               switch (type) {
8733               case 'svg':
8734               case 'math':
8735                 var wrapper = document.createElement('div');
8736                 wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8737                 return wrapper.childNodes[0].childNodes;
8738               default:
8739                 return template;
8740               }
8741             }
8742
8743
8744             function getTrustedContext(node, attrNormalizedName) {
8745               if (attrNormalizedName == "srcdoc") {
8746                 return $sce.HTML;
8747               }
8748               var tag = nodeName_(node);
8749               // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8750               if (attrNormalizedName == "xlinkHref" ||
8751                   (tag == "form" && attrNormalizedName == "action") ||
8752                   (tag != "img" && (attrNormalizedName == "src" ||
8753                                     attrNormalizedName == "ngSrc"))) {
8754                 return $sce.RESOURCE_URL;
8755               }
8756             }
8757
8758
8759             function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8760               var trustedContext = getTrustedContext(node, name);
8761               allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8762
8763               var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8764
8765               // no interpolation found -> ignore
8766               if (!interpolateFn) return;
8767
8768
8769               if (name === "multiple" && nodeName_(node) === "select") {
8770                 throw $compileMinErr("selmulti",
8771                     "Binding to the 'multiple' attribute is not supported. Element: {0}",
8772                     startingTag(node));
8773               }
8774
8775               directives.push({
8776                 priority: 100,
8777                 compile: function() {
8778                     return {
8779                       pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8780                         var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
8781
8782                         if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8783                           throw $compileMinErr('nodomevents',
8784                               "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8785                                   "ng- versions (such as ng-click instead of onclick) instead.");
8786                         }
8787
8788                         // If the attribute has changed since last $interpolate()ed
8789                         var newValue = attr[name];
8790                         if (newValue !== value) {
8791                           // we need to interpolate again since the attribute value has been updated
8792                           // (e.g. by another directive's compile function)
8793                           // ensure unset/empty values make interpolateFn falsy
8794                           interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8795                           value = newValue;
8796                         }
8797
8798                         // if attribute was updated so that there is no interpolation going on we don't want to
8799                         // register any observers
8800                         if (!interpolateFn) return;
8801
8802                         // initialize attr object so that it's ready in case we need the value for isolate
8803                         // scope initialization, otherwise the value would not be available from isolate
8804                         // directive's linking fn during linking phase
8805                         attr[name] = interpolateFn(scope);
8806
8807                         ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8808                         (attr.$$observers && attr.$$observers[name].$$scope || scope).
8809                           $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8810                             //special case for class attribute addition + removal
8811                             //so that class changes can tap into the animation
8812                             //hooks provided by the $animate service. Be sure to
8813                             //skip animations when the first digest occurs (when
8814                             //both the new and the old values are the same) since
8815                             //the CSS classes are the non-interpolated values
8816                             if (name === 'class' && newValue != oldValue) {
8817                               attr.$updateClass(newValue, oldValue);
8818                             } else {
8819                               attr.$set(name, newValue);
8820                             }
8821                           });
8822                       }
8823                     };
8824                   }
8825               });
8826             }
8827
8828
8829             /**
8830              * This is a special jqLite.replaceWith, which can replace items which
8831              * have no parents, provided that the containing jqLite collection is provided.
8832              *
8833              * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8834              *                               in the root of the tree.
8835              * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8836              *                                  the shell, but replace its DOM node reference.
8837              * @param {Node} newNode The new DOM node.
8838              */
8839             function replaceWith($rootElement, elementsToRemove, newNode) {
8840               var firstElementToRemove = elementsToRemove[0],
8841                   removeCount = elementsToRemove.length,
8842                   parent = firstElementToRemove.parentNode,
8843                   i, ii;
8844
8845               if ($rootElement) {
8846                 for (i = 0, ii = $rootElement.length; i < ii; i++) {
8847                   if ($rootElement[i] == firstElementToRemove) {
8848                     $rootElement[i++] = newNode;
8849                     for (var j = i, j2 = j + removeCount - 1,
8850                              jj = $rootElement.length;
8851                          j < jj; j++, j2++) {
8852                       if (j2 < jj) {
8853                         $rootElement[j] = $rootElement[j2];
8854                       } else {
8855                         delete $rootElement[j];
8856                       }
8857                     }
8858                     $rootElement.length -= removeCount - 1;
8859
8860                     // If the replaced element is also the jQuery .context then replace it
8861                     // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8862                     // http://api.jquery.com/context/
8863                     if ($rootElement.context === firstElementToRemove) {
8864                       $rootElement.context = newNode;
8865                     }
8866                     break;
8867                   }
8868                 }
8869               }
8870
8871               if (parent) {
8872                 parent.replaceChild(newNode, firstElementToRemove);
8873               }
8874
8875               // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8876               var fragment = document.createDocumentFragment();
8877               fragment.appendChild(firstElementToRemove);
8878
8879               if (jqLite.hasData(firstElementToRemove)) {
8880                 // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8881                 // data here because there's no public interface in jQuery to do that and copying over
8882                 // event listeners (which is the main use of private data) wouldn't work anyway.
8883                 jqLite.data(newNode, jqLite.data(firstElementToRemove));
8884
8885                 // Remove data of the replaced element. We cannot just call .remove()
8886                 // on the element it since that would deallocate scope that is needed
8887                 // for the new node. Instead, remove the data "manually".
8888                 if (!jQuery) {
8889                   delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8890                 } else {
8891                   // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8892                   // the replaced element. The cleanData version monkey-patched by Angular would cause
8893                   // the scope to be trashed and we do need the very same scope to work with the new
8894                   // element. However, we cannot just cache the non-patched version and use it here as
8895                   // that would break if another library patches the method after Angular does (one
8896                   // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8897                   // skipped this one time.
8898                   skipDestroyOnNextJQueryCleanData = true;
8899                   jQuery.cleanData([firstElementToRemove]);
8900                 }
8901               }
8902
8903               for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8904                 var element = elementsToRemove[k];
8905                 jqLite(element).remove(); // must do this way to clean up expando
8906                 fragment.appendChild(element);
8907                 delete elementsToRemove[k];
8908               }
8909
8910               elementsToRemove[0] = newNode;
8911               elementsToRemove.length = 1;
8912             }
8913
8914
8915             function cloneAndAnnotateFn(fn, annotation) {
8916               return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8917             }
8918
8919
8920             function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8921               try {
8922                 linkFn(scope, $element, attrs, controllers, transcludeFn);
8923               } catch (e) {
8924                 $exceptionHandler(e, startingTag($element));
8925               }
8926             }
8927
8928
8929             // Set up $watches for isolate scope and controller bindings. This process
8930             // only occurs for isolate scopes and new scopes with controllerAs.
8931             function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
8932               var removeWatchCollection = [];
8933               forEach(bindings, function(definition, scopeName) {
8934                 var attrName = definition.attrName,
8935                 optional = definition.optional,
8936                 mode = definition.mode, // @, =, or &
8937                 lastValue,
8938                 parentGet, parentSet, compare;
8939
8940                 switch (mode) {
8941
8942                   case '@':
8943                     if (!optional && !hasOwnProperty.call(attrs, attrName)) {
8944                       destination[scopeName] = attrs[attrName] = void 0;
8945                     }
8946                     attrs.$observe(attrName, function(value) {
8947                       if (isString(value)) {
8948                         destination[scopeName] = value;
8949                       }
8950                     });
8951                     attrs.$$observers[attrName].$$scope = scope;
8952                     if (isString(attrs[attrName])) {
8953                       // If the attribute has been provided then we trigger an interpolation to ensure
8954                       // the value is there for use in the link fn
8955                       destination[scopeName] = $interpolate(attrs[attrName])(scope);
8956                     }
8957                     break;
8958
8959                   case '=':
8960                     if (!hasOwnProperty.call(attrs, attrName)) {
8961                       if (optional) break;
8962                       attrs[attrName] = void 0;
8963                     }
8964                     if (optional && !attrs[attrName]) break;
8965
8966                     parentGet = $parse(attrs[attrName]);
8967                     if (parentGet.literal) {
8968                       compare = equals;
8969                     } else {
8970                       compare = function(a, b) { return a === b || (a !== a && b !== b); };
8971                     }
8972                     parentSet = parentGet.assign || function() {
8973                       // reset the change, or we will throw this exception on every $digest
8974                       lastValue = destination[scopeName] = parentGet(scope);
8975                       throw $compileMinErr('nonassign',
8976                           "Expression '{0}' used with directive '{1}' is non-assignable!",
8977                           attrs[attrName], directive.name);
8978                     };
8979                     lastValue = destination[scopeName] = parentGet(scope);
8980                     var parentValueWatch = function parentValueWatch(parentValue) {
8981                       if (!compare(parentValue, destination[scopeName])) {
8982                         // we are out of sync and need to copy
8983                         if (!compare(parentValue, lastValue)) {
8984                           // parent changed and it has precedence
8985                           destination[scopeName] = parentValue;
8986                         } else {
8987                           // if the parent can be assigned then do so
8988                           parentSet(scope, parentValue = destination[scopeName]);
8989                         }
8990                       }
8991                       return lastValue = parentValue;
8992                     };
8993                     parentValueWatch.$stateful = true;
8994                     var removeWatch;
8995                     if (definition.collection) {
8996                       removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8997                     } else {
8998                       removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8999                     }
9000                     removeWatchCollection.push(removeWatch);
9001                     break;
9002
9003                   case '&':
9004                     // Don't assign Object.prototype method to scope
9005                     parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
9006
9007                     // Don't assign noop to destination if expression is not valid
9008                     if (parentGet === noop && optional) break;
9009
9010                     destination[scopeName] = function(locals) {
9011                       return parentGet(scope, locals);
9012                     };
9013                     break;
9014                 }
9015               });
9016
9017               return removeWatchCollection.length && function removeWatches() {
9018                 for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
9019                   removeWatchCollection[i]();
9020                 }
9021               };
9022             }
9023           }];
9024         }
9025
9026         var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
9027         /**
9028          * Converts all accepted directives format into proper directive name.
9029          * @param name Name to normalize
9030          */
9031         function directiveNormalize(name) {
9032           return camelCase(name.replace(PREFIX_REGEXP, ''));
9033         }
9034
9035         /**
9036          * @ngdoc type
9037          * @name $compile.directive.Attributes
9038          *
9039          * @description
9040          * A shared object between directive compile / linking functions which contains normalized DOM
9041          * element attributes. The values reflect current binding state `{{ }}`. The normalization is
9042          * needed since all of these are treated as equivalent in Angular:
9043          *
9044          * ```
9045          *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
9046          * ```
9047          */
9048
9049         /**
9050          * @ngdoc property
9051          * @name $compile.directive.Attributes#$attr
9052          *
9053          * @description
9054          * A map of DOM element attribute names to the normalized name. This is
9055          * needed to do reverse lookup from normalized name back to actual name.
9056          */
9057
9058
9059         /**
9060          * @ngdoc method
9061          * @name $compile.directive.Attributes#$set
9062          * @kind function
9063          *
9064          * @description
9065          * Set DOM element attribute value.
9066          *
9067          *
9068          * @param {string} name Normalized element attribute name of the property to modify. The name is
9069          *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
9070          *          property to the original name.
9071          * @param {string} value Value to set the attribute to. The value can be an interpolated string.
9072          */
9073
9074
9075
9076         /**
9077          * Closure compiler type information
9078          */
9079
9080         function nodesetLinkingFn(
9081           /* angular.Scope */ scope,
9082           /* NodeList */ nodeList,
9083           /* Element */ rootElement,
9084           /* function(Function) */ boundTranscludeFn
9085         ) {}
9086
9087         function directiveLinkingFn(
9088           /* nodesetLinkingFn */ nodesetLinkingFn,
9089           /* angular.Scope */ scope,
9090           /* Node */ node,
9091           /* Element */ rootElement,
9092           /* function(Function) */ boundTranscludeFn
9093         ) {}
9094
9095         function tokenDifference(str1, str2) {
9096           var values = '',
9097               tokens1 = str1.split(/\s+/),
9098               tokens2 = str2.split(/\s+/);
9099
9100           outer:
9101           for (var i = 0; i < tokens1.length; i++) {
9102             var token = tokens1[i];
9103             for (var j = 0; j < tokens2.length; j++) {
9104               if (token == tokens2[j]) continue outer;
9105             }
9106             values += (values.length > 0 ? ' ' : '') + token;
9107           }
9108           return values;
9109         }
9110
9111         function removeComments(jqNodes) {
9112           jqNodes = jqLite(jqNodes);
9113           var i = jqNodes.length;
9114
9115           if (i <= 1) {
9116             return jqNodes;
9117           }
9118
9119           while (i--) {
9120             var node = jqNodes[i];
9121             if (node.nodeType === NODE_TYPE_COMMENT) {
9122               splice.call(jqNodes, i, 1);
9123             }
9124           }
9125           return jqNodes;
9126         }
9127
9128         var $controllerMinErr = minErr('$controller');
9129
9130
9131         var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
9132         function identifierForController(controller, ident) {
9133           if (ident && isString(ident)) return ident;
9134           if (isString(controller)) {
9135             var match = CNTRL_REG.exec(controller);
9136             if (match) return match[3];
9137           }
9138         }
9139
9140
9141         /**
9142          * @ngdoc provider
9143          * @name $controllerProvider
9144          * @description
9145          * The {@link ng.$controller $controller service} is used by Angular to create new
9146          * controllers.
9147          *
9148          * This provider allows controller registration via the
9149          * {@link ng.$controllerProvider#register register} method.
9150          */
9151         function $ControllerProvider() {
9152           var controllers = {},
9153               globals = false;
9154
9155           /**
9156            * @ngdoc method
9157            * @name $controllerProvider#register
9158            * @param {string|Object} name Controller name, or an object map of controllers where the keys are
9159            *    the names and the values are the constructors.
9160            * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
9161            *    annotations in the array notation).
9162            */
9163           this.register = function(name, constructor) {
9164             assertNotHasOwnProperty(name, 'controller');
9165             if (isObject(name)) {
9166               extend(controllers, name);
9167             } else {
9168               controllers[name] = constructor;
9169             }
9170           };
9171
9172           /**
9173            * @ngdoc method
9174            * @name $controllerProvider#allowGlobals
9175            * @description If called, allows `$controller` to find controller constructors on `window`
9176            */
9177           this.allowGlobals = function() {
9178             globals = true;
9179           };
9180
9181
9182           this.$get = ['$injector', '$window', function($injector, $window) {
9183
9184             /**
9185              * @ngdoc service
9186              * @name $controller
9187              * @requires $injector
9188              *
9189              * @param {Function|string} constructor If called with a function then it's considered to be the
9190              *    controller constructor function. Otherwise it's considered to be a string which is used
9191              *    to retrieve the controller constructor using the following steps:
9192              *
9193              *    * check if a controller with given name is registered via `$controllerProvider`
9194              *    * check if evaluating the string on the current scope returns a constructor
9195              *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
9196              *      `window` object (not recommended)
9197              *
9198              *    The string can use the `controller as property` syntax, where the controller instance is published
9199              *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
9200              *    to work correctly.
9201              *
9202              * @param {Object} locals Injection locals for Controller.
9203              * @return {Object} Instance of given controller.
9204              *
9205              * @description
9206              * `$controller` service is responsible for instantiating controllers.
9207              *
9208              * It's just a simple call to {@link auto.$injector $injector}, but extracted into
9209              * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
9210              */
9211             return function(expression, locals, later, ident) {
9212               // PRIVATE API:
9213               //   param `later` --- indicates that the controller's constructor is invoked at a later time.
9214               //                     If true, $controller will allocate the object with the correct
9215               //                     prototype chain, but will not invoke the controller until a returned
9216               //                     callback is invoked.
9217               //   param `ident` --- An optional label which overrides the label parsed from the controller
9218               //                     expression, if any.
9219               var instance, match, constructor, identifier;
9220               later = later === true;
9221               if (ident && isString(ident)) {
9222                 identifier = ident;
9223               }
9224
9225               if (isString(expression)) {
9226                 match = expression.match(CNTRL_REG);
9227                 if (!match) {
9228                   throw $controllerMinErr('ctrlfmt',
9229                     "Badly formed controller string '{0}'. " +
9230                     "Must match `__name__ as __id__` or `__name__`.", expression);
9231                 }
9232                 constructor = match[1],
9233                 identifier = identifier || match[3];
9234                 expression = controllers.hasOwnProperty(constructor)
9235                     ? controllers[constructor]
9236                     : getter(locals.$scope, constructor, true) ||
9237                         (globals ? getter($window, constructor, true) : undefined);
9238
9239                 assertArgFn(expression, constructor, true);
9240               }
9241
9242               if (later) {
9243                 // Instantiate controller later:
9244                 // This machinery is used to create an instance of the object before calling the
9245                 // controller's constructor itself.
9246                 //
9247                 // This allows properties to be added to the controller before the constructor is
9248                 // invoked. Primarily, this is used for isolate scope bindings in $compile.
9249                 //
9250                 // This feature is not intended for use by applications, and is thus not documented
9251                 // publicly.
9252                 // Object creation: http://jsperf.com/create-constructor/2
9253                 var controllerPrototype = (isArray(expression) ?
9254                   expression[expression.length - 1] : expression).prototype;
9255                 instance = Object.create(controllerPrototype || null);
9256
9257                 if (identifier) {
9258                   addIdentifier(locals, identifier, instance, constructor || expression.name);
9259                 }
9260
9261                 var instantiate;
9262                 return instantiate = extend(function() {
9263                   var result = $injector.invoke(expression, instance, locals, constructor);
9264                   if (result !== instance && (isObject(result) || isFunction(result))) {
9265                     instance = result;
9266                     if (identifier) {
9267                       // If result changed, re-assign controllerAs value to scope.
9268                       addIdentifier(locals, identifier, instance, constructor || expression.name);
9269                     }
9270                   }
9271                   return instance;
9272                 }, {
9273                   instance: instance,
9274                   identifier: identifier
9275                 });
9276               }
9277
9278               instance = $injector.instantiate(expression, locals, constructor);
9279
9280               if (identifier) {
9281                 addIdentifier(locals, identifier, instance, constructor || expression.name);
9282               }
9283
9284               return instance;
9285             };
9286
9287             function addIdentifier(locals, identifier, instance, name) {
9288               if (!(locals && isObject(locals.$scope))) {
9289                 throw minErr('$controller')('noscp',
9290                   "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
9291                   name, identifier);
9292               }
9293
9294               locals.$scope[identifier] = instance;
9295             }
9296           }];
9297         }
9298
9299         /**
9300          * @ngdoc service
9301          * @name $document
9302          * @requires $window
9303          *
9304          * @description
9305          * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
9306          *
9307          * @example
9308            <example module="documentExample">
9309              <file name="index.html">
9310                <div ng-controller="ExampleController">
9311                  <p>$document title: <b ng-bind="title"></b></p>
9312                  <p>window.document title: <b ng-bind="windowTitle"></b></p>
9313                </div>
9314              </file>
9315              <file name="script.js">
9316                angular.module('documentExample', [])
9317                  .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
9318                    $scope.title = $document[0].title;
9319                    $scope.windowTitle = angular.element(window.document)[0].title;
9320                  }]);
9321              </file>
9322            </example>
9323          */
9324         function $DocumentProvider() {
9325           this.$get = ['$window', function(window) {
9326             return jqLite(window.document);
9327           }];
9328         }
9329
9330         /**
9331          * @ngdoc service
9332          * @name $exceptionHandler
9333          * @requires ng.$log
9334          *
9335          * @description
9336          * Any uncaught exception in angular expressions is delegated to this service.
9337          * The default implementation simply delegates to `$log.error` which logs it into
9338          * the browser console.
9339          *
9340          * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
9341          * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
9342          *
9343          * ## Example:
9344          *
9345          * ```js
9346          *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
9347          *     return function(exception, cause) {
9348          *       exception.message += ' (caused by "' + cause + '")';
9349          *       throw exception;
9350          *     };
9351          *   });
9352          * ```
9353          *
9354          * This example will override the normal action of `$exceptionHandler`, to make angular
9355          * exceptions fail hard when they happen, instead of just logging to the console.
9356          *
9357          * <hr />
9358          * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
9359          * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
9360          * (unless executed during a digest).
9361          *
9362          * If you wish, you can manually delegate exceptions, e.g.
9363          * `try { ... } catch(e) { $exceptionHandler(e); }`
9364          *
9365          * @param {Error} exception Exception associated with the error.
9366          * @param {string=} cause optional information about the context in which
9367          *       the error was thrown.
9368          *
9369          */
9370         function $ExceptionHandlerProvider() {
9371           this.$get = ['$log', function($log) {
9372             return function(exception, cause) {
9373               $log.error.apply($log, arguments);
9374             };
9375           }];
9376         }
9377
9378         var $$ForceReflowProvider = function() {
9379           this.$get = ['$document', function($document) {
9380             return function(domNode) {
9381               //the line below will force the browser to perform a repaint so
9382               //that all the animated elements within the animation frame will
9383               //be properly updated and drawn on screen. This is required to
9384               //ensure that the preparation animation is properly flushed so that
9385               //the active state picks up from there. DO NOT REMOVE THIS LINE.
9386               //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
9387               //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
9388               //WILL TAKE YEARS AWAY FROM YOUR LIFE.
9389               if (domNode) {
9390                 if (!domNode.nodeType && domNode instanceof jqLite) {
9391                   domNode = domNode[0];
9392                 }
9393               } else {
9394                 domNode = $document[0].body;
9395               }
9396               return domNode.offsetWidth + 1;
9397             };
9398           }];
9399         };
9400
9401         var APPLICATION_JSON = 'application/json';
9402         var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
9403         var JSON_START = /^\[|^\{(?!\{)/;
9404         var JSON_ENDS = {
9405           '[': /]$/,
9406           '{': /}$/
9407         };
9408         var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
9409         var $httpMinErr = minErr('$http');
9410         var $httpMinErrLegacyFn = function(method) {
9411           return function() {
9412             throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
9413           };
9414         };
9415
9416         function serializeValue(v) {
9417           if (isObject(v)) {
9418             return isDate(v) ? v.toISOString() : toJson(v);
9419           }
9420           return v;
9421         }
9422
9423
9424         function $HttpParamSerializerProvider() {
9425           /**
9426            * @ngdoc service
9427            * @name $httpParamSerializer
9428            * @description
9429            *
9430            * Default {@link $http `$http`} params serializer that converts objects to strings
9431            * according to the following rules:
9432            *
9433            * * `{'foo': 'bar'}` results in `foo=bar`
9434            * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
9435            * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
9436            * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
9437            *
9438            * Note that serializer will sort the request parameters alphabetically.
9439            * */
9440
9441           this.$get = function() {
9442             return function ngParamSerializer(params) {
9443               if (!params) return '';
9444               var parts = [];
9445               forEachSorted(params, function(value, key) {
9446                 if (value === null || isUndefined(value)) return;
9447                 if (isArray(value)) {
9448                   forEach(value, function(v, k) {
9449                     parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
9450                   });
9451                 } else {
9452                   parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
9453                 }
9454               });
9455
9456               return parts.join('&');
9457             };
9458           };
9459         }
9460
9461         function $HttpParamSerializerJQLikeProvider() {
9462           /**
9463            * @ngdoc service
9464            * @name $httpParamSerializerJQLike
9465            * @description
9466            *
9467            * Alternative {@link $http `$http`} params serializer that follows
9468            * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
9469            * The serializer will also sort the params alphabetically.
9470            *
9471            * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
9472            *
9473            * ```js
9474            * $http({
9475            *   url: myUrl,
9476            *   method: 'GET',
9477            *   params: myParams,
9478            *   paramSerializer: '$httpParamSerializerJQLike'
9479            * });
9480            * ```
9481            *
9482            * It is also possible to set it as the default `paramSerializer` in the
9483            * {@link $httpProvider#defaults `$httpProvider`}.
9484            *
9485            * Additionally, you can inject the serializer and use it explicitly, for example to serialize
9486            * form data for submission:
9487            *
9488            * ```js
9489            * .controller(function($http, $httpParamSerializerJQLike) {
9490            *   //...
9491            *
9492            *   $http({
9493            *     url: myUrl,
9494            *     method: 'POST',
9495            *     data: $httpParamSerializerJQLike(myData),
9496            *     headers: {
9497            *       'Content-Type': 'application/x-www-form-urlencoded'
9498            *     }
9499            *   });
9500            *
9501            * });
9502            * ```
9503            *
9504            * */
9505           this.$get = function() {
9506             return function jQueryLikeParamSerializer(params) {
9507               if (!params) return '';
9508               var parts = [];
9509               serialize(params, '', true);
9510               return parts.join('&');
9511
9512               function serialize(toSerialize, prefix, topLevel) {
9513                 if (toSerialize === null || isUndefined(toSerialize)) return;
9514                 if (isArray(toSerialize)) {
9515                   forEach(toSerialize, function(value, index) {
9516                     serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
9517                   });
9518                 } else if (isObject(toSerialize) && !isDate(toSerialize)) {
9519                   forEachSorted(toSerialize, function(value, key) {
9520                     serialize(value, prefix +
9521                         (topLevel ? '' : '[') +
9522                         key +
9523                         (topLevel ? '' : ']'));
9524                   });
9525                 } else {
9526                   parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
9527                 }
9528               }
9529             };
9530           };
9531         }
9532
9533         function defaultHttpResponseTransform(data, headers) {
9534           if (isString(data)) {
9535             // Strip json vulnerability protection prefix and trim whitespace
9536             var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
9537
9538             if (tempData) {
9539               var contentType = headers('Content-Type');
9540               if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
9541                 data = fromJson(tempData);
9542               }
9543             }
9544           }
9545
9546           return data;
9547         }
9548
9549         function isJsonLike(str) {
9550             var jsonStart = str.match(JSON_START);
9551             return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
9552         }
9553
9554         /**
9555          * Parse headers into key value object
9556          *
9557          * @param {string} headers Raw headers as a string
9558          * @returns {Object} Parsed headers as key value object
9559          */
9560         function parseHeaders(headers) {
9561           var parsed = createMap(), i;
9562
9563           function fillInParsed(key, val) {
9564             if (key) {
9565               parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
9566             }
9567           }
9568
9569           if (isString(headers)) {
9570             forEach(headers.split('\n'), function(line) {
9571               i = line.indexOf(':');
9572               fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
9573             });
9574           } else if (isObject(headers)) {
9575             forEach(headers, function(headerVal, headerKey) {
9576               fillInParsed(lowercase(headerKey), trim(headerVal));
9577             });
9578           }
9579
9580           return parsed;
9581         }
9582
9583
9584         /**
9585          * Returns a function that provides access to parsed headers.
9586          *
9587          * Headers are lazy parsed when first requested.
9588          * @see parseHeaders
9589          *
9590          * @param {(string|Object)} headers Headers to provide access to.
9591          * @returns {function(string=)} Returns a getter function which if called with:
9592          *
9593          *   - if called with single an argument returns a single header value or null
9594          *   - if called with no arguments returns an object containing all headers.
9595          */
9596         function headersGetter(headers) {
9597           var headersObj;
9598
9599           return function(name) {
9600             if (!headersObj) headersObj =  parseHeaders(headers);
9601
9602             if (name) {
9603               var value = headersObj[lowercase(name)];
9604               if (value === void 0) {
9605                 value = null;
9606               }
9607               return value;
9608             }
9609
9610             return headersObj;
9611           };
9612         }
9613
9614
9615         /**
9616          * Chain all given functions
9617          *
9618          * This function is used for both request and response transforming
9619          *
9620          * @param {*} data Data to transform.
9621          * @param {function(string=)} headers HTTP headers getter fn.
9622          * @param {number} status HTTP status code of the response.
9623          * @param {(Function|Array.<Function>)} fns Function or an array of functions.
9624          * @returns {*} Transformed data.
9625          */
9626         function transformData(data, headers, status, fns) {
9627           if (isFunction(fns)) {
9628             return fns(data, headers, status);
9629           }
9630
9631           forEach(fns, function(fn) {
9632             data = fn(data, headers, status);
9633           });
9634
9635           return data;
9636         }
9637
9638
9639         function isSuccess(status) {
9640           return 200 <= status && status < 300;
9641         }
9642
9643
9644         /**
9645          * @ngdoc provider
9646          * @name $httpProvider
9647          * @description
9648          * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
9649          * */
9650         function $HttpProvider() {
9651           /**
9652            * @ngdoc property
9653            * @name $httpProvider#defaults
9654            * @description
9655            *
9656            * Object containing default values for all {@link ng.$http $http} requests.
9657            *
9658            * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
9659            * that will provide the cache for all requests who set their `cache` property to `true`.
9660            * If you set the `defaults.cache = false` then only requests that specify their own custom
9661            * cache object will be cached. See {@link $http#caching $http Caching} for more information.
9662            *
9663            * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
9664            * Defaults value is `'XSRF-TOKEN'`.
9665            *
9666            * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
9667            * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
9668            *
9669            * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
9670            * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
9671            * setting default headers.
9672            *     - **`defaults.headers.common`**
9673            *     - **`defaults.headers.post`**
9674            *     - **`defaults.headers.put`**
9675            *     - **`defaults.headers.patch`**
9676            *
9677            *
9678            * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
9679            *  used to the prepare string representation of request parameters (specified as an object).
9680            *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
9681            *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
9682            *
9683            **/
9684           var defaults = this.defaults = {
9685             // transform incoming response data
9686             transformResponse: [defaultHttpResponseTransform],
9687
9688             // transform outgoing request data
9689             transformRequest: [function(d) {
9690               return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
9691             }],
9692
9693             // default headers
9694             headers: {
9695               common: {
9696                 'Accept': 'application/json, text/plain, */*'
9697               },
9698               post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9699               put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9700               patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
9701             },
9702
9703             xsrfCookieName: 'XSRF-TOKEN',
9704             xsrfHeaderName: 'X-XSRF-TOKEN',
9705
9706             paramSerializer: '$httpParamSerializer'
9707           };
9708
9709           var useApplyAsync = false;
9710           /**
9711            * @ngdoc method
9712            * @name $httpProvider#useApplyAsync
9713            * @description
9714            *
9715            * Configure $http service to combine processing of multiple http responses received at around
9716            * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
9717            * significant performance improvement for bigger applications that make many HTTP requests
9718            * concurrently (common during application bootstrap).
9719            *
9720            * Defaults to false. If no value is specified, returns the current configured value.
9721            *
9722            * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
9723            *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
9724            *    to load and share the same digest cycle.
9725            *
9726            * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9727            *    otherwise, returns the current configured value.
9728            **/
9729           this.useApplyAsync = function(value) {
9730             if (isDefined(value)) {
9731               useApplyAsync = !!value;
9732               return this;
9733             }
9734             return useApplyAsync;
9735           };
9736
9737           var useLegacyPromise = true;
9738           /**
9739            * @ngdoc method
9740            * @name $httpProvider#useLegacyPromiseExtensions
9741            * @description
9742            *
9743            * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
9744            * This should be used to make sure that applications work without these methods.
9745            *
9746            * Defaults to true. If no value is specified, returns the current configured value.
9747            *
9748            * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
9749            *
9750            * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9751            *    otherwise, returns the current configured value.
9752            **/
9753           this.useLegacyPromiseExtensions = function(value) {
9754             if (isDefined(value)) {
9755               useLegacyPromise = !!value;
9756               return this;
9757             }
9758             return useLegacyPromise;
9759           };
9760
9761           /**
9762            * @ngdoc property
9763            * @name $httpProvider#interceptors
9764            * @description
9765            *
9766            * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
9767            * pre-processing of request or postprocessing of responses.
9768            *
9769            * These service factories are ordered by request, i.e. they are applied in the same order as the
9770            * array, on request, but reverse order, on response.
9771            *
9772            * {@link ng.$http#interceptors Interceptors detailed info}
9773            **/
9774           var interceptorFactories = this.interceptors = [];
9775
9776           this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
9777               function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
9778
9779             var defaultCache = $cacheFactory('$http');
9780
9781             /**
9782              * Make sure that default param serializer is exposed as a function
9783              */
9784             defaults.paramSerializer = isString(defaults.paramSerializer) ?
9785               $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
9786
9787             /**
9788              * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
9789              * The reversal is needed so that we can build up the interception chain around the
9790              * server request.
9791              */
9792             var reversedInterceptors = [];
9793
9794             forEach(interceptorFactories, function(interceptorFactory) {
9795               reversedInterceptors.unshift(isString(interceptorFactory)
9796                   ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
9797             });
9798
9799             /**
9800              * @ngdoc service
9801              * @kind function
9802              * @name $http
9803              * @requires ng.$httpBackend
9804              * @requires $cacheFactory
9805              * @requires $rootScope
9806              * @requires $q
9807              * @requires $injector
9808              *
9809              * @description
9810              * The `$http` service is a core Angular service that facilitates communication with the remote
9811              * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
9812              * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
9813              *
9814              * For unit testing applications that use `$http` service, see
9815              * {@link ngMock.$httpBackend $httpBackend mock}.
9816              *
9817              * For a higher level of abstraction, please check out the {@link ngResource.$resource
9818              * $resource} service.
9819              *
9820              * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
9821              * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
9822              * it is important to familiarize yourself with these APIs and the guarantees they provide.
9823              *
9824              *
9825              * ## General usage
9826              * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
9827              * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
9828              *
9829              * ```js
9830              *   // Simple GET request example:
9831              *   $http({
9832              *     method: 'GET',
9833              *     url: '/someUrl'
9834              *   }).then(function successCallback(response) {
9835              *       // this callback will be called asynchronously
9836              *       // when the response is available
9837              *     }, function errorCallback(response) {
9838              *       // called asynchronously if an error occurs
9839              *       // or server returns response with an error status.
9840              *     });
9841              * ```
9842              *
9843              * The response object has these properties:
9844              *
9845              *   - **data** – `{string|Object}` – The response body transformed with the transform
9846              *     functions.
9847              *   - **status** – `{number}` – HTTP status code of the response.
9848              *   - **headers** – `{function([headerName])}` – Header getter function.
9849              *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9850              *   - **statusText** – `{string}` – HTTP status text of the response.
9851              *
9852              * A response status code between 200 and 299 is considered a success status and
9853              * will result in the success callback being called. Note that if the response is a redirect,
9854              * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
9855              * called for such responses.
9856              *
9857              *
9858              * ## Shortcut methods
9859              *
9860              * Shortcut methods are also available. All shortcut methods require passing in the URL, and
9861              * request data must be passed in for POST/PUT requests. An optional config can be passed as the
9862              * last argument.
9863              *
9864              * ```js
9865              *   $http.get('/someUrl', config).then(successCallback, errorCallback);
9866              *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
9867              * ```
9868              *
9869              * Complete list of shortcut methods:
9870              *
9871              * - {@link ng.$http#get $http.get}
9872              * - {@link ng.$http#head $http.head}
9873              * - {@link ng.$http#post $http.post}
9874              * - {@link ng.$http#put $http.put}
9875              * - {@link ng.$http#delete $http.delete}
9876              * - {@link ng.$http#jsonp $http.jsonp}
9877              * - {@link ng.$http#patch $http.patch}
9878              *
9879              *
9880              * ## Writing Unit Tests that use $http
9881              * When unit testing (using {@link ngMock ngMock}), it is necessary to call
9882              * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
9883              * request using trained responses.
9884              *
9885              * ```
9886              * $httpBackend.expectGET(...);
9887              * $http.get(...);
9888              * $httpBackend.flush();
9889              * ```
9890              *
9891              * ## Deprecation Notice
9892              * <div class="alert alert-danger">
9893              *   The `$http` legacy promise methods `success` and `error` have been deprecated.
9894              *   Use the standard `then` method instead.
9895              *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
9896              *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
9897              * </div>
9898              *
9899              * ## Setting HTTP Headers
9900              *
9901              * The $http service will automatically add certain HTTP headers to all requests. These defaults
9902              * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
9903              * object, which currently contains this default configuration:
9904              *
9905              * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
9906              *   - `Accept: application/json, text/plain, * / *`
9907              * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
9908              *   - `Content-Type: application/json`
9909              * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
9910              *   - `Content-Type: application/json`
9911              *
9912              * To add or overwrite these defaults, simply add or remove a property from these configuration
9913              * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
9914              * with the lowercased HTTP method name as the key, e.g.
9915              * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
9916              *
9917              * The defaults can also be set at runtime via the `$http.defaults` object in the same
9918              * fashion. For example:
9919              *
9920              * ```
9921              * module.run(function($http) {
9922              *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
9923              * });
9924              * ```
9925              *
9926              * In addition, you can supply a `headers` property in the config object passed when
9927              * calling `$http(config)`, which overrides the defaults without changing them globally.
9928              *
9929              * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
9930              * Use the `headers` property, setting the desired header to `undefined`. For example:
9931              *
9932              * ```js
9933              * var req = {
9934              *  method: 'POST',
9935              *  url: 'http://example.com',
9936              *  headers: {
9937              *    'Content-Type': undefined
9938              *  },
9939              *  data: { test: 'test' }
9940              * }
9941              *
9942              * $http(req).then(function(){...}, function(){...});
9943              * ```
9944              *
9945              * ## Transforming Requests and Responses
9946              *
9947              * Both requests and responses can be transformed using transformation functions: `transformRequest`
9948              * and `transformResponse`. These properties can be a single function that returns
9949              * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
9950              * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
9951              *
9952              * ### Default Transformations
9953              *
9954              * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
9955              * `defaults.transformResponse` properties. If a request does not provide its own transformations
9956              * then these will be applied.
9957              *
9958              * You can augment or replace the default transformations by modifying these properties by adding to or
9959              * replacing the array.
9960              *
9961              * Angular provides the following default transformations:
9962              *
9963              * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
9964              *
9965              * - If the `data` property of the request configuration object contains an object, serialize it
9966              *   into JSON format.
9967              *
9968              * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9969              *
9970              *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9971              *  - If JSON response is detected, deserialize it using a JSON parser.
9972              *
9973              *
9974              * ### Overriding the Default Transformations Per Request
9975              *
9976              * If you wish override the request/response transformations only for a single request then provide
9977              * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9978              * into `$http`.
9979              *
9980              * Note that if you provide these properties on the config object the default transformations will be
9981              * overwritten. If you wish to augment the default transformations then you must include them in your
9982              * local transformation array.
9983              *
9984              * The following code demonstrates adding a new response transformation to be run after the default response
9985              * transformations have been run.
9986              *
9987              * ```js
9988              * function appendTransform(defaults, transform) {
9989              *
9990              *   // We can't guarantee that the default transformation is an array
9991              *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9992              *
9993              *   // Append the new transformation to the defaults
9994              *   return defaults.concat(transform);
9995              * }
9996              *
9997              * $http({
9998              *   url: '...',
9999              *   method: 'GET',
10000              *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
10001              *     return doTransform(value);
10002              *   })
10003              * });
10004              * ```
10005              *
10006              *
10007              * ## Caching
10008              *
10009              * To enable caching, set the request configuration `cache` property to `true` (to use default
10010              * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
10011              * When the cache is enabled, `$http` stores the response from the server in the specified
10012              * cache. The next time the same request is made, the response is served from the cache without
10013              * sending a request to the server.
10014              *
10015              * Note that even if the response is served from cache, delivery of the data is asynchronous in
10016              * the same way that real requests are.
10017              *
10018              * If there are multiple GET requests for the same URL that should be cached using the same
10019              * cache, but the cache is not populated yet, only one request to the server will be made and
10020              * the remaining requests will be fulfilled using the response from the first request.
10021              *
10022              * You can change the default cache to a new object (built with
10023              * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
10024              * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
10025              * their `cache` property to `true` will now use this cache object.
10026              *
10027              * If you set the default cache to `false` then only requests that specify their own custom
10028              * cache object will be cached.
10029              *
10030              * ## Interceptors
10031              *
10032              * Before you start creating interceptors, be sure to understand the
10033              * {@link ng.$q $q and deferred/promise APIs}.
10034              *
10035              * For purposes of global error handling, authentication, or any kind of synchronous or
10036              * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
10037              * able to intercept requests before they are handed to the server and
10038              * responses before they are handed over to the application code that
10039              * initiated these requests. The interceptors leverage the {@link ng.$q
10040              * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
10041              *
10042              * The interceptors are service factories that are registered with the `$httpProvider` by
10043              * adding them to the `$httpProvider.interceptors` array. The factory is called and
10044              * injected with dependencies (if specified) and returns the interceptor.
10045              *
10046              * There are two kinds of interceptors (and two kinds of rejection interceptors):
10047              *
10048              *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
10049              *     modify the `config` object or create a new one. The function needs to return the `config`
10050              *     object directly, or a promise containing the `config` or a new `config` object.
10051              *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
10052              *     resolved with a rejection.
10053              *   * `response`: interceptors get called with http `response` object. The function is free to
10054              *     modify the `response` object or create a new one. The function needs to return the `response`
10055              *     object directly, or as a promise containing the `response` or a new `response` object.
10056              *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
10057              *     resolved with a rejection.
10058              *
10059              *
10060              * ```js
10061              *   // register the interceptor as a service
10062              *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
10063              *     return {
10064              *       // optional method
10065              *       'request': function(config) {
10066              *         // do something on success
10067              *         return config;
10068              *       },
10069              *
10070              *       // optional method
10071              *      'requestError': function(rejection) {
10072              *         // do something on error
10073              *         if (canRecover(rejection)) {
10074              *           return responseOrNewPromise
10075              *         }
10076              *         return $q.reject(rejection);
10077              *       },
10078              *
10079              *
10080              *
10081              *       // optional method
10082              *       'response': function(response) {
10083              *         // do something on success
10084              *         return response;
10085              *       },
10086              *
10087              *       // optional method
10088              *      'responseError': function(rejection) {
10089              *         // do something on error
10090              *         if (canRecover(rejection)) {
10091              *           return responseOrNewPromise
10092              *         }
10093              *         return $q.reject(rejection);
10094              *       }
10095              *     };
10096              *   });
10097              *
10098              *   $httpProvider.interceptors.push('myHttpInterceptor');
10099              *
10100              *
10101              *   // alternatively, register the interceptor via an anonymous factory
10102              *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
10103              *     return {
10104              *      'request': function(config) {
10105              *          // same as above
10106              *       },
10107              *
10108              *       'response': function(response) {
10109              *          // same as above
10110              *       }
10111              *     };
10112              *   });
10113              * ```
10114              *
10115              * ## Security Considerations
10116              *
10117              * When designing web applications, consider security threats from:
10118              *
10119              * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10120              * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
10121              *
10122              * Both server and the client must cooperate in order to eliminate these threats. Angular comes
10123              * pre-configured with strategies that address these issues, but for this to work backend server
10124              * cooperation is required.
10125              *
10126              * ### JSON Vulnerability Protection
10127              *
10128              * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
10129              * allows third party website to turn your JSON resource URL into
10130              * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
10131              * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
10132              * Angular will automatically strip the prefix before processing it as JSON.
10133              *
10134              * For example if your server needs to return:
10135              * ```js
10136              * ['one','two']
10137              * ```
10138              *
10139              * which is vulnerable to attack, your server can return:
10140              * ```js
10141              * )]}',
10142              * ['one','two']
10143              * ```
10144              *
10145              * Angular will strip the prefix, before processing the JSON.
10146              *
10147              *
10148              * ### Cross Site Request Forgery (XSRF) Protection
10149              *
10150              * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
10151              * an unauthorized site can gain your user's private data. Angular provides a mechanism
10152              * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
10153              * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
10154              * JavaScript that runs on your domain could read the cookie, your server can be assured that
10155              * the XHR came from JavaScript running on your domain. The header will not be set for
10156              * cross-domain requests.
10157              *
10158              * To take advantage of this, your server needs to set a token in a JavaScript readable session
10159              * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
10160              * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
10161              * that only JavaScript running on your domain could have sent the request. The token must be
10162              * unique for each user and must be verifiable by the server (to prevent the JavaScript from
10163              * making up its own tokens). We recommend that the token is a digest of your site's
10164              * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
10165              * for added security.
10166              *
10167              * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
10168              * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
10169              * or the per-request config object.
10170              *
10171              * In order to prevent collisions in environments where multiple Angular apps share the
10172              * same domain or subdomain, we recommend that each application uses unique cookie name.
10173              *
10174              * @param {object} config Object describing the request to be made and how it should be
10175              *    processed. The object has following properties:
10176              *
10177              *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
10178              *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
10179              *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
10180              *      with the `paramSerializer` and appended as GET parameters.
10181              *    - **data** – `{string|Object}` – Data to be sent as the request message data.
10182              *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
10183              *      HTTP headers to send to the server. If the return value of a function is null, the
10184              *      header will not be sent. Functions accept a config object as an argument.
10185              *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
10186              *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
10187              *    - **transformRequest** –
10188              *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
10189              *      transform function or an array of such functions. The transform function takes the http
10190              *      request body and headers and returns its transformed (typically serialized) version.
10191              *      See {@link ng.$http#overriding-the-default-transformations-per-request
10192              *      Overriding the Default Transformations}
10193              *    - **transformResponse** –
10194              *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
10195              *      transform function or an array of such functions. The transform function takes the http
10196              *      response body, headers and status and returns its transformed (typically deserialized) version.
10197              *      See {@link ng.$http#overriding-the-default-transformations-per-request
10198              *      Overriding the Default TransformationjqLiks}
10199              *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
10200              *      prepare the string representation of request parameters (specified as an object).
10201              *      If specified as string, it is interpreted as function registered with the
10202              *      {@link $injector $injector}, which means you can create your own serializer
10203              *      by registering it as a {@link auto.$provide#service service}.
10204              *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
10205              *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
10206              *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
10207              *      GET request, otherwise if a cache instance built with
10208              *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
10209              *      caching.
10210              *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
10211              *      that should abort the request when resolved.
10212              *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
10213              *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
10214              *      for more information.
10215              *    - **responseType** - `{string}` - see
10216              *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
10217              *
10218              * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
10219              *                        when the request succeeds or fails.
10220              *
10221              *
10222              * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
10223              *   requests. This is primarily meant to be used for debugging purposes.
10224              *
10225              *
10226              * @example
10227         <example module="httpExample">
10228         <file name="index.html">
10229           <div ng-controller="FetchController">
10230             <select ng-model="method" aria-label="Request method">
10231               <option>GET</option>
10232               <option>JSONP</option>
10233             </select>
10234             <input type="text" ng-model="url" size="80" aria-label="URL" />
10235             <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
10236             <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
10237             <button id="samplejsonpbtn"
10238               ng-click="updateModel('JSONP',
10239                             'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
10240               Sample JSONP
10241             </button>
10242             <button id="invalidjsonpbtn"
10243               ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
10244                 Invalid JSONP
10245               </button>
10246             <pre>http status code: {{status}}</pre>
10247             <pre>http response data: {{data}}</pre>
10248           </div>
10249         </file>
10250         <file name="script.js">
10251           angular.module('httpExample', [])
10252             .controller('FetchController', ['$scope', '$http', '$templateCache',
10253               function($scope, $http, $templateCache) {
10254                 $scope.method = 'GET';
10255                 $scope.url = 'http-hello.html';
10256
10257                 $scope.fetch = function() {
10258                   $scope.code = null;
10259                   $scope.response = null;
10260
10261                   $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
10262                     then(function(response) {
10263                       $scope.status = response.status;
10264                       $scope.data = response.data;
10265                     }, function(response) {
10266                       $scope.data = response.data || "Request failed";
10267                       $scope.status = response.status;
10268                   });
10269                 };
10270
10271                 $scope.updateModel = function(method, url) {
10272                   $scope.method = method;
10273                   $scope.url = url;
10274                 };
10275               }]);
10276         </file>
10277         <file name="http-hello.html">
10278           Hello, $http!
10279         </file>
10280         <file name="protractor.js" type="protractor">
10281           var status = element(by.binding('status'));
10282           var data = element(by.binding('data'));
10283           var fetchBtn = element(by.id('fetchbtn'));
10284           var sampleGetBtn = element(by.id('samplegetbtn'));
10285           var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
10286           var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
10287
10288           it('should make an xhr GET request', function() {
10289             sampleGetBtn.click();
10290             fetchBtn.click();
10291             expect(status.getText()).toMatch('200');
10292             expect(data.getText()).toMatch(/Hello, \$http!/);
10293           });
10294
10295         // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
10296         // it('should make a JSONP request to angularjs.org', function() {
10297         //   sampleJsonpBtn.click();
10298         //   fetchBtn.click();
10299         //   expect(status.getText()).toMatch('200');
10300         //   expect(data.getText()).toMatch(/Super Hero!/);
10301         // });
10302
10303           it('should make JSONP request to invalid URL and invoke the error handler',
10304               function() {
10305             invalidJsonpBtn.click();
10306             fetchBtn.click();
10307             expect(status.getText()).toMatch('0');
10308             expect(data.getText()).toMatch('Request failed');
10309           });
10310         </file>
10311         </example>
10312              */
10313             function $http(requestConfig) {
10314
10315               if (!angular.isObject(requestConfig)) {
10316                 throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
10317               }
10318
10319               var config = extend({
10320                 method: 'get',
10321                 transformRequest: defaults.transformRequest,
10322                 transformResponse: defaults.transformResponse,
10323                 paramSerializer: defaults.paramSerializer
10324               }, requestConfig);
10325
10326               config.headers = mergeHeaders(requestConfig);
10327               config.method = uppercase(config.method);
10328               config.paramSerializer = isString(config.paramSerializer) ?
10329                 $injector.get(config.paramSerializer) : config.paramSerializer;
10330
10331               var serverRequest = function(config) {
10332                 var headers = config.headers;
10333                 var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
10334
10335                 // strip content-type if data is undefined
10336                 if (isUndefined(reqData)) {
10337                   forEach(headers, function(value, header) {
10338                     if (lowercase(header) === 'content-type') {
10339                         delete headers[header];
10340                     }
10341                   });
10342                 }
10343
10344                 if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
10345                   config.withCredentials = defaults.withCredentials;
10346                 }
10347
10348                 // send request
10349                 return sendReq(config, reqData).then(transformResponse, transformResponse);
10350               };
10351
10352               var chain = [serverRequest, undefined];
10353               var promise = $q.when(config);
10354
10355               // apply interceptors
10356               forEach(reversedInterceptors, function(interceptor) {
10357                 if (interceptor.request || interceptor.requestError) {
10358                   chain.unshift(interceptor.request, interceptor.requestError);
10359                 }
10360                 if (interceptor.response || interceptor.responseError) {
10361                   chain.push(interceptor.response, interceptor.responseError);
10362                 }
10363               });
10364
10365               while (chain.length) {
10366                 var thenFn = chain.shift();
10367                 var rejectFn = chain.shift();
10368
10369                 promise = promise.then(thenFn, rejectFn);
10370               }
10371
10372               if (useLegacyPromise) {
10373                 promise.success = function(fn) {
10374                   assertArgFn(fn, 'fn');
10375
10376                   promise.then(function(response) {
10377                     fn(response.data, response.status, response.headers, config);
10378                   });
10379                   return promise;
10380                 };
10381
10382                 promise.error = function(fn) {
10383                   assertArgFn(fn, 'fn');
10384
10385                   promise.then(null, function(response) {
10386                     fn(response.data, response.status, response.headers, config);
10387                   });
10388                   return promise;
10389                 };
10390               } else {
10391                 promise.success = $httpMinErrLegacyFn('success');
10392                 promise.error = $httpMinErrLegacyFn('error');
10393               }
10394
10395               return promise;
10396
10397               function transformResponse(response) {
10398                 // make a copy since the response must be cacheable
10399                 var resp = extend({}, response);
10400                 resp.data = transformData(response.data, response.headers, response.status,
10401                                           config.transformResponse);
10402                 return (isSuccess(response.status))
10403                   ? resp
10404                   : $q.reject(resp);
10405               }
10406
10407               function executeHeaderFns(headers, config) {
10408                 var headerContent, processedHeaders = {};
10409
10410                 forEach(headers, function(headerFn, header) {
10411                   if (isFunction(headerFn)) {
10412                     headerContent = headerFn(config);
10413                     if (headerContent != null) {
10414                       processedHeaders[header] = headerContent;
10415                     }
10416                   } else {
10417                     processedHeaders[header] = headerFn;
10418                   }
10419                 });
10420
10421                 return processedHeaders;
10422               }
10423
10424               function mergeHeaders(config) {
10425                 var defHeaders = defaults.headers,
10426                     reqHeaders = extend({}, config.headers),
10427                     defHeaderName, lowercaseDefHeaderName, reqHeaderName;
10428
10429                 defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
10430
10431                 // using for-in instead of forEach to avoid unecessary iteration after header has been found
10432                 defaultHeadersIteration:
10433                 for (defHeaderName in defHeaders) {
10434                   lowercaseDefHeaderName = lowercase(defHeaderName);
10435
10436                   for (reqHeaderName in reqHeaders) {
10437                     if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
10438                       continue defaultHeadersIteration;
10439                     }
10440                   }
10441
10442                   reqHeaders[defHeaderName] = defHeaders[defHeaderName];
10443                 }
10444
10445                 // execute if header value is a function for merged headers
10446                 return executeHeaderFns(reqHeaders, shallowCopy(config));
10447               }
10448             }
10449
10450             $http.pendingRequests = [];
10451
10452             /**
10453              * @ngdoc method
10454              * @name $http#get
10455              *
10456              * @description
10457              * Shortcut method to perform `GET` request.
10458              *
10459              * @param {string} url Relative or absolute URL specifying the destination of the request
10460              * @param {Object=} config Optional configuration object
10461              * @returns {HttpPromise} Future object
10462              */
10463
10464             /**
10465              * @ngdoc method
10466              * @name $http#delete
10467              *
10468              * @description
10469              * Shortcut method to perform `DELETE` request.
10470              *
10471              * @param {string} url Relative or absolute URL specifying the destination of the request
10472              * @param {Object=} config Optional configuration object
10473              * @returns {HttpPromise} Future object
10474              */
10475
10476             /**
10477              * @ngdoc method
10478              * @name $http#head
10479              *
10480              * @description
10481              * Shortcut method to perform `HEAD` request.
10482              *
10483              * @param {string} url Relative or absolute URL specifying the destination of the request
10484              * @param {Object=} config Optional configuration object
10485              * @returns {HttpPromise} Future object
10486              */
10487
10488             /**
10489              * @ngdoc method
10490              * @name $http#jsonp
10491              *
10492              * @description
10493              * Shortcut method to perform `JSONP` request.
10494              *
10495              * @param {string} url Relative or absolute URL specifying the destination of the request.
10496              *                     The name of the callback should be the string `JSON_CALLBACK`.
10497              * @param {Object=} config Optional configuration object
10498              * @returns {HttpPromise} Future object
10499              */
10500             createShortMethods('get', 'delete', 'head', 'jsonp');
10501
10502             /**
10503              * @ngdoc method
10504              * @name $http#post
10505              *
10506              * @description
10507              * Shortcut method to perform `POST` request.
10508              *
10509              * @param {string} url Relative or absolute URL specifying the destination of the request
10510              * @param {*} data Request content
10511              * @param {Object=} config Optional configuration object
10512              * @returns {HttpPromise} Future object
10513              */
10514
10515             /**
10516              * @ngdoc method
10517              * @name $http#put
10518              *
10519              * @description
10520              * Shortcut method to perform `PUT` request.
10521              *
10522              * @param {string} url Relative or absolute URL specifying the destination of the request
10523              * @param {*} data Request content
10524              * @param {Object=} config Optional configuration object
10525              * @returns {HttpPromise} Future object
10526              */
10527
10528              /**
10529               * @ngdoc method
10530               * @name $http#patch
10531               *
10532               * @description
10533               * Shortcut method to perform `PATCH` request.
10534               *
10535               * @param {string} url Relative or absolute URL specifying the destination of the request
10536               * @param {*} data Request content
10537               * @param {Object=} config Optional configuration object
10538               * @returns {HttpPromise} Future object
10539               */
10540             createShortMethodsWithData('post', 'put', 'patch');
10541
10542                 /**
10543                  * @ngdoc property
10544                  * @name $http#defaults
10545                  *
10546                  * @description
10547                  * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
10548                  * default headers, withCredentials as well as request and response transformations.
10549                  *
10550                  * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
10551                  */
10552             $http.defaults = defaults;
10553
10554
10555             return $http;
10556
10557
10558             function createShortMethods(names) {
10559               forEach(arguments, function(name) {
10560                 $http[name] = function(url, config) {
10561                   return $http(extend({}, config || {}, {
10562                     method: name,
10563                     url: url
10564                   }));
10565                 };
10566               });
10567             }
10568
10569
10570             function createShortMethodsWithData(name) {
10571               forEach(arguments, function(name) {
10572                 $http[name] = function(url, data, config) {
10573                   return $http(extend({}, config || {}, {
10574                     method: name,
10575                     url: url,
10576                     data: data
10577                   }));
10578                 };
10579               });
10580             }
10581
10582
10583             /**
10584              * Makes the request.
10585              *
10586              * !!! ACCESSES CLOSURE VARS:
10587              * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
10588              */
10589             function sendReq(config, reqData) {
10590               var deferred = $q.defer(),
10591                   promise = deferred.promise,
10592                   cache,
10593                   cachedResp,
10594                   reqHeaders = config.headers,
10595                   url = buildUrl(config.url, config.paramSerializer(config.params));
10596
10597               $http.pendingRequests.push(config);
10598               promise.then(removePendingReq, removePendingReq);
10599
10600
10601               if ((config.cache || defaults.cache) && config.cache !== false &&
10602                   (config.method === 'GET' || config.method === 'JSONP')) {
10603                 cache = isObject(config.cache) ? config.cache
10604                       : isObject(defaults.cache) ? defaults.cache
10605                       : defaultCache;
10606               }
10607
10608               if (cache) {
10609                 cachedResp = cache.get(url);
10610                 if (isDefined(cachedResp)) {
10611                   if (isPromiseLike(cachedResp)) {
10612                     // cached request has already been sent, but there is no response yet
10613                     cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
10614                   } else {
10615                     // serving from cache
10616                     if (isArray(cachedResp)) {
10617                       resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
10618                     } else {
10619                       resolvePromise(cachedResp, 200, {}, 'OK');
10620                     }
10621                   }
10622                 } else {
10623                   // put the promise for the non-transformed response into cache as a placeholder
10624                   cache.put(url, promise);
10625                 }
10626               }
10627
10628
10629               // if we won't have the response in cache, set the xsrf headers and
10630               // send the request to the backend
10631               if (isUndefined(cachedResp)) {
10632                 var xsrfValue = urlIsSameOrigin(config.url)
10633                     ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
10634                     : undefined;
10635                 if (xsrfValue) {
10636                   reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
10637                 }
10638
10639                 $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
10640                     config.withCredentials, config.responseType);
10641               }
10642
10643               return promise;
10644
10645
10646               /**
10647                * Callback registered to $httpBackend():
10648                *  - caches the response if desired
10649                *  - resolves the raw $http promise
10650                *  - calls $apply
10651                */
10652               function done(status, response, headersString, statusText) {
10653                 if (cache) {
10654                   if (isSuccess(status)) {
10655                     cache.put(url, [status, response, parseHeaders(headersString), statusText]);
10656                   } else {
10657                     // remove promise from the cache
10658                     cache.remove(url);
10659                   }
10660                 }
10661
10662                 function resolveHttpPromise() {
10663                   resolvePromise(response, status, headersString, statusText);
10664                 }
10665
10666                 if (useApplyAsync) {
10667                   $rootScope.$applyAsync(resolveHttpPromise);
10668                 } else {
10669                   resolveHttpPromise();
10670                   if (!$rootScope.$$phase) $rootScope.$apply();
10671                 }
10672               }
10673
10674
10675               /**
10676                * Resolves the raw $http promise.
10677                */
10678               function resolvePromise(response, status, headers, statusText) {
10679                 //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
10680                 status = status >= -1 ? status : 0;
10681
10682                 (isSuccess(status) ? deferred.resolve : deferred.reject)({
10683                   data: response,
10684                   status: status,
10685                   headers: headersGetter(headers),
10686                   config: config,
10687                   statusText: statusText
10688                 });
10689               }
10690
10691               function resolvePromiseWithResult(result) {
10692                 resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
10693               }
10694
10695               function removePendingReq() {
10696                 var idx = $http.pendingRequests.indexOf(config);
10697                 if (idx !== -1) $http.pendingRequests.splice(idx, 1);
10698               }
10699             }
10700
10701
10702             function buildUrl(url, serializedParams) {
10703               if (serializedParams.length > 0) {
10704                 url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
10705               }
10706               return url;
10707             }
10708           }];
10709         }
10710
10711         /**
10712          * @ngdoc service
10713          * @name $xhrFactory
10714          *
10715          * @description
10716          * Factory function used to create XMLHttpRequest objects.
10717          *
10718          * Replace or decorate this service to create your own custom XMLHttpRequest objects.
10719          *
10720          * ```
10721          * angular.module('myApp', [])
10722          * .factory('$xhrFactory', function() {
10723          *   return function createXhr(method, url) {
10724          *     return new window.XMLHttpRequest({mozSystem: true});
10725          *   };
10726          * });
10727          * ```
10728          *
10729          * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
10730          * @param {string} url URL of the request.
10731          */
10732         function $xhrFactoryProvider() {
10733           this.$get = function() {
10734             return function createXhr() {
10735               return new window.XMLHttpRequest();
10736             };
10737           };
10738         }
10739
10740         /**
10741          * @ngdoc service
10742          * @name $httpBackend
10743          * @requires $window
10744          * @requires $document
10745          * @requires $xhrFactory
10746          *
10747          * @description
10748          * HTTP backend used by the {@link ng.$http service} that delegates to
10749          * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
10750          *
10751          * You should never need to use this service directly, instead use the higher-level abstractions:
10752          * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
10753          *
10754          * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
10755          * $httpBackend} which can be trained with responses.
10756          */
10757         function $HttpBackendProvider() {
10758           this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
10759             return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
10760           }];
10761         }
10762
10763         function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
10764           // TODO(vojta): fix the signature
10765           return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
10766             $browser.$$incOutstandingRequestCount();
10767             url = url || $browser.url();
10768
10769             if (lowercase(method) == 'jsonp') {
10770               var callbackId = '_' + (callbacks.counter++).toString(36);
10771               callbacks[callbackId] = function(data) {
10772                 callbacks[callbackId].data = data;
10773                 callbacks[callbackId].called = true;
10774               };
10775
10776               var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
10777                   callbackId, function(status, text) {
10778                 completeRequest(callback, status, callbacks[callbackId].data, "", text);
10779                 callbacks[callbackId] = noop;
10780               });
10781             } else {
10782
10783               var xhr = createXhr(method, url);
10784
10785               xhr.open(method, url, true);
10786               forEach(headers, function(value, key) {
10787                 if (isDefined(value)) {
10788                     xhr.setRequestHeader(key, value);
10789                 }
10790               });
10791
10792               xhr.onload = function requestLoaded() {
10793                 var statusText = xhr.statusText || '';
10794
10795                 // responseText is the old-school way of retrieving response (supported by IE9)
10796                 // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
10797                 var response = ('response' in xhr) ? xhr.response : xhr.responseText;
10798
10799                 // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
10800                 var status = xhr.status === 1223 ? 204 : xhr.status;
10801
10802                 // fix status code when it is 0 (0 status is undocumented).
10803                 // Occurs when accessing file resources or on Android 4.1 stock browser
10804                 // while retrieving files from application cache.
10805                 if (status === 0) {
10806                   status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
10807                 }
10808
10809                 completeRequest(callback,
10810                     status,
10811                     response,
10812                     xhr.getAllResponseHeaders(),
10813                     statusText);
10814               };
10815
10816               var requestError = function() {
10817                 // The response is always empty
10818                 // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
10819                 completeRequest(callback, -1, null, null, '');
10820               };
10821
10822               xhr.onerror = requestError;
10823               xhr.onabort = requestError;
10824
10825               if (withCredentials) {
10826                 xhr.withCredentials = true;
10827               }
10828
10829               if (responseType) {
10830                 try {
10831                   xhr.responseType = responseType;
10832                 } catch (e) {
10833                   // WebKit added support for the json responseType value on 09/03/2013
10834                   // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
10835                   // known to throw when setting the value "json" as the response type. Other older
10836                   // browsers implementing the responseType
10837                   //
10838                   // The json response type can be ignored if not supported, because JSON payloads are
10839                   // parsed on the client-side regardless.
10840                   if (responseType !== 'json') {
10841                     throw e;
10842                   }
10843                 }
10844               }
10845
10846               xhr.send(isUndefined(post) ? null : post);
10847             }
10848
10849             if (timeout > 0) {
10850               var timeoutId = $browserDefer(timeoutRequest, timeout);
10851             } else if (isPromiseLike(timeout)) {
10852               timeout.then(timeoutRequest);
10853             }
10854
10855
10856             function timeoutRequest() {
10857               jsonpDone && jsonpDone();
10858               xhr && xhr.abort();
10859             }
10860
10861             function completeRequest(callback, status, response, headersString, statusText) {
10862               // cancel timeout and subsequent timeout promise resolution
10863               if (isDefined(timeoutId)) {
10864                 $browserDefer.cancel(timeoutId);
10865               }
10866               jsonpDone = xhr = null;
10867
10868               callback(status, response, headersString, statusText);
10869               $browser.$$completeOutstandingRequest(noop);
10870             }
10871           };
10872
10873           function jsonpReq(url, callbackId, done) {
10874             // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
10875             // - fetches local scripts via XHR and evals them
10876             // - adds and immediately removes script elements from the document
10877             var script = rawDocument.createElement('script'), callback = null;
10878             script.type = "text/javascript";
10879             script.src = url;
10880             script.async = true;
10881
10882             callback = function(event) {
10883               removeEventListenerFn(script, "load", callback);
10884               removeEventListenerFn(script, "error", callback);
10885               rawDocument.body.removeChild(script);
10886               script = null;
10887               var status = -1;
10888               var text = "unknown";
10889
10890               if (event) {
10891                 if (event.type === "load" && !callbacks[callbackId].called) {
10892                   event = { type: "error" };
10893                 }
10894                 text = event.type;
10895                 status = event.type === "error" ? 404 : 200;
10896               }
10897
10898               if (done) {
10899                 done(status, text);
10900               }
10901             };
10902
10903             addEventListenerFn(script, "load", callback);
10904             addEventListenerFn(script, "error", callback);
10905             rawDocument.body.appendChild(script);
10906             return callback;
10907           }
10908         }
10909
10910         var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
10911         $interpolateMinErr.throwNoconcat = function(text) {
10912           throw $interpolateMinErr('noconcat',
10913               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10914               "interpolations that concatenate multiple expressions when a trusted value is " +
10915               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10916         };
10917
10918         $interpolateMinErr.interr = function(text, err) {
10919           return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
10920         };
10921
10922         /**
10923          * @ngdoc provider
10924          * @name $interpolateProvider
10925          *
10926          * @description
10927          *
10928          * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
10929          *
10930          * @example
10931         <example module="customInterpolationApp">
10932         <file name="index.html">
10933         <script>
10934           var customInterpolationApp = angular.module('customInterpolationApp', []);
10935
10936           customInterpolationApp.config(function($interpolateProvider) {
10937             $interpolateProvider.startSymbol('//');
10938             $interpolateProvider.endSymbol('//');
10939           });
10940
10941
10942           customInterpolationApp.controller('DemoController', function() {
10943               this.label = "This binding is brought you by // interpolation symbols.";
10944           });
10945         </script>
10946         <div ng-app="App" ng-controller="DemoController as demo">
10947             //demo.label//
10948         </div>
10949         </file>
10950         <file name="protractor.js" type="protractor">
10951           it('should interpolate binding with custom symbols', function() {
10952             expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
10953           });
10954         </file>
10955         </example>
10956          */
10957         function $InterpolateProvider() {
10958           var startSymbol = '{{';
10959           var endSymbol = '}}';
10960
10961           /**
10962            * @ngdoc method
10963            * @name $interpolateProvider#startSymbol
10964            * @description
10965            * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
10966            *
10967            * @param {string=} value new value to set the starting symbol to.
10968            * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10969            */
10970           this.startSymbol = function(value) {
10971             if (value) {
10972               startSymbol = value;
10973               return this;
10974             } else {
10975               return startSymbol;
10976             }
10977           };
10978
10979           /**
10980            * @ngdoc method
10981            * @name $interpolateProvider#endSymbol
10982            * @description
10983            * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10984            *
10985            * @param {string=} value new value to set the ending symbol to.
10986            * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10987            */
10988           this.endSymbol = function(value) {
10989             if (value) {
10990               endSymbol = value;
10991               return this;
10992             } else {
10993               return endSymbol;
10994             }
10995           };
10996
10997
10998           this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10999             var startSymbolLength = startSymbol.length,
11000                 endSymbolLength = endSymbol.length,
11001                 escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
11002                 escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
11003
11004             function escape(ch) {
11005               return '\\\\\\' + ch;
11006             }
11007
11008             function unescapeText(text) {
11009               return text.replace(escapedStartRegexp, startSymbol).
11010                 replace(escapedEndRegexp, endSymbol);
11011             }
11012
11013             function stringify(value) {
11014               if (value == null) { // null || undefined
11015                 return '';
11016               }
11017               switch (typeof value) {
11018                 case 'string':
11019                   break;
11020                 case 'number':
11021                   value = '' + value;
11022                   break;
11023                 default:
11024                   value = toJson(value);
11025               }
11026
11027               return value;
11028             }
11029
11030             /**
11031              * @ngdoc service
11032              * @name $interpolate
11033              * @kind function
11034              *
11035              * @requires $parse
11036              * @requires $sce
11037              *
11038              * @description
11039              *
11040              * Compiles a string with markup into an interpolation function. This service is used by the
11041              * HTML {@link ng.$compile $compile} service for data binding. See
11042              * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
11043              * interpolation markup.
11044              *
11045              *
11046              * ```js
11047              *   var $interpolate = ...; // injected
11048              *   var exp = $interpolate('Hello {{name | uppercase}}!');
11049              *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
11050              * ```
11051              *
11052              * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
11053              * `true`, the interpolation function will return `undefined` unless all embedded expressions
11054              * evaluate to a value other than `undefined`.
11055              *
11056              * ```js
11057              *   var $interpolate = ...; // injected
11058              *   var context = {greeting: 'Hello', name: undefined };
11059              *
11060              *   // default "forgiving" mode
11061              *   var exp = $interpolate('{{greeting}} {{name}}!');
11062              *   expect(exp(context)).toEqual('Hello !');
11063              *
11064              *   // "allOrNothing" mode
11065              *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
11066              *   expect(exp(context)).toBeUndefined();
11067              *   context.name = 'Angular';
11068              *   expect(exp(context)).toEqual('Hello Angular!');
11069              * ```
11070              *
11071              * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
11072              *
11073              * ####Escaped Interpolation
11074              * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
11075              * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
11076              * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
11077              * or binding.
11078              *
11079              * This enables web-servers to prevent script injection attacks and defacing attacks, to some
11080              * degree, while also enabling code examples to work without relying on the
11081              * {@link ng.directive:ngNonBindable ngNonBindable} directive.
11082              *
11083              * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
11084              * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
11085              * interpolation start/end markers with their escaped counterparts.**
11086              *
11087              * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
11088              * output when the $interpolate service processes the text. So, for HTML elements interpolated
11089              * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
11090              * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
11091              * this is typically useful only when user-data is used in rendering a template from the server, or
11092              * when otherwise untrusted data is used by a directive.
11093              *
11094              * <example>
11095              *  <file name="index.html">
11096              *    <div ng-init="username='A user'">
11097              *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
11098              *        </p>
11099              *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
11100              *        application, but fails to accomplish their task, because the server has correctly
11101              *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
11102              *        characters.</p>
11103              *      <p>Instead, the result of the attempted script injection is visible, and can be removed
11104              *        from the database by an administrator.</p>
11105              *    </div>
11106              *  </file>
11107              * </example>
11108              *
11109              * @param {string} text The text with markup to interpolate.
11110              * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
11111              *    embedded expression in order to return an interpolation function. Strings with no
11112              *    embedded expression will return null for the interpolation function.
11113              * @param {string=} trustedContext when provided, the returned function passes the interpolated
11114              *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
11115              *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
11116              *    provides Strict Contextual Escaping for details.
11117              * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
11118              *    unless all embedded expressions evaluate to a value other than `undefined`.
11119              * @returns {function(context)} an interpolation function which is used to compute the
11120              *    interpolated string. The function has these parameters:
11121              *
11122              * - `context`: evaluation context for all expressions embedded in the interpolated text
11123              */
11124             function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
11125               allOrNothing = !!allOrNothing;
11126               var startIndex,
11127                   endIndex,
11128                   index = 0,
11129                   expressions = [],
11130                   parseFns = [],
11131                   textLength = text.length,
11132                   exp,
11133                   concat = [],
11134                   expressionPositions = [];
11135
11136               while (index < textLength) {
11137                 if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
11138                      ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
11139                   if (index !== startIndex) {
11140                     concat.push(unescapeText(text.substring(index, startIndex)));
11141                   }
11142                   exp = text.substring(startIndex + startSymbolLength, endIndex);
11143                   expressions.push(exp);
11144                   parseFns.push($parse(exp, parseStringifyInterceptor));
11145                   index = endIndex + endSymbolLength;
11146                   expressionPositions.push(concat.length);
11147                   concat.push('');
11148                 } else {
11149                   // we did not find an interpolation, so we have to add the remainder to the separators array
11150                   if (index !== textLength) {
11151                     concat.push(unescapeText(text.substring(index)));
11152                   }
11153                   break;
11154                 }
11155               }
11156
11157               // Concatenating expressions makes it hard to reason about whether some combination of
11158               // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
11159               // single expression be used for iframe[src], object[src], etc., we ensure that the value
11160               // that's used is assigned or constructed by some JS code somewhere that is more testable or
11161               // make it obvious that you bound the value to some user controlled value.  This helps reduce
11162               // the load when auditing for XSS issues.
11163               if (trustedContext && concat.length > 1) {
11164                   $interpolateMinErr.throwNoconcat(text);
11165               }
11166
11167               if (!mustHaveExpression || expressions.length) {
11168                 var compute = function(values) {
11169                   for (var i = 0, ii = expressions.length; i < ii; i++) {
11170                     if (allOrNothing && isUndefined(values[i])) return;
11171                     concat[expressionPositions[i]] = values[i];
11172                   }
11173                   return concat.join('');
11174                 };
11175
11176                 var getValue = function(value) {
11177                   return trustedContext ?
11178                     $sce.getTrusted(trustedContext, value) :
11179                     $sce.valueOf(value);
11180                 };
11181
11182                 return extend(function interpolationFn(context) {
11183                     var i = 0;
11184                     var ii = expressions.length;
11185                     var values = new Array(ii);
11186
11187                     try {
11188                       for (; i < ii; i++) {
11189                         values[i] = parseFns[i](context);
11190                       }
11191
11192                       return compute(values);
11193                     } catch (err) {
11194                       $exceptionHandler($interpolateMinErr.interr(text, err));
11195                     }
11196
11197                   }, {
11198                   // all of these properties are undocumented for now
11199                   exp: text, //just for compatibility with regular watchers created via $watch
11200                   expressions: expressions,
11201                   $$watchDelegate: function(scope, listener) {
11202                     var lastValue;
11203                     return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
11204                       var currValue = compute(values);
11205                       if (isFunction(listener)) {
11206                         listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
11207                       }
11208                       lastValue = currValue;
11209                     });
11210                   }
11211                 });
11212               }
11213
11214               function parseStringifyInterceptor(value) {
11215                 try {
11216                   value = getValue(value);
11217                   return allOrNothing && !isDefined(value) ? value : stringify(value);
11218                 } catch (err) {
11219                   $exceptionHandler($interpolateMinErr.interr(text, err));
11220                 }
11221               }
11222             }
11223
11224
11225             /**
11226              * @ngdoc method
11227              * @name $interpolate#startSymbol
11228              * @description
11229              * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
11230              *
11231              * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
11232              * the symbol.
11233              *
11234              * @returns {string} start symbol.
11235              */
11236             $interpolate.startSymbol = function() {
11237               return startSymbol;
11238             };
11239
11240
11241             /**
11242              * @ngdoc method
11243              * @name $interpolate#endSymbol
11244              * @description
11245              * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
11246              *
11247              * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
11248              * the symbol.
11249              *
11250              * @returns {string} end symbol.
11251              */
11252             $interpolate.endSymbol = function() {
11253               return endSymbol;
11254             };
11255
11256             return $interpolate;
11257           }];
11258         }
11259
11260         function $IntervalProvider() {
11261           this.$get = ['$rootScope', '$window', '$q', '$$q',
11262                function($rootScope,   $window,   $q,   $$q) {
11263             var intervals = {};
11264
11265
11266              /**
11267               * @ngdoc service
11268               * @name $interval
11269               *
11270               * @description
11271               * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
11272               * milliseconds.
11273               *
11274               * The return value of registering an interval function is a promise. This promise will be
11275               * notified upon each tick of the interval, and will be resolved after `count` iterations, or
11276               * run indefinitely if `count` is not defined. The value of the notification will be the
11277               * number of iterations that have run.
11278               * To cancel an interval, call `$interval.cancel(promise)`.
11279               *
11280               * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
11281               * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
11282               * time.
11283               *
11284               * <div class="alert alert-warning">
11285               * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
11286               * with them.  In particular they are not automatically destroyed when a controller's scope or a
11287               * directive's element are destroyed.
11288               * You should take this into consideration and make sure to always cancel the interval at the
11289               * appropriate moment.  See the example below for more details on how and when to do this.
11290               * </div>
11291               *
11292               * @param {function()} fn A function that should be called repeatedly.
11293               * @param {number} delay Number of milliseconds between each function call.
11294               * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
11295               *   indefinitely.
11296               * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
11297               *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
11298               * @param {...*=} Pass additional parameters to the executed function.
11299               * @returns {promise} A promise which will be notified on each iteration.
11300               *
11301               * @example
11302               * <example module="intervalExample">
11303               * <file name="index.html">
11304               *   <script>
11305               *     angular.module('intervalExample', [])
11306               *       .controller('ExampleController', ['$scope', '$interval',
11307               *         function($scope, $interval) {
11308               *           $scope.format = 'M/d/yy h:mm:ss a';
11309               *           $scope.blood_1 = 100;
11310               *           $scope.blood_2 = 120;
11311               *
11312               *           var stop;
11313               *           $scope.fight = function() {
11314               *             // Don't start a new fight if we are already fighting
11315               *             if ( angular.isDefined(stop) ) return;
11316               *
11317               *             stop = $interval(function() {
11318               *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
11319               *                 $scope.blood_1 = $scope.blood_1 - 3;
11320               *                 $scope.blood_2 = $scope.blood_2 - 4;
11321               *               } else {
11322               *                 $scope.stopFight();
11323               *               }
11324               *             }, 100);
11325               *           };
11326               *
11327               *           $scope.stopFight = function() {
11328               *             if (angular.isDefined(stop)) {
11329               *               $interval.cancel(stop);
11330               *               stop = undefined;
11331               *             }
11332               *           };
11333               *
11334               *           $scope.resetFight = function() {
11335               *             $scope.blood_1 = 100;
11336               *             $scope.blood_2 = 120;
11337               *           };
11338               *
11339               *           $scope.$on('$destroy', function() {
11340               *             // Make sure that the interval is destroyed too
11341               *             $scope.stopFight();
11342               *           });
11343               *         }])
11344               *       // Register the 'myCurrentTime' directive factory method.
11345               *       // We inject $interval and dateFilter service since the factory method is DI.
11346               *       .directive('myCurrentTime', ['$interval', 'dateFilter',
11347               *         function($interval, dateFilter) {
11348               *           // return the directive link function. (compile function not needed)
11349               *           return function(scope, element, attrs) {
11350               *             var format,  // date format
11351               *                 stopTime; // so that we can cancel the time updates
11352               *
11353               *             // used to update the UI
11354               *             function updateTime() {
11355               *               element.text(dateFilter(new Date(), format));
11356               *             }
11357               *
11358               *             // watch the expression, and update the UI on change.
11359               *             scope.$watch(attrs.myCurrentTime, function(value) {
11360               *               format = value;
11361               *               updateTime();
11362               *             });
11363               *
11364               *             stopTime = $interval(updateTime, 1000);
11365               *
11366               *             // listen on DOM destroy (removal) event, and cancel the next UI update
11367               *             // to prevent updating time after the DOM element was removed.
11368               *             element.on('$destroy', function() {
11369               *               $interval.cancel(stopTime);
11370               *             });
11371               *           }
11372               *         }]);
11373               *   </script>
11374               *
11375               *   <div>
11376               *     <div ng-controller="ExampleController">
11377               *       <label>Date format: <input ng-model="format"></label> <hr/>
11378               *       Current time is: <span my-current-time="format"></span>
11379               *       <hr/>
11380               *       Blood 1 : <font color='red'>{{blood_1}}</font>
11381               *       Blood 2 : <font color='red'>{{blood_2}}</font>
11382               *       <button type="button" data-ng-click="fight()">Fight</button>
11383               *       <button type="button" data-ng-click="stopFight()">StopFight</button>
11384               *       <button type="button" data-ng-click="resetFight()">resetFight</button>
11385               *     </div>
11386               *   </div>
11387               *
11388               * </file>
11389               * </example>
11390               */
11391             function interval(fn, delay, count, invokeApply) {
11392               var hasParams = arguments.length > 4,
11393                   args = hasParams ? sliceArgs(arguments, 4) : [],
11394                   setInterval = $window.setInterval,
11395                   clearInterval = $window.clearInterval,
11396                   iteration = 0,
11397                   skipApply = (isDefined(invokeApply) && !invokeApply),
11398                   deferred = (skipApply ? $$q : $q).defer(),
11399                   promise = deferred.promise;
11400
11401               count = isDefined(count) ? count : 0;
11402
11403               promise.then(null, null, (!hasParams) ? fn : function() {
11404                 fn.apply(null, args);
11405               });
11406
11407               promise.$$intervalId = setInterval(function tick() {
11408                 deferred.notify(iteration++);
11409
11410                 if (count > 0 && iteration >= count) {
11411                   deferred.resolve(iteration);
11412                   clearInterval(promise.$$intervalId);
11413                   delete intervals[promise.$$intervalId];
11414                 }
11415
11416                 if (!skipApply) $rootScope.$apply();
11417
11418               }, delay);
11419
11420               intervals[promise.$$intervalId] = deferred;
11421
11422               return promise;
11423             }
11424
11425
11426              /**
11427               * @ngdoc method
11428               * @name $interval#cancel
11429               *
11430               * @description
11431               * Cancels a task associated with the `promise`.
11432               *
11433               * @param {Promise=} promise returned by the `$interval` function.
11434               * @returns {boolean} Returns `true` if the task was successfully canceled.
11435               */
11436             interval.cancel = function(promise) {
11437               if (promise && promise.$$intervalId in intervals) {
11438                 intervals[promise.$$intervalId].reject('canceled');
11439                 $window.clearInterval(promise.$$intervalId);
11440                 delete intervals[promise.$$intervalId];
11441                 return true;
11442               }
11443               return false;
11444             };
11445
11446             return interval;
11447           }];
11448         }
11449
11450         /**
11451          * @ngdoc service
11452          * @name $locale
11453          *
11454          * @description
11455          * $locale service provides localization rules for various Angular components. As of right now the
11456          * only public api is:
11457          *
11458          * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
11459          */
11460
11461         var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
11462             DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
11463         var $locationMinErr = minErr('$location');
11464
11465
11466         /**
11467          * Encode path using encodeUriSegment, ignoring forward slashes
11468          *
11469          * @param {string} path Path to encode
11470          * @returns {string}
11471          */
11472         function encodePath(path) {
11473           var segments = path.split('/'),
11474               i = segments.length;
11475
11476           while (i--) {
11477             segments[i] = encodeUriSegment(segments[i]);
11478           }
11479
11480           return segments.join('/');
11481         }
11482
11483         function parseAbsoluteUrl(absoluteUrl, locationObj) {
11484           var parsedUrl = urlResolve(absoluteUrl);
11485
11486           locationObj.$$protocol = parsedUrl.protocol;
11487           locationObj.$$host = parsedUrl.hostname;
11488           locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
11489         }
11490
11491
11492         function parseAppUrl(relativeUrl, locationObj) {
11493           var prefixed = (relativeUrl.charAt(0) !== '/');
11494           if (prefixed) {
11495             relativeUrl = '/' + relativeUrl;
11496           }
11497           var match = urlResolve(relativeUrl);
11498           locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
11499               match.pathname.substring(1) : match.pathname);
11500           locationObj.$$search = parseKeyValue(match.search);
11501           locationObj.$$hash = decodeURIComponent(match.hash);
11502
11503           // make sure path starts with '/';
11504           if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
11505             locationObj.$$path = '/' + locationObj.$$path;
11506           }
11507         }
11508
11509
11510         /**
11511          *
11512          * @param {string} begin
11513          * @param {string} whole
11514          * @returns {string} returns text from whole after begin or undefined if it does not begin with
11515          *                   expected string.
11516          */
11517         function beginsWith(begin, whole) {
11518           if (whole.indexOf(begin) === 0) {
11519             return whole.substr(begin.length);
11520           }
11521         }
11522
11523
11524         function stripHash(url) {
11525           var index = url.indexOf('#');
11526           return index == -1 ? url : url.substr(0, index);
11527         }
11528
11529         function trimEmptyHash(url) {
11530           return url.replace(/(#.+)|#$/, '$1');
11531         }
11532
11533
11534         function stripFile(url) {
11535           return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
11536         }
11537
11538         /* return the server only (scheme://host:port) */
11539         function serverBase(url) {
11540           return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
11541         }
11542
11543
11544         /**
11545          * LocationHtml5Url represents an url
11546          * This object is exposed as $location service when HTML5 mode is enabled and supported
11547          *
11548          * @constructor
11549          * @param {string} appBase application base URL
11550          * @param {string} appBaseNoFile application base URL stripped of any filename
11551          * @param {string} basePrefix url path prefix
11552          */
11553         function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
11554           this.$$html5 = true;
11555           basePrefix = basePrefix || '';
11556           parseAbsoluteUrl(appBase, this);
11557
11558
11559           /**
11560            * Parse given html5 (regular) url string into properties
11561            * @param {string} url HTML5 url
11562            * @private
11563            */
11564           this.$$parse = function(url) {
11565             var pathUrl = beginsWith(appBaseNoFile, url);
11566             if (!isString(pathUrl)) {
11567               throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
11568                   appBaseNoFile);
11569             }
11570
11571             parseAppUrl(pathUrl, this);
11572
11573             if (!this.$$path) {
11574               this.$$path = '/';
11575             }
11576
11577             this.$$compose();
11578           };
11579
11580           /**
11581            * Compose url and update `absUrl` property
11582            * @private
11583            */
11584           this.$$compose = function() {
11585             var search = toKeyValue(this.$$search),
11586                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11587
11588             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11589             this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
11590           };
11591
11592           this.$$parseLinkUrl = function(url, relHref) {
11593             if (relHref && relHref[0] === '#') {
11594               // special case for links to hash fragments:
11595               // keep the old url and only replace the hash fragment
11596               this.hash(relHref.slice(1));
11597               return true;
11598             }
11599             var appUrl, prevAppUrl;
11600             var rewrittenUrl;
11601
11602             if (isDefined(appUrl = beginsWith(appBase, url))) {
11603               prevAppUrl = appUrl;
11604               if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
11605                 rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
11606               } else {
11607                 rewrittenUrl = appBase + prevAppUrl;
11608               }
11609             } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
11610               rewrittenUrl = appBaseNoFile + appUrl;
11611             } else if (appBaseNoFile == url + '/') {
11612               rewrittenUrl = appBaseNoFile;
11613             }
11614             if (rewrittenUrl) {
11615               this.$$parse(rewrittenUrl);
11616             }
11617             return !!rewrittenUrl;
11618           };
11619         }
11620
11621
11622         /**
11623          * LocationHashbangUrl represents url
11624          * This object is exposed as $location service when developer doesn't opt into html5 mode.
11625          * It also serves as the base class for html5 mode fallback on legacy browsers.
11626          *
11627          * @constructor
11628          * @param {string} appBase application base URL
11629          * @param {string} appBaseNoFile application base URL stripped of any filename
11630          * @param {string} hashPrefix hashbang prefix
11631          */
11632         function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
11633
11634           parseAbsoluteUrl(appBase, this);
11635
11636
11637           /**
11638            * Parse given hashbang url into properties
11639            * @param {string} url Hashbang url
11640            * @private
11641            */
11642           this.$$parse = function(url) {
11643             var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
11644             var withoutHashUrl;
11645
11646             if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
11647
11648               // The rest of the url starts with a hash so we have
11649               // got either a hashbang path or a plain hash fragment
11650               withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
11651               if (isUndefined(withoutHashUrl)) {
11652                 // There was no hashbang prefix so we just have a hash fragment
11653                 withoutHashUrl = withoutBaseUrl;
11654               }
11655
11656             } else {
11657               // There was no hashbang path nor hash fragment:
11658               // If we are in HTML5 mode we use what is left as the path;
11659               // Otherwise we ignore what is left
11660               if (this.$$html5) {
11661                 withoutHashUrl = withoutBaseUrl;
11662               } else {
11663                 withoutHashUrl = '';
11664                 if (isUndefined(withoutBaseUrl)) {
11665                   appBase = url;
11666                   this.replace();
11667                 }
11668               }
11669             }
11670
11671             parseAppUrl(withoutHashUrl, this);
11672
11673             this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
11674
11675             this.$$compose();
11676
11677             /*
11678              * In Windows, on an anchor node on documents loaded from
11679              * the filesystem, the browser will return a pathname
11680              * prefixed with the drive name ('/C:/path') when a
11681              * pathname without a drive is set:
11682              *  * a.setAttribute('href', '/foo')
11683              *   * a.pathname === '/C:/foo' //true
11684              *
11685              * Inside of Angular, we're always using pathnames that
11686              * do not include drive names for routing.
11687              */
11688             function removeWindowsDriveName(path, url, base) {
11689               /*
11690               Matches paths for file protocol on windows,
11691               such as /C:/foo/bar, and captures only /foo/bar.
11692               */
11693               var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
11694
11695               var firstPathSegmentMatch;
11696
11697               //Get the relative path from the input URL.
11698               if (url.indexOf(base) === 0) {
11699                 url = url.replace(base, '');
11700               }
11701
11702               // The input URL intentionally contains a first path segment that ends with a colon.
11703               if (windowsFilePathExp.exec(url)) {
11704                 return path;
11705               }
11706
11707               firstPathSegmentMatch = windowsFilePathExp.exec(path);
11708               return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
11709             }
11710           };
11711
11712           /**
11713            * Compose hashbang url and update `absUrl` property
11714            * @private
11715            */
11716           this.$$compose = function() {
11717             var search = toKeyValue(this.$$search),
11718                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11719
11720             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11721             this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
11722           };
11723
11724           this.$$parseLinkUrl = function(url, relHref) {
11725             if (stripHash(appBase) == stripHash(url)) {
11726               this.$$parse(url);
11727               return true;
11728             }
11729             return false;
11730           };
11731         }
11732
11733
11734         /**
11735          * LocationHashbangUrl represents url
11736          * This object is exposed as $location service when html5 history api is enabled but the browser
11737          * does not support it.
11738          *
11739          * @constructor
11740          * @param {string} appBase application base URL
11741          * @param {string} appBaseNoFile application base URL stripped of any filename
11742          * @param {string} hashPrefix hashbang prefix
11743          */
11744         function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
11745           this.$$html5 = true;
11746           LocationHashbangUrl.apply(this, arguments);
11747
11748           this.$$parseLinkUrl = function(url, relHref) {
11749             if (relHref && relHref[0] === '#') {
11750               // special case for links to hash fragments:
11751               // keep the old url and only replace the hash fragment
11752               this.hash(relHref.slice(1));
11753               return true;
11754             }
11755
11756             var rewrittenUrl;
11757             var appUrl;
11758
11759             if (appBase == stripHash(url)) {
11760               rewrittenUrl = url;
11761             } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
11762               rewrittenUrl = appBase + hashPrefix + appUrl;
11763             } else if (appBaseNoFile === url + '/') {
11764               rewrittenUrl = appBaseNoFile;
11765             }
11766             if (rewrittenUrl) {
11767               this.$$parse(rewrittenUrl);
11768             }
11769             return !!rewrittenUrl;
11770           };
11771
11772           this.$$compose = function() {
11773             var search = toKeyValue(this.$$search),
11774                 hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11775
11776             this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11777             // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
11778             this.$$absUrl = appBase + hashPrefix + this.$$url;
11779           };
11780
11781         }
11782
11783
11784         var locationPrototype = {
11785
11786           /**
11787            * Are we in html5 mode?
11788            * @private
11789            */
11790           $$html5: false,
11791
11792           /**
11793            * Has any change been replacing?
11794            * @private
11795            */
11796           $$replace: false,
11797
11798           /**
11799            * @ngdoc method
11800            * @name $location#absUrl
11801            *
11802            * @description
11803            * This method is getter only.
11804            *
11805            * Return full url representation with all segments encoded according to rules specified in
11806            * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
11807            *
11808            *
11809            * ```js
11810            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11811            * var absUrl = $location.absUrl();
11812            * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
11813            * ```
11814            *
11815            * @return {string} full url
11816            */
11817           absUrl: locationGetter('$$absUrl'),
11818
11819           /**
11820            * @ngdoc method
11821            * @name $location#url
11822            *
11823            * @description
11824            * This method is getter / setter.
11825            *
11826            * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
11827            *
11828            * Change path, search and hash, when called with parameter and return `$location`.
11829            *
11830            *
11831            * ```js
11832            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11833            * var url = $location.url();
11834            * // => "/some/path?foo=bar&baz=xoxo"
11835            * ```
11836            *
11837            * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
11838            * @return {string} url
11839            */
11840           url: function(url) {
11841             if (isUndefined(url)) {
11842               return this.$$url;
11843             }
11844
11845             var match = PATH_MATCH.exec(url);
11846             if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
11847             if (match[2] || match[1] || url === '') this.search(match[3] || '');
11848             this.hash(match[5] || '');
11849
11850             return this;
11851           },
11852
11853           /**
11854            * @ngdoc method
11855            * @name $location#protocol
11856            *
11857            * @description
11858            * This method is getter only.
11859            *
11860            * Return protocol of current url.
11861            *
11862            *
11863            * ```js
11864            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11865            * var protocol = $location.protocol();
11866            * // => "http"
11867            * ```
11868            *
11869            * @return {string} protocol of current url
11870            */
11871           protocol: locationGetter('$$protocol'),
11872
11873           /**
11874            * @ngdoc method
11875            * @name $location#host
11876            *
11877            * @description
11878            * This method is getter only.
11879            *
11880            * Return host of current url.
11881            *
11882            * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
11883            *
11884            *
11885            * ```js
11886            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11887            * var host = $location.host();
11888            * // => "example.com"
11889            *
11890            * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
11891            * host = $location.host();
11892            * // => "example.com"
11893            * host = location.host;
11894            * // => "example.com:8080"
11895            * ```
11896            *
11897            * @return {string} host of current url.
11898            */
11899           host: locationGetter('$$host'),
11900
11901           /**
11902            * @ngdoc method
11903            * @name $location#port
11904            *
11905            * @description
11906            * This method is getter only.
11907            *
11908            * Return port of current url.
11909            *
11910            *
11911            * ```js
11912            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11913            * var port = $location.port();
11914            * // => 80
11915            * ```
11916            *
11917            * @return {Number} port
11918            */
11919           port: locationGetter('$$port'),
11920
11921           /**
11922            * @ngdoc method
11923            * @name $location#path
11924            *
11925            * @description
11926            * This method is getter / setter.
11927            *
11928            * Return path of current url when called without any parameter.
11929            *
11930            * Change path when called with parameter and return `$location`.
11931            *
11932            * Note: Path should always begin with forward slash (/), this method will add the forward slash
11933            * if it is missing.
11934            *
11935            *
11936            * ```js
11937            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11938            * var path = $location.path();
11939            * // => "/some/path"
11940            * ```
11941            *
11942            * @param {(string|number)=} path New path
11943            * @return {string} path
11944            */
11945           path: locationGetterSetter('$$path', function(path) {
11946             path = path !== null ? path.toString() : '';
11947             return path.charAt(0) == '/' ? path : '/' + path;
11948           }),
11949
11950           /**
11951            * @ngdoc method
11952            * @name $location#search
11953            *
11954            * @description
11955            * This method is getter / setter.
11956            *
11957            * Return search part (as object) of current url when called without any parameter.
11958            *
11959            * Change search part when called with parameter and return `$location`.
11960            *
11961            *
11962            * ```js
11963            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11964            * var searchObject = $location.search();
11965            * // => {foo: 'bar', baz: 'xoxo'}
11966            *
11967            * // set foo to 'yipee'
11968            * $location.search('foo', 'yipee');
11969            * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11970            * ```
11971            *
11972            * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11973            * hash object.
11974            *
11975            * When called with a single argument the method acts as a setter, setting the `search` component
11976            * of `$location` to the specified value.
11977            *
11978            * If the argument is a hash object containing an array of values, these values will be encoded
11979            * as duplicate search parameters in the url.
11980            *
11981            * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11982            * will override only a single search property.
11983            *
11984            * If `paramValue` is an array, it will override the property of the `search` component of
11985            * `$location` specified via the first argument.
11986            *
11987            * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11988            *
11989            * If `paramValue` is `true`, the property specified via the first argument will be added with no
11990            * value nor trailing equal sign.
11991            *
11992            * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11993            * one or more arguments returns `$location` object itself.
11994            */
11995           search: function(search, paramValue) {
11996             switch (arguments.length) {
11997               case 0:
11998                 return this.$$search;
11999               case 1:
12000                 if (isString(search) || isNumber(search)) {
12001                   search = search.toString();
12002                   this.$$search = parseKeyValue(search);
12003                 } else if (isObject(search)) {
12004                   search = copy(search, {});
12005                   // remove object undefined or null properties
12006                   forEach(search, function(value, key) {
12007                     if (value == null) delete search[key];
12008                   });
12009
12010                   this.$$search = search;
12011                 } else {
12012                   throw $locationMinErr('isrcharg',
12013                       'The first argument of the `$location#search()` call must be a string or an object.');
12014                 }
12015                 break;
12016               default:
12017                 if (isUndefined(paramValue) || paramValue === null) {
12018                   delete this.$$search[search];
12019                 } else {
12020                   this.$$search[search] = paramValue;
12021                 }
12022             }
12023
12024             this.$$compose();
12025             return this;
12026           },
12027
12028           /**
12029            * @ngdoc method
12030            * @name $location#hash
12031            *
12032            * @description
12033            * This method is getter / setter.
12034            *
12035            * Returns the hash fragment when called without any parameters.
12036            *
12037            * Changes the hash fragment when called with a parameter and returns `$location`.
12038            *
12039            *
12040            * ```js
12041            * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
12042            * var hash = $location.hash();
12043            * // => "hashValue"
12044            * ```
12045            *
12046            * @param {(string|number)=} hash New hash fragment
12047            * @return {string} hash
12048            */
12049           hash: locationGetterSetter('$$hash', function(hash) {
12050             return hash !== null ? hash.toString() : '';
12051           }),
12052
12053           /**
12054            * @ngdoc method
12055            * @name $location#replace
12056            *
12057            * @description
12058            * If called, all changes to $location during the current `$digest` will replace the current history
12059            * record, instead of adding a new one.
12060            */
12061           replace: function() {
12062             this.$$replace = true;
12063             return this;
12064           }
12065         };
12066
12067         forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
12068           Location.prototype = Object.create(locationPrototype);
12069
12070           /**
12071            * @ngdoc method
12072            * @name $location#state
12073            *
12074            * @description
12075            * This method is getter / setter.
12076            *
12077            * Return the history state object when called without any parameter.
12078            *
12079            * Change the history state object when called with one parameter and return `$location`.
12080            * The state object is later passed to `pushState` or `replaceState`.
12081            *
12082            * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
12083            * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
12084            * older browsers (like IE9 or Android < 4.0), don't use this method.
12085            *
12086            * @param {object=} state State object for pushState or replaceState
12087            * @return {object} state
12088            */
12089           Location.prototype.state = function(state) {
12090             if (!arguments.length) {
12091               return this.$$state;
12092             }
12093
12094             if (Location !== LocationHtml5Url || !this.$$html5) {
12095               throw $locationMinErr('nostate', 'History API state support is available only ' +
12096                 'in HTML5 mode and only in browsers supporting HTML5 History API');
12097             }
12098             // The user might modify `stateObject` after invoking `$location.state(stateObject)`
12099             // but we're changing the $$state reference to $browser.state() during the $digest
12100             // so the modification window is narrow.
12101             this.$$state = isUndefined(state) ? null : state;
12102
12103             return this;
12104           };
12105         });
12106
12107
12108         function locationGetter(property) {
12109           return function() {
12110             return this[property];
12111           };
12112         }
12113
12114
12115         function locationGetterSetter(property, preprocess) {
12116           return function(value) {
12117             if (isUndefined(value)) {
12118               return this[property];
12119             }
12120
12121             this[property] = preprocess(value);
12122             this.$$compose();
12123
12124             return this;
12125           };
12126         }
12127
12128
12129         /**
12130          * @ngdoc service
12131          * @name $location
12132          *
12133          * @requires $rootElement
12134          *
12135          * @description
12136          * The $location service parses the URL in the browser address bar (based on the
12137          * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
12138          * available to your application. Changes to the URL in the address bar are reflected into
12139          * $location service and changes to $location are reflected into the browser address bar.
12140          *
12141          * **The $location service:**
12142          *
12143          * - Exposes the current URL in the browser address bar, so you can
12144          *   - Watch and observe the URL.
12145          *   - Change the URL.
12146          * - Synchronizes the URL with the browser when the user
12147          *   - Changes the address bar.
12148          *   - Clicks the back or forward button (or clicks a History link).
12149          *   - Clicks on a link.
12150          * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
12151          *
12152          * For more information see {@link guide/$location Developer Guide: Using $location}
12153          */
12154
12155         /**
12156          * @ngdoc provider
12157          * @name $locationProvider
12158          * @description
12159          * Use the `$locationProvider` to configure how the application deep linking paths are stored.
12160          */
12161         function $LocationProvider() {
12162           var hashPrefix = '',
12163               html5Mode = {
12164                 enabled: false,
12165                 requireBase: true,
12166                 rewriteLinks: true
12167               };
12168
12169           /**
12170            * @ngdoc method
12171            * @name $locationProvider#hashPrefix
12172            * @description
12173            * @param {string=} prefix Prefix for hash part (containing path and search)
12174            * @returns {*} current value if used as getter or itself (chaining) if used as setter
12175            */
12176           this.hashPrefix = function(prefix) {
12177             if (isDefined(prefix)) {
12178               hashPrefix = prefix;
12179               return this;
12180             } else {
12181               return hashPrefix;
12182             }
12183           };
12184
12185           /**
12186            * @ngdoc method
12187            * @name $locationProvider#html5Mode
12188            * @description
12189            * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
12190            *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
12191            *   properties:
12192            *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
12193            *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
12194            *     support `pushState`.
12195            *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
12196            *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
12197            *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
12198            *     See the {@link guide/$location $location guide for more information}
12199            *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
12200            *     enables/disables url rewriting for relative links.
12201            *
12202            * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
12203            */
12204           this.html5Mode = function(mode) {
12205             if (isBoolean(mode)) {
12206               html5Mode.enabled = mode;
12207               return this;
12208             } else if (isObject(mode)) {
12209
12210               if (isBoolean(mode.enabled)) {
12211                 html5Mode.enabled = mode.enabled;
12212               }
12213
12214               if (isBoolean(mode.requireBase)) {
12215                 html5Mode.requireBase = mode.requireBase;
12216               }
12217
12218               if (isBoolean(mode.rewriteLinks)) {
12219                 html5Mode.rewriteLinks = mode.rewriteLinks;
12220               }
12221
12222               return this;
12223             } else {
12224               return html5Mode;
12225             }
12226           };
12227
12228           /**
12229            * @ngdoc event
12230            * @name $location#$locationChangeStart
12231            * @eventType broadcast on root scope
12232            * @description
12233            * Broadcasted before a URL will change.
12234            *
12235            * This change can be prevented by calling
12236            * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
12237            * details about event object. Upon successful change
12238            * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
12239            *
12240            * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12241            * the browser supports the HTML5 History API.
12242            *
12243            * @param {Object} angularEvent Synthetic event object.
12244            * @param {string} newUrl New URL
12245            * @param {string=} oldUrl URL that was before it was changed.
12246            * @param {string=} newState New history state object
12247            * @param {string=} oldState History state object that was before it was changed.
12248            */
12249
12250           /**
12251            * @ngdoc event
12252            * @name $location#$locationChangeSuccess
12253            * @eventType broadcast on root scope
12254            * @description
12255            * Broadcasted after a URL was changed.
12256            *
12257            * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
12258            * the browser supports the HTML5 History API.
12259            *
12260            * @param {Object} angularEvent Synthetic event object.
12261            * @param {string} newUrl New URL
12262            * @param {string=} oldUrl URL that was before it was changed.
12263            * @param {string=} newState New history state object
12264            * @param {string=} oldState History state object that was before it was changed.
12265            */
12266
12267           this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
12268               function($rootScope, $browser, $sniffer, $rootElement, $window) {
12269             var $location,
12270                 LocationMode,
12271                 baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
12272                 initialUrl = $browser.url(),
12273                 appBase;
12274
12275             if (html5Mode.enabled) {
12276               if (!baseHref && html5Mode.requireBase) {
12277                 throw $locationMinErr('nobase',
12278                   "$location in HTML5 mode requires a <base> tag to be present!");
12279               }
12280               appBase = serverBase(initialUrl) + (baseHref || '/');
12281               LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
12282             } else {
12283               appBase = stripHash(initialUrl);
12284               LocationMode = LocationHashbangUrl;
12285             }
12286             var appBaseNoFile = stripFile(appBase);
12287
12288             $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
12289             $location.$$parseLinkUrl(initialUrl, initialUrl);
12290
12291             $location.$$state = $browser.state();
12292
12293             var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
12294
12295             function setBrowserUrlWithFallback(url, replace, state) {
12296               var oldUrl = $location.url();
12297               var oldState = $location.$$state;
12298               try {
12299                 $browser.url(url, replace, state);
12300
12301                 // Make sure $location.state() returns referentially identical (not just deeply equal)
12302                 // state object; this makes possible quick checking if the state changed in the digest
12303                 // loop. Checking deep equality would be too expensive.
12304                 $location.$$state = $browser.state();
12305               } catch (e) {
12306                 // Restore old values if pushState fails
12307                 $location.url(oldUrl);
12308                 $location.$$state = oldState;
12309
12310                 throw e;
12311               }
12312             }
12313
12314             $rootElement.on('click', function(event) {
12315               // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
12316               // currently we open nice url link and redirect then
12317
12318               if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
12319
12320               var elm = jqLite(event.target);
12321
12322               // traverse the DOM up to find first A tag
12323               while (nodeName_(elm[0]) !== 'a') {
12324                 // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
12325                 if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
12326               }
12327
12328               var absHref = elm.prop('href');
12329               // get the actual href attribute - see
12330               // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
12331               var relHref = elm.attr('href') || elm.attr('xlink:href');
12332
12333               if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
12334                 // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
12335                 // an animation.
12336                 absHref = urlResolve(absHref.animVal).href;
12337               }
12338
12339               // Ignore when url is started with javascript: or mailto:
12340               if (IGNORE_URI_REGEXP.test(absHref)) return;
12341
12342               if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
12343                 if ($location.$$parseLinkUrl(absHref, relHref)) {
12344                   // We do a preventDefault for all urls that are part of the angular application,
12345                   // in html5mode and also without, so that we are able to abort navigation without
12346                   // getting double entries in the location history.
12347                   event.preventDefault();
12348                   // update location manually
12349                   if ($location.absUrl() != $browser.url()) {
12350                     $rootScope.$apply();
12351                     // hack to work around FF6 bug 684208 when scenario runner clicks on links
12352                     $window.angular['ff-684208-preventDefault'] = true;
12353                   }
12354                 }
12355               }
12356             });
12357
12358
12359             // rewrite hashbang url <> html5 url
12360             if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
12361               $browser.url($location.absUrl(), true);
12362             }
12363
12364             var initializing = true;
12365
12366             // update $location when $browser url changes
12367             $browser.onUrlChange(function(newUrl, newState) {
12368
12369               if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
12370                 // If we are navigating outside of the app then force a reload
12371                 $window.location.href = newUrl;
12372                 return;
12373               }
12374
12375               $rootScope.$evalAsync(function() {
12376                 var oldUrl = $location.absUrl();
12377                 var oldState = $location.$$state;
12378                 var defaultPrevented;
12379                 newUrl = trimEmptyHash(newUrl);
12380                 $location.$$parse(newUrl);
12381                 $location.$$state = newState;
12382
12383                 defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12384                     newState, oldState).defaultPrevented;
12385
12386                 // if the location was changed by a `$locationChangeStart` handler then stop
12387                 // processing this location change
12388                 if ($location.absUrl() !== newUrl) return;
12389
12390                 if (defaultPrevented) {
12391                   $location.$$parse(oldUrl);
12392                   $location.$$state = oldState;
12393                   setBrowserUrlWithFallback(oldUrl, false, oldState);
12394                 } else {
12395                   initializing = false;
12396                   afterLocationChange(oldUrl, oldState);
12397                 }
12398               });
12399               if (!$rootScope.$$phase) $rootScope.$digest();
12400             });
12401
12402             // update browser
12403             $rootScope.$watch(function $locationWatch() {
12404               var oldUrl = trimEmptyHash($browser.url());
12405               var newUrl = trimEmptyHash($location.absUrl());
12406               var oldState = $browser.state();
12407               var currentReplace = $location.$$replace;
12408               var urlOrStateChanged = oldUrl !== newUrl ||
12409                 ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
12410
12411               if (initializing || urlOrStateChanged) {
12412                 initializing = false;
12413
12414                 $rootScope.$evalAsync(function() {
12415                   var newUrl = $location.absUrl();
12416                   var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12417                       $location.$$state, oldState).defaultPrevented;
12418
12419                   // if the location was changed by a `$locationChangeStart` handler then stop
12420                   // processing this location change
12421                   if ($location.absUrl() !== newUrl) return;
12422
12423                   if (defaultPrevented) {
12424                     $location.$$parse(oldUrl);
12425                     $location.$$state = oldState;
12426                   } else {
12427                     if (urlOrStateChanged) {
12428                       setBrowserUrlWithFallback(newUrl, currentReplace,
12429                                                 oldState === $location.$$state ? null : $location.$$state);
12430                     }
12431                     afterLocationChange(oldUrl, oldState);
12432                   }
12433                 });
12434               }
12435
12436               $location.$$replace = false;
12437
12438               // we don't need to return anything because $evalAsync will make the digest loop dirty when
12439               // there is a change
12440             });
12441
12442             return $location;
12443
12444             function afterLocationChange(oldUrl, oldState) {
12445               $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
12446                 $location.$$state, oldState);
12447             }
12448         }];
12449         }
12450
12451         /**
12452          * @ngdoc service
12453          * @name $log
12454          * @requires $window
12455          *
12456          * @description
12457          * Simple service for logging. Default implementation safely writes the message
12458          * into the browser's console (if present).
12459          *
12460          * The main purpose of this service is to simplify debugging and troubleshooting.
12461          *
12462          * The default is to log `debug` messages. You can use
12463          * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
12464          *
12465          * @example
12466            <example module="logExample">
12467              <file name="script.js">
12468                angular.module('logExample', [])
12469                  .controller('LogController', ['$scope', '$log', function($scope, $log) {
12470                    $scope.$log = $log;
12471                    $scope.message = 'Hello World!';
12472                  }]);
12473              </file>
12474              <file name="index.html">
12475                <div ng-controller="LogController">
12476                  <p>Reload this page with open console, enter text and hit the log button...</p>
12477                  <label>Message:
12478                  <input type="text" ng-model="message" /></label>
12479                  <button ng-click="$log.log(message)">log</button>
12480                  <button ng-click="$log.warn(message)">warn</button>
12481                  <button ng-click="$log.info(message)">info</button>
12482                  <button ng-click="$log.error(message)">error</button>
12483                  <button ng-click="$log.debug(message)">debug</button>
12484                </div>
12485              </file>
12486            </example>
12487          */
12488
12489         /**
12490          * @ngdoc provider
12491          * @name $logProvider
12492          * @description
12493          * Use the `$logProvider` to configure how the application logs messages
12494          */
12495         function $LogProvider() {
12496           var debug = true,
12497               self = this;
12498
12499           /**
12500            * @ngdoc method
12501            * @name $logProvider#debugEnabled
12502            * @description
12503            * @param {boolean=} flag enable or disable debug level messages
12504            * @returns {*} current value if used as getter or itself (chaining) if used as setter
12505            */
12506           this.debugEnabled = function(flag) {
12507             if (isDefined(flag)) {
12508               debug = flag;
12509             return this;
12510             } else {
12511               return debug;
12512             }
12513           };
12514
12515           this.$get = ['$window', function($window) {
12516             return {
12517               /**
12518                * @ngdoc method
12519                * @name $log#log
12520                *
12521                * @description
12522                * Write a log message
12523                */
12524               log: consoleLog('log'),
12525
12526               /**
12527                * @ngdoc method
12528                * @name $log#info
12529                *
12530                * @description
12531                * Write an information message
12532                */
12533               info: consoleLog('info'),
12534
12535               /**
12536                * @ngdoc method
12537                * @name $log#warn
12538                *
12539                * @description
12540                * Write a warning message
12541                */
12542               warn: consoleLog('warn'),
12543
12544               /**
12545                * @ngdoc method
12546                * @name $log#error
12547                *
12548                * @description
12549                * Write an error message
12550                */
12551               error: consoleLog('error'),
12552
12553               /**
12554                * @ngdoc method
12555                * @name $log#debug
12556                *
12557                * @description
12558                * Write a debug message
12559                */
12560               debug: (function() {
12561                 var fn = consoleLog('debug');
12562
12563                 return function() {
12564                   if (debug) {
12565                     fn.apply(self, arguments);
12566                   }
12567                 };
12568               }())
12569             };
12570
12571             function formatError(arg) {
12572               if (arg instanceof Error) {
12573                 if (arg.stack) {
12574                   arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
12575                       ? 'Error: ' + arg.message + '\n' + arg.stack
12576                       : arg.stack;
12577                 } else if (arg.sourceURL) {
12578                   arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
12579                 }
12580               }
12581               return arg;
12582             }
12583
12584             function consoleLog(type) {
12585               var console = $window.console || {},
12586                   logFn = console[type] || console.log || noop,
12587                   hasApply = false;
12588
12589               // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
12590               // The reason behind this is that console.log has type "object" in IE8...
12591               try {
12592                 hasApply = !!logFn.apply;
12593               } catch (e) {}
12594
12595               if (hasApply) {
12596                 return function() {
12597                   var args = [];
12598                   forEach(arguments, function(arg) {
12599                     args.push(formatError(arg));
12600                   });
12601                   return logFn.apply(console, args);
12602                 };
12603               }
12604
12605               // we are IE which either doesn't have window.console => this is noop and we do nothing,
12606               // or we are IE where console.log doesn't have apply so we log at least first 2 args
12607               return function(arg1, arg2) {
12608                 logFn(arg1, arg2 == null ? '' : arg2);
12609               };
12610             }
12611           }];
12612         }
12613
12614         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
12615          *     Any commits to this file should be reviewed with security in mind.  *
12616          *   Changes to this file can potentially create security vulnerabilities. *
12617          *          An approval from 2 Core members with history of modifying      *
12618          *                         this file is required.                          *
12619          *                                                                         *
12620          *  Does the change somehow allow for arbitrary javascript to be executed? *
12621          *    Or allows for someone to change the prototype of built-in objects?   *
12622          *     Or gives undesired access to variables likes document or window?    *
12623          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12624
12625         var $parseMinErr = minErr('$parse');
12626
12627         // Sandboxing Angular Expressions
12628         // ------------------------------
12629         // Angular expressions are generally considered safe because these expressions only have direct
12630         // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
12631         // obtaining a reference to native JS functions such as the Function constructor.
12632         //
12633         // As an example, consider the following Angular expression:
12634         //
12635         //   {}.toString.constructor('alert("evil JS code")')
12636         //
12637         // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
12638         // against the expression language, but not to prevent exploits that were enabled by exposing
12639         // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
12640         // practice and therefore we are not even trying to protect against interaction with an object
12641         // explicitly exposed in this way.
12642         //
12643         // In general, it is not possible to access a Window object from an angular expression unless a
12644         // window or some DOM object that has a reference to window is published onto a Scope.
12645         // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
12646         // native objects.
12647         //
12648         // See https://docs.angularjs.org/guide/security
12649
12650
12651         function ensureSafeMemberName(name, fullExpression) {
12652           if (name === "__defineGetter__" || name === "__defineSetter__"
12653               || name === "__lookupGetter__" || name === "__lookupSetter__"
12654               || name === "__proto__") {
12655             throw $parseMinErr('isecfld',
12656                 'Attempting to access a disallowed field in Angular expressions! '
12657                 + 'Expression: {0}', fullExpression);
12658           }
12659           return name;
12660         }
12661
12662         function getStringValue(name, fullExpression) {
12663           // From the JavaScript docs:
12664           // Property names must be strings. This means that non-string objects cannot be used
12665           // as keys in an object. Any non-string object, including a number, is typecasted
12666           // into a string via the toString method.
12667           //
12668           // So, to ensure that we are checking the same `name` that JavaScript would use,
12669           // we cast it to a string, if possible.
12670           // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
12671           // this is, this will handle objects that misbehave.
12672           name = name + '';
12673           if (!isString(name)) {
12674             throw $parseMinErr('iseccst',
12675                 'Cannot convert object to primitive value! '
12676                 + 'Expression: {0}', fullExpression);
12677           }
12678           return name;
12679         }
12680
12681         function ensureSafeObject(obj, fullExpression) {
12682           // nifty check if obj is Function that is fast and works across iframes and other contexts
12683           if (obj) {
12684             if (obj.constructor === obj) {
12685               throw $parseMinErr('isecfn',
12686                   'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12687                   fullExpression);
12688             } else if (// isWindow(obj)
12689                 obj.window === obj) {
12690               throw $parseMinErr('isecwindow',
12691                   'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
12692                   fullExpression);
12693             } else if (// isElement(obj)
12694                 obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
12695               throw $parseMinErr('isecdom',
12696                   'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
12697                   fullExpression);
12698             } else if (// block Object so that we can't get hold of dangerous Object.* methods
12699                 obj === Object) {
12700               throw $parseMinErr('isecobj',
12701                   'Referencing Object in Angular expressions is disallowed! Expression: {0}',
12702                   fullExpression);
12703             }
12704           }
12705           return obj;
12706         }
12707
12708         var CALL = Function.prototype.call;
12709         var APPLY = Function.prototype.apply;
12710         var BIND = Function.prototype.bind;
12711
12712         function ensureSafeFunction(obj, fullExpression) {
12713           if (obj) {
12714             if (obj.constructor === obj) {
12715               throw $parseMinErr('isecfn',
12716                 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12717                 fullExpression);
12718             } else if (obj === CALL || obj === APPLY || obj === BIND) {
12719               throw $parseMinErr('isecff',
12720                 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
12721                 fullExpression);
12722             }
12723           }
12724         }
12725
12726         function ensureSafeAssignContext(obj, fullExpression) {
12727           if (obj) {
12728             if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
12729                 obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
12730               throw $parseMinErr('isecaf',
12731                 'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
12732             }
12733           }
12734         }
12735
12736         var OPERATORS = createMap();
12737         forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
12738         var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
12739
12740
12741         /////////////////////////////////////////
12742
12743
12744         /**
12745          * @constructor
12746          */
12747         var Lexer = function(options) {
12748           this.options = options;
12749         };
12750
12751         Lexer.prototype = {
12752           constructor: Lexer,
12753
12754           lex: function(text) {
12755             this.text = text;
12756             this.index = 0;
12757             this.tokens = [];
12758
12759             while (this.index < this.text.length) {
12760               var ch = this.text.charAt(this.index);
12761               if (ch === '"' || ch === "'") {
12762                 this.readString(ch);
12763               } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
12764                 this.readNumber();
12765               } else if (this.isIdent(ch)) {
12766                 this.readIdent();
12767               } else if (this.is(ch, '(){}[].,;:?')) {
12768                 this.tokens.push({index: this.index, text: ch});
12769                 this.index++;
12770               } else if (this.isWhitespace(ch)) {
12771                 this.index++;
12772               } else {
12773                 var ch2 = ch + this.peek();
12774                 var ch3 = ch2 + this.peek(2);
12775                 var op1 = OPERATORS[ch];
12776                 var op2 = OPERATORS[ch2];
12777                 var op3 = OPERATORS[ch3];
12778                 if (op1 || op2 || op3) {
12779                   var token = op3 ? ch3 : (op2 ? ch2 : ch);
12780                   this.tokens.push({index: this.index, text: token, operator: true});
12781                   this.index += token.length;
12782                 } else {
12783                   this.throwError('Unexpected next character ', this.index, this.index + 1);
12784                 }
12785               }
12786             }
12787             return this.tokens;
12788           },
12789
12790           is: function(ch, chars) {
12791             return chars.indexOf(ch) !== -1;
12792           },
12793
12794           peek: function(i) {
12795             var num = i || 1;
12796             return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
12797           },
12798
12799           isNumber: function(ch) {
12800             return ('0' <= ch && ch <= '9') && typeof ch === "string";
12801           },
12802
12803           isWhitespace: function(ch) {
12804             // IE treats non-breaking space as \u00A0
12805             return (ch === ' ' || ch === '\r' || ch === '\t' ||
12806                     ch === '\n' || ch === '\v' || ch === '\u00A0');
12807           },
12808
12809           isIdent: function(ch) {
12810             return ('a' <= ch && ch <= 'z' ||
12811                     'A' <= ch && ch <= 'Z' ||
12812                     '_' === ch || ch === '$');
12813           },
12814
12815           isExpOperator: function(ch) {
12816             return (ch === '-' || ch === '+' || this.isNumber(ch));
12817           },
12818
12819           throwError: function(error, start, end) {
12820             end = end || this.index;
12821             var colStr = (isDefined(start)
12822                     ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
12823                     : ' ' + end);
12824             throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
12825                 error, colStr, this.text);
12826           },
12827
12828           readNumber: function() {
12829             var number = '';
12830             var start = this.index;
12831             while (this.index < this.text.length) {
12832               var ch = lowercase(this.text.charAt(this.index));
12833               if (ch == '.' || this.isNumber(ch)) {
12834                 number += ch;
12835               } else {
12836                 var peekCh = this.peek();
12837                 if (ch == 'e' && this.isExpOperator(peekCh)) {
12838                   number += ch;
12839                 } else if (this.isExpOperator(ch) &&
12840                     peekCh && this.isNumber(peekCh) &&
12841                     number.charAt(number.length - 1) == 'e') {
12842                   number += ch;
12843                 } else if (this.isExpOperator(ch) &&
12844                     (!peekCh || !this.isNumber(peekCh)) &&
12845                     number.charAt(number.length - 1) == 'e') {
12846                   this.throwError('Invalid exponent');
12847                 } else {
12848                   break;
12849                 }
12850               }
12851               this.index++;
12852             }
12853             this.tokens.push({
12854               index: start,
12855               text: number,
12856               constant: true,
12857               value: Number(number)
12858             });
12859           },
12860
12861           readIdent: function() {
12862             var start = this.index;
12863             while (this.index < this.text.length) {
12864               var ch = this.text.charAt(this.index);
12865               if (!(this.isIdent(ch) || this.isNumber(ch))) {
12866                 break;
12867               }
12868               this.index++;
12869             }
12870             this.tokens.push({
12871               index: start,
12872               text: this.text.slice(start, this.index),
12873               identifier: true
12874             });
12875           },
12876
12877           readString: function(quote) {
12878             var start = this.index;
12879             this.index++;
12880             var string = '';
12881             var rawString = quote;
12882             var escape = false;
12883             while (this.index < this.text.length) {
12884               var ch = this.text.charAt(this.index);
12885               rawString += ch;
12886               if (escape) {
12887                 if (ch === 'u') {
12888                   var hex = this.text.substring(this.index + 1, this.index + 5);
12889                   if (!hex.match(/[\da-f]{4}/i)) {
12890                     this.throwError('Invalid unicode escape [\\u' + hex + ']');
12891                   }
12892                   this.index += 4;
12893                   string += String.fromCharCode(parseInt(hex, 16));
12894                 } else {
12895                   var rep = ESCAPE[ch];
12896                   string = string + (rep || ch);
12897                 }
12898                 escape = false;
12899               } else if (ch === '\\') {
12900                 escape = true;
12901               } else if (ch === quote) {
12902                 this.index++;
12903                 this.tokens.push({
12904                   index: start,
12905                   text: rawString,
12906                   constant: true,
12907                   value: string
12908                 });
12909                 return;
12910               } else {
12911                 string += ch;
12912               }
12913               this.index++;
12914             }
12915             this.throwError('Unterminated quote', start);
12916           }
12917         };
12918
12919         var AST = function(lexer, options) {
12920           this.lexer = lexer;
12921           this.options = options;
12922         };
12923
12924         AST.Program = 'Program';
12925         AST.ExpressionStatement = 'ExpressionStatement';
12926         AST.AssignmentExpression = 'AssignmentExpression';
12927         AST.ConditionalExpression = 'ConditionalExpression';
12928         AST.LogicalExpression = 'LogicalExpression';
12929         AST.BinaryExpression = 'BinaryExpression';
12930         AST.UnaryExpression = 'UnaryExpression';
12931         AST.CallExpression = 'CallExpression';
12932         AST.MemberExpression = 'MemberExpression';
12933         AST.Identifier = 'Identifier';
12934         AST.Literal = 'Literal';
12935         AST.ArrayExpression = 'ArrayExpression';
12936         AST.Property = 'Property';
12937         AST.ObjectExpression = 'ObjectExpression';
12938         AST.ThisExpression = 'ThisExpression';
12939
12940         // Internal use only
12941         AST.NGValueParameter = 'NGValueParameter';
12942
12943         AST.prototype = {
12944           ast: function(text) {
12945             this.text = text;
12946             this.tokens = this.lexer.lex(text);
12947
12948             var value = this.program();
12949
12950             if (this.tokens.length !== 0) {
12951               this.throwError('is an unexpected token', this.tokens[0]);
12952             }
12953
12954             return value;
12955           },
12956
12957           program: function() {
12958             var body = [];
12959             while (true) {
12960               if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12961                 body.push(this.expressionStatement());
12962               if (!this.expect(';')) {
12963                 return { type: AST.Program, body: body};
12964               }
12965             }
12966           },
12967
12968           expressionStatement: function() {
12969             return { type: AST.ExpressionStatement, expression: this.filterChain() };
12970           },
12971
12972           filterChain: function() {
12973             var left = this.expression();
12974             var token;
12975             while ((token = this.expect('|'))) {
12976               left = this.filter(left);
12977             }
12978             return left;
12979           },
12980
12981           expression: function() {
12982             return this.assignment();
12983           },
12984
12985           assignment: function() {
12986             var result = this.ternary();
12987             if (this.expect('=')) {
12988               result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
12989             }
12990             return result;
12991           },
12992
12993           ternary: function() {
12994             var test = this.logicalOR();
12995             var alternate;
12996             var consequent;
12997             if (this.expect('?')) {
12998               alternate = this.expression();
12999               if (this.consume(':')) {
13000                 consequent = this.expression();
13001                 return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
13002               }
13003             }
13004             return test;
13005           },
13006
13007           logicalOR: function() {
13008             var left = this.logicalAND();
13009             while (this.expect('||')) {
13010               left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
13011             }
13012             return left;
13013           },
13014
13015           logicalAND: function() {
13016             var left = this.equality();
13017             while (this.expect('&&')) {
13018               left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
13019             }
13020             return left;
13021           },
13022
13023           equality: function() {
13024             var left = this.relational();
13025             var token;
13026             while ((token = this.expect('==','!=','===','!=='))) {
13027               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
13028             }
13029             return left;
13030           },
13031
13032           relational: function() {
13033             var left = this.additive();
13034             var token;
13035             while ((token = this.expect('<', '>', '<=', '>='))) {
13036               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
13037             }
13038             return left;
13039           },
13040
13041           additive: function() {
13042             var left = this.multiplicative();
13043             var token;
13044             while ((token = this.expect('+','-'))) {
13045               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
13046             }
13047             return left;
13048           },
13049
13050           multiplicative: function() {
13051             var left = this.unary();
13052             var token;
13053             while ((token = this.expect('*','/','%'))) {
13054               left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
13055             }
13056             return left;
13057           },
13058
13059           unary: function() {
13060             var token;
13061             if ((token = this.expect('+', '-', '!'))) {
13062               return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
13063             } else {
13064               return this.primary();
13065             }
13066           },
13067
13068           primary: function() {
13069             var primary;
13070             if (this.expect('(')) {
13071               primary = this.filterChain();
13072               this.consume(')');
13073             } else if (this.expect('[')) {
13074               primary = this.arrayDeclaration();
13075             } else if (this.expect('{')) {
13076               primary = this.object();
13077             } else if (this.constants.hasOwnProperty(this.peek().text)) {
13078               primary = copy(this.constants[this.consume().text]);
13079             } else if (this.peek().identifier) {
13080               primary = this.identifier();
13081             } else if (this.peek().constant) {
13082               primary = this.constant();
13083             } else {
13084               this.throwError('not a primary expression', this.peek());
13085             }
13086
13087             var next;
13088             while ((next = this.expect('(', '[', '.'))) {
13089               if (next.text === '(') {
13090                 primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
13091                 this.consume(')');
13092               } else if (next.text === '[') {
13093                 primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
13094                 this.consume(']');
13095               } else if (next.text === '.') {
13096                 primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
13097               } else {
13098                 this.throwError('IMPOSSIBLE');
13099               }
13100             }
13101             return primary;
13102           },
13103
13104           filter: function(baseExpression) {
13105             var args = [baseExpression];
13106             var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
13107
13108             while (this.expect(':')) {
13109               args.push(this.expression());
13110             }
13111
13112             return result;
13113           },
13114
13115           parseArguments: function() {
13116             var args = [];
13117             if (this.peekToken().text !== ')') {
13118               do {
13119                 args.push(this.expression());
13120               } while (this.expect(','));
13121             }
13122             return args;
13123           },
13124
13125           identifier: function() {
13126             var token = this.consume();
13127             if (!token.identifier) {
13128               this.throwError('is not a valid identifier', token);
13129             }
13130             return { type: AST.Identifier, name: token.text };
13131           },
13132
13133           constant: function() {
13134             // TODO check that it is a constant
13135             return { type: AST.Literal, value: this.consume().value };
13136           },
13137
13138           arrayDeclaration: function() {
13139             var elements = [];
13140             if (this.peekToken().text !== ']') {
13141               do {
13142                 if (this.peek(']')) {
13143                   // Support trailing commas per ES5.1.
13144                   break;
13145                 }
13146                 elements.push(this.expression());
13147               } while (this.expect(','));
13148             }
13149             this.consume(']');
13150
13151             return { type: AST.ArrayExpression, elements: elements };
13152           },
13153
13154           object: function() {
13155             var properties = [], property;
13156             if (this.peekToken().text !== '}') {
13157               do {
13158                 if (this.peek('}')) {
13159                   // Support trailing commas per ES5.1.
13160                   break;
13161                 }
13162                 property = {type: AST.Property, kind: 'init'};
13163                 if (this.peek().constant) {
13164                   property.key = this.constant();
13165                 } else if (this.peek().identifier) {
13166                   property.key = this.identifier();
13167                 } else {
13168                   this.throwError("invalid key", this.peek());
13169                 }
13170                 this.consume(':');
13171                 property.value = this.expression();
13172                 properties.push(property);
13173               } while (this.expect(','));
13174             }
13175             this.consume('}');
13176
13177             return {type: AST.ObjectExpression, properties: properties };
13178           },
13179
13180           throwError: function(msg, token) {
13181             throw $parseMinErr('syntax',
13182                 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
13183                   token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
13184           },
13185
13186           consume: function(e1) {
13187             if (this.tokens.length === 0) {
13188               throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13189             }
13190
13191             var token = this.expect(e1);
13192             if (!token) {
13193               this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
13194             }
13195             return token;
13196           },
13197
13198           peekToken: function() {
13199             if (this.tokens.length === 0) {
13200               throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
13201             }
13202             return this.tokens[0];
13203           },
13204
13205           peek: function(e1, e2, e3, e4) {
13206             return this.peekAhead(0, e1, e2, e3, e4);
13207           },
13208
13209           peekAhead: function(i, e1, e2, e3, e4) {
13210             if (this.tokens.length > i) {
13211               var token = this.tokens[i];
13212               var t = token.text;
13213               if (t === e1 || t === e2 || t === e3 || t === e4 ||
13214                   (!e1 && !e2 && !e3 && !e4)) {
13215                 return token;
13216               }
13217             }
13218             return false;
13219           },
13220
13221           expect: function(e1, e2, e3, e4) {
13222             var token = this.peek(e1, e2, e3, e4);
13223             if (token) {
13224               this.tokens.shift();
13225               return token;
13226             }
13227             return false;
13228           },
13229
13230
13231           /* `undefined` is not a constant, it is an identifier,
13232            * but using it as an identifier is not supported
13233            */
13234           constants: {
13235             'true': { type: AST.Literal, value: true },
13236             'false': { type: AST.Literal, value: false },
13237             'null': { type: AST.Literal, value: null },
13238             'undefined': {type: AST.Literal, value: undefined },
13239             'this': {type: AST.ThisExpression }
13240           }
13241         };
13242
13243         function ifDefined(v, d) {
13244           return typeof v !== 'undefined' ? v : d;
13245         }
13246
13247         function plusFn(l, r) {
13248           if (typeof l === 'undefined') return r;
13249           if (typeof r === 'undefined') return l;
13250           return l + r;
13251         }
13252
13253         function isStateless($filter, filterName) {
13254           var fn = $filter(filterName);
13255           return !fn.$stateful;
13256         }
13257
13258         function findConstantAndWatchExpressions(ast, $filter) {
13259           var allConstants;
13260           var argsToWatch;
13261           switch (ast.type) {
13262           case AST.Program:
13263             allConstants = true;
13264             forEach(ast.body, function(expr) {
13265               findConstantAndWatchExpressions(expr.expression, $filter);
13266               allConstants = allConstants && expr.expression.constant;
13267             });
13268             ast.constant = allConstants;
13269             break;
13270           case AST.Literal:
13271             ast.constant = true;
13272             ast.toWatch = [];
13273             break;
13274           case AST.UnaryExpression:
13275             findConstantAndWatchExpressions(ast.argument, $filter);
13276             ast.constant = ast.argument.constant;
13277             ast.toWatch = ast.argument.toWatch;
13278             break;
13279           case AST.BinaryExpression:
13280             findConstantAndWatchExpressions(ast.left, $filter);
13281             findConstantAndWatchExpressions(ast.right, $filter);
13282             ast.constant = ast.left.constant && ast.right.constant;
13283             ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
13284             break;
13285           case AST.LogicalExpression:
13286             findConstantAndWatchExpressions(ast.left, $filter);
13287             findConstantAndWatchExpressions(ast.right, $filter);
13288             ast.constant = ast.left.constant && ast.right.constant;
13289             ast.toWatch = ast.constant ? [] : [ast];
13290             break;
13291           case AST.ConditionalExpression:
13292             findConstantAndWatchExpressions(ast.test, $filter);
13293             findConstantAndWatchExpressions(ast.alternate, $filter);
13294             findConstantAndWatchExpressions(ast.consequent, $filter);
13295             ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
13296             ast.toWatch = ast.constant ? [] : [ast];
13297             break;
13298           case AST.Identifier:
13299             ast.constant = false;
13300             ast.toWatch = [ast];
13301             break;
13302           case AST.MemberExpression:
13303             findConstantAndWatchExpressions(ast.object, $filter);
13304             if (ast.computed) {
13305               findConstantAndWatchExpressions(ast.property, $filter);
13306             }
13307             ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
13308             ast.toWatch = [ast];
13309             break;
13310           case AST.CallExpression:
13311             allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
13312             argsToWatch = [];
13313             forEach(ast.arguments, function(expr) {
13314               findConstantAndWatchExpressions(expr, $filter);
13315               allConstants = allConstants && expr.constant;
13316               if (!expr.constant) {
13317                 argsToWatch.push.apply(argsToWatch, expr.toWatch);
13318               }
13319             });
13320             ast.constant = allConstants;
13321             ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
13322             break;
13323           case AST.AssignmentExpression:
13324             findConstantAndWatchExpressions(ast.left, $filter);
13325             findConstantAndWatchExpressions(ast.right, $filter);
13326             ast.constant = ast.left.constant && ast.right.constant;
13327             ast.toWatch = [ast];
13328             break;
13329           case AST.ArrayExpression:
13330             allConstants = true;
13331             argsToWatch = [];
13332             forEach(ast.elements, function(expr) {
13333               findConstantAndWatchExpressions(expr, $filter);
13334               allConstants = allConstants && expr.constant;
13335               if (!expr.constant) {
13336                 argsToWatch.push.apply(argsToWatch, expr.toWatch);
13337               }
13338             });
13339             ast.constant = allConstants;
13340             ast.toWatch = argsToWatch;
13341             break;
13342           case AST.ObjectExpression:
13343             allConstants = true;
13344             argsToWatch = [];
13345             forEach(ast.properties, function(property) {
13346               findConstantAndWatchExpressions(property.value, $filter);
13347               allConstants = allConstants && property.value.constant;
13348               if (!property.value.constant) {
13349                 argsToWatch.push.apply(argsToWatch, property.value.toWatch);
13350               }
13351             });
13352             ast.constant = allConstants;
13353             ast.toWatch = argsToWatch;
13354             break;
13355           case AST.ThisExpression:
13356             ast.constant = false;
13357             ast.toWatch = [];
13358             break;
13359           }
13360         }
13361
13362         function getInputs(body) {
13363           if (body.length != 1) return;
13364           var lastExpression = body[0].expression;
13365           var candidate = lastExpression.toWatch;
13366           if (candidate.length !== 1) return candidate;
13367           return candidate[0] !== lastExpression ? candidate : undefined;
13368         }
13369
13370         function isAssignable(ast) {
13371           return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
13372         }
13373
13374         function assignableAST(ast) {
13375           if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
13376             return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
13377           }
13378         }
13379
13380         function isLiteral(ast) {
13381           return ast.body.length === 0 ||
13382               ast.body.length === 1 && (
13383               ast.body[0].expression.type === AST.Literal ||
13384               ast.body[0].expression.type === AST.ArrayExpression ||
13385               ast.body[0].expression.type === AST.ObjectExpression);
13386         }
13387
13388         function isConstant(ast) {
13389           return ast.constant;
13390         }
13391
13392         function ASTCompiler(astBuilder, $filter) {
13393           this.astBuilder = astBuilder;
13394           this.$filter = $filter;
13395         }
13396
13397         ASTCompiler.prototype = {
13398           compile: function(expression, expensiveChecks) {
13399             var self = this;
13400             var ast = this.astBuilder.ast(expression);
13401             this.state = {
13402               nextId: 0,
13403               filters: {},
13404               expensiveChecks: expensiveChecks,
13405               fn: {vars: [], body: [], own: {}},
13406               assign: {vars: [], body: [], own: {}},
13407               inputs: []
13408             };
13409             findConstantAndWatchExpressions(ast, self.$filter);
13410             var extra = '';
13411             var assignable;
13412             this.stage = 'assign';
13413             if ((assignable = assignableAST(ast))) {
13414               this.state.computing = 'assign';
13415               var result = this.nextId();
13416               this.recurse(assignable, result);
13417               this.return_(result);
13418               extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
13419             }
13420             var toWatch = getInputs(ast.body);
13421             self.stage = 'inputs';
13422             forEach(toWatch, function(watch, key) {
13423               var fnKey = 'fn' + key;
13424               self.state[fnKey] = {vars: [], body: [], own: {}};
13425               self.state.computing = fnKey;
13426               var intoId = self.nextId();
13427               self.recurse(watch, intoId);
13428               self.return_(intoId);
13429               self.state.inputs.push(fnKey);
13430               watch.watchId = key;
13431             });
13432             this.state.computing = 'fn';
13433             this.stage = 'main';
13434             this.recurse(ast);
13435             var fnString =
13436               // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
13437               // This is a workaround for this until we do a better job at only removing the prefix only when we should.
13438               '"' + this.USE + ' ' + this.STRICT + '";\n' +
13439               this.filterPrefix() +
13440               'var fn=' + this.generateFunction('fn', 's,l,a,i') +
13441               extra +
13442               this.watchFns() +
13443               'return fn;';
13444
13445             /* jshint -W054 */
13446             var fn = (new Function('$filter',
13447                 'ensureSafeMemberName',
13448                 'ensureSafeObject',
13449                 'ensureSafeFunction',
13450                 'getStringValue',
13451                 'ensureSafeAssignContext',
13452                 'ifDefined',
13453                 'plus',
13454                 'text',
13455                 fnString))(
13456                   this.$filter,
13457                   ensureSafeMemberName,
13458                   ensureSafeObject,
13459                   ensureSafeFunction,
13460                   getStringValue,
13461                   ensureSafeAssignContext,
13462                   ifDefined,
13463                   plusFn,
13464                   expression);
13465             /* jshint +W054 */
13466             this.state = this.stage = undefined;
13467             fn.literal = isLiteral(ast);
13468             fn.constant = isConstant(ast);
13469             return fn;
13470           },
13471
13472           USE: 'use',
13473
13474           STRICT: 'strict',
13475
13476           watchFns: function() {
13477             var result = [];
13478             var fns = this.state.inputs;
13479             var self = this;
13480             forEach(fns, function(name) {
13481               result.push('var ' + name + '=' + self.generateFunction(name, 's'));
13482             });
13483             if (fns.length) {
13484               result.push('fn.inputs=[' + fns.join(',') + '];');
13485             }
13486             return result.join('');
13487           },
13488
13489           generateFunction: function(name, params) {
13490             return 'function(' + params + '){' +
13491                 this.varsPrefix(name) +
13492                 this.body(name) +
13493                 '};';
13494           },
13495
13496           filterPrefix: function() {
13497             var parts = [];
13498             var self = this;
13499             forEach(this.state.filters, function(id, filter) {
13500               parts.push(id + '=$filter(' + self.escape(filter) + ')');
13501             });
13502             if (parts.length) return 'var ' + parts.join(',') + ';';
13503             return '';
13504           },
13505
13506           varsPrefix: function(section) {
13507             return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
13508           },
13509
13510           body: function(section) {
13511             return this.state[section].body.join('');
13512           },
13513
13514           recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13515             var left, right, self = this, args, expression;
13516             recursionFn = recursionFn || noop;
13517             if (!skipWatchIdCheck && isDefined(ast.watchId)) {
13518               intoId = intoId || this.nextId();
13519               this.if_('i',
13520                 this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
13521                 this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
13522               );
13523               return;
13524             }
13525             switch (ast.type) {
13526             case AST.Program:
13527               forEach(ast.body, function(expression, pos) {
13528                 self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
13529                 if (pos !== ast.body.length - 1) {
13530                   self.current().body.push(right, ';');
13531                 } else {
13532                   self.return_(right);
13533                 }
13534               });
13535               break;
13536             case AST.Literal:
13537               expression = this.escape(ast.value);
13538               this.assign(intoId, expression);
13539               recursionFn(expression);
13540               break;
13541             case AST.UnaryExpression:
13542               this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
13543               expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
13544               this.assign(intoId, expression);
13545               recursionFn(expression);
13546               break;
13547             case AST.BinaryExpression:
13548               this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
13549               this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
13550               if (ast.operator === '+') {
13551                 expression = this.plus(left, right);
13552               } else if (ast.operator === '-') {
13553                 expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
13554               } else {
13555                 expression = '(' + left + ')' + ast.operator + '(' + right + ')';
13556               }
13557               this.assign(intoId, expression);
13558               recursionFn(expression);
13559               break;
13560             case AST.LogicalExpression:
13561               intoId = intoId || this.nextId();
13562               self.recurse(ast.left, intoId);
13563               self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
13564               recursionFn(intoId);
13565               break;
13566             case AST.ConditionalExpression:
13567               intoId = intoId || this.nextId();
13568               self.recurse(ast.test, intoId);
13569               self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
13570               recursionFn(intoId);
13571               break;
13572             case AST.Identifier:
13573               intoId = intoId || this.nextId();
13574               if (nameId) {
13575                 nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
13576                 nameId.computed = false;
13577                 nameId.name = ast.name;
13578               }
13579               ensureSafeMemberName(ast.name);
13580               self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
13581                 function() {
13582                   self.if_(self.stage === 'inputs' || 's', function() {
13583                     if (create && create !== 1) {
13584                       self.if_(
13585                         self.not(self.nonComputedMember('s', ast.name)),
13586                         self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
13587                     }
13588                     self.assign(intoId, self.nonComputedMember('s', ast.name));
13589                   });
13590                 }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
13591                 );
13592               if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
13593                 self.addEnsureSafeObject(intoId);
13594               }
13595               recursionFn(intoId);
13596               break;
13597             case AST.MemberExpression:
13598               left = nameId && (nameId.context = this.nextId()) || this.nextId();
13599               intoId = intoId || this.nextId();
13600               self.recurse(ast.object, left, undefined, function() {
13601                 self.if_(self.notNull(left), function() {
13602                   if (ast.computed) {
13603                     right = self.nextId();
13604                     self.recurse(ast.property, right);
13605                     self.getStringValue(right);
13606                     self.addEnsureSafeMemberName(right);
13607                     if (create && create !== 1) {
13608                       self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
13609                     }
13610                     expression = self.ensureSafeObject(self.computedMember(left, right));
13611                     self.assign(intoId, expression);
13612                     if (nameId) {
13613                       nameId.computed = true;
13614                       nameId.name = right;
13615                     }
13616                   } else {
13617                     ensureSafeMemberName(ast.property.name);
13618                     if (create && create !== 1) {
13619                       self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
13620                     }
13621                     expression = self.nonComputedMember(left, ast.property.name);
13622                     if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
13623                       expression = self.ensureSafeObject(expression);
13624                     }
13625                     self.assign(intoId, expression);
13626                     if (nameId) {
13627                       nameId.computed = false;
13628                       nameId.name = ast.property.name;
13629                     }
13630                   }
13631                 }, function() {
13632                   self.assign(intoId, 'undefined');
13633                 });
13634                 recursionFn(intoId);
13635               }, !!create);
13636               break;
13637             case AST.CallExpression:
13638               intoId = intoId || this.nextId();
13639               if (ast.filter) {
13640                 right = self.filter(ast.callee.name);
13641                 args = [];
13642                 forEach(ast.arguments, function(expr) {
13643                   var argument = self.nextId();
13644                   self.recurse(expr, argument);
13645                   args.push(argument);
13646                 });
13647                 expression = right + '(' + args.join(',') + ')';
13648                 self.assign(intoId, expression);
13649                 recursionFn(intoId);
13650               } else {
13651                 right = self.nextId();
13652                 left = {};
13653                 args = [];
13654                 self.recurse(ast.callee, right, left, function() {
13655                   self.if_(self.notNull(right), function() {
13656                     self.addEnsureSafeFunction(right);
13657                     forEach(ast.arguments, function(expr) {
13658                       self.recurse(expr, self.nextId(), undefined, function(argument) {
13659                         args.push(self.ensureSafeObject(argument));
13660                       });
13661                     });
13662                     if (left.name) {
13663                       if (!self.state.expensiveChecks) {
13664                         self.addEnsureSafeObject(left.context);
13665                       }
13666                       expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
13667                     } else {
13668                       expression = right + '(' + args.join(',') + ')';
13669                     }
13670                     expression = self.ensureSafeObject(expression);
13671                     self.assign(intoId, expression);
13672                   }, function() {
13673                     self.assign(intoId, 'undefined');
13674                   });
13675                   recursionFn(intoId);
13676                 });
13677               }
13678               break;
13679             case AST.AssignmentExpression:
13680               right = this.nextId();
13681               left = {};
13682               if (!isAssignable(ast.left)) {
13683                 throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
13684               }
13685               this.recurse(ast.left, undefined, left, function() {
13686                 self.if_(self.notNull(left.context), function() {
13687                   self.recurse(ast.right, right);
13688                   self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
13689                   self.addEnsureSafeAssignContext(left.context);
13690                   expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
13691                   self.assign(intoId, expression);
13692                   recursionFn(intoId || expression);
13693                 });
13694               }, 1);
13695               break;
13696             case AST.ArrayExpression:
13697               args = [];
13698               forEach(ast.elements, function(expr) {
13699                 self.recurse(expr, self.nextId(), undefined, function(argument) {
13700                   args.push(argument);
13701                 });
13702               });
13703               expression = '[' + args.join(',') + ']';
13704               this.assign(intoId, expression);
13705               recursionFn(expression);
13706               break;
13707             case AST.ObjectExpression:
13708               args = [];
13709               forEach(ast.properties, function(property) {
13710                 self.recurse(property.value, self.nextId(), undefined, function(expr) {
13711                   args.push(self.escape(
13712                       property.key.type === AST.Identifier ? property.key.name :
13713                         ('' + property.key.value)) +
13714                       ':' + expr);
13715                 });
13716               });
13717               expression = '{' + args.join(',') + '}';
13718               this.assign(intoId, expression);
13719               recursionFn(expression);
13720               break;
13721             case AST.ThisExpression:
13722               this.assign(intoId, 's');
13723               recursionFn('s');
13724               break;
13725             case AST.NGValueParameter:
13726               this.assign(intoId, 'v');
13727               recursionFn('v');
13728               break;
13729             }
13730           },
13731
13732           getHasOwnProperty: function(element, property) {
13733             var key = element + '.' + property;
13734             var own = this.current().own;
13735             if (!own.hasOwnProperty(key)) {
13736               own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
13737             }
13738             return own[key];
13739           },
13740
13741           assign: function(id, value) {
13742             if (!id) return;
13743             this.current().body.push(id, '=', value, ';');
13744             return id;
13745           },
13746
13747           filter: function(filterName) {
13748             if (!this.state.filters.hasOwnProperty(filterName)) {
13749               this.state.filters[filterName] = this.nextId(true);
13750             }
13751             return this.state.filters[filterName];
13752           },
13753
13754           ifDefined: function(id, defaultValue) {
13755             return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
13756           },
13757
13758           plus: function(left, right) {
13759             return 'plus(' + left + ',' + right + ')';
13760           },
13761
13762           return_: function(id) {
13763             this.current().body.push('return ', id, ';');
13764           },
13765
13766           if_: function(test, alternate, consequent) {
13767             if (test === true) {
13768               alternate();
13769             } else {
13770               var body = this.current().body;
13771               body.push('if(', test, '){');
13772               alternate();
13773               body.push('}');
13774               if (consequent) {
13775                 body.push('else{');
13776                 consequent();
13777                 body.push('}');
13778               }
13779             }
13780           },
13781
13782           not: function(expression) {
13783             return '!(' + expression + ')';
13784           },
13785
13786           notNull: function(expression) {
13787             return expression + '!=null';
13788           },
13789
13790           nonComputedMember: function(left, right) {
13791             return left + '.' + right;
13792           },
13793
13794           computedMember: function(left, right) {
13795             return left + '[' + right + ']';
13796           },
13797
13798           member: function(left, right, computed) {
13799             if (computed) return this.computedMember(left, right);
13800             return this.nonComputedMember(left, right);
13801           },
13802
13803           addEnsureSafeObject: function(item) {
13804             this.current().body.push(this.ensureSafeObject(item), ';');
13805           },
13806
13807           addEnsureSafeMemberName: function(item) {
13808             this.current().body.push(this.ensureSafeMemberName(item), ';');
13809           },
13810
13811           addEnsureSafeFunction: function(item) {
13812             this.current().body.push(this.ensureSafeFunction(item), ';');
13813           },
13814
13815           addEnsureSafeAssignContext: function(item) {
13816             this.current().body.push(this.ensureSafeAssignContext(item), ';');
13817           },
13818
13819           ensureSafeObject: function(item) {
13820             return 'ensureSafeObject(' + item + ',text)';
13821           },
13822
13823           ensureSafeMemberName: function(item) {
13824             return 'ensureSafeMemberName(' + item + ',text)';
13825           },
13826
13827           ensureSafeFunction: function(item) {
13828             return 'ensureSafeFunction(' + item + ',text)';
13829           },
13830
13831           getStringValue: function(item) {
13832             this.assign(item, 'getStringValue(' + item + ',text)');
13833           },
13834
13835           ensureSafeAssignContext: function(item) {
13836             return 'ensureSafeAssignContext(' + item + ',text)';
13837           },
13838
13839           lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13840             var self = this;
13841             return function() {
13842               self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
13843             };
13844           },
13845
13846           lazyAssign: function(id, value) {
13847             var self = this;
13848             return function() {
13849               self.assign(id, value);
13850             };
13851           },
13852
13853           stringEscapeRegex: /[^ a-zA-Z0-9]/g,
13854
13855           stringEscapeFn: function(c) {
13856             return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
13857           },
13858
13859           escape: function(value) {
13860             if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
13861             if (isNumber(value)) return value.toString();
13862             if (value === true) return 'true';
13863             if (value === false) return 'false';
13864             if (value === null) return 'null';
13865             if (typeof value === 'undefined') return 'undefined';
13866
13867             throw $parseMinErr('esc', 'IMPOSSIBLE');
13868           },
13869
13870           nextId: function(skip, init) {
13871             var id = 'v' + (this.state.nextId++);
13872             if (!skip) {
13873               this.current().vars.push(id + (init ? '=' + init : ''));
13874             }
13875             return id;
13876           },
13877
13878           current: function() {
13879             return this.state[this.state.computing];
13880           }
13881         };
13882
13883
13884         function ASTInterpreter(astBuilder, $filter) {
13885           this.astBuilder = astBuilder;
13886           this.$filter = $filter;
13887         }
13888
13889         ASTInterpreter.prototype = {
13890           compile: function(expression, expensiveChecks) {
13891             var self = this;
13892             var ast = this.astBuilder.ast(expression);
13893             this.expression = expression;
13894             this.expensiveChecks = expensiveChecks;
13895             findConstantAndWatchExpressions(ast, self.$filter);
13896             var assignable;
13897             var assign;
13898             if ((assignable = assignableAST(ast))) {
13899               assign = this.recurse(assignable);
13900             }
13901             var toWatch = getInputs(ast.body);
13902             var inputs;
13903             if (toWatch) {
13904               inputs = [];
13905               forEach(toWatch, function(watch, key) {
13906                 var input = self.recurse(watch);
13907                 watch.input = input;
13908                 inputs.push(input);
13909                 watch.watchId = key;
13910               });
13911             }
13912             var expressions = [];
13913             forEach(ast.body, function(expression) {
13914               expressions.push(self.recurse(expression.expression));
13915             });
13916             var fn = ast.body.length === 0 ? function() {} :
13917                      ast.body.length === 1 ? expressions[0] :
13918                      function(scope, locals) {
13919                        var lastValue;
13920                        forEach(expressions, function(exp) {
13921                          lastValue = exp(scope, locals);
13922                        });
13923                        return lastValue;
13924                      };
13925             if (assign) {
13926               fn.assign = function(scope, value, locals) {
13927                 return assign(scope, locals, value);
13928               };
13929             }
13930             if (inputs) {
13931               fn.inputs = inputs;
13932             }
13933             fn.literal = isLiteral(ast);
13934             fn.constant = isConstant(ast);
13935             return fn;
13936           },
13937
13938           recurse: function(ast, context, create) {
13939             var left, right, self = this, args, expression;
13940             if (ast.input) {
13941               return this.inputs(ast.input, ast.watchId);
13942             }
13943             switch (ast.type) {
13944             case AST.Literal:
13945               return this.value(ast.value, context);
13946             case AST.UnaryExpression:
13947               right = this.recurse(ast.argument);
13948               return this['unary' + ast.operator](right, context);
13949             case AST.BinaryExpression:
13950               left = this.recurse(ast.left);
13951               right = this.recurse(ast.right);
13952               return this['binary' + ast.operator](left, right, context);
13953             case AST.LogicalExpression:
13954               left = this.recurse(ast.left);
13955               right = this.recurse(ast.right);
13956               return this['binary' + ast.operator](left, right, context);
13957             case AST.ConditionalExpression:
13958               return this['ternary?:'](
13959                 this.recurse(ast.test),
13960                 this.recurse(ast.alternate),
13961                 this.recurse(ast.consequent),
13962                 context
13963               );
13964             case AST.Identifier:
13965               ensureSafeMemberName(ast.name, self.expression);
13966               return self.identifier(ast.name,
13967                                      self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
13968                                      context, create, self.expression);
13969             case AST.MemberExpression:
13970               left = this.recurse(ast.object, false, !!create);
13971               if (!ast.computed) {
13972                 ensureSafeMemberName(ast.property.name, self.expression);
13973                 right = ast.property.name;
13974               }
13975               if (ast.computed) right = this.recurse(ast.property);
13976               return ast.computed ?
13977                 this.computedMember(left, right, context, create, self.expression) :
13978                 this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
13979             case AST.CallExpression:
13980               args = [];
13981               forEach(ast.arguments, function(expr) {
13982                 args.push(self.recurse(expr));
13983               });
13984               if (ast.filter) right = this.$filter(ast.callee.name);
13985               if (!ast.filter) right = this.recurse(ast.callee, true);
13986               return ast.filter ?
13987                 function(scope, locals, assign, inputs) {
13988                   var values = [];
13989                   for (var i = 0; i < args.length; ++i) {
13990                     values.push(args[i](scope, locals, assign, inputs));
13991                   }
13992                   var value = right.apply(undefined, values, inputs);
13993                   return context ? {context: undefined, name: undefined, value: value} : value;
13994                 } :
13995                 function(scope, locals, assign, inputs) {
13996                   var rhs = right(scope, locals, assign, inputs);
13997                   var value;
13998                   if (rhs.value != null) {
13999                     ensureSafeObject(rhs.context, self.expression);
14000                     ensureSafeFunction(rhs.value, self.expression);
14001                     var values = [];
14002                     for (var i = 0; i < args.length; ++i) {
14003                       values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
14004                     }
14005                     value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
14006                   }
14007                   return context ? {value: value} : value;
14008                 };
14009             case AST.AssignmentExpression:
14010               left = this.recurse(ast.left, true, 1);
14011               right = this.recurse(ast.right);
14012               return function(scope, locals, assign, inputs) {
14013                 var lhs = left(scope, locals, assign, inputs);
14014                 var rhs = right(scope, locals, assign, inputs);
14015                 ensureSafeObject(lhs.value, self.expression);
14016                 ensureSafeAssignContext(lhs.context);
14017                 lhs.context[lhs.name] = rhs;
14018                 return context ? {value: rhs} : rhs;
14019               };
14020             case AST.ArrayExpression:
14021               args = [];
14022               forEach(ast.elements, function(expr) {
14023                 args.push(self.recurse(expr));
14024               });
14025               return function(scope, locals, assign, inputs) {
14026                 var value = [];
14027                 for (var i = 0; i < args.length; ++i) {
14028                   value.push(args[i](scope, locals, assign, inputs));
14029                 }
14030                 return context ? {value: value} : value;
14031               };
14032             case AST.ObjectExpression:
14033               args = [];
14034               forEach(ast.properties, function(property) {
14035                 args.push({key: property.key.type === AST.Identifier ?
14036                                 property.key.name :
14037                                 ('' + property.key.value),
14038                            value: self.recurse(property.value)
14039                 });
14040               });
14041               return function(scope, locals, assign, inputs) {
14042                 var value = {};
14043                 for (var i = 0; i < args.length; ++i) {
14044                   value[args[i].key] = args[i].value(scope, locals, assign, inputs);
14045                 }
14046                 return context ? {value: value} : value;
14047               };
14048             case AST.ThisExpression:
14049               return function(scope) {
14050                 return context ? {value: scope} : scope;
14051               };
14052             case AST.NGValueParameter:
14053               return function(scope, locals, assign, inputs) {
14054                 return context ? {value: assign} : assign;
14055               };
14056             }
14057           },
14058
14059           'unary+': function(argument, context) {
14060             return function(scope, locals, assign, inputs) {
14061               var arg = argument(scope, locals, assign, inputs);
14062               if (isDefined(arg)) {
14063                 arg = +arg;
14064               } else {
14065                 arg = 0;
14066               }
14067               return context ? {value: arg} : arg;
14068             };
14069           },
14070           'unary-': function(argument, context) {
14071             return function(scope, locals, assign, inputs) {
14072               var arg = argument(scope, locals, assign, inputs);
14073               if (isDefined(arg)) {
14074                 arg = -arg;
14075               } else {
14076                 arg = 0;
14077               }
14078               return context ? {value: arg} : arg;
14079             };
14080           },
14081           'unary!': function(argument, context) {
14082             return function(scope, locals, assign, inputs) {
14083               var arg = !argument(scope, locals, assign, inputs);
14084               return context ? {value: arg} : arg;
14085             };
14086           },
14087           'binary+': function(left, right, context) {
14088             return function(scope, locals, assign, inputs) {
14089               var lhs = left(scope, locals, assign, inputs);
14090               var rhs = right(scope, locals, assign, inputs);
14091               var arg = plusFn(lhs, rhs);
14092               return context ? {value: arg} : arg;
14093             };
14094           },
14095           'binary-': function(left, right, context) {
14096             return function(scope, locals, assign, inputs) {
14097               var lhs = left(scope, locals, assign, inputs);
14098               var rhs = right(scope, locals, assign, inputs);
14099               var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
14100               return context ? {value: arg} : arg;
14101             };
14102           },
14103           'binary*': function(left, right, context) {
14104             return function(scope, locals, assign, inputs) {
14105               var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
14106               return context ? {value: arg} : arg;
14107             };
14108           },
14109           'binary/': function(left, right, context) {
14110             return function(scope, locals, assign, inputs) {
14111               var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
14112               return context ? {value: arg} : arg;
14113             };
14114           },
14115           'binary%': function(left, right, context) {
14116             return function(scope, locals, assign, inputs) {
14117               var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
14118               return context ? {value: arg} : arg;
14119             };
14120           },
14121           'binary===': function(left, right, context) {
14122             return function(scope, locals, assign, inputs) {
14123               var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
14124               return context ? {value: arg} : arg;
14125             };
14126           },
14127           'binary!==': function(left, right, context) {
14128             return function(scope, locals, assign, inputs) {
14129               var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
14130               return context ? {value: arg} : arg;
14131             };
14132           },
14133           'binary==': function(left, right, context) {
14134             return function(scope, locals, assign, inputs) {
14135               var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
14136               return context ? {value: arg} : arg;
14137             };
14138           },
14139           'binary!=': function(left, right, context) {
14140             return function(scope, locals, assign, inputs) {
14141               var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
14142               return context ? {value: arg} : arg;
14143             };
14144           },
14145           'binary<': function(left, right, context) {
14146             return function(scope, locals, assign, inputs) {
14147               var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
14148               return context ? {value: arg} : arg;
14149             };
14150           },
14151           'binary>': function(left, right, context) {
14152             return function(scope, locals, assign, inputs) {
14153               var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
14154               return context ? {value: arg} : arg;
14155             };
14156           },
14157           'binary<=': function(left, right, context) {
14158             return function(scope, locals, assign, inputs) {
14159               var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
14160               return context ? {value: arg} : arg;
14161             };
14162           },
14163           'binary>=': function(left, right, context) {
14164             return function(scope, locals, assign, inputs) {
14165               var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
14166               return context ? {value: arg} : arg;
14167             };
14168           },
14169           'binary&&': function(left, right, context) {
14170             return function(scope, locals, assign, inputs) {
14171               var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
14172               return context ? {value: arg} : arg;
14173             };
14174           },
14175           'binary||': function(left, right, context) {
14176             return function(scope, locals, assign, inputs) {
14177               var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
14178               return context ? {value: arg} : arg;
14179             };
14180           },
14181           'ternary?:': function(test, alternate, consequent, context) {
14182             return function(scope, locals, assign, inputs) {
14183               var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
14184               return context ? {value: arg} : arg;
14185             };
14186           },
14187           value: function(value, context) {
14188             return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
14189           },
14190           identifier: function(name, expensiveChecks, context, create, expression) {
14191             return function(scope, locals, assign, inputs) {
14192               var base = locals && (name in locals) ? locals : scope;
14193               if (create && create !== 1 && base && !(base[name])) {
14194                 base[name] = {};
14195               }
14196               var value = base ? base[name] : undefined;
14197               if (expensiveChecks) {
14198                 ensureSafeObject(value, expression);
14199               }
14200               if (context) {
14201                 return {context: base, name: name, value: value};
14202               } else {
14203                 return value;
14204               }
14205             };
14206           },
14207           computedMember: function(left, right, context, create, expression) {
14208             return function(scope, locals, assign, inputs) {
14209               var lhs = left(scope, locals, assign, inputs);
14210               var rhs;
14211               var value;
14212               if (lhs != null) {
14213                 rhs = right(scope, locals, assign, inputs);
14214                 rhs = getStringValue(rhs);
14215                 ensureSafeMemberName(rhs, expression);
14216                 if (create && create !== 1 && lhs && !(lhs[rhs])) {
14217                   lhs[rhs] = {};
14218                 }
14219                 value = lhs[rhs];
14220                 ensureSafeObject(value, expression);
14221               }
14222               if (context) {
14223                 return {context: lhs, name: rhs, value: value};
14224               } else {
14225                 return value;
14226               }
14227             };
14228           },
14229           nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
14230             return function(scope, locals, assign, inputs) {
14231               var lhs = left(scope, locals, assign, inputs);
14232               if (create && create !== 1 && lhs && !(lhs[right])) {
14233                 lhs[right] = {};
14234               }
14235               var value = lhs != null ? lhs[right] : undefined;
14236               if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
14237                 ensureSafeObject(value, expression);
14238               }
14239               if (context) {
14240                 return {context: lhs, name: right, value: value};
14241               } else {
14242                 return value;
14243               }
14244             };
14245           },
14246           inputs: function(input, watchId) {
14247             return function(scope, value, locals, inputs) {
14248               if (inputs) return inputs[watchId];
14249               return input(scope, value, locals);
14250             };
14251           }
14252         };
14253
14254         /**
14255          * @constructor
14256          */
14257         var Parser = function(lexer, $filter, options) {
14258           this.lexer = lexer;
14259           this.$filter = $filter;
14260           this.options = options;
14261           this.ast = new AST(this.lexer);
14262           this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
14263                                            new ASTCompiler(this.ast, $filter);
14264         };
14265
14266         Parser.prototype = {
14267           constructor: Parser,
14268
14269           parse: function(text) {
14270             return this.astCompiler.compile(text, this.options.expensiveChecks);
14271           }
14272         };
14273
14274         var getterFnCacheDefault = createMap();
14275         var getterFnCacheExpensive = createMap();
14276
14277         function isPossiblyDangerousMemberName(name) {
14278           return name == 'constructor';
14279         }
14280
14281         var objectValueOf = Object.prototype.valueOf;
14282
14283         function getValueOf(value) {
14284           return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
14285         }
14286
14287         ///////////////////////////////////
14288
14289         /**
14290          * @ngdoc service
14291          * @name $parse
14292          * @kind function
14293          *
14294          * @description
14295          *
14296          * Converts Angular {@link guide/expression expression} into a function.
14297          *
14298          * ```js
14299          *   var getter = $parse('user.name');
14300          *   var setter = getter.assign;
14301          *   var context = {user:{name:'angular'}};
14302          *   var locals = {user:{name:'local'}};
14303          *
14304          *   expect(getter(context)).toEqual('angular');
14305          *   setter(context, 'newValue');
14306          *   expect(context.user.name).toEqual('newValue');
14307          *   expect(getter(context, locals)).toEqual('local');
14308          * ```
14309          *
14310          *
14311          * @param {string} expression String expression to compile.
14312          * @returns {function(context, locals)} a function which represents the compiled expression:
14313          *
14314          *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14315          *      are evaluated against (typically a scope object).
14316          *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14317          *      `context`.
14318          *
14319          *    The returned function also has the following properties:
14320          *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
14321          *        literal.
14322          *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
14323          *        constant literals.
14324          *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
14325          *        set to a function to change its value on the given context.
14326          *
14327          */
14328
14329
14330         /**
14331          * @ngdoc provider
14332          * @name $parseProvider
14333          *
14334          * @description
14335          * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
14336          *  service.
14337          */
14338         function $ParseProvider() {
14339           var cacheDefault = createMap();
14340           var cacheExpensive = createMap();
14341
14342           this.$get = ['$filter', function($filter) {
14343             var noUnsafeEval = csp().noUnsafeEval;
14344             var $parseOptions = {
14345                   csp: noUnsafeEval,
14346                   expensiveChecks: false
14347                 },
14348                 $parseOptionsExpensive = {
14349                   csp: noUnsafeEval,
14350                   expensiveChecks: true
14351                 };
14352
14353             return function $parse(exp, interceptorFn, expensiveChecks) {
14354               var parsedExpression, oneTime, cacheKey;
14355
14356               switch (typeof exp) {
14357                 case 'string':
14358                   exp = exp.trim();
14359                   cacheKey = exp;
14360
14361                   var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
14362                   parsedExpression = cache[cacheKey];
14363
14364                   if (!parsedExpression) {
14365                     if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
14366                       oneTime = true;
14367                       exp = exp.substring(2);
14368                     }
14369                     var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
14370                     var lexer = new Lexer(parseOptions);
14371                     var parser = new Parser(lexer, $filter, parseOptions);
14372                     parsedExpression = parser.parse(exp);
14373                     if (parsedExpression.constant) {
14374                       parsedExpression.$$watchDelegate = constantWatchDelegate;
14375                     } else if (oneTime) {
14376                       parsedExpression.$$watchDelegate = parsedExpression.literal ?
14377                           oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
14378                     } else if (parsedExpression.inputs) {
14379                       parsedExpression.$$watchDelegate = inputsWatchDelegate;
14380                     }
14381                     cache[cacheKey] = parsedExpression;
14382                   }
14383                   return addInterceptor(parsedExpression, interceptorFn);
14384
14385                 case 'function':
14386                   return addInterceptor(exp, interceptorFn);
14387
14388                 default:
14389                   return noop;
14390               }
14391             };
14392
14393             function expressionInputDirtyCheck(newValue, oldValueOfValue) {
14394
14395               if (newValue == null || oldValueOfValue == null) { // null/undefined
14396                 return newValue === oldValueOfValue;
14397               }
14398
14399               if (typeof newValue === 'object') {
14400
14401                 // attempt to convert the value to a primitive type
14402                 // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
14403                 //             be cheaply dirty-checked
14404                 newValue = getValueOf(newValue);
14405
14406                 if (typeof newValue === 'object') {
14407                   // objects/arrays are not supported - deep-watching them would be too expensive
14408                   return false;
14409                 }
14410
14411                 // fall-through to the primitive equality check
14412               }
14413
14414               //Primitive or NaN
14415               return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
14416             }
14417
14418             function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
14419               var inputExpressions = parsedExpression.inputs;
14420               var lastResult;
14421
14422               if (inputExpressions.length === 1) {
14423                 var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
14424                 inputExpressions = inputExpressions[0];
14425                 return scope.$watch(function expressionInputWatch(scope) {
14426                   var newInputValue = inputExpressions(scope);
14427                   if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
14428                     lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
14429                     oldInputValueOf = newInputValue && getValueOf(newInputValue);
14430                   }
14431                   return lastResult;
14432                 }, listener, objectEquality, prettyPrintExpression);
14433               }
14434
14435               var oldInputValueOfValues = [];
14436               var oldInputValues = [];
14437               for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14438                 oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
14439                 oldInputValues[i] = null;
14440               }
14441
14442               return scope.$watch(function expressionInputsWatch(scope) {
14443                 var changed = false;
14444
14445                 for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14446                   var newInputValue = inputExpressions[i](scope);
14447                   if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
14448                     oldInputValues[i] = newInputValue;
14449                     oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
14450                   }
14451                 }
14452
14453                 if (changed) {
14454                   lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
14455                 }
14456
14457                 return lastResult;
14458               }, listener, objectEquality, prettyPrintExpression);
14459             }
14460
14461             function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14462               var unwatch, lastValue;
14463               return unwatch = scope.$watch(function oneTimeWatch(scope) {
14464                 return parsedExpression(scope);
14465               }, function oneTimeListener(value, old, scope) {
14466                 lastValue = value;
14467                 if (isFunction(listener)) {
14468                   listener.apply(this, arguments);
14469                 }
14470                 if (isDefined(value)) {
14471                   scope.$$postDigest(function() {
14472                     if (isDefined(lastValue)) {
14473                       unwatch();
14474                     }
14475                   });
14476                 }
14477               }, objectEquality);
14478             }
14479
14480             function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14481               var unwatch, lastValue;
14482               return unwatch = scope.$watch(function oneTimeWatch(scope) {
14483                 return parsedExpression(scope);
14484               }, function oneTimeListener(value, old, scope) {
14485                 lastValue = value;
14486                 if (isFunction(listener)) {
14487                   listener.call(this, value, old, scope);
14488                 }
14489                 if (isAllDefined(value)) {
14490                   scope.$$postDigest(function() {
14491                     if (isAllDefined(lastValue)) unwatch();
14492                   });
14493                 }
14494               }, objectEquality);
14495
14496               function isAllDefined(value) {
14497                 var allDefined = true;
14498                 forEach(value, function(val) {
14499                   if (!isDefined(val)) allDefined = false;
14500                 });
14501                 return allDefined;
14502               }
14503             }
14504
14505             function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14506               var unwatch;
14507               return unwatch = scope.$watch(function constantWatch(scope) {
14508                 return parsedExpression(scope);
14509               }, function constantListener(value, old, scope) {
14510                 if (isFunction(listener)) {
14511                   listener.apply(this, arguments);
14512                 }
14513                 unwatch();
14514               }, objectEquality);
14515             }
14516
14517             function addInterceptor(parsedExpression, interceptorFn) {
14518               if (!interceptorFn) return parsedExpression;
14519               var watchDelegate = parsedExpression.$$watchDelegate;
14520               var useInputs = false;
14521
14522               var regularWatch =
14523                   watchDelegate !== oneTimeLiteralWatchDelegate &&
14524                   watchDelegate !== oneTimeWatchDelegate;
14525
14526               var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
14527                 var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
14528                 return interceptorFn(value, scope, locals);
14529               } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
14530                 var value = parsedExpression(scope, locals, assign, inputs);
14531                 var result = interceptorFn(value, scope, locals);
14532                 // we only return the interceptor's result if the
14533                 // initial value is defined (for bind-once)
14534                 return isDefined(value) ? result : value;
14535               };
14536
14537               // Propagate $$watchDelegates other then inputsWatchDelegate
14538               if (parsedExpression.$$watchDelegate &&
14539                   parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
14540                 fn.$$watchDelegate = parsedExpression.$$watchDelegate;
14541               } else if (!interceptorFn.$stateful) {
14542                 // If there is an interceptor, but no watchDelegate then treat the interceptor like
14543                 // we treat filters - it is assumed to be a pure function unless flagged with $stateful
14544                 fn.$$watchDelegate = inputsWatchDelegate;
14545                 useInputs = !parsedExpression.inputs;
14546                 fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
14547               }
14548
14549               return fn;
14550             }
14551           }];
14552         }
14553
14554         /**
14555          * @ngdoc service
14556          * @name $q
14557          * @requires $rootScope
14558          *
14559          * @description
14560          * A service that helps you run functions asynchronously, and use their return values (or exceptions)
14561          * when they are done processing.
14562          *
14563          * This is an implementation of promises/deferred objects inspired by
14564          * [Kris Kowal's Q](https://github.com/kriskowal/q).
14565          *
14566          * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
14567          * implementations, and the other which resembles ES6 promises to some degree.
14568          *
14569          * # $q constructor
14570          *
14571          * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
14572          * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
14573          * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
14574          *
14575          * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
14576          * available yet.
14577          *
14578          * It can be used like so:
14579          *
14580          * ```js
14581          *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14582          *   // are available in the current lexical scope (they could have been injected or passed in).
14583          *
14584          *   function asyncGreet(name) {
14585          *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
14586          *     return $q(function(resolve, reject) {
14587          *       setTimeout(function() {
14588          *         if (okToGreet(name)) {
14589          *           resolve('Hello, ' + name + '!');
14590          *         } else {
14591          *           reject('Greeting ' + name + ' is not allowed.');
14592          *         }
14593          *       }, 1000);
14594          *     });
14595          *   }
14596          *
14597          *   var promise = asyncGreet('Robin Hood');
14598          *   promise.then(function(greeting) {
14599          *     alert('Success: ' + greeting);
14600          *   }, function(reason) {
14601          *     alert('Failed: ' + reason);
14602          *   });
14603          * ```
14604          *
14605          * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14606          *
14607          * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
14608          *
14609          * However, the more traditional CommonJS-style usage is still available, and documented below.
14610          *
14611          * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
14612          * interface for interacting with an object that represents the result of an action that is
14613          * performed asynchronously, and may or may not be finished at any given point in time.
14614          *
14615          * From the perspective of dealing with error handling, deferred and promise APIs are to
14616          * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
14617          *
14618          * ```js
14619          *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14620          *   // are available in the current lexical scope (they could have been injected or passed in).
14621          *
14622          *   function asyncGreet(name) {
14623          *     var deferred = $q.defer();
14624          *
14625          *     setTimeout(function() {
14626          *       deferred.notify('About to greet ' + name + '.');
14627          *
14628          *       if (okToGreet(name)) {
14629          *         deferred.resolve('Hello, ' + name + '!');
14630          *       } else {
14631          *         deferred.reject('Greeting ' + name + ' is not allowed.');
14632          *       }
14633          *     }, 1000);
14634          *
14635          *     return deferred.promise;
14636          *   }
14637          *
14638          *   var promise = asyncGreet('Robin Hood');
14639          *   promise.then(function(greeting) {
14640          *     alert('Success: ' + greeting);
14641          *   }, function(reason) {
14642          *     alert('Failed: ' + reason);
14643          *   }, function(update) {
14644          *     alert('Got notification: ' + update);
14645          *   });
14646          * ```
14647          *
14648          * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
14649          * comes in the way of guarantees that promise and deferred APIs make, see
14650          * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
14651          *
14652          * Additionally the promise api allows for composition that is very hard to do with the
14653          * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
14654          * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
14655          * section on serial or parallel joining of promises.
14656          *
14657          * # The Deferred API
14658          *
14659          * A new instance of deferred is constructed by calling `$q.defer()`.
14660          *
14661          * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
14662          * that can be used for signaling the successful or unsuccessful completion, as well as the status
14663          * of the task.
14664          *
14665          * **Methods**
14666          *
14667          * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
14668          *   constructed via `$q.reject`, the promise will be rejected instead.
14669          * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
14670          *   resolving it with a rejection constructed via `$q.reject`.
14671          * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
14672          *   multiple times before the promise is either resolved or rejected.
14673          *
14674          * **Properties**
14675          *
14676          * - promise – `{Promise}` – promise object associated with this deferred.
14677          *
14678          *
14679          * # The Promise API
14680          *
14681          * A new promise instance is created when a deferred instance is created and can be retrieved by
14682          * calling `deferred.promise`.
14683          *
14684          * The purpose of the promise object is to allow for interested parties to get access to the result
14685          * of the deferred task when it completes.
14686          *
14687          * **Methods**
14688          *
14689          * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
14690          *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
14691          *   as soon as the result is available. The callbacks are called with a single argument: the result
14692          *   or rejection reason. Additionally, the notify callback may be called zero or more times to
14693          *   provide a progress indication, before the promise is resolved or rejected.
14694          *
14695          *   This method *returns a new promise* which is resolved or rejected via the return value of the
14696          *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
14697          *   with the value which is resolved in that promise using
14698          *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
14699          *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
14700          *   resolved or rejected from the notifyCallback method.
14701          *
14702          * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
14703          *
14704          * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
14705          *   but to do so without modifying the final value. This is useful to release resources or do some
14706          *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
14707          *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
14708          *   more information.
14709          *
14710          * # Chaining promises
14711          *
14712          * Because calling the `then` method of a promise returns a new derived promise, it is easily
14713          * possible to create a chain of promises:
14714          *
14715          * ```js
14716          *   promiseB = promiseA.then(function(result) {
14717          *     return result + 1;
14718          *   });
14719          *
14720          *   // promiseB will be resolved immediately after promiseA is resolved and its value
14721          *   // will be the result of promiseA incremented by 1
14722          * ```
14723          *
14724          * It is possible to create chains of any length and since a promise can be resolved with another
14725          * promise (which will defer its resolution further), it is possible to pause/defer resolution of
14726          * the promises at any point in the chain. This makes it possible to implement powerful APIs like
14727          * $http's response interceptors.
14728          *
14729          *
14730          * # Differences between Kris Kowal's Q and $q
14731          *
14732          *  There are two main differences:
14733          *
14734          * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
14735          *   mechanism in angular, which means faster propagation of resolution or rejection into your
14736          *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
14737          * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
14738          *   all the important functionality needed for common async tasks.
14739          *
14740          *  # Testing
14741          *
14742          *  ```js
14743          *    it('should simulate promise', inject(function($q, $rootScope) {
14744          *      var deferred = $q.defer();
14745          *      var promise = deferred.promise;
14746          *      var resolvedValue;
14747          *
14748          *      promise.then(function(value) { resolvedValue = value; });
14749          *      expect(resolvedValue).toBeUndefined();
14750          *
14751          *      // Simulate resolving of promise
14752          *      deferred.resolve(123);
14753          *      // Note that the 'then' function does not get called synchronously.
14754          *      // This is because we want the promise API to always be async, whether or not
14755          *      // it got called synchronously or asynchronously.
14756          *      expect(resolvedValue).toBeUndefined();
14757          *
14758          *      // Propagate promise resolution to 'then' functions using $apply().
14759          *      $rootScope.$apply();
14760          *      expect(resolvedValue).toEqual(123);
14761          *    }));
14762          *  ```
14763          *
14764          * @param {function(function, function)} resolver Function which is responsible for resolving or
14765          *   rejecting the newly created promise. The first parameter is a function which resolves the
14766          *   promise, the second parameter is a function which rejects the promise.
14767          *
14768          * @returns {Promise} The newly created promise.
14769          */
14770         function $QProvider() {
14771
14772           this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
14773             return qFactory(function(callback) {
14774               $rootScope.$evalAsync(callback);
14775             }, $exceptionHandler);
14776           }];
14777         }
14778
14779         function $$QProvider() {
14780           this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
14781             return qFactory(function(callback) {
14782               $browser.defer(callback);
14783             }, $exceptionHandler);
14784           }];
14785         }
14786
14787         /**
14788          * Constructs a promise manager.
14789          *
14790          * @param {function(function)} nextTick Function for executing functions in the next turn.
14791          * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
14792          *     debugging purposes.
14793          * @returns {object} Promise manager.
14794          */
14795         function qFactory(nextTick, exceptionHandler) {
14796           var $qMinErr = minErr('$q', TypeError);
14797           function callOnce(self, resolveFn, rejectFn) {
14798             var called = false;
14799             function wrap(fn) {
14800               return function(value) {
14801                 if (called) return;
14802                 called = true;
14803                 fn.call(self, value);
14804               };
14805             }
14806
14807             return [wrap(resolveFn), wrap(rejectFn)];
14808           }
14809
14810           /**
14811            * @ngdoc method
14812            * @name ng.$q#defer
14813            * @kind function
14814            *
14815            * @description
14816            * Creates a `Deferred` object which represents a task which will finish in the future.
14817            *
14818            * @returns {Deferred} Returns a new instance of deferred.
14819            */
14820           var defer = function() {
14821             return new Deferred();
14822           };
14823
14824           function Promise() {
14825             this.$$state = { status: 0 };
14826           }
14827
14828           extend(Promise.prototype, {
14829             then: function(onFulfilled, onRejected, progressBack) {
14830               if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
14831                 return this;
14832               }
14833               var result = new Deferred();
14834
14835               this.$$state.pending = this.$$state.pending || [];
14836               this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
14837               if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
14838
14839               return result.promise;
14840             },
14841
14842             "catch": function(callback) {
14843               return this.then(null, callback);
14844             },
14845
14846             "finally": function(callback, progressBack) {
14847               return this.then(function(value) {
14848                 return handleCallback(value, true, callback);
14849               }, function(error) {
14850                 return handleCallback(error, false, callback);
14851               }, progressBack);
14852             }
14853           });
14854
14855           //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
14856           function simpleBind(context, fn) {
14857             return function(value) {
14858               fn.call(context, value);
14859             };
14860           }
14861
14862           function processQueue(state) {
14863             var fn, deferred, pending;
14864
14865             pending = state.pending;
14866             state.processScheduled = false;
14867             state.pending = undefined;
14868             for (var i = 0, ii = pending.length; i < ii; ++i) {
14869               deferred = pending[i][0];
14870               fn = pending[i][state.status];
14871               try {
14872                 if (isFunction(fn)) {
14873                   deferred.resolve(fn(state.value));
14874                 } else if (state.status === 1) {
14875                   deferred.resolve(state.value);
14876                 } else {
14877                   deferred.reject(state.value);
14878                 }
14879               } catch (e) {
14880                 deferred.reject(e);
14881                 exceptionHandler(e);
14882               }
14883             }
14884           }
14885
14886           function scheduleProcessQueue(state) {
14887             if (state.processScheduled || !state.pending) return;
14888             state.processScheduled = true;
14889             nextTick(function() { processQueue(state); });
14890           }
14891
14892           function Deferred() {
14893             this.promise = new Promise();
14894             //Necessary to support unbound execution :/
14895             this.resolve = simpleBind(this, this.resolve);
14896             this.reject = simpleBind(this, this.reject);
14897             this.notify = simpleBind(this, this.notify);
14898           }
14899
14900           extend(Deferred.prototype, {
14901             resolve: function(val) {
14902               if (this.promise.$$state.status) return;
14903               if (val === this.promise) {
14904                 this.$$reject($qMinErr(
14905                   'qcycle',
14906                   "Expected promise to be resolved with value other than itself '{0}'",
14907                   val));
14908               } else {
14909                 this.$$resolve(val);
14910               }
14911
14912             },
14913
14914             $$resolve: function(val) {
14915               var then, fns;
14916
14917               fns = callOnce(this, this.$$resolve, this.$$reject);
14918               try {
14919                 if ((isObject(val) || isFunction(val))) then = val && val.then;
14920                 if (isFunction(then)) {
14921                   this.promise.$$state.status = -1;
14922                   then.call(val, fns[0], fns[1], this.notify);
14923                 } else {
14924                   this.promise.$$state.value = val;
14925                   this.promise.$$state.status = 1;
14926                   scheduleProcessQueue(this.promise.$$state);
14927                 }
14928               } catch (e) {
14929                 fns[1](e);
14930                 exceptionHandler(e);
14931               }
14932             },
14933
14934             reject: function(reason) {
14935               if (this.promise.$$state.status) return;
14936               this.$$reject(reason);
14937             },
14938
14939             $$reject: function(reason) {
14940               this.promise.$$state.value = reason;
14941               this.promise.$$state.status = 2;
14942               scheduleProcessQueue(this.promise.$$state);
14943             },
14944
14945             notify: function(progress) {
14946               var callbacks = this.promise.$$state.pending;
14947
14948               if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
14949                 nextTick(function() {
14950                   var callback, result;
14951                   for (var i = 0, ii = callbacks.length; i < ii; i++) {
14952                     result = callbacks[i][0];
14953                     callback = callbacks[i][3];
14954                     try {
14955                       result.notify(isFunction(callback) ? callback(progress) : progress);
14956                     } catch (e) {
14957                       exceptionHandler(e);
14958                     }
14959                   }
14960                 });
14961               }
14962             }
14963           });
14964
14965           /**
14966            * @ngdoc method
14967            * @name $q#reject
14968            * @kind function
14969            *
14970            * @description
14971            * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
14972            * used to forward rejection in a chain of promises. If you are dealing with the last promise in
14973            * a promise chain, you don't need to worry about it.
14974            *
14975            * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
14976            * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
14977            * a promise error callback and you want to forward the error to the promise derived from the
14978            * current promise, you have to "rethrow" the error by returning a rejection constructed via
14979            * `reject`.
14980            *
14981            * ```js
14982            *   promiseB = promiseA.then(function(result) {
14983            *     // success: do something and resolve promiseB
14984            *     //          with the old or a new result
14985            *     return result;
14986            *   }, function(reason) {
14987            *     // error: handle the error if possible and
14988            *     //        resolve promiseB with newPromiseOrValue,
14989            *     //        otherwise forward the rejection to promiseB
14990            *     if (canHandle(reason)) {
14991            *      // handle the error and recover
14992            *      return newPromiseOrValue;
14993            *     }
14994            *     return $q.reject(reason);
14995            *   });
14996            * ```
14997            *
14998            * @param {*} reason Constant, message, exception or an object representing the rejection reason.
14999            * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
15000            */
15001           var reject = function(reason) {
15002             var result = new Deferred();
15003             result.reject(reason);
15004             return result.promise;
15005           };
15006
15007           var makePromise = function makePromise(value, resolved) {
15008             var result = new Deferred();
15009             if (resolved) {
15010               result.resolve(value);
15011             } else {
15012               result.reject(value);
15013             }
15014             return result.promise;
15015           };
15016
15017           var handleCallback = function handleCallback(value, isResolved, callback) {
15018             var callbackOutput = null;
15019             try {
15020               if (isFunction(callback)) callbackOutput = callback();
15021             } catch (e) {
15022               return makePromise(e, false);
15023             }
15024             if (isPromiseLike(callbackOutput)) {
15025               return callbackOutput.then(function() {
15026                 return makePromise(value, isResolved);
15027               }, function(error) {
15028                 return makePromise(error, false);
15029               });
15030             } else {
15031               return makePromise(value, isResolved);
15032             }
15033           };
15034
15035           /**
15036            * @ngdoc method
15037            * @name $q#when
15038            * @kind function
15039            *
15040            * @description
15041            * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
15042            * This is useful when you are dealing with an object that might or might not be a promise, or if
15043            * the promise comes from a source that can't be trusted.
15044            *
15045            * @param {*} value Value or a promise
15046            * @param {Function=} successCallback
15047            * @param {Function=} errorCallback
15048            * @param {Function=} progressCallback
15049            * @returns {Promise} Returns a promise of the passed value or promise
15050            */
15051
15052
15053           var when = function(value, callback, errback, progressBack) {
15054             var result = new Deferred();
15055             result.resolve(value);
15056             return result.promise.then(callback, errback, progressBack);
15057           };
15058
15059           /**
15060            * @ngdoc method
15061            * @name $q#resolve
15062            * @kind function
15063            *
15064            * @description
15065            * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
15066            *
15067            * @param {*} value Value or a promise
15068            * @param {Function=} successCallback
15069            * @param {Function=} errorCallback
15070            * @param {Function=} progressCallback
15071            * @returns {Promise} Returns a promise of the passed value or promise
15072            */
15073           var resolve = when;
15074
15075           /**
15076            * @ngdoc method
15077            * @name $q#all
15078            * @kind function
15079            *
15080            * @description
15081            * Combines multiple promises into a single promise that is resolved when all of the input
15082            * promises are resolved.
15083            *
15084            * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
15085            * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
15086            *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
15087            *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
15088            *   with the same rejection value.
15089            */
15090
15091           function all(promises) {
15092             var deferred = new Deferred(),
15093                 counter = 0,
15094                 results = isArray(promises) ? [] : {};
15095
15096             forEach(promises, function(promise, key) {
15097               counter++;
15098               when(promise).then(function(value) {
15099                 if (results.hasOwnProperty(key)) return;
15100                 results[key] = value;
15101                 if (!(--counter)) deferred.resolve(results);
15102               }, function(reason) {
15103                 if (results.hasOwnProperty(key)) return;
15104                 deferred.reject(reason);
15105               });
15106             });
15107
15108             if (counter === 0) {
15109               deferred.resolve(results);
15110             }
15111
15112             return deferred.promise;
15113           }
15114
15115           var $Q = function Q(resolver) {
15116             if (!isFunction(resolver)) {
15117               throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
15118             }
15119
15120             if (!(this instanceof Q)) {
15121               // More useful when $Q is the Promise itself.
15122               return new Q(resolver);
15123             }
15124
15125             var deferred = new Deferred();
15126
15127             function resolveFn(value) {
15128               deferred.resolve(value);
15129             }
15130
15131             function rejectFn(reason) {
15132               deferred.reject(reason);
15133             }
15134
15135             resolver(resolveFn, rejectFn);
15136
15137             return deferred.promise;
15138           };
15139
15140           $Q.defer = defer;
15141           $Q.reject = reject;
15142           $Q.when = when;
15143           $Q.resolve = resolve;
15144           $Q.all = all;
15145
15146           return $Q;
15147         }
15148
15149         function $$RAFProvider() { //rAF
15150           this.$get = ['$window', '$timeout', function($window, $timeout) {
15151             var requestAnimationFrame = $window.requestAnimationFrame ||
15152                                         $window.webkitRequestAnimationFrame;
15153
15154             var cancelAnimationFrame = $window.cancelAnimationFrame ||
15155                                        $window.webkitCancelAnimationFrame ||
15156                                        $window.webkitCancelRequestAnimationFrame;
15157
15158             var rafSupported = !!requestAnimationFrame;
15159             var raf = rafSupported
15160               ? function(fn) {
15161                   var id = requestAnimationFrame(fn);
15162                   return function() {
15163                     cancelAnimationFrame(id);
15164                   };
15165                 }
15166               : function(fn) {
15167                   var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
15168                   return function() {
15169                     $timeout.cancel(timer);
15170                   };
15171                 };
15172
15173             raf.supported = rafSupported;
15174
15175             return raf;
15176           }];
15177         }
15178
15179         /**
15180          * DESIGN NOTES
15181          *
15182          * The design decisions behind the scope are heavily favored for speed and memory consumption.
15183          *
15184          * The typical use of scope is to watch the expressions, which most of the time return the same
15185          * value as last time so we optimize the operation.
15186          *
15187          * Closures construction is expensive in terms of speed as well as memory:
15188          *   - No closures, instead use prototypical inheritance for API
15189          *   - Internal state needs to be stored on scope directly, which means that private state is
15190          *     exposed as $$____ properties
15191          *
15192          * Loop operations are optimized by using while(count--) { ... }
15193          *   - This means that in order to keep the same order of execution as addition we have to add
15194          *     items to the array at the beginning (unshift) instead of at the end (push)
15195          *
15196          * Child scopes are created and removed often
15197          *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
15198          *
15199          * There are fewer watches than observers. This is why you don't want the observer to be implemented
15200          * in the same way as watch. Watch requires return of the initialization function which is expensive
15201          * to construct.
15202          */
15203
15204
15205         /**
15206          * @ngdoc provider
15207          * @name $rootScopeProvider
15208          * @description
15209          *
15210          * Provider for the $rootScope service.
15211          */
15212
15213         /**
15214          * @ngdoc method
15215          * @name $rootScopeProvider#digestTtl
15216          * @description
15217          *
15218          * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
15219          * assuming that the model is unstable.
15220          *
15221          * The current default is 10 iterations.
15222          *
15223          * In complex applications it's possible that the dependencies between `$watch`s will result in
15224          * several digest iterations. However if an application needs more than the default 10 digest
15225          * iterations for its model to stabilize then you should investigate what is causing the model to
15226          * continuously change during the digest.
15227          *
15228          * Increasing the TTL could have performance implications, so you should not change it without
15229          * proper justification.
15230          *
15231          * @param {number} limit The number of digest iterations.
15232          */
15233
15234
15235         /**
15236          * @ngdoc service
15237          * @name $rootScope
15238          * @description
15239          *
15240          * Every application has a single root {@link ng.$rootScope.Scope scope}.
15241          * All other scopes are descendant scopes of the root scope. Scopes provide separation
15242          * between the model and the view, via a mechanism for watching the model for changes.
15243          * They also provide event emission/broadcast and subscription facility. See the
15244          * {@link guide/scope developer guide on scopes}.
15245          */
15246         function $RootScopeProvider() {
15247           var TTL = 10;
15248           var $rootScopeMinErr = minErr('$rootScope');
15249           var lastDirtyWatch = null;
15250           var applyAsyncId = null;
15251
15252           this.digestTtl = function(value) {
15253             if (arguments.length) {
15254               TTL = value;
15255             }
15256             return TTL;
15257           };
15258
15259           function createChildScopeClass(parent) {
15260             function ChildScope() {
15261               this.$$watchers = this.$$nextSibling =
15262                   this.$$childHead = this.$$childTail = null;
15263               this.$$listeners = {};
15264               this.$$listenerCount = {};
15265               this.$$watchersCount = 0;
15266               this.$id = nextUid();
15267               this.$$ChildScope = null;
15268             }
15269             ChildScope.prototype = parent;
15270             return ChildScope;
15271           }
15272
15273           this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
15274               function($injector, $exceptionHandler, $parse, $browser) {
15275
15276             function destroyChildScope($event) {
15277                 $event.currentScope.$$destroyed = true;
15278             }
15279
15280             function cleanUpScope($scope) {
15281
15282               if (msie === 9) {
15283                 // There is a memory leak in IE9 if all child scopes are not disconnected
15284                 // completely when a scope is destroyed. So this code will recurse up through
15285                 // all this scopes children
15286                 //
15287                 // See issue https://github.com/angular/angular.js/issues/10706
15288                 $scope.$$childHead && cleanUpScope($scope.$$childHead);
15289                 $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
15290               }
15291
15292               // The code below works around IE9 and V8's memory leaks
15293               //
15294               // See:
15295               // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15296               // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15297               // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15298
15299               $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
15300                   $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
15301             }
15302
15303             /**
15304              * @ngdoc type
15305              * @name $rootScope.Scope
15306              *
15307              * @description
15308              * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
15309              * {@link auto.$injector $injector}. Child scopes are created using the
15310              * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
15311              * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
15312              * an in-depth introduction and usage examples.
15313              *
15314              *
15315              * # Inheritance
15316              * A scope can inherit from a parent scope, as in this example:
15317              * ```js
15318                  var parent = $rootScope;
15319                  var child = parent.$new();
15320
15321                  parent.salutation = "Hello";
15322                  expect(child.salutation).toEqual('Hello');
15323
15324                  child.salutation = "Welcome";
15325                  expect(child.salutation).toEqual('Welcome');
15326                  expect(parent.salutation).toEqual('Hello');
15327              * ```
15328              *
15329              * When interacting with `Scope` in tests, additional helper methods are available on the
15330              * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
15331              * details.
15332              *
15333              *
15334              * @param {Object.<string, function()>=} providers Map of service factory which need to be
15335              *                                       provided for the current scope. Defaults to {@link ng}.
15336              * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
15337              *                              append/override services provided by `providers`. This is handy
15338              *                              when unit-testing and having the need to override a default
15339              *                              service.
15340              * @returns {Object} Newly created scope.
15341              *
15342              */
15343             function Scope() {
15344               this.$id = nextUid();
15345               this.$$phase = this.$parent = this.$$watchers =
15346                              this.$$nextSibling = this.$$prevSibling =
15347                              this.$$childHead = this.$$childTail = null;
15348               this.$root = this;
15349               this.$$destroyed = false;
15350               this.$$listeners = {};
15351               this.$$listenerCount = {};
15352               this.$$watchersCount = 0;
15353               this.$$isolateBindings = null;
15354             }
15355
15356             /**
15357              * @ngdoc property
15358              * @name $rootScope.Scope#$id
15359              *
15360              * @description
15361              * Unique scope ID (monotonically increasing) useful for debugging.
15362              */
15363
15364              /**
15365               * @ngdoc property
15366               * @name $rootScope.Scope#$parent
15367               *
15368               * @description
15369               * Reference to the parent scope.
15370               */
15371
15372               /**
15373                * @ngdoc property
15374                * @name $rootScope.Scope#$root
15375                *
15376                * @description
15377                * Reference to the root scope.
15378                */
15379
15380             Scope.prototype = {
15381               constructor: Scope,
15382               /**
15383                * @ngdoc method
15384                * @name $rootScope.Scope#$new
15385                * @kind function
15386                *
15387                * @description
15388                * Creates a new child {@link ng.$rootScope.Scope scope}.
15389                *
15390                * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
15391                * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
15392                *
15393                * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
15394                * desired for the scope and its child scopes to be permanently detached from the parent and
15395                * thus stop participating in model change detection and listener notification by invoking.
15396                *
15397                * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
15398                *         parent scope. The scope is isolated, as it can not see parent scope properties.
15399                *         When creating widgets, it is useful for the widget to not accidentally read parent
15400                *         state.
15401                *
15402                * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
15403                *                              of the newly created scope. Defaults to `this` scope if not provided.
15404                *                              This is used when creating a transclude scope to correctly place it
15405                *                              in the scope hierarchy while maintaining the correct prototypical
15406                *                              inheritance.
15407                *
15408                * @returns {Object} The newly created child scope.
15409                *
15410                */
15411               $new: function(isolate, parent) {
15412                 var child;
15413
15414                 parent = parent || this;
15415
15416                 if (isolate) {
15417                   child = new Scope();
15418                   child.$root = this.$root;
15419                 } else {
15420                   // Only create a child scope class if somebody asks for one,
15421                   // but cache it to allow the VM to optimize lookups.
15422                   if (!this.$$ChildScope) {
15423                     this.$$ChildScope = createChildScopeClass(this);
15424                   }
15425                   child = new this.$$ChildScope();
15426                 }
15427                 child.$parent = parent;
15428                 child.$$prevSibling = parent.$$childTail;
15429                 if (parent.$$childHead) {
15430                   parent.$$childTail.$$nextSibling = child;
15431                   parent.$$childTail = child;
15432                 } else {
15433                   parent.$$childHead = parent.$$childTail = child;
15434                 }
15435
15436                 // When the new scope is not isolated or we inherit from `this`, and
15437                 // the parent scope is destroyed, the property `$$destroyed` is inherited
15438                 // prototypically. In all other cases, this property needs to be set
15439                 // when the parent scope is destroyed.
15440                 // The listener needs to be added after the parent is set
15441                 if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
15442
15443                 return child;
15444               },
15445
15446               /**
15447                * @ngdoc method
15448                * @name $rootScope.Scope#$watch
15449                * @kind function
15450                *
15451                * @description
15452                * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
15453                *
15454                * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
15455                *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
15456                *   its value when executed multiple times with the same input because it may be executed multiple
15457                *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
15458                *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
15459                * - The `listener` is called only when the value from the current `watchExpression` and the
15460                *   previous call to `watchExpression` are not equal (with the exception of the initial run,
15461                *   see below). Inequality is determined according to reference inequality,
15462                *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
15463                *    via the `!==` Javascript operator, unless `objectEquality == true`
15464                *   (see next point)
15465                * - When `objectEquality == true`, inequality of the `watchExpression` is determined
15466                *   according to the {@link angular.equals} function. To save the value of the object for
15467                *   later comparison, the {@link angular.copy} function is used. This therefore means that
15468                *   watching complex objects will have adverse memory and performance implications.
15469                * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
15470                *   This is achieved by rerunning the watchers until no changes are detected. The rerun
15471                *   iteration limit is 10 to prevent an infinite loop deadlock.
15472                *
15473                *
15474                * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
15475                * you can register a `watchExpression` function with no `listener`. (Be prepared for
15476                * multiple calls to your `watchExpression` because it will execute multiple times in a
15477                * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
15478                *
15479                * After a watcher is registered with the scope, the `listener` fn is called asynchronously
15480                * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
15481                * watcher. In rare cases, this is undesirable because the listener is called when the result
15482                * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
15483                * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
15484                * listener was called due to initialization.
15485                *
15486                *
15487                *
15488                * # Example
15489                * ```js
15490                    // let's assume that scope was dependency injected as the $rootScope
15491                    var scope = $rootScope;
15492                    scope.name = 'misko';
15493                    scope.counter = 0;
15494
15495                    expect(scope.counter).toEqual(0);
15496                    scope.$watch('name', function(newValue, oldValue) {
15497                      scope.counter = scope.counter + 1;
15498                    });
15499                    expect(scope.counter).toEqual(0);
15500
15501                    scope.$digest();
15502                    // the listener is always called during the first $digest loop after it was registered
15503                    expect(scope.counter).toEqual(1);
15504
15505                    scope.$digest();
15506                    // but now it will not be called unless the value changes
15507                    expect(scope.counter).toEqual(1);
15508
15509                    scope.name = 'adam';
15510                    scope.$digest();
15511                    expect(scope.counter).toEqual(2);
15512
15513
15514
15515                    // Using a function as a watchExpression
15516                    var food;
15517                    scope.foodCounter = 0;
15518                    expect(scope.foodCounter).toEqual(0);
15519                    scope.$watch(
15520                      // This function returns the value being watched. It is called for each turn of the $digest loop
15521                      function() { return food; },
15522                      // This is the change listener, called when the value returned from the above function changes
15523                      function(newValue, oldValue) {
15524                        if ( newValue !== oldValue ) {
15525                          // Only increment the counter if the value changed
15526                          scope.foodCounter = scope.foodCounter + 1;
15527                        }
15528                      }
15529                    );
15530                    // No digest has been run so the counter will be zero
15531                    expect(scope.foodCounter).toEqual(0);
15532
15533                    // Run the digest but since food has not changed count will still be zero
15534                    scope.$digest();
15535                    expect(scope.foodCounter).toEqual(0);
15536
15537                    // Update food and run digest.  Now the counter will increment
15538                    food = 'cheeseburger';
15539                    scope.$digest();
15540                    expect(scope.foodCounter).toEqual(1);
15541
15542                * ```
15543                *
15544                *
15545                *
15546                * @param {(function()|string)} watchExpression Expression that is evaluated on each
15547                *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
15548                *    a call to the `listener`.
15549                *
15550                *    - `string`: Evaluated as {@link guide/expression expression}
15551                *    - `function(scope)`: called with current `scope` as a parameter.
15552                * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
15553                *    of `watchExpression` changes.
15554                *
15555                *    - `newVal` contains the current value of the `watchExpression`
15556                *    - `oldVal` contains the previous value of the `watchExpression`
15557                *    - `scope` refers to the current scope
15558                * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
15559                *     comparing for reference equality.
15560                * @returns {function()} Returns a deregistration function for this listener.
15561                */
15562               $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
15563                 var get = $parse(watchExp);
15564
15565                 if (get.$$watchDelegate) {
15566                   return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
15567                 }
15568                 var scope = this,
15569                     array = scope.$$watchers,
15570                     watcher = {
15571                       fn: listener,
15572                       last: initWatchVal,
15573                       get: get,
15574                       exp: prettyPrintExpression || watchExp,
15575                       eq: !!objectEquality
15576                     };
15577
15578                 lastDirtyWatch = null;
15579
15580                 if (!isFunction(listener)) {
15581                   watcher.fn = noop;
15582                 }
15583
15584                 if (!array) {
15585                   array = scope.$$watchers = [];
15586                 }
15587                 // we use unshift since we use a while loop in $digest for speed.
15588                 // the while loop reads in reverse order.
15589                 array.unshift(watcher);
15590                 incrementWatchersCount(this, 1);
15591
15592                 return function deregisterWatch() {
15593                   if (arrayRemove(array, watcher) >= 0) {
15594                     incrementWatchersCount(scope, -1);
15595                   }
15596                   lastDirtyWatch = null;
15597                 };
15598               },
15599
15600               /**
15601                * @ngdoc method
15602                * @name $rootScope.Scope#$watchGroup
15603                * @kind function
15604                *
15605                * @description
15606                * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
15607                * If any one expression in the collection changes the `listener` is executed.
15608                *
15609                * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
15610                *   call to $digest() to see if any items changes.
15611                * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
15612                *
15613                * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
15614                * watched using {@link ng.$rootScope.Scope#$watch $watch()}
15615                *
15616                * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
15617                *    expression in `watchExpressions` changes
15618                *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
15619                *    those of `watchExpression`
15620                *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
15621                *    those of `watchExpression`
15622                *    The `scope` refers to the current scope.
15623                * @returns {function()} Returns a de-registration function for all listeners.
15624                */
15625               $watchGroup: function(watchExpressions, listener) {
15626                 var oldValues = new Array(watchExpressions.length);
15627                 var newValues = new Array(watchExpressions.length);
15628                 var deregisterFns = [];
15629                 var self = this;
15630                 var changeReactionScheduled = false;
15631                 var firstRun = true;
15632
15633                 if (!watchExpressions.length) {
15634                   // No expressions means we call the listener ASAP
15635                   var shouldCall = true;
15636                   self.$evalAsync(function() {
15637                     if (shouldCall) listener(newValues, newValues, self);
15638                   });
15639                   return function deregisterWatchGroup() {
15640                     shouldCall = false;
15641                   };
15642                 }
15643
15644                 if (watchExpressions.length === 1) {
15645                   // Special case size of one
15646                   return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
15647                     newValues[0] = value;
15648                     oldValues[0] = oldValue;
15649                     listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
15650                   });
15651                 }
15652
15653                 forEach(watchExpressions, function(expr, i) {
15654                   var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
15655                     newValues[i] = value;
15656                     oldValues[i] = oldValue;
15657                     if (!changeReactionScheduled) {
15658                       changeReactionScheduled = true;
15659                       self.$evalAsync(watchGroupAction);
15660                     }
15661                   });
15662                   deregisterFns.push(unwatchFn);
15663                 });
15664
15665                 function watchGroupAction() {
15666                   changeReactionScheduled = false;
15667
15668                   if (firstRun) {
15669                     firstRun = false;
15670                     listener(newValues, newValues, self);
15671                   } else {
15672                     listener(newValues, oldValues, self);
15673                   }
15674                 }
15675
15676                 return function deregisterWatchGroup() {
15677                   while (deregisterFns.length) {
15678                     deregisterFns.shift()();
15679                   }
15680                 };
15681               },
15682
15683
15684               /**
15685                * @ngdoc method
15686                * @name $rootScope.Scope#$watchCollection
15687                * @kind function
15688                *
15689                * @description
15690                * Shallow watches the properties of an object and fires whenever any of the properties change
15691                * (for arrays, this implies watching the array items; for object maps, this implies watching
15692                * the properties). If a change is detected, the `listener` callback is fired.
15693                *
15694                * - The `obj` collection is observed via standard $watch operation and is examined on every
15695                *   call to $digest() to see if any items have been added, removed, or moved.
15696                * - The `listener` is called whenever anything within the `obj` has changed. Examples include
15697                *   adding, removing, and moving items belonging to an object or array.
15698                *
15699                *
15700                * # Example
15701                * ```js
15702                   $scope.names = ['igor', 'matias', 'misko', 'james'];
15703                   $scope.dataCount = 4;
15704
15705                   $scope.$watchCollection('names', function(newNames, oldNames) {
15706                     $scope.dataCount = newNames.length;
15707                   });
15708
15709                   expect($scope.dataCount).toEqual(4);
15710                   $scope.$digest();
15711
15712                   //still at 4 ... no changes
15713                   expect($scope.dataCount).toEqual(4);
15714
15715                   $scope.names.pop();
15716                   $scope.$digest();
15717
15718                   //now there's been a change
15719                   expect($scope.dataCount).toEqual(3);
15720                * ```
15721                *
15722                *
15723                * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
15724                *    expression value should evaluate to an object or an array which is observed on each
15725                *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
15726                *    collection will trigger a call to the `listener`.
15727                *
15728                * @param {function(newCollection, oldCollection, scope)} listener a callback function called
15729                *    when a change is detected.
15730                *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
15731                *    - The `oldCollection` object is a copy of the former collection data.
15732                *      Due to performance considerations, the`oldCollection` value is computed only if the
15733                *      `listener` function declares two or more arguments.
15734                *    - The `scope` argument refers to the current scope.
15735                *
15736                * @returns {function()} Returns a de-registration function for this listener. When the
15737                *    de-registration function is executed, the internal watch operation is terminated.
15738                */
15739               $watchCollection: function(obj, listener) {
15740                 $watchCollectionInterceptor.$stateful = true;
15741
15742                 var self = this;
15743                 // the current value, updated on each dirty-check run
15744                 var newValue;
15745                 // a shallow copy of the newValue from the last dirty-check run,
15746                 // updated to match newValue during dirty-check run
15747                 var oldValue;
15748                 // a shallow copy of the newValue from when the last change happened
15749                 var veryOldValue;
15750                 // only track veryOldValue if the listener is asking for it
15751                 var trackVeryOldValue = (listener.length > 1);
15752                 var changeDetected = 0;
15753                 var changeDetector = $parse(obj, $watchCollectionInterceptor);
15754                 var internalArray = [];
15755                 var internalObject = {};
15756                 var initRun = true;
15757                 var oldLength = 0;
15758
15759                 function $watchCollectionInterceptor(_value) {
15760                   newValue = _value;
15761                   var newLength, key, bothNaN, newItem, oldItem;
15762
15763                   // If the new value is undefined, then return undefined as the watch may be a one-time watch
15764                   if (isUndefined(newValue)) return;
15765
15766                   if (!isObject(newValue)) { // if primitive
15767                     if (oldValue !== newValue) {
15768                       oldValue = newValue;
15769                       changeDetected++;
15770                     }
15771                   } else if (isArrayLike(newValue)) {
15772                     if (oldValue !== internalArray) {
15773                       // we are transitioning from something which was not an array into array.
15774                       oldValue = internalArray;
15775                       oldLength = oldValue.length = 0;
15776                       changeDetected++;
15777                     }
15778
15779                     newLength = newValue.length;
15780
15781                     if (oldLength !== newLength) {
15782                       // if lengths do not match we need to trigger change notification
15783                       changeDetected++;
15784                       oldValue.length = oldLength = newLength;
15785                     }
15786                     // copy the items to oldValue and look for changes.
15787                     for (var i = 0; i < newLength; i++) {
15788                       oldItem = oldValue[i];
15789                       newItem = newValue[i];
15790
15791                       bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15792                       if (!bothNaN && (oldItem !== newItem)) {
15793                         changeDetected++;
15794                         oldValue[i] = newItem;
15795                       }
15796                     }
15797                   } else {
15798                     if (oldValue !== internalObject) {
15799                       // we are transitioning from something which was not an object into object.
15800                       oldValue = internalObject = {};
15801                       oldLength = 0;
15802                       changeDetected++;
15803                     }
15804                     // copy the items to oldValue and look for changes.
15805                     newLength = 0;
15806                     for (key in newValue) {
15807                       if (hasOwnProperty.call(newValue, key)) {
15808                         newLength++;
15809                         newItem = newValue[key];
15810                         oldItem = oldValue[key];
15811
15812                         if (key in oldValue) {
15813                           bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15814                           if (!bothNaN && (oldItem !== newItem)) {
15815                             changeDetected++;
15816                             oldValue[key] = newItem;
15817                           }
15818                         } else {
15819                           oldLength++;
15820                           oldValue[key] = newItem;
15821                           changeDetected++;
15822                         }
15823                       }
15824                     }
15825                     if (oldLength > newLength) {
15826                       // we used to have more keys, need to find them and destroy them.
15827                       changeDetected++;
15828                       for (key in oldValue) {
15829                         if (!hasOwnProperty.call(newValue, key)) {
15830                           oldLength--;
15831                           delete oldValue[key];
15832                         }
15833                       }
15834                     }
15835                   }
15836                   return changeDetected;
15837                 }
15838
15839                 function $watchCollectionAction() {
15840                   if (initRun) {
15841                     initRun = false;
15842                     listener(newValue, newValue, self);
15843                   } else {
15844                     listener(newValue, veryOldValue, self);
15845                   }
15846
15847                   // make a copy for the next time a collection is changed
15848                   if (trackVeryOldValue) {
15849                     if (!isObject(newValue)) {
15850                       //primitive
15851                       veryOldValue = newValue;
15852                     } else if (isArrayLike(newValue)) {
15853                       veryOldValue = new Array(newValue.length);
15854                       for (var i = 0; i < newValue.length; i++) {
15855                         veryOldValue[i] = newValue[i];
15856                       }
15857                     } else { // if object
15858                       veryOldValue = {};
15859                       for (var key in newValue) {
15860                         if (hasOwnProperty.call(newValue, key)) {
15861                           veryOldValue[key] = newValue[key];
15862                         }
15863                       }
15864                     }
15865                   }
15866                 }
15867
15868                 return this.$watch(changeDetector, $watchCollectionAction);
15869               },
15870
15871               /**
15872                * @ngdoc method
15873                * @name $rootScope.Scope#$digest
15874                * @kind function
15875                *
15876                * @description
15877                * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
15878                * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
15879                * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
15880                * until no more listeners are firing. This means that it is possible to get into an infinite
15881                * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
15882                * iterations exceeds 10.
15883                *
15884                * Usually, you don't call `$digest()` directly in
15885                * {@link ng.directive:ngController controllers} or in
15886                * {@link ng.$compileProvider#directive directives}.
15887                * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
15888                * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
15889                *
15890                * If you want to be notified whenever `$digest()` is called,
15891                * you can register a `watchExpression` function with
15892                * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
15893                *
15894                * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
15895                *
15896                * # Example
15897                * ```js
15898                    var scope = ...;
15899                    scope.name = 'misko';
15900                    scope.counter = 0;
15901
15902                    expect(scope.counter).toEqual(0);
15903                    scope.$watch('name', function(newValue, oldValue) {
15904                      scope.counter = scope.counter + 1;
15905                    });
15906                    expect(scope.counter).toEqual(0);
15907
15908                    scope.$digest();
15909                    // the listener is always called during the first $digest loop after it was registered
15910                    expect(scope.counter).toEqual(1);
15911
15912                    scope.$digest();
15913                    // but now it will not be called unless the value changes
15914                    expect(scope.counter).toEqual(1);
15915
15916                    scope.name = 'adam';
15917                    scope.$digest();
15918                    expect(scope.counter).toEqual(2);
15919                * ```
15920                *
15921                */
15922               $digest: function() {
15923                 var watch, value, last,
15924                     watchers,
15925                     length,
15926                     dirty, ttl = TTL,
15927                     next, current, target = this,
15928                     watchLog = [],
15929                     logIdx, logMsg, asyncTask;
15930
15931                 beginPhase('$digest');
15932                 // Check for changes to browser url that happened in sync before the call to $digest
15933                 $browser.$$checkUrlChange();
15934
15935                 if (this === $rootScope && applyAsyncId !== null) {
15936                   // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
15937                   // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
15938                   $browser.defer.cancel(applyAsyncId);
15939                   flushApplyAsync();
15940                 }
15941
15942                 lastDirtyWatch = null;
15943
15944                 do { // "while dirty" loop
15945                   dirty = false;
15946                   current = target;
15947
15948                   while (asyncQueue.length) {
15949                     try {
15950                       asyncTask = asyncQueue.shift();
15951                       asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
15952                     } catch (e) {
15953                       $exceptionHandler(e);
15954                     }
15955                     lastDirtyWatch = null;
15956                   }
15957
15958                   traverseScopesLoop:
15959                   do { // "traverse the scopes" loop
15960                     if ((watchers = current.$$watchers)) {
15961                       // process our watches
15962                       length = watchers.length;
15963                       while (length--) {
15964                         try {
15965                           watch = watchers[length];
15966                           // Most common watches are on primitives, in which case we can short
15967                           // circuit it with === operator, only when === fails do we use .equals
15968                           if (watch) {
15969                             if ((value = watch.get(current)) !== (last = watch.last) &&
15970                                 !(watch.eq
15971                                     ? equals(value, last)
15972                                     : (typeof value === 'number' && typeof last === 'number'
15973                                        && isNaN(value) && isNaN(last)))) {
15974                               dirty = true;
15975                               lastDirtyWatch = watch;
15976                               watch.last = watch.eq ? copy(value, null) : value;
15977                               watch.fn(value, ((last === initWatchVal) ? value : last), current);
15978                               if (ttl < 5) {
15979                                 logIdx = 4 - ttl;
15980                                 if (!watchLog[logIdx]) watchLog[logIdx] = [];
15981                                 watchLog[logIdx].push({
15982                                   msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
15983                                   newVal: value,
15984                                   oldVal: last
15985                                 });
15986                               }
15987                             } else if (watch === lastDirtyWatch) {
15988                               // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
15989                               // have already been tested.
15990                               dirty = false;
15991                               break traverseScopesLoop;
15992                             }
15993                           }
15994                         } catch (e) {
15995                           $exceptionHandler(e);
15996                         }
15997                       }
15998                     }
15999
16000                     // Insanity Warning: scope depth-first traversal
16001                     // yes, this code is a bit crazy, but it works and we have tests to prove it!
16002                     // this piece should be kept in sync with the traversal in $broadcast
16003                     if (!(next = ((current.$$watchersCount && current.$$childHead) ||
16004                         (current !== target && current.$$nextSibling)))) {
16005                       while (current !== target && !(next = current.$$nextSibling)) {
16006                         current = current.$parent;
16007                       }
16008                     }
16009                   } while ((current = next));
16010
16011                   // `break traverseScopesLoop;` takes us to here
16012
16013                   if ((dirty || asyncQueue.length) && !(ttl--)) {
16014                     clearPhase();
16015                     throw $rootScopeMinErr('infdig',
16016                         '{0} $digest() iterations reached. Aborting!\n' +
16017                         'Watchers fired in the last 5 iterations: {1}',
16018                         TTL, watchLog);
16019                   }
16020
16021                 } while (dirty || asyncQueue.length);
16022
16023                 clearPhase();
16024
16025                 while (postDigestQueue.length) {
16026                   try {
16027                     postDigestQueue.shift()();
16028                   } catch (e) {
16029                     $exceptionHandler(e);
16030                   }
16031                 }
16032               },
16033
16034
16035               /**
16036                * @ngdoc event
16037                * @name $rootScope.Scope#$destroy
16038                * @eventType broadcast on scope being destroyed
16039                *
16040                * @description
16041                * Broadcasted when a scope and its children are being destroyed.
16042                *
16043                * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
16044                * clean up DOM bindings before an element is removed from the DOM.
16045                */
16046
16047               /**
16048                * @ngdoc method
16049                * @name $rootScope.Scope#$destroy
16050                * @kind function
16051                *
16052                * @description
16053                * Removes the current scope (and all of its children) from the parent scope. Removal implies
16054                * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
16055                * propagate to the current scope and its children. Removal also implies that the current
16056                * scope is eligible for garbage collection.
16057                *
16058                * The `$destroy()` is usually used by directives such as
16059                * {@link ng.directive:ngRepeat ngRepeat} for managing the
16060                * unrolling of the loop.
16061                *
16062                * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
16063                * Application code can register a `$destroy` event handler that will give it a chance to
16064                * perform any necessary cleanup.
16065                *
16066                * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
16067                * clean up DOM bindings before an element is removed from the DOM.
16068                */
16069               $destroy: function() {
16070                 // We can't destroy a scope that has been already destroyed.
16071                 if (this.$$destroyed) return;
16072                 var parent = this.$parent;
16073
16074                 this.$broadcast('$destroy');
16075                 this.$$destroyed = true;
16076
16077                 if (this === $rootScope) {
16078                   //Remove handlers attached to window when $rootScope is removed
16079                   $browser.$$applicationDestroyed();
16080                 }
16081
16082                 incrementWatchersCount(this, -this.$$watchersCount);
16083                 for (var eventName in this.$$listenerCount) {
16084                   decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
16085                 }
16086
16087                 // sever all the references to parent scopes (after this cleanup, the current scope should
16088                 // not be retained by any of our references and should be eligible for garbage collection)
16089                 if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
16090                 if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
16091                 if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
16092                 if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
16093
16094                 // Disable listeners, watchers and apply/digest methods
16095                 this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
16096                 this.$on = this.$watch = this.$watchGroup = function() { return noop; };
16097                 this.$$listeners = {};
16098
16099                 // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
16100                 this.$$nextSibling = null;
16101                 cleanUpScope(this);
16102               },
16103
16104               /**
16105                * @ngdoc method
16106                * @name $rootScope.Scope#$eval
16107                * @kind function
16108                *
16109                * @description
16110                * Executes the `expression` on the current scope and returns the result. Any exceptions in
16111                * the expression are propagated (uncaught). This is useful when evaluating Angular
16112                * expressions.
16113                *
16114                * # Example
16115                * ```js
16116                    var scope = ng.$rootScope.Scope();
16117                    scope.a = 1;
16118                    scope.b = 2;
16119
16120                    expect(scope.$eval('a+b')).toEqual(3);
16121                    expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
16122                * ```
16123                *
16124                * @param {(string|function())=} expression An angular expression to be executed.
16125                *
16126                *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
16127                *    - `function(scope)`: execute the function with the current `scope` parameter.
16128                *
16129                * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16130                * @returns {*} The result of evaluating the expression.
16131                */
16132               $eval: function(expr, locals) {
16133                 return $parse(expr)(this, locals);
16134               },
16135
16136               /**
16137                * @ngdoc method
16138                * @name $rootScope.Scope#$evalAsync
16139                * @kind function
16140                *
16141                * @description
16142                * Executes the expression on the current scope at a later point in time.
16143                *
16144                * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
16145                * that:
16146                *
16147                *   - it will execute after the function that scheduled the evaluation (preferably before DOM
16148                *     rendering).
16149                *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
16150                *     `expression` execution.
16151                *
16152                * Any exceptions from the execution of the expression are forwarded to the
16153                * {@link ng.$exceptionHandler $exceptionHandler} service.
16154                *
16155                * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
16156                * will be scheduled. However, it is encouraged to always call code that changes the model
16157                * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
16158                *
16159                * @param {(string|function())=} expression An angular expression to be executed.
16160                *
16161                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16162                *    - `function(scope)`: execute the function with the current `scope` parameter.
16163                *
16164                * @param {(object)=} locals Local variables object, useful for overriding values in scope.
16165                */
16166               $evalAsync: function(expr, locals) {
16167                 // if we are outside of an $digest loop and this is the first time we are scheduling async
16168                 // task also schedule async auto-flush
16169                 if (!$rootScope.$$phase && !asyncQueue.length) {
16170                   $browser.defer(function() {
16171                     if (asyncQueue.length) {
16172                       $rootScope.$digest();
16173                     }
16174                   });
16175                 }
16176
16177                 asyncQueue.push({scope: this, expression: expr, locals: locals});
16178               },
16179
16180               $$postDigest: function(fn) {
16181                 postDigestQueue.push(fn);
16182               },
16183
16184               /**
16185                * @ngdoc method
16186                * @name $rootScope.Scope#$apply
16187                * @kind function
16188                *
16189                * @description
16190                * `$apply()` is used to execute an expression in angular from outside of the angular
16191                * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
16192                * Because we are calling into the angular framework we need to perform proper scope life
16193                * cycle of {@link ng.$exceptionHandler exception handling},
16194                * {@link ng.$rootScope.Scope#$digest executing watches}.
16195                *
16196                * ## Life cycle
16197                *
16198                * # Pseudo-Code of `$apply()`
16199                * ```js
16200                    function $apply(expr) {
16201                      try {
16202                        return $eval(expr);
16203                      } catch (e) {
16204                        $exceptionHandler(e);
16205                      } finally {
16206                        $root.$digest();
16207                      }
16208                    }
16209                * ```
16210                *
16211                *
16212                * Scope's `$apply()` method transitions through the following stages:
16213                *
16214                * 1. The {@link guide/expression expression} is executed using the
16215                *    {@link ng.$rootScope.Scope#$eval $eval()} method.
16216                * 2. Any exceptions from the execution of the expression are forwarded to the
16217                *    {@link ng.$exceptionHandler $exceptionHandler} service.
16218                * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
16219                *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
16220                *
16221                *
16222                * @param {(string|function())=} exp An angular expression to be executed.
16223                *
16224                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16225                *    - `function(scope)`: execute the function with current `scope` parameter.
16226                *
16227                * @returns {*} The result of evaluating the expression.
16228                */
16229               $apply: function(expr) {
16230                 try {
16231                   beginPhase('$apply');
16232                   try {
16233                     return this.$eval(expr);
16234                   } finally {
16235                     clearPhase();
16236                   }
16237                 } catch (e) {
16238                   $exceptionHandler(e);
16239                 } finally {
16240                   try {
16241                     $rootScope.$digest();
16242                   } catch (e) {
16243                     $exceptionHandler(e);
16244                     throw e;
16245                   }
16246                 }
16247               },
16248
16249               /**
16250                * @ngdoc method
16251                * @name $rootScope.Scope#$applyAsync
16252                * @kind function
16253                *
16254                * @description
16255                * Schedule the invocation of $apply to occur at a later time. The actual time difference
16256                * varies across browsers, but is typically around ~10 milliseconds.
16257                *
16258                * This can be used to queue up multiple expressions which need to be evaluated in the same
16259                * digest.
16260                *
16261                * @param {(string|function())=} exp An angular expression to be executed.
16262                *
16263                *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
16264                *    - `function(scope)`: execute the function with current `scope` parameter.
16265                */
16266               $applyAsync: function(expr) {
16267                 var scope = this;
16268                 expr && applyAsyncQueue.push($applyAsyncExpression);
16269                 scheduleApplyAsync();
16270
16271                 function $applyAsyncExpression() {
16272                   scope.$eval(expr);
16273                 }
16274               },
16275
16276               /**
16277                * @ngdoc method
16278                * @name $rootScope.Scope#$on
16279                * @kind function
16280                *
16281                * @description
16282                * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
16283                * discussion of event life cycle.
16284                *
16285                * The event listener function format is: `function(event, args...)`. The `event` object
16286                * passed into the listener has the following attributes:
16287                *
16288                *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
16289                *     `$broadcast`-ed.
16290                *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
16291                *     event propagates through the scope hierarchy, this property is set to null.
16292                *   - `name` - `{string}`: name of the event.
16293                *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
16294                *     further event propagation (available only for events that were `$emit`-ed).
16295                *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
16296                *     to true.
16297                *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
16298                *
16299                * @param {string} name Event name to listen on.
16300                * @param {function(event, ...args)} listener Function to call when the event is emitted.
16301                * @returns {function()} Returns a deregistration function for this listener.
16302                */
16303               $on: function(name, listener) {
16304                 var namedListeners = this.$$listeners[name];
16305                 if (!namedListeners) {
16306                   this.$$listeners[name] = namedListeners = [];
16307                 }
16308                 namedListeners.push(listener);
16309
16310                 var current = this;
16311                 do {
16312                   if (!current.$$listenerCount[name]) {
16313                     current.$$listenerCount[name] = 0;
16314                   }
16315                   current.$$listenerCount[name]++;
16316                 } while ((current = current.$parent));
16317
16318                 var self = this;
16319                 return function() {
16320                   var indexOfListener = namedListeners.indexOf(listener);
16321                   if (indexOfListener !== -1) {
16322                     namedListeners[indexOfListener] = null;
16323                     decrementListenerCount(self, 1, name);
16324                   }
16325                 };
16326               },
16327
16328
16329               /**
16330                * @ngdoc method
16331                * @name $rootScope.Scope#$emit
16332                * @kind function
16333                *
16334                * @description
16335                * Dispatches an event `name` upwards through the scope hierarchy notifying the
16336                * registered {@link ng.$rootScope.Scope#$on} listeners.
16337                *
16338                * The event life cycle starts at the scope on which `$emit` was called. All
16339                * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16340                * notified. Afterwards, the event traverses upwards toward the root scope and calls all
16341                * registered listeners along the way. The event will stop propagating if one of the listeners
16342                * cancels it.
16343                *
16344                * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16345                * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16346                *
16347                * @param {string} name Event name to emit.
16348                * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16349                * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
16350                */
16351               $emit: function(name, args) {
16352                 var empty = [],
16353                     namedListeners,
16354                     scope = this,
16355                     stopPropagation = false,
16356                     event = {
16357                       name: name,
16358                       targetScope: scope,
16359                       stopPropagation: function() {stopPropagation = true;},
16360                       preventDefault: function() {
16361                         event.defaultPrevented = true;
16362                       },
16363                       defaultPrevented: false
16364                     },
16365                     listenerArgs = concat([event], arguments, 1),
16366                     i, length;
16367
16368                 do {
16369                   namedListeners = scope.$$listeners[name] || empty;
16370                   event.currentScope = scope;
16371                   for (i = 0, length = namedListeners.length; i < length; i++) {
16372
16373                     // if listeners were deregistered, defragment the array
16374                     if (!namedListeners[i]) {
16375                       namedListeners.splice(i, 1);
16376                       i--;
16377                       length--;
16378                       continue;
16379                     }
16380                     try {
16381                       //allow all listeners attached to the current scope to run
16382                       namedListeners[i].apply(null, listenerArgs);
16383                     } catch (e) {
16384                       $exceptionHandler(e);
16385                     }
16386                   }
16387                   //if any listener on the current scope stops propagation, prevent bubbling
16388                   if (stopPropagation) {
16389                     event.currentScope = null;
16390                     return event;
16391                   }
16392                   //traverse upwards
16393                   scope = scope.$parent;
16394                 } while (scope);
16395
16396                 event.currentScope = null;
16397
16398                 return event;
16399               },
16400
16401
16402               /**
16403                * @ngdoc method
16404                * @name $rootScope.Scope#$broadcast
16405                * @kind function
16406                *
16407                * @description
16408                * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
16409                * registered {@link ng.$rootScope.Scope#$on} listeners.
16410                *
16411                * The event life cycle starts at the scope on which `$broadcast` was called. All
16412                * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
16413                * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
16414                * scope and calls all registered listeners along the way. The event cannot be canceled.
16415                *
16416                * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16417                * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16418                *
16419                * @param {string} name Event name to broadcast.
16420                * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16421                * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
16422                */
16423               $broadcast: function(name, args) {
16424                 var target = this,
16425                     current = target,
16426                     next = target,
16427                     event = {
16428                       name: name,
16429                       targetScope: target,
16430                       preventDefault: function() {
16431                         event.defaultPrevented = true;
16432                       },
16433                       defaultPrevented: false
16434                     };
16435
16436                 if (!target.$$listenerCount[name]) return event;
16437
16438                 var listenerArgs = concat([event], arguments, 1),
16439                     listeners, i, length;
16440
16441                 //down while you can, then up and next sibling or up and next sibling until back at root
16442                 while ((current = next)) {
16443                   event.currentScope = current;
16444                   listeners = current.$$listeners[name] || [];
16445                   for (i = 0, length = listeners.length; i < length; i++) {
16446                     // if listeners were deregistered, defragment the array
16447                     if (!listeners[i]) {
16448                       listeners.splice(i, 1);
16449                       i--;
16450                       length--;
16451                       continue;
16452                     }
16453
16454                     try {
16455                       listeners[i].apply(null, listenerArgs);
16456                     } catch (e) {
16457                       $exceptionHandler(e);
16458                     }
16459                   }
16460
16461                   // Insanity Warning: scope depth-first traversal
16462                   // yes, this code is a bit crazy, but it works and we have tests to prove it!
16463                   // this piece should be kept in sync with the traversal in $digest
16464                   // (though it differs due to having the extra check for $$listenerCount)
16465                   if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
16466                       (current !== target && current.$$nextSibling)))) {
16467                     while (current !== target && !(next = current.$$nextSibling)) {
16468                       current = current.$parent;
16469                     }
16470                   }
16471                 }
16472
16473                 event.currentScope = null;
16474                 return event;
16475               }
16476             };
16477
16478             var $rootScope = new Scope();
16479
16480             //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
16481             var asyncQueue = $rootScope.$$asyncQueue = [];
16482             var postDigestQueue = $rootScope.$$postDigestQueue = [];
16483             var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
16484
16485             return $rootScope;
16486
16487
16488             function beginPhase(phase) {
16489               if ($rootScope.$$phase) {
16490                 throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
16491               }
16492
16493               $rootScope.$$phase = phase;
16494             }
16495
16496             function clearPhase() {
16497               $rootScope.$$phase = null;
16498             }
16499
16500             function incrementWatchersCount(current, count) {
16501               do {
16502                 current.$$watchersCount += count;
16503               } while ((current = current.$parent));
16504             }
16505
16506             function decrementListenerCount(current, count, name) {
16507               do {
16508                 current.$$listenerCount[name] -= count;
16509
16510                 if (current.$$listenerCount[name] === 0) {
16511                   delete current.$$listenerCount[name];
16512                 }
16513               } while ((current = current.$parent));
16514             }
16515
16516             /**
16517              * function used as an initial value for watchers.
16518              * because it's unique we can easily tell it apart from other values
16519              */
16520             function initWatchVal() {}
16521
16522             function flushApplyAsync() {
16523               while (applyAsyncQueue.length) {
16524                 try {
16525                   applyAsyncQueue.shift()();
16526                 } catch (e) {
16527                   $exceptionHandler(e);
16528                 }
16529               }
16530               applyAsyncId = null;
16531             }
16532
16533             function scheduleApplyAsync() {
16534               if (applyAsyncId === null) {
16535                 applyAsyncId = $browser.defer(function() {
16536                   $rootScope.$apply(flushApplyAsync);
16537                 });
16538               }
16539             }
16540           }];
16541         }
16542
16543         /**
16544          * @description
16545          * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
16546          */
16547         function $$SanitizeUriProvider() {
16548           var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
16549             imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
16550
16551           /**
16552            * @description
16553            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16554            * urls during a[href] sanitization.
16555            *
16556            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16557            *
16558            * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16559            * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16560            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16561            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16562            *
16563            * @param {RegExp=} regexp New regexp to whitelist urls with.
16564            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16565            *    chaining otherwise.
16566            */
16567           this.aHrefSanitizationWhitelist = function(regexp) {
16568             if (isDefined(regexp)) {
16569               aHrefSanitizationWhitelist = regexp;
16570               return this;
16571             }
16572             return aHrefSanitizationWhitelist;
16573           };
16574
16575
16576           /**
16577            * @description
16578            * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16579            * urls during img[src] sanitization.
16580            *
16581            * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16582            *
16583            * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16584            * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16585            * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16586            * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16587            *
16588            * @param {RegExp=} regexp New regexp to whitelist urls with.
16589            * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16590            *    chaining otherwise.
16591            */
16592           this.imgSrcSanitizationWhitelist = function(regexp) {
16593             if (isDefined(regexp)) {
16594               imgSrcSanitizationWhitelist = regexp;
16595               return this;
16596             }
16597             return imgSrcSanitizationWhitelist;
16598           };
16599
16600           this.$get = function() {
16601             return function sanitizeUri(uri, isImage) {
16602               var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
16603               var normalizedVal;
16604               normalizedVal = urlResolve(uri).href;
16605               if (normalizedVal !== '' && !normalizedVal.match(regex)) {
16606                 return 'unsafe:' + normalizedVal;
16607               }
16608               return uri;
16609             };
16610           };
16611         }
16612
16613         /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16614          *     Any commits to this file should be reviewed with security in mind.  *
16615          *   Changes to this file can potentially create security vulnerabilities. *
16616          *          An approval from 2 Core members with history of modifying      *
16617          *                         this file is required.                          *
16618          *                                                                         *
16619          *  Does the change somehow allow for arbitrary javascript to be executed? *
16620          *    Or allows for someone to change the prototype of built-in objects?   *
16621          *     Or gives undesired access to variables likes document or window?    *
16622          * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16623
16624         var $sceMinErr = minErr('$sce');
16625
16626         var SCE_CONTEXTS = {
16627           HTML: 'html',
16628           CSS: 'css',
16629           URL: 'url',
16630           // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
16631           // url.  (e.g. ng-include, script src, templateUrl)
16632           RESOURCE_URL: 'resourceUrl',
16633           JS: 'js'
16634         };
16635
16636         // Helper functions follow.
16637
16638         function adjustMatcher(matcher) {
16639           if (matcher === 'self') {
16640             return matcher;
16641           } else if (isString(matcher)) {
16642             // Strings match exactly except for 2 wildcards - '*' and '**'.
16643             // '*' matches any character except those from the set ':/.?&'.
16644             // '**' matches any character (like .* in a RegExp).
16645             // More than 2 *'s raises an error as it's ill defined.
16646             if (matcher.indexOf('***') > -1) {
16647               throw $sceMinErr('iwcard',
16648                   'Illegal sequence *** in string matcher.  String: {0}', matcher);
16649             }
16650             matcher = escapeForRegexp(matcher).
16651                           replace('\\*\\*', '.*').
16652                           replace('\\*', '[^:/.?&;]*');
16653             return new RegExp('^' + matcher + '$');
16654           } else if (isRegExp(matcher)) {
16655             // The only other type of matcher allowed is a Regexp.
16656             // Match entire URL / disallow partial matches.
16657             // Flags are reset (i.e. no global, ignoreCase or multiline)
16658             return new RegExp('^' + matcher.source + '$');
16659           } else {
16660             throw $sceMinErr('imatcher',
16661                 'Matchers may only be "self", string patterns or RegExp objects');
16662           }
16663         }
16664
16665
16666         function adjustMatchers(matchers) {
16667           var adjustedMatchers = [];
16668           if (isDefined(matchers)) {
16669             forEach(matchers, function(matcher) {
16670               adjustedMatchers.push(adjustMatcher(matcher));
16671             });
16672           }
16673           return adjustedMatchers;
16674         }
16675
16676
16677         /**
16678          * @ngdoc service
16679          * @name $sceDelegate
16680          * @kind function
16681          *
16682          * @description
16683          *
16684          * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
16685          * Contextual Escaping (SCE)} services to AngularJS.
16686          *
16687          * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
16688          * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
16689          * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
16690          * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
16691          * work because `$sce` delegates to `$sceDelegate` for these operations.
16692          *
16693          * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
16694          *
16695          * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
16696          * can override it completely to change the behavior of `$sce`, the common case would
16697          * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
16698          * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
16699          * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
16700          * $sceDelegateProvider.resourceUrlWhitelist} and {@link
16701          * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16702          */
16703
16704         /**
16705          * @ngdoc provider
16706          * @name $sceDelegateProvider
16707          * @description
16708          *
16709          * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
16710          * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
16711          * that the URLs used for sourcing Angular templates are safe.  Refer {@link
16712          * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
16713          * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16714          *
16715          * For the general details about this service in Angular, read the main page for {@link ng.$sce
16716          * Strict Contextual Escaping (SCE)}.
16717          *
16718          * **Example**:  Consider the following case. <a name="example"></a>
16719          *
16720          * - your app is hosted at url `http://myapp.example.com/`
16721          * - but some of your templates are hosted on other domains you control such as
16722          *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
16723          * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
16724          *
16725          * Here is what a secure configuration for this scenario might look like:
16726          *
16727          * ```
16728          *  angular.module('myApp', []).config(function($sceDelegateProvider) {
16729          *    $sceDelegateProvider.resourceUrlWhitelist([
16730          *      // Allow same origin resource loads.
16731          *      'self',
16732          *      // Allow loading from our assets domain.  Notice the difference between * and **.
16733          *      'http://srv*.assets.example.com/**'
16734          *    ]);
16735          *
16736          *    // The blacklist overrides the whitelist so the open redirect here is blocked.
16737          *    $sceDelegateProvider.resourceUrlBlacklist([
16738          *      'http://myapp.example.com/clickThru**'
16739          *    ]);
16740          *  });
16741          * ```
16742          */
16743
16744         function $SceDelegateProvider() {
16745           this.SCE_CONTEXTS = SCE_CONTEXTS;
16746
16747           // Resource URLs can also be trusted by policy.
16748           var resourceUrlWhitelist = ['self'],
16749               resourceUrlBlacklist = [];
16750
16751           /**
16752            * @ngdoc method
16753            * @name $sceDelegateProvider#resourceUrlWhitelist
16754            * @kind function
16755            *
16756            * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
16757            *     provided.  This must be an array or null.  A snapshot of this array is used so further
16758            *     changes to the array are ignored.
16759            *
16760            *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16761            *     allowed in this array.
16762            *
16763            *     Note: **an empty whitelist array will block all URLs**!
16764            *
16765            * @return {Array} the currently set whitelist array.
16766            *
16767            * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
16768            * same origin resource requests.
16769            *
16770            * @description
16771            * Sets/Gets the whitelist of trusted resource URLs.
16772            */
16773           this.resourceUrlWhitelist = function(value) {
16774             if (arguments.length) {
16775               resourceUrlWhitelist = adjustMatchers(value);
16776             }
16777             return resourceUrlWhitelist;
16778           };
16779
16780           /**
16781            * @ngdoc method
16782            * @name $sceDelegateProvider#resourceUrlBlacklist
16783            * @kind function
16784            *
16785            * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
16786            *     provided.  This must be an array or null.  A snapshot of this array is used so further
16787            *     changes to the array are ignored.
16788            *
16789            *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16790            *     allowed in this array.
16791            *
16792            *     The typical usage for the blacklist is to **block
16793            *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
16794            *     these would otherwise be trusted but actually return content from the redirected domain.
16795            *
16796            *     Finally, **the blacklist overrides the whitelist** and has the final say.
16797            *
16798            * @return {Array} the currently set blacklist array.
16799            *
16800            * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
16801            * is no blacklist.)
16802            *
16803            * @description
16804            * Sets/Gets the blacklist of trusted resource URLs.
16805            */
16806
16807           this.resourceUrlBlacklist = function(value) {
16808             if (arguments.length) {
16809               resourceUrlBlacklist = adjustMatchers(value);
16810             }
16811             return resourceUrlBlacklist;
16812           };
16813
16814           this.$get = ['$injector', function($injector) {
16815
16816             var htmlSanitizer = function htmlSanitizer(html) {
16817               throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16818             };
16819
16820             if ($injector.has('$sanitize')) {
16821               htmlSanitizer = $injector.get('$sanitize');
16822             }
16823
16824
16825             function matchUrl(matcher, parsedUrl) {
16826               if (matcher === 'self') {
16827                 return urlIsSameOrigin(parsedUrl);
16828               } else {
16829                 // definitely a regex.  See adjustMatchers()
16830                 return !!matcher.exec(parsedUrl.href);
16831               }
16832             }
16833
16834             function isResourceUrlAllowedByPolicy(url) {
16835               var parsedUrl = urlResolve(url.toString());
16836               var i, n, allowed = false;
16837               // Ensure that at least one item from the whitelist allows this url.
16838               for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
16839                 if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
16840                   allowed = true;
16841                   break;
16842                 }
16843               }
16844               if (allowed) {
16845                 // Ensure that no item from the blacklist blocked this url.
16846                 for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
16847                   if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
16848                     allowed = false;
16849                     break;
16850                   }
16851                 }
16852               }
16853               return allowed;
16854             }
16855
16856             function generateHolderType(Base) {
16857               var holderType = function TrustedValueHolderType(trustedValue) {
16858                 this.$$unwrapTrustedValue = function() {
16859                   return trustedValue;
16860                 };
16861               };
16862               if (Base) {
16863                 holderType.prototype = new Base();
16864               }
16865               holderType.prototype.valueOf = function sceValueOf() {
16866                 return this.$$unwrapTrustedValue();
16867               };
16868               holderType.prototype.toString = function sceToString() {
16869                 return this.$$unwrapTrustedValue().toString();
16870               };
16871               return holderType;
16872             }
16873
16874             var trustedValueHolderBase = generateHolderType(),
16875                 byType = {};
16876
16877             byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
16878             byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
16879             byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
16880             byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
16881             byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
16882
16883             /**
16884              * @ngdoc method
16885              * @name $sceDelegate#trustAs
16886              *
16887              * @description
16888              * Returns an object that is trusted by angular for use in specified strict
16889              * contextual escaping contexts (such as ng-bind-html, ng-include, any src
16890              * attribute interpolation, any dom event binding attribute interpolation
16891              * such as for onclick,  etc.) that uses the provided value.
16892              * See {@link ng.$sce $sce} for enabling strict contextual escaping.
16893              *
16894              * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
16895              *   resourceUrl, html, js and css.
16896              * @param {*} value The value that that should be considered trusted/safe.
16897              * @returns {*} A value that can be used to stand in for the provided `value` in places
16898              * where Angular expects a $sce.trustAs() return value.
16899              */
16900             function trustAs(type, trustedValue) {
16901               var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16902               if (!Constructor) {
16903                 throw $sceMinErr('icontext',
16904                     'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
16905                     type, trustedValue);
16906               }
16907               if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
16908                 return trustedValue;
16909               }
16910               // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
16911               // mutable objects, we ensure here that the value passed in is actually a string.
16912               if (typeof trustedValue !== 'string') {
16913                 throw $sceMinErr('itype',
16914                     'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
16915                     type);
16916               }
16917               return new Constructor(trustedValue);
16918             }
16919
16920             /**
16921              * @ngdoc method
16922              * @name $sceDelegate#valueOf
16923              *
16924              * @description
16925              * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
16926              * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
16927              * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
16928              *
16929              * If the passed parameter is not a value that had been returned by {@link
16930              * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
16931              *
16932              * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
16933              *      call or anything else.
16934              * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
16935              *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
16936              *     `value` unchanged.
16937              */
16938             function valueOf(maybeTrusted) {
16939               if (maybeTrusted instanceof trustedValueHolderBase) {
16940                 return maybeTrusted.$$unwrapTrustedValue();
16941               } else {
16942                 return maybeTrusted;
16943               }
16944             }
16945
16946             /**
16947              * @ngdoc method
16948              * @name $sceDelegate#getTrusted
16949              *
16950              * @description
16951              * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
16952              * returns the originally supplied value if the queried context type is a supertype of the
16953              * created type.  If this condition isn't satisfied, throws an exception.
16954              *
16955              * @param {string} type The kind of context in which this value is to be used.
16956              * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
16957              *     `$sceDelegate.trustAs`} call.
16958              * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
16959              *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
16960              */
16961             function getTrusted(type, maybeTrusted) {
16962               if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
16963                 return maybeTrusted;
16964               }
16965               var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16966               if (constructor && maybeTrusted instanceof constructor) {
16967                 return maybeTrusted.$$unwrapTrustedValue();
16968               }
16969               // If we get here, then we may only take one of two actions.
16970               // 1. sanitize the value for the requested type, or
16971               // 2. throw an exception.
16972               if (type === SCE_CONTEXTS.RESOURCE_URL) {
16973                 if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
16974                   return maybeTrusted;
16975                 } else {
16976                   throw $sceMinErr('insecurl',
16977                       'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
16978                       maybeTrusted.toString());
16979                 }
16980               } else if (type === SCE_CONTEXTS.HTML) {
16981                 return htmlSanitizer(maybeTrusted);
16982               }
16983               throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16984             }
16985
16986             return { trustAs: trustAs,
16987                      getTrusted: getTrusted,
16988                      valueOf: valueOf };
16989           }];
16990         }
16991
16992
16993         /**
16994          * @ngdoc provider
16995          * @name $sceProvider
16996          * @description
16997          *
16998          * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
16999          * -   enable/disable Strict Contextual Escaping (SCE) in a module
17000          * -   override the default implementation with a custom delegate
17001          *
17002          * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
17003          */
17004
17005         /* jshint maxlen: false*/
17006
17007         /**
17008          * @ngdoc service
17009          * @name $sce
17010          * @kind function
17011          *
17012          * @description
17013          *
17014          * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
17015          *
17016          * # Strict Contextual Escaping
17017          *
17018          * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
17019          * contexts to result in a value that is marked as safe to use for that context.  One example of
17020          * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
17021          * to these contexts as privileged or SCE contexts.
17022          *
17023          * As of version 1.2, Angular ships with SCE enabled by default.
17024          *
17025          * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
17026          * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
17027          * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
17028          * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
17029          * to the top of your HTML document.
17030          *
17031          * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
17032          * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
17033          *
17034          * Here's an example of a binding in a privileged context:
17035          *
17036          * ```
17037          * <input ng-model="userHtml" aria-label="User input">
17038          * <div ng-bind-html="userHtml"></div>
17039          * ```
17040          *
17041          * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
17042          * disabled, this application allows the user to render arbitrary HTML into the DIV.
17043          * In a more realistic example, one may be rendering user comments, blog articles, etc. via
17044          * bindings.  (HTML is just one example of a context where rendering user controlled input creates
17045          * security vulnerabilities.)
17046          *
17047          * For the case of HTML, you might use a library, either on the client side, or on the server side,
17048          * to sanitize unsafe HTML before binding to the value and rendering it in the document.
17049          *
17050          * How would you ensure that every place that used these types of bindings was bound to a value that
17051          * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
17052          * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
17053          * properties/fields and forgot to update the binding to the sanitized value?
17054          *
17055          * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
17056          * determine that something explicitly says it's safe to use a value for binding in that
17057          * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
17058          * for those values that you can easily tell are safe - because they were received from your server,
17059          * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
17060          * allowing only the files in a specific directory to do this.  Ensuring that the internal API
17061          * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
17062          *
17063          * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
17064          * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
17065          * obtain values that will be accepted by SCE / privileged contexts.
17066          *
17067          *
17068          * ## How does it work?
17069          *
17070          * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
17071          * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
17072          * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
17073          * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
17074          *
17075          * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
17076          * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
17077          * simplified):
17078          *
17079          * ```
17080          * var ngBindHtmlDirective = ['$sce', function($sce) {
17081          *   return function(scope, element, attr) {
17082          *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
17083          *       element.html(value || '');
17084          *     });
17085          *   };
17086          * }];
17087          * ```
17088          *
17089          * ## Impact on loading templates
17090          *
17091          * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
17092          * `templateUrl`'s specified by {@link guide/directive directives}.
17093          *
17094          * By default, Angular only loads templates from the same domain and protocol as the application
17095          * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
17096          * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
17097          * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
17098          * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
17099          *
17100          * *Please note*:
17101          * The browser's
17102          * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
17103          * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
17104          * policy apply in addition to this and may further restrict whether the template is successfully
17105          * loaded.  This means that without the right CORS policy, loading templates from a different domain
17106          * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
17107          * browsers.
17108          *
17109          * ## This feels like too much overhead
17110          *
17111          * It's important to remember that SCE only applies to interpolation expressions.
17112          *
17113          * If your expressions are constant literals, they're automatically trusted and you don't need to
17114          * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
17115          * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
17116          *
17117          * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
17118          * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
17119          *
17120          * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
17121          * templates in `ng-include` from your application's domain without having to even know about SCE.
17122          * It blocks loading templates from other domains or loading templates over http from an https
17123          * served document.  You can change these by setting your own custom {@link
17124          * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
17125          * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
17126          *
17127          * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
17128          * application that's secure and can be audited to verify that with much more ease than bolting
17129          * security onto an application later.
17130          *
17131          * <a name="contexts"></a>
17132          * ## What trusted context types are supported?
17133          *
17134          * | Context             | Notes          |
17135          * |---------------------|----------------|
17136          * | `$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. |
17137          * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
17138          * | `$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. |
17139          * | `$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. |
17140          * | `$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. |
17141          *
17142          * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
17143          *
17144          *  Each element in these arrays must be one of the following:
17145          *
17146          *  - **'self'**
17147          *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
17148          *      domain** as the application document using the **same protocol**.
17149          *  - **String** (except the special value `'self'`)
17150          *    - The string is matched against the full *normalized / absolute URL* of the resource
17151          *      being tested (substring matches are not good enough.)
17152          *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
17153          *      match themselves.
17154          *    - `*`: matches zero or more occurrences of any character other than one of the following 6
17155          *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
17156          *      in a whitelist.
17157          *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
17158          *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
17159          *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
17160          *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
17161          *      http://foo.example.com/templates/**).
17162          *  - **RegExp** (*see caveat below*)
17163          *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
17164          *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
17165          *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
17166          *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
17167          *      small number of cases.  A `.` character in the regex used when matching the scheme or a
17168          *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
17169          *      is highly recommended to use the string patterns and only fall back to regular expressions
17170          *      as a last resort.
17171          *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
17172          *      matched against the **entire** *normalized / absolute URL* of the resource being tested
17173          *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
17174          *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
17175          *    - If you are generating your JavaScript from some other templating engine (not
17176          *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
17177          *      remember to escape your regular expression (and be aware that you might need more than
17178          *      one level of escaping depending on your templating engine and the way you interpolated
17179          *      the value.)  Do make use of your platform's escaping mechanism as it might be good
17180          *      enough before coding your own.  E.g. Ruby has
17181          *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
17182          *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
17183          *      Javascript lacks a similar built in function for escaping.  Take a look at Google
17184          *      Closure library's [goog.string.regExpEscape(s)](
17185          *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
17186          *
17187          * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
17188          *
17189          * ## Show me an example using SCE.
17190          *
17191          * <example module="mySceApp" deps="angular-sanitize.js">
17192          * <file name="index.html">
17193          *   <div ng-controller="AppController as myCtrl">
17194          *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
17195          *     <b>User comments</b><br>
17196          *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
17197          *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
17198          *     exploit.
17199          *     <div class="well">
17200          *       <div ng-repeat="userComment in myCtrl.userComments">
17201          *         <b>{{userComment.name}}</b>:
17202          *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
17203          *         <br>
17204          *       </div>
17205          *     </div>
17206          *   </div>
17207          * </file>
17208          *
17209          * <file name="script.js">
17210          *   angular.module('mySceApp', ['ngSanitize'])
17211          *     .controller('AppController', ['$http', '$templateCache', '$sce',
17212          *       function($http, $templateCache, $sce) {
17213          *         var self = this;
17214          *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
17215          *           self.userComments = userComments;
17216          *         });
17217          *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
17218          *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17219          *             'sanitization.&quot;">Hover over this text.</span>');
17220          *       }]);
17221          * </file>
17222          *
17223          * <file name="test_data.json">
17224          * [
17225          *   { "name": "Alice",
17226          *     "htmlComment":
17227          *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
17228          *   },
17229          *   { "name": "Bob",
17230          *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
17231          *   }
17232          * ]
17233          * </file>
17234          *
17235          * <file name="protractor.js" type="protractor">
17236          *   describe('SCE doc demo', function() {
17237          *     it('should sanitize untrusted values', function() {
17238          *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
17239          *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
17240          *     });
17241          *
17242          *     it('should NOT sanitize explicitly trusted values', function() {
17243          *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
17244          *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
17245          *           'sanitization.&quot;">Hover over this text.</span>');
17246          *     });
17247          *   });
17248          * </file>
17249          * </example>
17250          *
17251          *
17252          *
17253          * ## Can I disable SCE completely?
17254          *
17255          * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
17256          * for little coding overhead.  It will be much harder to take an SCE disabled application and
17257          * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
17258          * for cases where you have a lot of existing code that was written before SCE was introduced and
17259          * you're migrating them a module at a time.
17260          *
17261          * That said, here's how you can completely disable SCE:
17262          *
17263          * ```
17264          * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
17265          *   // Completely disable SCE.  For demonstration purposes only!
17266          *   // Do not use in new projects.
17267          *   $sceProvider.enabled(false);
17268          * });
17269          * ```
17270          *
17271          */
17272         /* jshint maxlen: 100 */
17273
17274         function $SceProvider() {
17275           var enabled = true;
17276
17277           /**
17278            * @ngdoc method
17279            * @name $sceProvider#enabled
17280            * @kind function
17281            *
17282            * @param {boolean=} value If provided, then enables/disables SCE.
17283            * @return {boolean} true if SCE is enabled, false otherwise.
17284            *
17285            * @description
17286            * Enables/disables SCE and returns the current value.
17287            */
17288           this.enabled = function(value) {
17289             if (arguments.length) {
17290               enabled = !!value;
17291             }
17292             return enabled;
17293           };
17294
17295
17296           /* Design notes on the default implementation for SCE.
17297            *
17298            * The API contract for the SCE delegate
17299            * -------------------------------------
17300            * The SCE delegate object must provide the following 3 methods:
17301            *
17302            * - trustAs(contextEnum, value)
17303            *     This method is used to tell the SCE service that the provided value is OK to use in the
17304            *     contexts specified by contextEnum.  It must return an object that will be accepted by
17305            *     getTrusted() for a compatible contextEnum and return this value.
17306            *
17307            * - valueOf(value)
17308            *     For values that were not produced by trustAs(), return them as is.  For values that were
17309            *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
17310            *     trustAs is wrapping the given values into some type, this operation unwraps it when given
17311            *     such a value.
17312            *
17313            * - getTrusted(contextEnum, value)
17314            *     This function should return the a value that is safe to use in the context specified by
17315            *     contextEnum or throw and exception otherwise.
17316            *
17317            * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
17318            * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
17319            * instance, an implementation could maintain a registry of all trusted objects by context.  In
17320            * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
17321            * return the same object passed in if it was found in the registry under a compatible context or
17322            * throw an exception otherwise.  An implementation might only wrap values some of the time based
17323            * on some criteria.  getTrusted() might return a value and not throw an exception for special
17324            * constants or objects even if not wrapped.  All such implementations fulfill this contract.
17325            *
17326            *
17327            * A note on the inheritance model for SCE contexts
17328            * ------------------------------------------------
17329            * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
17330            * is purely an implementation details.
17331            *
17332            * The contract is simply this:
17333            *
17334            *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
17335            *     will also succeed.
17336            *
17337            * Inheritance happens to capture this in a natural way.  In some future, we
17338            * may not use inheritance anymore.  That is OK because no code outside of
17339            * sce.js and sceSpecs.js would need to be aware of this detail.
17340            */
17341
17342           this.$get = ['$parse', '$sceDelegate', function(
17343                         $parse,   $sceDelegate) {
17344             // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
17345             // the "expression(javascript expression)" syntax which is insecure.
17346             if (enabled && msie < 8) {
17347               throw $sceMinErr('iequirks',
17348                 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
17349                 'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
17350                 'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
17351             }
17352
17353             var sce = shallowCopy(SCE_CONTEXTS);
17354
17355             /**
17356              * @ngdoc method
17357              * @name $sce#isEnabled
17358              * @kind function
17359              *
17360              * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
17361              * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
17362              *
17363              * @description
17364              * Returns a boolean indicating if SCE is enabled.
17365              */
17366             sce.isEnabled = function() {
17367               return enabled;
17368             };
17369             sce.trustAs = $sceDelegate.trustAs;
17370             sce.getTrusted = $sceDelegate.getTrusted;
17371             sce.valueOf = $sceDelegate.valueOf;
17372
17373             if (!enabled) {
17374               sce.trustAs = sce.getTrusted = function(type, value) { return value; };
17375               sce.valueOf = identity;
17376             }
17377
17378             /**
17379              * @ngdoc method
17380              * @name $sce#parseAs
17381              *
17382              * @description
17383              * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
17384              * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
17385              * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
17386              * *result*)}
17387              *
17388              * @param {string} type The kind of SCE context in which this result will be used.
17389              * @param {string} expression String expression to compile.
17390              * @returns {function(context, locals)} a function which represents the compiled expression:
17391              *
17392              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17393              *      are evaluated against (typically a scope object).
17394              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17395              *      `context`.
17396              */
17397             sce.parseAs = function sceParseAs(type, expr) {
17398               var parsed = $parse(expr);
17399               if (parsed.literal && parsed.constant) {
17400                 return parsed;
17401               } else {
17402                 return $parse(expr, function(value) {
17403                   return sce.getTrusted(type, value);
17404                 });
17405               }
17406             };
17407
17408             /**
17409              * @ngdoc method
17410              * @name $sce#trustAs
17411              *
17412              * @description
17413              * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
17414              * returns an object that is trusted by angular for use in specified strict contextual
17415              * escaping contexts (such as ng-bind-html, ng-include, any src attribute
17416              * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
17417              * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
17418              * escaping.
17419              *
17420              * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
17421              *   resourceUrl, html, js and css.
17422              * @param {*} value The value that that should be considered trusted/safe.
17423              * @returns {*} A value that can be used to stand in for the provided `value` in places
17424              * where Angular expects a $sce.trustAs() return value.
17425              */
17426
17427             /**
17428              * @ngdoc method
17429              * @name $sce#trustAsHtml
17430              *
17431              * @description
17432              * Shorthand method.  `$sce.trustAsHtml(value)` →
17433              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
17434              *
17435              * @param {*} value The value to trustAs.
17436              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
17437              *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
17438              *     only accept expressions that are either literal constants or are the
17439              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17440              */
17441
17442             /**
17443              * @ngdoc method
17444              * @name $sce#trustAsUrl
17445              *
17446              * @description
17447              * Shorthand method.  `$sce.trustAsUrl(value)` →
17448              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
17449              *
17450              * @param {*} value The value to trustAs.
17451              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
17452              *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
17453              *     only accept expressions that are either literal constants or are the
17454              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17455              */
17456
17457             /**
17458              * @ngdoc method
17459              * @name $sce#trustAsResourceUrl
17460              *
17461              * @description
17462              * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
17463              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
17464              *
17465              * @param {*} value The value to trustAs.
17466              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
17467              *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
17468              *     only accept expressions that are either literal constants or are the return
17469              *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
17470              */
17471
17472             /**
17473              * @ngdoc method
17474              * @name $sce#trustAsJs
17475              *
17476              * @description
17477              * Shorthand method.  `$sce.trustAsJs(value)` →
17478              *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
17479              *
17480              * @param {*} value The value to trustAs.
17481              * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
17482              *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
17483              *     only accept expressions that are either literal constants or are the
17484              *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17485              */
17486
17487             /**
17488              * @ngdoc method
17489              * @name $sce#getTrusted
17490              *
17491              * @description
17492              * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
17493              * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
17494              * originally supplied value if the queried context type is a supertype of the created type.
17495              * If this condition isn't satisfied, throws an exception.
17496              *
17497              * @param {string} type The kind of context in which this value is to be used.
17498              * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
17499              *                         call.
17500              * @returns {*} The value the was originally provided to
17501              *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
17502              *              Otherwise, throws an exception.
17503              */
17504
17505             /**
17506              * @ngdoc method
17507              * @name $sce#getTrustedHtml
17508              *
17509              * @description
17510              * Shorthand method.  `$sce.getTrustedHtml(value)` →
17511              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
17512              *
17513              * @param {*} value The value to pass to `$sce.getTrusted`.
17514              * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
17515              */
17516
17517             /**
17518              * @ngdoc method
17519              * @name $sce#getTrustedCss
17520              *
17521              * @description
17522              * Shorthand method.  `$sce.getTrustedCss(value)` →
17523              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
17524              *
17525              * @param {*} value The value to pass to `$sce.getTrusted`.
17526              * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
17527              */
17528
17529             /**
17530              * @ngdoc method
17531              * @name $sce#getTrustedUrl
17532              *
17533              * @description
17534              * Shorthand method.  `$sce.getTrustedUrl(value)` →
17535              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
17536              *
17537              * @param {*} value The value to pass to `$sce.getTrusted`.
17538              * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
17539              */
17540
17541             /**
17542              * @ngdoc method
17543              * @name $sce#getTrustedResourceUrl
17544              *
17545              * @description
17546              * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
17547              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
17548              *
17549              * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
17550              * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
17551              */
17552
17553             /**
17554              * @ngdoc method
17555              * @name $sce#getTrustedJs
17556              *
17557              * @description
17558              * Shorthand method.  `$sce.getTrustedJs(value)` →
17559              *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
17560              *
17561              * @param {*} value The value to pass to `$sce.getTrusted`.
17562              * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
17563              */
17564
17565             /**
17566              * @ngdoc method
17567              * @name $sce#parseAsHtml
17568              *
17569              * @description
17570              * Shorthand method.  `$sce.parseAsHtml(expression string)` →
17571              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
17572              *
17573              * @param {string} expression String expression to compile.
17574              * @returns {function(context, locals)} a function which represents the compiled expression:
17575              *
17576              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17577              *      are evaluated against (typically a scope object).
17578              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17579              *      `context`.
17580              */
17581
17582             /**
17583              * @ngdoc method
17584              * @name $sce#parseAsCss
17585              *
17586              * @description
17587              * Shorthand method.  `$sce.parseAsCss(value)` →
17588              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
17589              *
17590              * @param {string} expression String expression to compile.
17591              * @returns {function(context, locals)} a function which represents the compiled expression:
17592              *
17593              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17594              *      are evaluated against (typically a scope object).
17595              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17596              *      `context`.
17597              */
17598
17599             /**
17600              * @ngdoc method
17601              * @name $sce#parseAsUrl
17602              *
17603              * @description
17604              * Shorthand method.  `$sce.parseAsUrl(value)` →
17605              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
17606              *
17607              * @param {string} expression String expression to compile.
17608              * @returns {function(context, locals)} a function which represents the compiled expression:
17609              *
17610              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17611              *      are evaluated against (typically a scope object).
17612              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17613              *      `context`.
17614              */
17615
17616             /**
17617              * @ngdoc method
17618              * @name $sce#parseAsResourceUrl
17619              *
17620              * @description
17621              * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
17622              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
17623              *
17624              * @param {string} expression String expression to compile.
17625              * @returns {function(context, locals)} a function which represents the compiled expression:
17626              *
17627              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17628              *      are evaluated against (typically a scope object).
17629              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17630              *      `context`.
17631              */
17632
17633             /**
17634              * @ngdoc method
17635              * @name $sce#parseAsJs
17636              *
17637              * @description
17638              * Shorthand method.  `$sce.parseAsJs(value)` →
17639              *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
17640              *
17641              * @param {string} expression String expression to compile.
17642              * @returns {function(context, locals)} a function which represents the compiled expression:
17643              *
17644              *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17645              *      are evaluated against (typically a scope object).
17646              *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17647              *      `context`.
17648              */
17649
17650             // Shorthand delegations.
17651             var parse = sce.parseAs,
17652                 getTrusted = sce.getTrusted,
17653                 trustAs = sce.trustAs;
17654
17655             forEach(SCE_CONTEXTS, function(enumValue, name) {
17656               var lName = lowercase(name);
17657               sce[camelCase("parse_as_" + lName)] = function(expr) {
17658                 return parse(enumValue, expr);
17659               };
17660               sce[camelCase("get_trusted_" + lName)] = function(value) {
17661                 return getTrusted(enumValue, value);
17662               };
17663               sce[camelCase("trust_as_" + lName)] = function(value) {
17664                 return trustAs(enumValue, value);
17665               };
17666             });
17667
17668             return sce;
17669           }];
17670         }
17671
17672         /**
17673          * !!! This is an undocumented "private" service !!!
17674          *
17675          * @name $sniffer
17676          * @requires $window
17677          * @requires $document
17678          *
17679          * @property {boolean} history Does the browser support html5 history api ?
17680          * @property {boolean} transitions Does the browser support CSS transition events ?
17681          * @property {boolean} animations Does the browser support CSS animation events ?
17682          *
17683          * @description
17684          * This is very simple implementation of testing browser's features.
17685          */
17686         function $SnifferProvider() {
17687           this.$get = ['$window', '$document', function($window, $document) {
17688             var eventSupport = {},
17689                 android =
17690                   toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
17691                 boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
17692                 document = $document[0] || {},
17693                 vendorPrefix,
17694                 vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
17695                 bodyStyle = document.body && document.body.style,
17696                 transitions = false,
17697                 animations = false,
17698                 match;
17699
17700             if (bodyStyle) {
17701               for (var prop in bodyStyle) {
17702                 if (match = vendorRegex.exec(prop)) {
17703                   vendorPrefix = match[0];
17704                   vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
17705                   break;
17706                 }
17707               }
17708
17709               if (!vendorPrefix) {
17710                 vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
17711               }
17712
17713               transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
17714               animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
17715
17716               if (android && (!transitions ||  !animations)) {
17717                 transitions = isString(bodyStyle.webkitTransition);
17718                 animations = isString(bodyStyle.webkitAnimation);
17719               }
17720             }
17721
17722
17723             return {
17724               // Android has history.pushState, but it does not update location correctly
17725               // so let's not use the history API at all.
17726               // http://code.google.com/p/android/issues/detail?id=17471
17727               // https://github.com/angular/angular.js/issues/904
17728
17729               // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
17730               // so let's not use the history API also
17731               // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
17732               // jshint -W018
17733               history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
17734               // jshint +W018
17735               hasEvent: function(event) {
17736                 // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
17737                 // it. In particular the event is not fired when backspace or delete key are pressed or
17738                 // when cut operation is performed.
17739                 // IE10+ implements 'input' event but it erroneously fires under various situations,
17740                 // e.g. when placeholder changes, or a form is focused.
17741                 if (event === 'input' && msie <= 11) return false;
17742
17743                 if (isUndefined(eventSupport[event])) {
17744                   var divElm = document.createElement('div');
17745                   eventSupport[event] = 'on' + event in divElm;
17746                 }
17747
17748                 return eventSupport[event];
17749               },
17750               csp: csp(),
17751               vendorPrefix: vendorPrefix,
17752               transitions: transitions,
17753               animations: animations,
17754               android: android
17755             };
17756           }];
17757         }
17758
17759         var $compileMinErr = minErr('$compile');
17760
17761         /**
17762          * @ngdoc service
17763          * @name $templateRequest
17764          *
17765          * @description
17766          * The `$templateRequest` service runs security checks then downloads the provided template using
17767          * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
17768          * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
17769          * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
17770          * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
17771          * when `tpl` is of type string and `$templateCache` has the matching entry.
17772          *
17773          * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
17774          * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
17775          *
17776          * @return {Promise} a promise for the HTTP response data of the given URL.
17777          *
17778          * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
17779          */
17780         function $TemplateRequestProvider() {
17781           this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
17782             function handleRequestFn(tpl, ignoreRequestError) {
17783               handleRequestFn.totalPendingRequests++;
17784
17785               // We consider the template cache holds only trusted templates, so
17786               // there's no need to go through whitelisting again for keys that already
17787               // are included in there. This also makes Angular accept any script
17788               // directive, no matter its name. However, we still need to unwrap trusted
17789               // types.
17790               if (!isString(tpl) || !$templateCache.get(tpl)) {
17791                 tpl = $sce.getTrustedResourceUrl(tpl);
17792               }
17793
17794               var transformResponse = $http.defaults && $http.defaults.transformResponse;
17795
17796               if (isArray(transformResponse)) {
17797                 transformResponse = transformResponse.filter(function(transformer) {
17798                   return transformer !== defaultHttpResponseTransform;
17799                 });
17800               } else if (transformResponse === defaultHttpResponseTransform) {
17801                 transformResponse = null;
17802               }
17803
17804               var httpOptions = {
17805                 cache: $templateCache,
17806                 transformResponse: transformResponse
17807               };
17808
17809               return $http.get(tpl, httpOptions)
17810                 ['finally'](function() {
17811                   handleRequestFn.totalPendingRequests--;
17812                 })
17813                 .then(function(response) {
17814                   $templateCache.put(tpl, response.data);
17815                   return response.data;
17816                 }, handleError);
17817
17818               function handleError(resp) {
17819                 if (!ignoreRequestError) {
17820                   throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
17821                     tpl, resp.status, resp.statusText);
17822                 }
17823                 return $q.reject(resp);
17824               }
17825             }
17826
17827             handleRequestFn.totalPendingRequests = 0;
17828
17829             return handleRequestFn;
17830           }];
17831         }
17832
17833         function $$TestabilityProvider() {
17834           this.$get = ['$rootScope', '$browser', '$location',
17835                function($rootScope,   $browser,   $location) {
17836
17837             /**
17838              * @name $testability
17839              *
17840              * @description
17841              * The private $$testability service provides a collection of methods for use when debugging
17842              * or by automated test and debugging tools.
17843              */
17844             var testability = {};
17845
17846             /**
17847              * @name $$testability#findBindings
17848              *
17849              * @description
17850              * Returns an array of elements that are bound (via ng-bind or {{}})
17851              * to expressions matching the input.
17852              *
17853              * @param {Element} element The element root to search from.
17854              * @param {string} expression The binding expression to match.
17855              * @param {boolean} opt_exactMatch If true, only returns exact matches
17856              *     for the expression. Filters and whitespace are ignored.
17857              */
17858             testability.findBindings = function(element, expression, opt_exactMatch) {
17859               var bindings = element.getElementsByClassName('ng-binding');
17860               var matches = [];
17861               forEach(bindings, function(binding) {
17862                 var dataBinding = angular.element(binding).data('$binding');
17863                 if (dataBinding) {
17864                   forEach(dataBinding, function(bindingName) {
17865                     if (opt_exactMatch) {
17866                       var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
17867                       if (matcher.test(bindingName)) {
17868                         matches.push(binding);
17869                       }
17870                     } else {
17871                       if (bindingName.indexOf(expression) != -1) {
17872                         matches.push(binding);
17873                       }
17874                     }
17875                   });
17876                 }
17877               });
17878               return matches;
17879             };
17880
17881             /**
17882              * @name $$testability#findModels
17883              *
17884              * @description
17885              * Returns an array of elements that are two-way found via ng-model to
17886              * expressions matching the input.
17887              *
17888              * @param {Element} element The element root to search from.
17889              * @param {string} expression The model expression to match.
17890              * @param {boolean} opt_exactMatch If true, only returns exact matches
17891              *     for the expression.
17892              */
17893             testability.findModels = function(element, expression, opt_exactMatch) {
17894               var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
17895               for (var p = 0; p < prefixes.length; ++p) {
17896                 var attributeEquals = opt_exactMatch ? '=' : '*=';
17897                 var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
17898                 var elements = element.querySelectorAll(selector);
17899                 if (elements.length) {
17900                   return elements;
17901                 }
17902               }
17903             };
17904
17905             /**
17906              * @name $$testability#getLocation
17907              *
17908              * @description
17909              * Shortcut for getting the location in a browser agnostic way. Returns
17910              *     the path, search, and hash. (e.g. /path?a=b#hash)
17911              */
17912             testability.getLocation = function() {
17913               return $location.url();
17914             };
17915
17916             /**
17917              * @name $$testability#setLocation
17918              *
17919              * @description
17920              * Shortcut for navigating to a location without doing a full page reload.
17921              *
17922              * @param {string} url The location url (path, search and hash,
17923              *     e.g. /path?a=b#hash) to go to.
17924              */
17925             testability.setLocation = function(url) {
17926               if (url !== $location.url()) {
17927                 $location.url(url);
17928                 $rootScope.$digest();
17929               }
17930             };
17931
17932             /**
17933              * @name $$testability#whenStable
17934              *
17935              * @description
17936              * Calls the callback when $timeout and $http requests are completed.
17937              *
17938              * @param {function} callback
17939              */
17940             testability.whenStable = function(callback) {
17941               $browser.notifyWhenNoOutstandingRequests(callback);
17942             };
17943
17944             return testability;
17945           }];
17946         }
17947
17948         function $TimeoutProvider() {
17949           this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
17950                function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
17951
17952             var deferreds = {};
17953
17954
17955              /**
17956               * @ngdoc service
17957               * @name $timeout
17958               *
17959               * @description
17960               * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
17961               * block and delegates any exceptions to
17962               * {@link ng.$exceptionHandler $exceptionHandler} service.
17963               *
17964               * The return value of calling `$timeout` is a promise, which will be resolved when
17965               * the delay has passed and the timeout function, if provided, is executed.
17966               *
17967               * To cancel a timeout request, call `$timeout.cancel(promise)`.
17968               *
17969               * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
17970               * synchronously flush the queue of deferred functions.
17971               *
17972               * If you only want a promise that will be resolved after some specified delay
17973               * then you can call `$timeout` without the `fn` function.
17974               *
17975               * @param {function()=} fn A function, whose execution should be delayed.
17976               * @param {number=} [delay=0] Delay in milliseconds.
17977               * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17978               *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17979               * @param {...*=} Pass additional parameters to the executed function.
17980               * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
17981               *   promise will be resolved with is the return value of the `fn` function.
17982               *
17983               */
17984             function timeout(fn, delay, invokeApply) {
17985               if (!isFunction(fn)) {
17986                 invokeApply = delay;
17987                 delay = fn;
17988                 fn = noop;
17989               }
17990
17991               var args = sliceArgs(arguments, 3),
17992                   skipApply = (isDefined(invokeApply) && !invokeApply),
17993                   deferred = (skipApply ? $$q : $q).defer(),
17994                   promise = deferred.promise,
17995                   timeoutId;
17996
17997               timeoutId = $browser.defer(function() {
17998                 try {
17999                   deferred.resolve(fn.apply(null, args));
18000                 } catch (e) {
18001                   deferred.reject(e);
18002                   $exceptionHandler(e);
18003                 }
18004                 finally {
18005                   delete deferreds[promise.$$timeoutId];
18006                 }
18007
18008                 if (!skipApply) $rootScope.$apply();
18009               }, delay);
18010
18011               promise.$$timeoutId = timeoutId;
18012               deferreds[timeoutId] = deferred;
18013
18014               return promise;
18015             }
18016
18017
18018              /**
18019               * @ngdoc method
18020               * @name $timeout#cancel
18021               *
18022               * @description
18023               * Cancels a task associated with the `promise`. As a result of this, the promise will be
18024               * resolved with a rejection.
18025               *
18026               * @param {Promise=} promise Promise returned by the `$timeout` function.
18027               * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
18028               *   canceled.
18029               */
18030             timeout.cancel = function(promise) {
18031               if (promise && promise.$$timeoutId in deferreds) {
18032                 deferreds[promise.$$timeoutId].reject('canceled');
18033                 delete deferreds[promise.$$timeoutId];
18034                 return $browser.defer.cancel(promise.$$timeoutId);
18035               }
18036               return false;
18037             };
18038
18039             return timeout;
18040           }];
18041         }
18042
18043         // NOTE:  The usage of window and document instead of $window and $document here is
18044         // deliberate.  This service depends on the specific behavior of anchor nodes created by the
18045         // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
18046         // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
18047         // doesn't know about mocked locations and resolves URLs to the real document - which is
18048         // exactly the behavior needed here.  There is little value is mocking these out for this
18049         // service.
18050         var urlParsingNode = document.createElement("a");
18051         var originUrl = urlResolve(window.location.href);
18052
18053
18054         /**
18055          *
18056          * Implementation Notes for non-IE browsers
18057          * ----------------------------------------
18058          * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
18059          * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
18060          * URL will be resolved into an absolute URL in the context of the application document.
18061          * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
18062          * properties are all populated to reflect the normalized URL.  This approach has wide
18063          * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
18064          * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
18065          *
18066          * Implementation Notes for IE
18067          * ---------------------------
18068          * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
18069          * browsers.  However, the parsed components will not be set if the URL assigned did not specify
18070          * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
18071          * work around that by performing the parsing in a 2nd step by taking a previously normalized
18072          * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
18073          * properties such as protocol, hostname, port, etc.
18074          *
18075          * References:
18076          *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
18077          *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
18078          *   http://url.spec.whatwg.org/#urlutils
18079          *   https://github.com/angular/angular.js/pull/2902
18080          *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
18081          *
18082          * @kind function
18083          * @param {string} url The URL to be parsed.
18084          * @description Normalizes and parses a URL.
18085          * @returns {object} Returns the normalized URL as a dictionary.
18086          *
18087          *   | member name   | Description    |
18088          *   |---------------|----------------|
18089          *   | href          | A normalized version of the provided URL if it was not an absolute URL |
18090          *   | protocol      | The protocol including the trailing colon                              |
18091          *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
18092          *   | search        | The search params, minus the question mark                             |
18093          *   | hash          | The hash string, minus the hash symbol
18094          *   | hostname      | The hostname
18095          *   | port          | The port, without ":"
18096          *   | pathname      | The pathname, beginning with "/"
18097          *
18098          */
18099         function urlResolve(url) {
18100           var href = url;
18101
18102           if (msie) {
18103             // Normalize before parse.  Refer Implementation Notes on why this is
18104             // done in two steps on IE.
18105             urlParsingNode.setAttribute("href", href);
18106             href = urlParsingNode.href;
18107           }
18108
18109           urlParsingNode.setAttribute('href', href);
18110
18111           // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
18112           return {
18113             href: urlParsingNode.href,
18114             protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
18115             host: urlParsingNode.host,
18116             search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
18117             hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
18118             hostname: urlParsingNode.hostname,
18119             port: urlParsingNode.port,
18120             pathname: (urlParsingNode.pathname.charAt(0) === '/')
18121               ? urlParsingNode.pathname
18122               : '/' + urlParsingNode.pathname
18123           };
18124         }
18125
18126         /**
18127          * Parse a request URL and determine whether this is a same-origin request as the application document.
18128          *
18129          * @param {string|object} requestUrl The url of the request as a string that will be resolved
18130          * or a parsed URL object.
18131          * @returns {boolean} Whether the request is for the same origin as the application document.
18132          */
18133         function urlIsSameOrigin(requestUrl) {
18134           var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
18135           return (parsed.protocol === originUrl.protocol &&
18136                   parsed.host === originUrl.host);
18137         }
18138
18139         /**
18140          * @ngdoc service
18141          * @name $window
18142          *
18143          * @description
18144          * A reference to the browser's `window` object. While `window`
18145          * is globally available in JavaScript, it causes testability problems, because
18146          * it is a global variable. In angular we always refer to it through the
18147          * `$window` service, so it may be overridden, removed or mocked for testing.
18148          *
18149          * Expressions, like the one defined for the `ngClick` directive in the example
18150          * below, are evaluated with respect to the current scope.  Therefore, there is
18151          * no risk of inadvertently coding in a dependency on a global value in such an
18152          * expression.
18153          *
18154          * @example
18155            <example module="windowExample">
18156              <file name="index.html">
18157                <script>
18158                  angular.module('windowExample', [])
18159                    .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
18160                      $scope.greeting = 'Hello, World!';
18161                      $scope.doGreeting = function(greeting) {
18162                        $window.alert(greeting);
18163                      };
18164                    }]);
18165                </script>
18166                <div ng-controller="ExampleController">
18167                  <input type="text" ng-model="greeting" aria-label="greeting" />
18168                  <button ng-click="doGreeting(greeting)">ALERT</button>
18169                </div>
18170              </file>
18171              <file name="protractor.js" type="protractor">
18172               it('should display the greeting in the input box', function() {
18173                element(by.model('greeting')).sendKeys('Hello, E2E Tests');
18174                // If we click the button it will block the test runner
18175                // element(':button').click();
18176               });
18177              </file>
18178            </example>
18179          */
18180         function $WindowProvider() {
18181           this.$get = valueFn(window);
18182         }
18183
18184         /**
18185          * @name $$cookieReader
18186          * @requires $document
18187          *
18188          * @description
18189          * This is a private service for reading cookies used by $http and ngCookies
18190          *
18191          * @return {Object} a key/value map of the current cookies
18192          */
18193         function $$CookieReader($document) {
18194           var rawDocument = $document[0] || {};
18195           var lastCookies = {};
18196           var lastCookieString = '';
18197
18198           function safeDecodeURIComponent(str) {
18199             try {
18200               return decodeURIComponent(str);
18201             } catch (e) {
18202               return str;
18203             }
18204           }
18205
18206           return function() {
18207             var cookieArray, cookie, i, index, name;
18208             var currentCookieString = rawDocument.cookie || '';
18209
18210             if (currentCookieString !== lastCookieString) {
18211               lastCookieString = currentCookieString;
18212               cookieArray = lastCookieString.split('; ');
18213               lastCookies = {};
18214
18215               for (i = 0; i < cookieArray.length; i++) {
18216                 cookie = cookieArray[i];
18217                 index = cookie.indexOf('=');
18218                 if (index > 0) { //ignore nameless cookies
18219                   name = safeDecodeURIComponent(cookie.substring(0, index));
18220                   // the first value that is seen for a cookie is the most
18221                   // specific one.  values for the same cookie name that
18222                   // follow are for less specific paths.
18223                   if (isUndefined(lastCookies[name])) {
18224                     lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
18225                   }
18226                 }
18227               }
18228             }
18229             return lastCookies;
18230           };
18231         }
18232
18233         $$CookieReader.$inject = ['$document'];
18234
18235         function $$CookieReaderProvider() {
18236           this.$get = $$CookieReader;
18237         }
18238
18239         /* global currencyFilter: true,
18240          dateFilter: true,
18241          filterFilter: true,
18242          jsonFilter: true,
18243          limitToFilter: true,
18244          lowercaseFilter: true,
18245          numberFilter: true,
18246          orderByFilter: true,
18247          uppercaseFilter: true,
18248          */
18249
18250         /**
18251          * @ngdoc provider
18252          * @name $filterProvider
18253          * @description
18254          *
18255          * Filters are just functions which transform input to an output. However filters need to be
18256          * Dependency Injected. To achieve this a filter definition consists of a factory function which is
18257          * annotated with dependencies and is responsible for creating a filter function.
18258          *
18259          * <div class="alert alert-warning">
18260          * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18261          * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18262          * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18263          * (`myapp_subsection_filterx`).
18264          * </div>
18265          *
18266          * ```js
18267          *   // Filter registration
18268          *   function MyModule($provide, $filterProvider) {
18269          *     // create a service to demonstrate injection (not always needed)
18270          *     $provide.value('greet', function(name){
18271          *       return 'Hello ' + name + '!';
18272          *     });
18273          *
18274          *     // register a filter factory which uses the
18275          *     // greet service to demonstrate DI.
18276          *     $filterProvider.register('greet', function(greet){
18277          *       // return the filter function which uses the greet service
18278          *       // to generate salutation
18279          *       return function(text) {
18280          *         // filters need to be forgiving so check input validity
18281          *         return text && greet(text) || text;
18282          *       };
18283          *     });
18284          *   }
18285          * ```
18286          *
18287          * The filter function is registered with the `$injector` under the filter name suffix with
18288          * `Filter`.
18289          *
18290          * ```js
18291          *   it('should be the same instance', inject(
18292          *     function($filterProvider) {
18293          *       $filterProvider.register('reverse', function(){
18294          *         return ...;
18295          *       });
18296          *     },
18297          *     function($filter, reverseFilter) {
18298          *       expect($filter('reverse')).toBe(reverseFilter);
18299          *     });
18300          * ```
18301          *
18302          *
18303          * For more information about how angular filters work, and how to create your own filters, see
18304          * {@link guide/filter Filters} in the Angular Developer Guide.
18305          */
18306
18307         /**
18308          * @ngdoc service
18309          * @name $filter
18310          * @kind function
18311          * @description
18312          * Filters are used for formatting data displayed to the user.
18313          *
18314          * The general syntax in templates is as follows:
18315          *
18316          *         {{ expression [| filter_name[:parameter_value] ... ] }}
18317          *
18318          * @param {String} name Name of the filter function to retrieve
18319          * @return {Function} the filter function
18320          * @example
18321            <example name="$filter" module="filterExample">
18322              <file name="index.html">
18323                <div ng-controller="MainCtrl">
18324                 <h3>{{ originalText }}</h3>
18325                 <h3>{{ filteredText }}</h3>
18326                </div>
18327              </file>
18328
18329              <file name="script.js">
18330               angular.module('filterExample', [])
18331               .controller('MainCtrl', function($scope, $filter) {
18332                 $scope.originalText = 'hello';
18333                 $scope.filteredText = $filter('uppercase')($scope.originalText);
18334               });
18335              </file>
18336            </example>
18337           */
18338         $FilterProvider.$inject = ['$provide'];
18339         function $FilterProvider($provide) {
18340           var suffix = 'Filter';
18341
18342           /**
18343            * @ngdoc method
18344            * @name $filterProvider#register
18345            * @param {string|Object} name Name of the filter function, or an object map of filters where
18346            *    the keys are the filter names and the values are the filter factories.
18347            *
18348            *    <div class="alert alert-warning">
18349            *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
18350            *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
18351            *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
18352            *    (`myapp_subsection_filterx`).
18353            *    </div>
18354             * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
18355            * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
18356            *    of the registered filter instances.
18357            */
18358           function register(name, factory) {
18359             if (isObject(name)) {
18360               var filters = {};
18361               forEach(name, function(filter, key) {
18362                 filters[key] = register(key, filter);
18363               });
18364               return filters;
18365             } else {
18366               return $provide.factory(name + suffix, factory);
18367             }
18368           }
18369           this.register = register;
18370
18371           this.$get = ['$injector', function($injector) {
18372             return function(name) {
18373               return $injector.get(name + suffix);
18374             };
18375           }];
18376
18377           ////////////////////////////////////////
18378
18379           /* global
18380             currencyFilter: false,
18381             dateFilter: false,
18382             filterFilter: false,
18383             jsonFilter: false,
18384             limitToFilter: false,
18385             lowercaseFilter: false,
18386             numberFilter: false,
18387             orderByFilter: false,
18388             uppercaseFilter: false,
18389           */
18390
18391           register('currency', currencyFilter);
18392           register('date', dateFilter);
18393           register('filter', filterFilter);
18394           register('json', jsonFilter);
18395           register('limitTo', limitToFilter);
18396           register('lowercase', lowercaseFilter);
18397           register('number', numberFilter);
18398           register('orderBy', orderByFilter);
18399           register('uppercase', uppercaseFilter);
18400         }
18401
18402         /**
18403          * @ngdoc filter
18404          * @name filter
18405          * @kind function
18406          *
18407          * @description
18408          * Selects a subset of items from `array` and returns it as a new array.
18409          *
18410          * @param {Array} array The source array.
18411          * @param {string|Object|function()} expression The predicate to be used for selecting items from
18412          *   `array`.
18413          *
18414          *   Can be one of:
18415          *
18416          *   - `string`: The string is used for matching against the contents of the `array`. All strings or
18417          *     objects with string properties in `array` that match this string will be returned. This also
18418          *     applies to nested object properties.
18419          *     The predicate can be negated by prefixing the string with `!`.
18420          *
18421          *   - `Object`: A pattern object can be used to filter specific properties on objects contained
18422          *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
18423          *     which have property `name` containing "M" and property `phone` containing "1". A special
18424          *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
18425          *     property of the object or its nested object properties. That's equivalent to the simple
18426          *     substring match with a `string` as described above. The predicate can be negated by prefixing
18427          *     the string with `!`.
18428          *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
18429          *     not containing "M".
18430          *
18431          *     Note that a named property will match properties on the same level only, while the special
18432          *     `$` property will match properties on the same level or deeper. E.g. an array item like
18433          *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
18434          *     **will** be matched by `{$: 'John'}`.
18435          *
18436          *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
18437          *     The function is called for each element of the array, with the element, its index, and
18438          *     the entire array itself as arguments.
18439          *
18440          *     The final result is an array of those elements that the predicate returned true for.
18441          *
18442          * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
18443          *     determining if the expected value (from the filter expression) and actual value (from
18444          *     the object in the array) should be considered a match.
18445          *
18446          *   Can be one of:
18447          *
18448          *   - `function(actual, expected)`:
18449          *     The function will be given the object value and the predicate value to compare and
18450          *     should return true if both values should be considered equal.
18451          *
18452          *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
18453          *     This is essentially strict comparison of expected and actual.
18454          *
18455          *   - `false|undefined`: A short hand for a function which will look for a substring match in case
18456          *     insensitive way.
18457          *
18458          *     Primitive values are converted to strings. Objects are not compared against primitives,
18459          *     unless they have a custom `toString` method (e.g. `Date` objects).
18460          *
18461          * @example
18462            <example>
18463              <file name="index.html">
18464                <div ng-init="friends = [{name:'John', phone:'555-1276'},
18465                                         {name:'Mary', phone:'800-BIG-MARY'},
18466                                         {name:'Mike', phone:'555-4321'},
18467                                         {name:'Adam', phone:'555-5678'},
18468                                         {name:'Julie', phone:'555-8765'},
18469                                         {name:'Juliette', phone:'555-5678'}]"></div>
18470
18471                <label>Search: <input ng-model="searchText"></label>
18472                <table id="searchTextResults">
18473                  <tr><th>Name</th><th>Phone</th></tr>
18474                  <tr ng-repeat="friend in friends | filter:searchText">
18475                    <td>{{friend.name}}</td>
18476                    <td>{{friend.phone}}</td>
18477                  </tr>
18478                </table>
18479                <hr>
18480                <label>Any: <input ng-model="search.$"></label> <br>
18481                <label>Name only <input ng-model="search.name"></label><br>
18482                <label>Phone only <input ng-model="search.phone"></label><br>
18483                <label>Equality <input type="checkbox" ng-model="strict"></label><br>
18484                <table id="searchObjResults">
18485                  <tr><th>Name</th><th>Phone</th></tr>
18486                  <tr ng-repeat="friendObj in friends | filter:search:strict">
18487                    <td>{{friendObj.name}}</td>
18488                    <td>{{friendObj.phone}}</td>
18489                  </tr>
18490                </table>
18491              </file>
18492              <file name="protractor.js" type="protractor">
18493                var expectFriendNames = function(expectedNames, key) {
18494                  element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
18495                    arr.forEach(function(wd, i) {
18496                      expect(wd.getText()).toMatch(expectedNames[i]);
18497                    });
18498                  });
18499                };
18500
18501                it('should search across all fields when filtering with a string', function() {
18502                  var searchText = element(by.model('searchText'));
18503                  searchText.clear();
18504                  searchText.sendKeys('m');
18505                  expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
18506
18507                  searchText.clear();
18508                  searchText.sendKeys('76');
18509                  expectFriendNames(['John', 'Julie'], 'friend');
18510                });
18511
18512                it('should search in specific fields when filtering with a predicate object', function() {
18513                  var searchAny = element(by.model('search.$'));
18514                  searchAny.clear();
18515                  searchAny.sendKeys('i');
18516                  expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
18517                });
18518                it('should use a equal comparison when comparator is true', function() {
18519                  var searchName = element(by.model('search.name'));
18520                  var strict = element(by.model('strict'));
18521                  searchName.clear();
18522                  searchName.sendKeys('Julie');
18523                  strict.click();
18524                  expectFriendNames(['Julie'], 'friendObj');
18525                });
18526              </file>
18527            </example>
18528          */
18529         function filterFilter() {
18530           return function(array, expression, comparator) {
18531             if (!isArrayLike(array)) {
18532               if (array == null) {
18533                 return array;
18534               } else {
18535                 throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
18536               }
18537             }
18538
18539             var expressionType = getTypeForFilter(expression);
18540             var predicateFn;
18541             var matchAgainstAnyProp;
18542
18543             switch (expressionType) {
18544               case 'function':
18545                 predicateFn = expression;
18546                 break;
18547               case 'boolean':
18548               case 'null':
18549               case 'number':
18550               case 'string':
18551                 matchAgainstAnyProp = true;
18552                 //jshint -W086
18553               case 'object':
18554                 //jshint +W086
18555                 predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
18556                 break;
18557               default:
18558                 return array;
18559             }
18560
18561             return Array.prototype.filter.call(array, predicateFn);
18562           };
18563         }
18564
18565         // Helper functions for `filterFilter`
18566         function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
18567           var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
18568           var predicateFn;
18569
18570           if (comparator === true) {
18571             comparator = equals;
18572           } else if (!isFunction(comparator)) {
18573             comparator = function(actual, expected) {
18574               if (isUndefined(actual)) {
18575                 // No substring matching against `undefined`
18576                 return false;
18577               }
18578               if ((actual === null) || (expected === null)) {
18579                 // No substring matching against `null`; only match against `null`
18580                 return actual === expected;
18581               }
18582               if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
18583                 // Should not compare primitives against objects, unless they have custom `toString` method
18584                 return false;
18585               }
18586
18587               actual = lowercase('' + actual);
18588               expected = lowercase('' + expected);
18589               return actual.indexOf(expected) !== -1;
18590             };
18591           }
18592
18593           predicateFn = function(item) {
18594             if (shouldMatchPrimitives && !isObject(item)) {
18595               return deepCompare(item, expression.$, comparator, false);
18596             }
18597             return deepCompare(item, expression, comparator, matchAgainstAnyProp);
18598           };
18599
18600           return predicateFn;
18601         }
18602
18603         function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
18604           var actualType = getTypeForFilter(actual);
18605           var expectedType = getTypeForFilter(expected);
18606
18607           if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
18608             return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
18609           } else if (isArray(actual)) {
18610             // In case `actual` is an array, consider it a match
18611             // if ANY of it's items matches `expected`
18612             return actual.some(function(item) {
18613               return deepCompare(item, expected, comparator, matchAgainstAnyProp);
18614             });
18615           }
18616
18617           switch (actualType) {
18618             case 'object':
18619               var key;
18620               if (matchAgainstAnyProp) {
18621                 for (key in actual) {
18622                   if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
18623                     return true;
18624                   }
18625                 }
18626                 return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
18627               } else if (expectedType === 'object') {
18628                 for (key in expected) {
18629                   var expectedVal = expected[key];
18630                   if (isFunction(expectedVal) || isUndefined(expectedVal)) {
18631                     continue;
18632                   }
18633
18634                   var matchAnyProperty = key === '$';
18635                   var actualVal = matchAnyProperty ? actual : actual[key];
18636                   if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
18637                     return false;
18638                   }
18639                 }
18640                 return true;
18641               } else {
18642                 return comparator(actual, expected);
18643               }
18644               break;
18645             case 'function':
18646               return false;
18647             default:
18648               return comparator(actual, expected);
18649           }
18650         }
18651
18652         // Used for easily differentiating between `null` and actual `object`
18653         function getTypeForFilter(val) {
18654           return (val === null) ? 'null' : typeof val;
18655         }
18656
18657         /**
18658          * @ngdoc filter
18659          * @name currency
18660          * @kind function
18661          *
18662          * @description
18663          * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
18664          * symbol for current locale is used.
18665          *
18666          * @param {number} amount Input to filter.
18667          * @param {string=} symbol Currency symbol or identifier to be displayed.
18668          * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
18669          * @returns {string} Formatted number.
18670          *
18671          *
18672          * @example
18673            <example module="currencyExample">
18674              <file name="index.html">
18675                <script>
18676                  angular.module('currencyExample', [])
18677                    .controller('ExampleController', ['$scope', function($scope) {
18678                      $scope.amount = 1234.56;
18679                    }]);
18680                </script>
18681                <div ng-controller="ExampleController">
18682                  <input type="number" ng-model="amount" aria-label="amount"> <br>
18683                  default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
18684                  custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
18685                  no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
18686                </div>
18687              </file>
18688              <file name="protractor.js" type="protractor">
18689                it('should init with 1234.56', function() {
18690                  expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
18691                  expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
18692                  expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
18693                });
18694                it('should update', function() {
18695                  if (browser.params.browser == 'safari') {
18696                    // Safari does not understand the minus key. See
18697                    // https://github.com/angular/protractor/issues/481
18698                    return;
18699                  }
18700                  element(by.model('amount')).clear();
18701                  element(by.model('amount')).sendKeys('-1234');
18702                  expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
18703                  expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
18704                  expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
18705                });
18706              </file>
18707            </example>
18708          */
18709         currencyFilter.$inject = ['$locale'];
18710         function currencyFilter($locale) {
18711           var formats = $locale.NUMBER_FORMATS;
18712           return function(amount, currencySymbol, fractionSize) {
18713             if (isUndefined(currencySymbol)) {
18714               currencySymbol = formats.CURRENCY_SYM;
18715             }
18716
18717             if (isUndefined(fractionSize)) {
18718               fractionSize = formats.PATTERNS[1].maxFrac;
18719             }
18720
18721             // if null or undefined pass it through
18722             return (amount == null)
18723                 ? amount
18724                 : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
18725                     replace(/\u00A4/g, currencySymbol);
18726           };
18727         }
18728
18729         /**
18730          * @ngdoc filter
18731          * @name number
18732          * @kind function
18733          *
18734          * @description
18735          * Formats a number as text.
18736          *
18737          * If the input is null or undefined, it will just be returned.
18738          * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
18739          * If the input is not a number an empty string is returned.
18740          *
18741          *
18742          * @param {number|string} number Number to format.
18743          * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
18744          * If this is not provided then the fraction size is computed from the current locale's number
18745          * formatting pattern. In the case of the default locale, it will be 3.
18746          * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
18747          *
18748          * @example
18749            <example module="numberFilterExample">
18750              <file name="index.html">
18751                <script>
18752                  angular.module('numberFilterExample', [])
18753                    .controller('ExampleController', ['$scope', function($scope) {
18754                      $scope.val = 1234.56789;
18755                    }]);
18756                </script>
18757                <div ng-controller="ExampleController">
18758                  <label>Enter number: <input ng-model='val'></label><br>
18759                  Default formatting: <span id='number-default'>{{val | number}}</span><br>
18760                  No fractions: <span>{{val | number:0}}</span><br>
18761                  Negative number: <span>{{-val | number:4}}</span>
18762                </div>
18763              </file>
18764              <file name="protractor.js" type="protractor">
18765                it('should format numbers', function() {
18766                  expect(element(by.id('number-default')).getText()).toBe('1,234.568');
18767                  expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
18768                  expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
18769                });
18770
18771                it('should update', function() {
18772                  element(by.model('val')).clear();
18773                  element(by.model('val')).sendKeys('3374.333');
18774                  expect(element(by.id('number-default')).getText()).toBe('3,374.333');
18775                  expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
18776                  expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
18777               });
18778              </file>
18779            </example>
18780          */
18781
18782
18783         numberFilter.$inject = ['$locale'];
18784         function numberFilter($locale) {
18785           var formats = $locale.NUMBER_FORMATS;
18786           return function(number, fractionSize) {
18787
18788             // if null or undefined pass it through
18789             return (number == null)
18790                 ? number
18791                 : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
18792                                fractionSize);
18793           };
18794         }
18795
18796         var DECIMAL_SEP = '.';
18797         function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18798           if (isObject(number)) return '';
18799
18800           var isNegative = number < 0;
18801           number = Math.abs(number);
18802
18803           var isInfinity = number === Infinity;
18804           if (!isInfinity && !isFinite(number)) return '';
18805
18806           var numStr = number + '',
18807               formatedText = '',
18808               hasExponent = false,
18809               parts = [];
18810
18811           if (isInfinity) formatedText = '\u221e';
18812
18813           if (!isInfinity && numStr.indexOf('e') !== -1) {
18814             var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
18815             if (match && match[2] == '-' && match[3] > fractionSize + 1) {
18816               number = 0;
18817             } else {
18818               formatedText = numStr;
18819               hasExponent = true;
18820             }
18821           }
18822
18823           if (!isInfinity && !hasExponent) {
18824             var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
18825
18826             // determine fractionSize if it is not specified
18827             if (isUndefined(fractionSize)) {
18828               fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
18829             }
18830
18831             // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
18832             // inspired by:
18833             // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
18834             number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
18835
18836             var fraction = ('' + number).split(DECIMAL_SEP);
18837             var whole = fraction[0];
18838             fraction = fraction[1] || '';
18839
18840             var i, pos = 0,
18841                 lgroup = pattern.lgSize,
18842                 group = pattern.gSize;
18843
18844             if (whole.length >= (lgroup + group)) {
18845               pos = whole.length - lgroup;
18846               for (i = 0; i < pos; i++) {
18847                 if ((pos - i) % group === 0 && i !== 0) {
18848                   formatedText += groupSep;
18849                 }
18850                 formatedText += whole.charAt(i);
18851               }
18852             }
18853
18854             for (i = pos; i < whole.length; i++) {
18855               if ((whole.length - i) % lgroup === 0 && i !== 0) {
18856                 formatedText += groupSep;
18857               }
18858               formatedText += whole.charAt(i);
18859             }
18860
18861             // format fraction part.
18862             while (fraction.length < fractionSize) {
18863               fraction += '0';
18864             }
18865
18866             if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
18867           } else {
18868             if (fractionSize > 0 && number < 1) {
18869               formatedText = number.toFixed(fractionSize);
18870               number = parseFloat(formatedText);
18871               formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
18872             }
18873           }
18874
18875           if (number === 0) {
18876             isNegative = false;
18877           }
18878
18879           parts.push(isNegative ? pattern.negPre : pattern.posPre,
18880                      formatedText,
18881                      isNegative ? pattern.negSuf : pattern.posSuf);
18882           return parts.join('');
18883         }
18884
18885         function padNumber(num, digits, trim) {
18886           var neg = '';
18887           if (num < 0) {
18888             neg =  '-';
18889             num = -num;
18890           }
18891           num = '' + num;
18892           while (num.length < digits) num = '0' + num;
18893           if (trim) {
18894             num = num.substr(num.length - digits);
18895           }
18896           return neg + num;
18897         }
18898
18899
18900         function dateGetter(name, size, offset, trim) {
18901           offset = offset || 0;
18902           return function(date) {
18903             var value = date['get' + name]();
18904             if (offset > 0 || value > -offset) {
18905               value += offset;
18906             }
18907             if (value === 0 && offset == -12) value = 12;
18908             return padNumber(value, size, trim);
18909           };
18910         }
18911
18912         function dateStrGetter(name, shortForm) {
18913           return function(date, formats) {
18914             var value = date['get' + name]();
18915             var get = uppercase(shortForm ? ('SHORT' + name) : name);
18916
18917             return formats[get][value];
18918           };
18919         }
18920
18921         function timeZoneGetter(date, formats, offset) {
18922           var zone = -1 * offset;
18923           var paddedZone = (zone >= 0) ? "+" : "";
18924
18925           paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
18926                         padNumber(Math.abs(zone % 60), 2);
18927
18928           return paddedZone;
18929         }
18930
18931         function getFirstThursdayOfYear(year) {
18932             // 0 = index of January
18933             var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
18934             // 4 = index of Thursday (+1 to account for 1st = 5)
18935             // 11 = index of *next* Thursday (+1 account for 1st = 12)
18936             return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
18937         }
18938
18939         function getThursdayThisWeek(datetime) {
18940             return new Date(datetime.getFullYear(), datetime.getMonth(),
18941               // 4 = index of Thursday
18942               datetime.getDate() + (4 - datetime.getDay()));
18943         }
18944
18945         function weekGetter(size) {
18946            return function(date) {
18947               var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
18948                  thisThurs = getThursdayThisWeek(date);
18949
18950               var diff = +thisThurs - +firstThurs,
18951                  result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
18952
18953               return padNumber(result, size);
18954            };
18955         }
18956
18957         function ampmGetter(date, formats) {
18958           return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
18959         }
18960
18961         function eraGetter(date, formats) {
18962           return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
18963         }
18964
18965         function longEraGetter(date, formats) {
18966           return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
18967         }
18968
18969         var DATE_FORMATS = {
18970           yyyy: dateGetter('FullYear', 4),
18971             yy: dateGetter('FullYear', 2, 0, true),
18972              y: dateGetter('FullYear', 1),
18973           MMMM: dateStrGetter('Month'),
18974            MMM: dateStrGetter('Month', true),
18975             MM: dateGetter('Month', 2, 1),
18976              M: dateGetter('Month', 1, 1),
18977             dd: dateGetter('Date', 2),
18978              d: dateGetter('Date', 1),
18979             HH: dateGetter('Hours', 2),
18980              H: dateGetter('Hours', 1),
18981             hh: dateGetter('Hours', 2, -12),
18982              h: dateGetter('Hours', 1, -12),
18983             mm: dateGetter('Minutes', 2),
18984              m: dateGetter('Minutes', 1),
18985             ss: dateGetter('Seconds', 2),
18986              s: dateGetter('Seconds', 1),
18987              // while ISO 8601 requires fractions to be prefixed with `.` or `,`
18988              // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
18989            sss: dateGetter('Milliseconds', 3),
18990           EEEE: dateStrGetter('Day'),
18991            EEE: dateStrGetter('Day', true),
18992              a: ampmGetter,
18993              Z: timeZoneGetter,
18994             ww: weekGetter(2),
18995              w: weekGetter(1),
18996              G: eraGetter,
18997              GG: eraGetter,
18998              GGG: eraGetter,
18999              GGGG: longEraGetter
19000         };
19001
19002         var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
19003             NUMBER_STRING = /^\-?\d+$/;
19004
19005         /**
19006          * @ngdoc filter
19007          * @name date
19008          * @kind function
19009          *
19010          * @description
19011          *   Formats `date` to a string based on the requested `format`.
19012          *
19013          *   `format` string can be composed of the following elements:
19014          *
19015          *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
19016          *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
19017          *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
19018          *   * `'MMMM'`: Month in year (January-December)
19019          *   * `'MMM'`: Month in year (Jan-Dec)
19020          *   * `'MM'`: Month in year, padded (01-12)
19021          *   * `'M'`: Month in year (1-12)
19022          *   * `'dd'`: Day in month, padded (01-31)
19023          *   * `'d'`: Day in month (1-31)
19024          *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
19025          *   * `'EEE'`: Day in Week, (Sun-Sat)
19026          *   * `'HH'`: Hour in day, padded (00-23)
19027          *   * `'H'`: Hour in day (0-23)
19028          *   * `'hh'`: Hour in AM/PM, padded (01-12)
19029          *   * `'h'`: Hour in AM/PM, (1-12)
19030          *   * `'mm'`: Minute in hour, padded (00-59)
19031          *   * `'m'`: Minute in hour (0-59)
19032          *   * `'ss'`: Second in minute, padded (00-59)
19033          *   * `'s'`: Second in minute (0-59)
19034          *   * `'sss'`: Millisecond in second, padded (000-999)
19035          *   * `'a'`: AM/PM marker
19036          *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
19037          *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
19038          *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
19039          *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
19040          *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
19041          *
19042          *   `format` string can also be one of the following predefined
19043          *   {@link guide/i18n localizable formats}:
19044          *
19045          *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
19046          *     (e.g. Sep 3, 2010 12:05:08 PM)
19047          *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
19048          *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
19049          *     (e.g. Friday, September 3, 2010)
19050          *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
19051          *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
19052          *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
19053          *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
19054          *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
19055          *
19056          *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
19057          *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
19058          *   (e.g. `"h 'o''clock'"`).
19059          *
19060          * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
19061          *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
19062          *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
19063          *    specified in the string input, the time is considered to be in the local timezone.
19064          * @param {string=} format Formatting rules (see Description). If not specified,
19065          *    `mediumDate` is used.
19066          * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
19067          *    continental US time zone abbreviations, but for general use, use a time zone offset, for
19068          *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
19069          *    If not specified, the timezone of the browser will be used.
19070          * @returns {string} Formatted string or the input if input is not recognized as date/millis.
19071          *
19072          * @example
19073            <example>
19074              <file name="index.html">
19075                <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
19076                    <span>{{1288323623006 | date:'medium'}}</span><br>
19077                <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
19078                   <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
19079                <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
19080                   <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
19081                <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
19082                   <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
19083              </file>
19084              <file name="protractor.js" type="protractor">
19085                it('should format date', function() {
19086                  expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
19087                     toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
19088                  expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
19089                     toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
19090                  expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
19091                     toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
19092                  expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
19093                     toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
19094                });
19095              </file>
19096            </example>
19097          */
19098         dateFilter.$inject = ['$locale'];
19099         function dateFilter($locale) {
19100
19101
19102           var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
19103                              // 1        2       3         4          5          6          7          8  9     10      11
19104           function jsonStringToDate(string) {
19105             var match;
19106             if (match = string.match(R_ISO8601_STR)) {
19107               var date = new Date(0),
19108                   tzHour = 0,
19109                   tzMin  = 0,
19110                   dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
19111                   timeSetter = match[8] ? date.setUTCHours : date.setHours;
19112
19113               if (match[9]) {
19114                 tzHour = toInt(match[9] + match[10]);
19115                 tzMin = toInt(match[9] + match[11]);
19116               }
19117               dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
19118               var h = toInt(match[4] || 0) - tzHour;
19119               var m = toInt(match[5] || 0) - tzMin;
19120               var s = toInt(match[6] || 0);
19121               var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
19122               timeSetter.call(date, h, m, s, ms);
19123               return date;
19124             }
19125             return string;
19126           }
19127
19128
19129           return function(date, format, timezone) {
19130             var text = '',
19131                 parts = [],
19132                 fn, match;
19133
19134             format = format || 'mediumDate';
19135             format = $locale.DATETIME_FORMATS[format] || format;
19136             if (isString(date)) {
19137               date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
19138             }
19139
19140             if (isNumber(date)) {
19141               date = new Date(date);
19142             }
19143
19144             if (!isDate(date) || !isFinite(date.getTime())) {
19145               return date;
19146             }
19147
19148             while (format) {
19149               match = DATE_FORMATS_SPLIT.exec(format);
19150               if (match) {
19151                 parts = concat(parts, match, 1);
19152                 format = parts.pop();
19153               } else {
19154                 parts.push(format);
19155                 format = null;
19156               }
19157             }
19158
19159             var dateTimezoneOffset = date.getTimezoneOffset();
19160             if (timezone) {
19161               dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
19162               date = convertTimezoneToLocal(date, timezone, true);
19163             }
19164             forEach(parts, function(value) {
19165               fn = DATE_FORMATS[value];
19166               text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
19167                          : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
19168             });
19169
19170             return text;
19171           };
19172         }
19173
19174
19175         /**
19176          * @ngdoc filter
19177          * @name json
19178          * @kind function
19179          *
19180          * @description
19181          *   Allows you to convert a JavaScript object into JSON string.
19182          *
19183          *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
19184          *   the binding is automatically converted to JSON.
19185          *
19186          * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
19187          * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
19188          * @returns {string} JSON string.
19189          *
19190          *
19191          * @example
19192            <example>
19193              <file name="index.html">
19194                <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
19195                <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
19196              </file>
19197              <file name="protractor.js" type="protractor">
19198                it('should jsonify filtered objects', function() {
19199                  expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
19200                  expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
19201                });
19202              </file>
19203            </example>
19204          *
19205          */
19206         function jsonFilter() {
19207           return function(object, spacing) {
19208             if (isUndefined(spacing)) {
19209                 spacing = 2;
19210             }
19211             return toJson(object, spacing);
19212           };
19213         }
19214
19215
19216         /**
19217          * @ngdoc filter
19218          * @name lowercase
19219          * @kind function
19220          * @description
19221          * Converts string to lowercase.
19222          * @see angular.lowercase
19223          */
19224         var lowercaseFilter = valueFn(lowercase);
19225
19226
19227         /**
19228          * @ngdoc filter
19229          * @name uppercase
19230          * @kind function
19231          * @description
19232          * Converts string to uppercase.
19233          * @see angular.uppercase
19234          */
19235         var uppercaseFilter = valueFn(uppercase);
19236
19237         /**
19238          * @ngdoc filter
19239          * @name limitTo
19240          * @kind function
19241          *
19242          * @description
19243          * Creates a new array or string containing only a specified number of elements. The elements
19244          * are taken from either the beginning or the end of the source array, string or number, as specified by
19245          * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
19246          * converted to a string.
19247          *
19248          * @param {Array|string|number} input Source array, string or number to be limited.
19249          * @param {string|number} limit The length of the returned array or string. If the `limit` number
19250          *     is positive, `limit` number of items from the beginning of the source array/string are copied.
19251          *     If the number is negative, `limit` number  of items from the end of the source array/string
19252          *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
19253          *     the input will be returned unchanged.
19254          * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
19255          *     indicates an offset from the end of `input`. Defaults to `0`.
19256          * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
19257          *     had less than `limit` elements.
19258          *
19259          * @example
19260            <example module="limitToExample">
19261              <file name="index.html">
19262                <script>
19263                  angular.module('limitToExample', [])
19264                    .controller('ExampleController', ['$scope', function($scope) {
19265                      $scope.numbers = [1,2,3,4,5,6,7,8,9];
19266                      $scope.letters = "abcdefghi";
19267                      $scope.longNumber = 2345432342;
19268                      $scope.numLimit = 3;
19269                      $scope.letterLimit = 3;
19270                      $scope.longNumberLimit = 3;
19271                    }]);
19272                </script>
19273                <div ng-controller="ExampleController">
19274                  <label>
19275                     Limit {{numbers}} to:
19276                     <input type="number" step="1" ng-model="numLimit">
19277                  </label>
19278                  <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
19279                  <label>
19280                     Limit {{letters}} to:
19281                     <input type="number" step="1" ng-model="letterLimit">
19282                  </label>
19283                  <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
19284                  <label>
19285                     Limit {{longNumber}} to:
19286                     <input type="number" step="1" ng-model="longNumberLimit">
19287                  </label>
19288                  <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
19289                </div>
19290              </file>
19291              <file name="protractor.js" type="protractor">
19292                var numLimitInput = element(by.model('numLimit'));
19293                var letterLimitInput = element(by.model('letterLimit'));
19294                var longNumberLimitInput = element(by.model('longNumberLimit'));
19295                var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
19296                var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
19297                var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
19298
19299                it('should limit the number array to first three items', function() {
19300                  expect(numLimitInput.getAttribute('value')).toBe('3');
19301                  expect(letterLimitInput.getAttribute('value')).toBe('3');
19302                  expect(longNumberLimitInput.getAttribute('value')).toBe('3');
19303                  expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
19304                  expect(limitedLetters.getText()).toEqual('Output letters: abc');
19305                  expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
19306                });
19307
19308                // There is a bug in safari and protractor that doesn't like the minus key
19309                // it('should update the output when -3 is entered', function() {
19310                //   numLimitInput.clear();
19311                //   numLimitInput.sendKeys('-3');
19312                //   letterLimitInput.clear();
19313                //   letterLimitInput.sendKeys('-3');
19314                //   longNumberLimitInput.clear();
19315                //   longNumberLimitInput.sendKeys('-3');
19316                //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
19317                //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
19318                //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
19319                // });
19320
19321                it('should not exceed the maximum size of input array', function() {
19322                  numLimitInput.clear();
19323                  numLimitInput.sendKeys('100');
19324                  letterLimitInput.clear();
19325                  letterLimitInput.sendKeys('100');
19326                  longNumberLimitInput.clear();
19327                  longNumberLimitInput.sendKeys('100');
19328                  expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
19329                  expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
19330                  expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
19331                });
19332              </file>
19333            </example>
19334         */
19335         function limitToFilter() {
19336           return function(input, limit, begin) {
19337             if (Math.abs(Number(limit)) === Infinity) {
19338               limit = Number(limit);
19339             } else {
19340               limit = toInt(limit);
19341             }
19342             if (isNaN(limit)) return input;
19343
19344             if (isNumber(input)) input = input.toString();
19345             if (!isArray(input) && !isString(input)) return input;
19346
19347             begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
19348             begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
19349
19350             if (limit >= 0) {
19351               return input.slice(begin, begin + limit);
19352             } else {
19353               if (begin === 0) {
19354                 return input.slice(limit, input.length);
19355               } else {
19356                 return input.slice(Math.max(0, begin + limit), begin);
19357               }
19358             }
19359           };
19360         }
19361
19362         /**
19363          * @ngdoc filter
19364          * @name orderBy
19365          * @kind function
19366          *
19367          * @description
19368          * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
19369          * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
19370          * as expected, make sure they are actually being saved as numbers and not strings.
19371          *
19372          * @param {Array} array The array to sort.
19373          * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
19374          *    used by the comparator to determine the order of elements.
19375          *
19376          *    Can be one of:
19377          *
19378          *    - `function`: Getter function. The result of this function will be sorted using the
19379          *      `<`, `===`, `>` operator.
19380          *    - `string`: An Angular expression. The result of this expression is used to compare elements
19381          *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
19382          *      3 first characters of a property called `name`). The result of a constant expression
19383          *      is interpreted as a property name to be used in comparisons (for example `"special name"`
19384          *      to sort object by the value of their `special name` property). An expression can be
19385          *      optionally prefixed with `+` or `-` to control ascending or descending sort order
19386          *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
19387          *      element itself is used to compare where sorting.
19388          *    - `Array`: An array of function or string predicates. The first predicate in the array
19389          *      is used for sorting, but when two items are equivalent, the next predicate is used.
19390          *
19391          *    If the predicate is missing or empty then it defaults to `'+'`.
19392          *
19393          * @param {boolean=} reverse Reverse the order of the array.
19394          * @returns {Array} Sorted copy of the source array.
19395          *
19396          *
19397          * @example
19398          * The example below demonstrates a simple ngRepeat, where the data is sorted
19399          * by age in descending order (predicate is set to `'-age'`).
19400          * `reverse` is not set, which means it defaults to `false`.
19401            <example module="orderByExample">
19402              <file name="index.html">
19403                <script>
19404                  angular.module('orderByExample', [])
19405                    .controller('ExampleController', ['$scope', function($scope) {
19406                      $scope.friends =
19407                          [{name:'John', phone:'555-1212', age:10},
19408                           {name:'Mary', phone:'555-9876', age:19},
19409                           {name:'Mike', phone:'555-4321', age:21},
19410                           {name:'Adam', phone:'555-5678', age:35},
19411                           {name:'Julie', phone:'555-8765', age:29}];
19412                    }]);
19413                </script>
19414                <div ng-controller="ExampleController">
19415                  <table class="friend">
19416                    <tr>
19417                      <th>Name</th>
19418                      <th>Phone Number</th>
19419                      <th>Age</th>
19420                    </tr>
19421                    <tr ng-repeat="friend in friends | orderBy:'-age'">
19422                      <td>{{friend.name}}</td>
19423                      <td>{{friend.phone}}</td>
19424                      <td>{{friend.age}}</td>
19425                    </tr>
19426                  </table>
19427                </div>
19428              </file>
19429            </example>
19430          *
19431          * The predicate and reverse parameters can be controlled dynamically through scope properties,
19432          * as shown in the next example.
19433          * @example
19434            <example module="orderByExample">
19435              <file name="index.html">
19436                <script>
19437                  angular.module('orderByExample', [])
19438                    .controller('ExampleController', ['$scope', function($scope) {
19439                      $scope.friends =
19440                          [{name:'John', phone:'555-1212', age:10},
19441                           {name:'Mary', phone:'555-9876', age:19},
19442                           {name:'Mike', phone:'555-4321', age:21},
19443                           {name:'Adam', phone:'555-5678', age:35},
19444                           {name:'Julie', phone:'555-8765', age:29}];
19445                      $scope.predicate = 'age';
19446                      $scope.reverse = true;
19447                      $scope.order = function(predicate) {
19448                        $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
19449                        $scope.predicate = predicate;
19450                      };
19451                    }]);
19452                </script>
19453                <style type="text/css">
19454                  .sortorder:after {
19455                    content: '\25b2';
19456                  }
19457                  .sortorder.reverse:after {
19458                    content: '\25bc';
19459                  }
19460                </style>
19461                <div ng-controller="ExampleController">
19462                  <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
19463                  <hr/>
19464                  [ <a href="" ng-click="predicate=''">unsorted</a> ]
19465                  <table class="friend">
19466                    <tr>
19467                      <th>
19468                        <a href="" ng-click="order('name')">Name</a>
19469                        <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
19470                      </th>
19471                      <th>
19472                        <a href="" ng-click="order('phone')">Phone Number</a>
19473                        <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
19474                      </th>
19475                      <th>
19476                        <a href="" ng-click="order('age')">Age</a>
19477                        <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
19478                      </th>
19479                    </tr>
19480                    <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19481                      <td>{{friend.name}}</td>
19482                      <td>{{friend.phone}}</td>
19483                      <td>{{friend.age}}</td>
19484                    </tr>
19485                  </table>
19486                </div>
19487              </file>
19488            </example>
19489          *
19490          * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
19491          * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
19492          * desired parameters.
19493          *
19494          * Example:
19495          *
19496          * @example
19497           <example module="orderByExample">
19498             <file name="index.html">
19499               <div ng-controller="ExampleController">
19500                 <table class="friend">
19501                   <tr>
19502                     <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
19503                       (<a href="" ng-click="order('-name',false)">^</a>)</th>
19504                     <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
19505                     <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
19506                   </tr>
19507                   <tr ng-repeat="friend in friends">
19508                     <td>{{friend.name}}</td>
19509                     <td>{{friend.phone}}</td>
19510                     <td>{{friend.age}}</td>
19511                   </tr>
19512                 </table>
19513               </div>
19514             </file>
19515
19516             <file name="script.js">
19517               angular.module('orderByExample', [])
19518                 .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
19519                   var orderBy = $filter('orderBy');
19520                   $scope.friends = [
19521                     { name: 'John',    phone: '555-1212',    age: 10 },
19522                     { name: 'Mary',    phone: '555-9876',    age: 19 },
19523                     { name: 'Mike',    phone: '555-4321',    age: 21 },
19524                     { name: 'Adam',    phone: '555-5678',    age: 35 },
19525                     { name: 'Julie',   phone: '555-8765',    age: 29 }
19526                   ];
19527                   $scope.order = function(predicate, reverse) {
19528                     $scope.friends = orderBy($scope.friends, predicate, reverse);
19529                   };
19530                   $scope.order('-age',false);
19531                 }]);
19532             </file>
19533         </example>
19534          */
19535         orderByFilter.$inject = ['$parse'];
19536         function orderByFilter($parse) {
19537           return function(array, sortPredicate, reverseOrder) {
19538
19539             if (!(isArrayLike(array))) return array;
19540
19541             if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
19542             if (sortPredicate.length === 0) { sortPredicate = ['+']; }
19543
19544             var predicates = processPredicates(sortPredicate, reverseOrder);
19545             // Add a predicate at the end that evaluates to the element index. This makes the
19546             // sort stable as it works as a tie-breaker when all the input predicates cannot
19547             // distinguish between two elements.
19548             predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
19549
19550             // The next three lines are a version of a Swartzian Transform idiom from Perl
19551             // (sometimes called the Decorate-Sort-Undecorate idiom)
19552             // See https://en.wikipedia.org/wiki/Schwartzian_transform
19553             var compareValues = Array.prototype.map.call(array, getComparisonObject);
19554             compareValues.sort(doComparison);
19555             array = compareValues.map(function(item) { return item.value; });
19556
19557             return array;
19558
19559             function getComparisonObject(value, index) {
19560               return {
19561                 value: value,
19562                 predicateValues: predicates.map(function(predicate) {
19563                   return getPredicateValue(predicate.get(value), index);
19564                 })
19565               };
19566             }
19567
19568             function doComparison(v1, v2) {
19569               var result = 0;
19570               for (var index=0, length = predicates.length; index < length; ++index) {
19571                 result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
19572                 if (result) break;
19573               }
19574               return result;
19575             }
19576           };
19577
19578           function processPredicates(sortPredicate, reverseOrder) {
19579             reverseOrder = reverseOrder ? -1 : 1;
19580             return sortPredicate.map(function(predicate) {
19581               var descending = 1, get = identity;
19582
19583               if (isFunction(predicate)) {
19584                 get = predicate;
19585               } else if (isString(predicate)) {
19586                 if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
19587                   descending = predicate.charAt(0) == '-' ? -1 : 1;
19588                   predicate = predicate.substring(1);
19589                 }
19590                 if (predicate !== '') {
19591                   get = $parse(predicate);
19592                   if (get.constant) {
19593                     var key = get();
19594                     get = function(value) { return value[key]; };
19595                   }
19596                 }
19597               }
19598               return { get: get, descending: descending * reverseOrder };
19599             });
19600           }
19601
19602           function isPrimitive(value) {
19603             switch (typeof value) {
19604               case 'number': /* falls through */
19605               case 'boolean': /* falls through */
19606               case 'string':
19607                 return true;
19608               default:
19609                 return false;
19610             }
19611           }
19612
19613           function objectValue(value, index) {
19614             // If `valueOf` is a valid function use that
19615             if (typeof value.valueOf === 'function') {
19616               value = value.valueOf();
19617               if (isPrimitive(value)) return value;
19618             }
19619             // If `toString` is a valid function and not the one from `Object.prototype` use that
19620             if (hasCustomToString(value)) {
19621               value = value.toString();
19622               if (isPrimitive(value)) return value;
19623             }
19624             // We have a basic object so we use the position of the object in the collection
19625             return index;
19626           }
19627
19628           function getPredicateValue(value, index) {
19629             var type = typeof value;
19630             if (value === null) {
19631               type = 'string';
19632               value = 'null';
19633             } else if (type === 'string') {
19634               value = value.toLowerCase();
19635             } else if (type === 'object') {
19636               value = objectValue(value, index);
19637             }
19638             return { value: value, type: type };
19639           }
19640
19641           function compare(v1, v2) {
19642             var result = 0;
19643             if (v1.type === v2.type) {
19644               if (v1.value !== v2.value) {
19645                 result = v1.value < v2.value ? -1 : 1;
19646               }
19647             } else {
19648               result = v1.type < v2.type ? -1 : 1;
19649             }
19650             return result;
19651           }
19652         }
19653
19654         function ngDirective(directive) {
19655           if (isFunction(directive)) {
19656             directive = {
19657               link: directive
19658             };
19659           }
19660           directive.restrict = directive.restrict || 'AC';
19661           return valueFn(directive);
19662         }
19663
19664         /**
19665          * @ngdoc directive
19666          * @name a
19667          * @restrict E
19668          *
19669          * @description
19670          * Modifies the default behavior of the html A tag so that the default action is prevented when
19671          * the href attribute is empty.
19672          *
19673          * This change permits the easy creation of action links with the `ngClick` directive
19674          * without changing the location or causing page reloads, e.g.:
19675          * `<a href="" ng-click="list.addItem()">Add Item</a>`
19676          */
19677         var htmlAnchorDirective = valueFn({
19678           restrict: 'E',
19679           compile: function(element, attr) {
19680             if (!attr.href && !attr.xlinkHref) {
19681               return function(scope, element) {
19682                 // If the linked element is not an anchor tag anymore, do nothing
19683                 if (element[0].nodeName.toLowerCase() !== 'a') return;
19684
19685                 // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
19686                 var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
19687                            'xlink:href' : 'href';
19688                 element.on('click', function(event) {
19689                   // if we have no href url, then don't navigate anywhere.
19690                   if (!element.attr(href)) {
19691                     event.preventDefault();
19692                   }
19693                 });
19694               };
19695             }
19696           }
19697         });
19698
19699         /**
19700          * @ngdoc directive
19701          * @name ngHref
19702          * @restrict A
19703          * @priority 99
19704          *
19705          * @description
19706          * Using Angular markup like `{{hash}}` in an href attribute will
19707          * make the link go to the wrong URL if the user clicks it before
19708          * Angular has a chance to replace the `{{hash}}` markup with its
19709          * value. Until Angular replaces the markup the link will be broken
19710          * and will most likely return a 404 error. The `ngHref` directive
19711          * solves this problem.
19712          *
19713          * The wrong way to write it:
19714          * ```html
19715          * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19716          * ```
19717          *
19718          * The correct way to write it:
19719          * ```html
19720          * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19721          * ```
19722          *
19723          * @element A
19724          * @param {template} ngHref any string which can contain `{{}}` markup.
19725          *
19726          * @example
19727          * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
19728          * in links and their different behaviors:
19729             <example>
19730               <file name="index.html">
19731                 <input ng-model="value" /><br />
19732                 <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
19733                 <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
19734                 <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
19735                 <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
19736                 <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
19737                 <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
19738               </file>
19739               <file name="protractor.js" type="protractor">
19740                 it('should execute ng-click but not reload when href without value', function() {
19741                   element(by.id('link-1')).click();
19742                   expect(element(by.model('value')).getAttribute('value')).toEqual('1');
19743                   expect(element(by.id('link-1')).getAttribute('href')).toBe('');
19744                 });
19745
19746                 it('should execute ng-click but not reload when href empty string', function() {
19747                   element(by.id('link-2')).click();
19748                   expect(element(by.model('value')).getAttribute('value')).toEqual('2');
19749                   expect(element(by.id('link-2')).getAttribute('href')).toBe('');
19750                 });
19751
19752                 it('should execute ng-click and change url when ng-href specified', function() {
19753                   expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
19754
19755                   element(by.id('link-3')).click();
19756
19757                   // At this point, we navigate away from an Angular page, so we need
19758                   // to use browser.driver to get the base webdriver.
19759
19760                   browser.wait(function() {
19761                     return browser.driver.getCurrentUrl().then(function(url) {
19762                       return url.match(/\/123$/);
19763                     });
19764                   }, 5000, 'page should navigate to /123');
19765                 });
19766
19767                 it('should execute ng-click but not reload when href empty string and name specified', function() {
19768                   element(by.id('link-4')).click();
19769                   expect(element(by.model('value')).getAttribute('value')).toEqual('4');
19770                   expect(element(by.id('link-4')).getAttribute('href')).toBe('');
19771                 });
19772
19773                 it('should execute ng-click but not reload when no href but name specified', function() {
19774                   element(by.id('link-5')).click();
19775                   expect(element(by.model('value')).getAttribute('value')).toEqual('5');
19776                   expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
19777                 });
19778
19779                 it('should only change url when only ng-href', function() {
19780                   element(by.model('value')).clear();
19781                   element(by.model('value')).sendKeys('6');
19782                   expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
19783
19784                   element(by.id('link-6')).click();
19785
19786                   // At this point, we navigate away from an Angular page, so we need
19787                   // to use browser.driver to get the base webdriver.
19788                   browser.wait(function() {
19789                     return browser.driver.getCurrentUrl().then(function(url) {
19790                       return url.match(/\/6$/);
19791                     });
19792                   }, 5000, 'page should navigate to /6');
19793                 });
19794               </file>
19795             </example>
19796          */
19797
19798         /**
19799          * @ngdoc directive
19800          * @name ngSrc
19801          * @restrict A
19802          * @priority 99
19803          *
19804          * @description
19805          * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
19806          * work right: The browser will fetch from the URL with the literal
19807          * text `{{hash}}` until Angular replaces the expression inside
19808          * `{{hash}}`. The `ngSrc` directive solves this problem.
19809          *
19810          * The buggy way to write it:
19811          * ```html
19812          * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
19813          * ```
19814          *
19815          * The correct way to write it:
19816          * ```html
19817          * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
19818          * ```
19819          *
19820          * @element IMG
19821          * @param {template} ngSrc any string which can contain `{{}}` markup.
19822          */
19823
19824         /**
19825          * @ngdoc directive
19826          * @name ngSrcset
19827          * @restrict A
19828          * @priority 99
19829          *
19830          * @description
19831          * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
19832          * work right: The browser will fetch from the URL with the literal
19833          * text `{{hash}}` until Angular replaces the expression inside
19834          * `{{hash}}`. The `ngSrcset` directive solves this problem.
19835          *
19836          * The buggy way to write it:
19837          * ```html
19838          * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
19839          * ```
19840          *
19841          * The correct way to write it:
19842          * ```html
19843          * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
19844          * ```
19845          *
19846          * @element IMG
19847          * @param {template} ngSrcset any string which can contain `{{}}` markup.
19848          */
19849
19850         /**
19851          * @ngdoc directive
19852          * @name ngDisabled
19853          * @restrict A
19854          * @priority 100
19855          *
19856          * @description
19857          *
19858          * This directive sets the `disabled` attribute on the element if the
19859          * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
19860          *
19861          * A special directive is necessary because we cannot use interpolation inside the `disabled`
19862          * attribute.  The following example would make the button enabled on Chrome/Firefox
19863          * but not on older IEs:
19864          *
19865          * ```html
19866          * <!-- See below for an example of ng-disabled being used correctly -->
19867          * <div ng-init="isDisabled = false">
19868          *  <button disabled="{{isDisabled}}">Disabled</button>
19869          * </div>
19870          * ```
19871          *
19872          * This is because the HTML specification does not require browsers to preserve the values of
19873          * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
19874          * If we put an Angular interpolation expression into such an attribute then the
19875          * binding information would be lost when the browser removes the attribute.
19876          *
19877          * @example
19878             <example>
19879               <file name="index.html">
19880                 <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
19881                 <button ng-model="button" ng-disabled="checked">Button</button>
19882               </file>
19883               <file name="protractor.js" type="protractor">
19884                 it('should toggle button', function() {
19885                   expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
19886                   element(by.model('checked')).click();
19887                   expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
19888                 });
19889               </file>
19890             </example>
19891          *
19892          * @element INPUT
19893          * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
19894          *     then the `disabled` attribute will be set on the element
19895          */
19896
19897
19898         /**
19899          * @ngdoc directive
19900          * @name ngChecked
19901          * @restrict A
19902          * @priority 100
19903          *
19904          * @description
19905          * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
19906          *
19907          * Note that this directive should not be used together with {@link ngModel `ngModel`},
19908          * as this can lead to unexpected behavior.
19909          *
19910          * ### Why do we need `ngChecked`?
19911          *
19912          * The HTML specification does not require browsers to preserve the values of boolean attributes
19913          * such as checked. (Their presence means true and their absence means false.)
19914          * If we put an Angular interpolation expression into such an attribute then the
19915          * binding information would be lost when the browser removes the attribute.
19916          * The `ngChecked` directive solves this problem for the `checked` attribute.
19917          * This complementary directive is not removed by the browser and so provides
19918          * a permanent reliable place to store the binding information.
19919          * @example
19920             <example>
19921               <file name="index.html">
19922                 <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
19923                 <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
19924               </file>
19925               <file name="protractor.js" type="protractor">
19926                 it('should check both checkBoxes', function() {
19927                   expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
19928                   element(by.model('master')).click();
19929                   expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
19930                 });
19931               </file>
19932             </example>
19933          *
19934          * @element INPUT
19935          * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
19936          *     then the `checked` attribute will be set on the element
19937          */
19938
19939
19940         /**
19941          * @ngdoc directive
19942          * @name ngReadonly
19943          * @restrict A
19944          * @priority 100
19945          *
19946          * @description
19947          * The HTML specification does not require browsers to preserve the values of boolean attributes
19948          * such as readonly. (Their presence means true and their absence means false.)
19949          * If we put an Angular interpolation expression into such an attribute then the
19950          * binding information would be lost when the browser removes the attribute.
19951          * The `ngReadonly` directive solves this problem for the `readonly` attribute.
19952          * This complementary directive is not removed by the browser and so provides
19953          * a permanent reliable place to store the binding information.
19954          * @example
19955             <example>
19956               <file name="index.html">
19957                 <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
19958                 <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
19959               </file>
19960               <file name="protractor.js" type="protractor">
19961                 it('should toggle readonly attr', function() {
19962                   expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
19963                   element(by.model('checked')).click();
19964                   expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
19965                 });
19966               </file>
19967             </example>
19968          *
19969          * @element INPUT
19970          * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
19971          *     then special attribute "readonly" will be set on the element
19972          */
19973
19974
19975         /**
19976          * @ngdoc directive
19977          * @name ngSelected
19978          * @restrict A
19979          * @priority 100
19980          *
19981          * @description
19982          * The HTML specification does not require browsers to preserve the values of boolean attributes
19983          * such as selected. (Their presence means true and their absence means false.)
19984          * If we put an Angular interpolation expression into such an attribute then the
19985          * binding information would be lost when the browser removes the attribute.
19986          * The `ngSelected` directive solves this problem for the `selected` attribute.
19987          * This complementary directive is not removed by the browser and so provides
19988          * a permanent reliable place to store the binding information.
19989          *
19990          * @example
19991             <example>
19992               <file name="index.html">
19993                 <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
19994                 <select aria-label="ngSelected demo">
19995                   <option>Hello!</option>
19996                   <option id="greet" ng-selected="selected">Greetings!</option>
19997                 </select>
19998               </file>
19999               <file name="protractor.js" type="protractor">
20000                 it('should select Greetings!', function() {
20001                   expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
20002                   element(by.model('selected')).click();
20003                   expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
20004                 });
20005               </file>
20006             </example>
20007          *
20008          * @element OPTION
20009          * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
20010          *     then special attribute "selected" will be set on the element
20011          */
20012
20013         /**
20014          * @ngdoc directive
20015          * @name ngOpen
20016          * @restrict A
20017          * @priority 100
20018          *
20019          * @description
20020          * The HTML specification does not require browsers to preserve the values of boolean attributes
20021          * such as open. (Their presence means true and their absence means false.)
20022          * If we put an Angular interpolation expression into such an attribute then the
20023          * binding information would be lost when the browser removes the attribute.
20024          * The `ngOpen` directive solves this problem for the `open` attribute.
20025          * This complementary directive is not removed by the browser and so provides
20026          * a permanent reliable place to store the binding information.
20027          * @example
20028              <example>
20029                <file name="index.html">
20030                  <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
20031                  <details id="details" ng-open="open">
20032                     <summary>Show/Hide me</summary>
20033                  </details>
20034                </file>
20035                <file name="protractor.js" type="protractor">
20036                  it('should toggle open', function() {
20037                    expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
20038                    element(by.model('open')).click();
20039                    expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
20040                  });
20041                </file>
20042              </example>
20043          *
20044          * @element DETAILS
20045          * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
20046          *     then special attribute "open" will be set on the element
20047          */
20048
20049         var ngAttributeAliasDirectives = {};
20050
20051         // boolean attrs are evaluated
20052         forEach(BOOLEAN_ATTR, function(propName, attrName) {
20053           // binding to multiple is not supported
20054           if (propName == "multiple") return;
20055
20056           function defaultLinkFn(scope, element, attr) {
20057             scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
20058               attr.$set(attrName, !!value);
20059             });
20060           }
20061
20062           var normalized = directiveNormalize('ng-' + attrName);
20063           var linkFn = defaultLinkFn;
20064
20065           if (propName === 'checked') {
20066             linkFn = function(scope, element, attr) {
20067               // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
20068               if (attr.ngModel !== attr[normalized]) {
20069                 defaultLinkFn(scope, element, attr);
20070               }
20071             };
20072           }
20073
20074           ngAttributeAliasDirectives[normalized] = function() {
20075             return {
20076               restrict: 'A',
20077               priority: 100,
20078               link: linkFn
20079             };
20080           };
20081         });
20082
20083         // aliased input attrs are evaluated
20084         forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
20085           ngAttributeAliasDirectives[ngAttr] = function() {
20086             return {
20087               priority: 100,
20088               link: function(scope, element, attr) {
20089                 //special case ngPattern when a literal regular expression value
20090                 //is used as the expression (this way we don't have to watch anything).
20091                 if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
20092                   var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
20093                   if (match) {
20094                     attr.$set("ngPattern", new RegExp(match[1], match[2]));
20095                     return;
20096                   }
20097                 }
20098
20099                 scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
20100                   attr.$set(ngAttr, value);
20101                 });
20102               }
20103             };
20104           };
20105         });
20106
20107         // ng-src, ng-srcset, ng-href are interpolated
20108         forEach(['src', 'srcset', 'href'], function(attrName) {
20109           var normalized = directiveNormalize('ng-' + attrName);
20110           ngAttributeAliasDirectives[normalized] = function() {
20111             return {
20112               priority: 99, // it needs to run after the attributes are interpolated
20113               link: function(scope, element, attr) {
20114                 var propName = attrName,
20115                     name = attrName;
20116
20117                 if (attrName === 'href' &&
20118                     toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
20119                   name = 'xlinkHref';
20120                   attr.$attr[name] = 'xlink:href';
20121                   propName = null;
20122                 }
20123
20124                 attr.$observe(normalized, function(value) {
20125                   if (!value) {
20126                     if (attrName === 'href') {
20127                       attr.$set(name, null);
20128                     }
20129                     return;
20130                   }
20131
20132                   attr.$set(name, value);
20133
20134                   // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
20135                   // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
20136                   // to set the property as well to achieve the desired effect.
20137                   // we use attr[attrName] value since $set can sanitize the url.
20138                   if (msie && propName) element.prop(propName, attr[name]);
20139                 });
20140               }
20141             };
20142           };
20143         });
20144
20145         /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
20146          */
20147         var nullFormCtrl = {
20148           $addControl: noop,
20149           $$renameControl: nullFormRenameControl,
20150           $removeControl: noop,
20151           $setValidity: noop,
20152           $setDirty: noop,
20153           $setPristine: noop,
20154           $setSubmitted: noop
20155         },
20156         SUBMITTED_CLASS = 'ng-submitted';
20157
20158         function nullFormRenameControl(control, name) {
20159           control.$name = name;
20160         }
20161
20162         /**
20163          * @ngdoc type
20164          * @name form.FormController
20165          *
20166          * @property {boolean} $pristine True if user has not interacted with the form yet.
20167          * @property {boolean} $dirty True if user has already interacted with the form.
20168          * @property {boolean} $valid True if all of the containing forms and controls are valid.
20169          * @property {boolean} $invalid True if at least one containing control or form is invalid.
20170          * @property {boolean} $pending True if at least one containing control or form is pending.
20171          * @property {boolean} $submitted True if user has submitted the form even if its invalid.
20172          *
20173          * @property {Object} $error Is an object hash, containing references to controls or
20174          *  forms with failing validators, where:
20175          *
20176          *  - keys are validation tokens (error names),
20177          *  - values are arrays of controls or forms that have a failing validator for given error name.
20178          *
20179          *  Built-in validation tokens:
20180          *
20181          *  - `email`
20182          *  - `max`
20183          *  - `maxlength`
20184          *  - `min`
20185          *  - `minlength`
20186          *  - `number`
20187          *  - `pattern`
20188          *  - `required`
20189          *  - `url`
20190          *  - `date`
20191          *  - `datetimelocal`
20192          *  - `time`
20193          *  - `week`
20194          *  - `month`
20195          *
20196          * @description
20197          * `FormController` keeps track of all its controls and nested forms as well as the state of them,
20198          * such as being valid/invalid or dirty/pristine.
20199          *
20200          * Each {@link ng.directive:form form} directive creates an instance
20201          * of `FormController`.
20202          *
20203          */
20204         //asks for $scope to fool the BC controller module
20205         FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
20206         function FormController(element, attrs, $scope, $animate, $interpolate) {
20207           var form = this,
20208               controls = [];
20209
20210           // init state
20211           form.$error = {};
20212           form.$$success = {};
20213           form.$pending = undefined;
20214           form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
20215           form.$dirty = false;
20216           form.$pristine = true;
20217           form.$valid = true;
20218           form.$invalid = false;
20219           form.$submitted = false;
20220           form.$$parentForm = nullFormCtrl;
20221
20222           /**
20223            * @ngdoc method
20224            * @name form.FormController#$rollbackViewValue
20225            *
20226            * @description
20227            * Rollback all form controls pending updates to the `$modelValue`.
20228            *
20229            * Updates may be pending by a debounced event or because the input is waiting for a some future
20230            * event defined in `ng-model-options`. This method is typically needed by the reset button of
20231            * a form that uses `ng-model-options` to pend updates.
20232            */
20233           form.$rollbackViewValue = function() {
20234             forEach(controls, function(control) {
20235               control.$rollbackViewValue();
20236             });
20237           };
20238
20239           /**
20240            * @ngdoc method
20241            * @name form.FormController#$commitViewValue
20242            *
20243            * @description
20244            * Commit all form controls pending updates to the `$modelValue`.
20245            *
20246            * Updates may be pending by a debounced event or because the input is waiting for a some future
20247            * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
20248            * usually handles calling this in response to input events.
20249            */
20250           form.$commitViewValue = function() {
20251             forEach(controls, function(control) {
20252               control.$commitViewValue();
20253             });
20254           };
20255
20256           /**
20257            * @ngdoc method
20258            * @name form.FormController#$addControl
20259            * @param {object} control control object, either a {@link form.FormController} or an
20260            * {@link ngModel.NgModelController}
20261            *
20262            * @description
20263            * Register a control with the form. Input elements using ngModelController do this automatically
20264            * when they are linked.
20265            *
20266            * Note that the current state of the control will not be reflected on the new parent form. This
20267            * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
20268            * state.
20269            *
20270            * However, if the method is used programmatically, for example by adding dynamically created controls,
20271            * or controls that have been previously removed without destroying their corresponding DOM element,
20272            * it's the developers responsiblity to make sure the current state propagates to the parent form.
20273            *
20274            * For example, if an input control is added that is already `$dirty` and has `$error` properties,
20275            * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
20276            */
20277           form.$addControl = function(control) {
20278             // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
20279             // and not added to the scope.  Now we throw an error.
20280             assertNotHasOwnProperty(control.$name, 'input');
20281             controls.push(control);
20282
20283             if (control.$name) {
20284               form[control.$name] = control;
20285             }
20286
20287             control.$$parentForm = form;
20288           };
20289
20290           // Private API: rename a form control
20291           form.$$renameControl = function(control, newName) {
20292             var oldName = control.$name;
20293
20294             if (form[oldName] === control) {
20295               delete form[oldName];
20296             }
20297             form[newName] = control;
20298             control.$name = newName;
20299           };
20300
20301           /**
20302            * @ngdoc method
20303            * @name form.FormController#$removeControl
20304            * @param {object} control control object, either a {@link form.FormController} or an
20305            * {@link ngModel.NgModelController}
20306            *
20307            * @description
20308            * Deregister a control from the form.
20309            *
20310            * Input elements using ngModelController do this automatically when they are destroyed.
20311            *
20312            * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
20313            * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
20314            * different from case to case. For example, removing the only `$dirty` control from a form may or
20315            * may not mean that the form is still `$dirty`.
20316            */
20317           form.$removeControl = function(control) {
20318             if (control.$name && form[control.$name] === control) {
20319               delete form[control.$name];
20320             }
20321             forEach(form.$pending, function(value, name) {
20322               form.$setValidity(name, null, control);
20323             });
20324             forEach(form.$error, function(value, name) {
20325               form.$setValidity(name, null, control);
20326             });
20327             forEach(form.$$success, function(value, name) {
20328               form.$setValidity(name, null, control);
20329             });
20330
20331             arrayRemove(controls, control);
20332             control.$$parentForm = nullFormCtrl;
20333           };
20334
20335
20336           /**
20337            * @ngdoc method
20338            * @name form.FormController#$setValidity
20339            *
20340            * @description
20341            * Sets the validity of a form control.
20342            *
20343            * This method will also propagate to parent forms.
20344            */
20345           addSetValidityMethod({
20346             ctrl: this,
20347             $element: element,
20348             set: function(object, property, controller) {
20349               var list = object[property];
20350               if (!list) {
20351                 object[property] = [controller];
20352               } else {
20353                 var index = list.indexOf(controller);
20354                 if (index === -1) {
20355                   list.push(controller);
20356                 }
20357               }
20358             },
20359             unset: function(object, property, controller) {
20360               var list = object[property];
20361               if (!list) {
20362                 return;
20363               }
20364               arrayRemove(list, controller);
20365               if (list.length === 0) {
20366                 delete object[property];
20367               }
20368             },
20369             $animate: $animate
20370           });
20371
20372           /**
20373            * @ngdoc method
20374            * @name form.FormController#$setDirty
20375            *
20376            * @description
20377            * Sets the form to a dirty state.
20378            *
20379            * This method can be called to add the 'ng-dirty' class and set the form to a dirty
20380            * state (ng-dirty class). This method will also propagate to parent forms.
20381            */
20382           form.$setDirty = function() {
20383             $animate.removeClass(element, PRISTINE_CLASS);
20384             $animate.addClass(element, DIRTY_CLASS);
20385             form.$dirty = true;
20386             form.$pristine = false;
20387             form.$$parentForm.$setDirty();
20388           };
20389
20390           /**
20391            * @ngdoc method
20392            * @name form.FormController#$setPristine
20393            *
20394            * @description
20395            * Sets the form to its pristine state.
20396            *
20397            * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
20398            * state (ng-pristine class). This method will also propagate to all the controls contained
20399            * in this form.
20400            *
20401            * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
20402            * saving or resetting it.
20403            */
20404           form.$setPristine = function() {
20405             $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
20406             form.$dirty = false;
20407             form.$pristine = true;
20408             form.$submitted = false;
20409             forEach(controls, function(control) {
20410               control.$setPristine();
20411             });
20412           };
20413
20414           /**
20415            * @ngdoc method
20416            * @name form.FormController#$setUntouched
20417            *
20418            * @description
20419            * Sets the form to its untouched state.
20420            *
20421            * This method can be called to remove the 'ng-touched' class and set the form controls to their
20422            * untouched state (ng-untouched class).
20423            *
20424            * Setting a form controls back to their untouched state is often useful when setting the form
20425            * back to its pristine state.
20426            */
20427           form.$setUntouched = function() {
20428             forEach(controls, function(control) {
20429               control.$setUntouched();
20430             });
20431           };
20432
20433           /**
20434            * @ngdoc method
20435            * @name form.FormController#$setSubmitted
20436            *
20437            * @description
20438            * Sets the form to its submitted state.
20439            */
20440           form.$setSubmitted = function() {
20441             $animate.addClass(element, SUBMITTED_CLASS);
20442             form.$submitted = true;
20443             form.$$parentForm.$setSubmitted();
20444           };
20445         }
20446
20447         /**
20448          * @ngdoc directive
20449          * @name ngForm
20450          * @restrict EAC
20451          *
20452          * @description
20453          * Nestable alias of {@link ng.directive:form `form`} directive. HTML
20454          * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
20455          * sub-group of controls needs to be determined.
20456          *
20457          * Note: the purpose of `ngForm` is to group controls,
20458          * but not to be a replacement for the `<form>` tag with all of its capabilities
20459          * (e.g. posting to the server, ...).
20460          *
20461          * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
20462          *                       related scope, under this name.
20463          *
20464          */
20465
20466          /**
20467          * @ngdoc directive
20468          * @name form
20469          * @restrict E
20470          *
20471          * @description
20472          * Directive that instantiates
20473          * {@link form.FormController FormController}.
20474          *
20475          * If the `name` attribute is specified, the form controller is published onto the current scope under
20476          * this name.
20477          *
20478          * # Alias: {@link ng.directive:ngForm `ngForm`}
20479          *
20480          * In Angular, forms can be nested. This means that the outer form is valid when all of the child
20481          * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
20482          * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
20483          * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
20484          * using Angular validation directives in forms that are dynamically generated using the
20485          * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
20486          * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
20487          * `ngForm` directive and nest these in an outer `form` element.
20488          *
20489          *
20490          * # CSS classes
20491          *  - `ng-valid` is set if the form is valid.
20492          *  - `ng-invalid` is set if the form is invalid.
20493          *  - `ng-pending` is set if the form is pending.
20494          *  - `ng-pristine` is set if the form is pristine.
20495          *  - `ng-dirty` is set if the form is dirty.
20496          *  - `ng-submitted` is set if the form was submitted.
20497          *
20498          * Keep in mind that ngAnimate can detect each of these classes when added and removed.
20499          *
20500          *
20501          * # Submitting a form and preventing the default action
20502          *
20503          * Since the role of forms in client-side Angular applications is different than in classical
20504          * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
20505          * page reload that sends the data to the server. Instead some javascript logic should be triggered
20506          * to handle the form submission in an application-specific way.
20507          *
20508          * For this reason, Angular prevents the default action (form submission to the server) unless the
20509          * `<form>` element has an `action` attribute specified.
20510          *
20511          * You can use one of the following two ways to specify what javascript method should be called when
20512          * a form is submitted:
20513          *
20514          * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
20515          * - {@link ng.directive:ngClick ngClick} directive on the first
20516           *  button or input field of type submit (input[type=submit])
20517          *
20518          * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
20519          * or {@link ng.directive:ngClick ngClick} directives.
20520          * This is because of the following form submission rules in the HTML specification:
20521          *
20522          * - If a form has only one input field then hitting enter in this field triggers form submit
20523          * (`ngSubmit`)
20524          * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
20525          * doesn't trigger submit
20526          * - if a form has one or more input fields and one or more buttons or input[type=submit] then
20527          * hitting enter in any of the input fields will trigger the click handler on the *first* button or
20528          * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
20529          *
20530          * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
20531          * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
20532          * to have access to the updated model.
20533          *
20534          * ## Animation Hooks
20535          *
20536          * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
20537          * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
20538          * other validations that are performed within the form. Animations in ngForm are similar to how
20539          * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
20540          * as JS animations.
20541          *
20542          * The following example shows a simple way to utilize CSS transitions to style a form element
20543          * that has been rendered as invalid after it has been validated:
20544          *
20545          * <pre>
20546          * //be sure to include ngAnimate as a module to hook into more
20547          * //advanced animations
20548          * .my-form {
20549          *   transition:0.5s linear all;
20550          *   background: white;
20551          * }
20552          * .my-form.ng-invalid {
20553          *   background: red;
20554          *   color:white;
20555          * }
20556          * </pre>
20557          *
20558          * @example
20559             <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
20560               <file name="index.html">
20561                <script>
20562                  angular.module('formExample', [])
20563                    .controller('FormController', ['$scope', function($scope) {
20564                      $scope.userType = 'guest';
20565                    }]);
20566                </script>
20567                <style>
20568                 .my-form {
20569                   transition:all linear 0.5s;
20570                   background: transparent;
20571                 }
20572                 .my-form.ng-invalid {
20573                   background: red;
20574                 }
20575                </style>
20576                <form name="myForm" ng-controller="FormController" class="my-form">
20577                  userType: <input name="input" ng-model="userType" required>
20578                  <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
20579                  <code>userType = {{userType}}</code><br>
20580                  <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
20581                  <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
20582                  <code>myForm.$valid = {{myForm.$valid}}</code><br>
20583                  <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
20584                 </form>
20585               </file>
20586               <file name="protractor.js" type="protractor">
20587                 it('should initialize to model', function() {
20588                   var userType = element(by.binding('userType'));
20589                   var valid = element(by.binding('myForm.input.$valid'));
20590
20591                   expect(userType.getText()).toContain('guest');
20592                   expect(valid.getText()).toContain('true');
20593                 });
20594
20595                 it('should be invalid if empty', function() {
20596                   var userType = element(by.binding('userType'));
20597                   var valid = element(by.binding('myForm.input.$valid'));
20598                   var userInput = element(by.model('userType'));
20599
20600                   userInput.clear();
20601                   userInput.sendKeys('');
20602
20603                   expect(userType.getText()).toEqual('userType =');
20604                   expect(valid.getText()).toContain('false');
20605                 });
20606               </file>
20607             </example>
20608          *
20609          * @param {string=} name Name of the form. If specified, the form controller will be published into
20610          *                       related scope, under this name.
20611          */
20612         var formDirectiveFactory = function(isNgForm) {
20613           return ['$timeout', '$parse', function($timeout, $parse) {
20614             var formDirective = {
20615               name: 'form',
20616               restrict: isNgForm ? 'EAC' : 'E',
20617               require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
20618               controller: FormController,
20619               compile: function ngFormCompile(formElement, attr) {
20620                 // Setup initial state of the control
20621                 formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
20622
20623                 var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
20624
20625                 return {
20626                   pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
20627                     var controller = ctrls[0];
20628
20629                     // if `action` attr is not present on the form, prevent the default action (submission)
20630                     if (!('action' in attr)) {
20631                       // we can't use jq events because if a form is destroyed during submission the default
20632                       // action is not prevented. see #1238
20633                       //
20634                       // IE 9 is not affected because it doesn't fire a submit event and try to do a full
20635                       // page reload if the form was destroyed by submission of the form via a click handler
20636                       // on a button in the form. Looks like an IE9 specific bug.
20637                       var handleFormSubmission = function(event) {
20638                         scope.$apply(function() {
20639                           controller.$commitViewValue();
20640                           controller.$setSubmitted();
20641                         });
20642
20643                         event.preventDefault();
20644                       };
20645
20646                       addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20647
20648                       // unregister the preventDefault listener so that we don't not leak memory but in a
20649                       // way that will achieve the prevention of the default action.
20650                       formElement.on('$destroy', function() {
20651                         $timeout(function() {
20652                           removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20653                         }, 0, false);
20654                       });
20655                     }
20656
20657                     var parentFormCtrl = ctrls[1] || controller.$$parentForm;
20658                     parentFormCtrl.$addControl(controller);
20659
20660                     var setter = nameAttr ? getSetter(controller.$name) : noop;
20661
20662                     if (nameAttr) {
20663                       setter(scope, controller);
20664                       attr.$observe(nameAttr, function(newValue) {
20665                         if (controller.$name === newValue) return;
20666                         setter(scope, undefined);
20667                         controller.$$parentForm.$$renameControl(controller, newValue);
20668                         setter = getSetter(controller.$name);
20669                         setter(scope, controller);
20670                       });
20671                     }
20672                     formElement.on('$destroy', function() {
20673                       controller.$$parentForm.$removeControl(controller);
20674                       setter(scope, undefined);
20675                       extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
20676                     });
20677                   }
20678                 };
20679               }
20680             };
20681
20682             return formDirective;
20683
20684             function getSetter(expression) {
20685               if (expression === '') {
20686                 //create an assignable expression, so forms with an empty name can be renamed later
20687                 return $parse('this[""]').assign;
20688               }
20689               return $parse(expression).assign || noop;
20690             }
20691           }];
20692         };
20693
20694         var formDirective = formDirectiveFactory();
20695         var ngFormDirective = formDirectiveFactory(true);
20696
20697         /* global VALID_CLASS: false,
20698           INVALID_CLASS: false,
20699           PRISTINE_CLASS: false,
20700           DIRTY_CLASS: false,
20701           UNTOUCHED_CLASS: false,
20702           TOUCHED_CLASS: false,
20703           ngModelMinErr: false,
20704         */
20705
20706         // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20707         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)/;
20708         // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
20709         var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
20710         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;
20711         var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
20712         var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
20713         var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20714         var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
20715         var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
20716         var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20717
20718         var inputType = {
20719
20720           /**
20721            * @ngdoc input
20722            * @name input[text]
20723            *
20724            * @description
20725            * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
20726            *
20727            *
20728            * @param {string} ngModel Assignable angular expression to data-bind to.
20729            * @param {string=} name Property name of the form under which the control is published.
20730            * @param {string=} required Adds `required` validation error key if the value is not entered.
20731            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20732            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20733            *    `required` when you want to data-bind to the `required` attribute.
20734            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20735            *    minlength.
20736            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20737            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20738            *    any length.
20739            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20740            *    that contains the regular expression body that will be converted to a regular expression
20741            *    as in the ngPattern directive.
20742            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20743            *    a RegExp found by evaluating the Angular expression given in the attribute value.
20744            *    If the expression evaluates to a RegExp object, then this is used directly.
20745            *    If the expression evaluates to a string, then it will be converted to a RegExp
20746            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20747            *    `new RegExp('^abc$')`.<br />
20748            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20749            *    start at the index of the last search's match, thus not taking the whole input value into
20750            *    account.
20751            * @param {string=} ngChange Angular expression to be executed when input changes due to user
20752            *    interaction with the input element.
20753            * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20754            *    This parameter is ignored for input[type=password] controls, which will never trim the
20755            *    input.
20756            *
20757            * @example
20758               <example name="text-input-directive" module="textInputExample">
20759                 <file name="index.html">
20760                  <script>
20761                    angular.module('textInputExample', [])
20762                      .controller('ExampleController', ['$scope', function($scope) {
20763                        $scope.example = {
20764                          text: 'guest',
20765                          word: /^\s*\w*\s*$/
20766                        };
20767                      }]);
20768                  </script>
20769                  <form name="myForm" ng-controller="ExampleController">
20770                    <label>Single word:
20771                      <input type="text" name="input" ng-model="example.text"
20772                             ng-pattern="example.word" required ng-trim="false">
20773                    </label>
20774                    <div role="alert">
20775                      <span class="error" ng-show="myForm.input.$error.required">
20776                        Required!</span>
20777                      <span class="error" ng-show="myForm.input.$error.pattern">
20778                        Single word only!</span>
20779                    </div>
20780                    <tt>text = {{example.text}}</tt><br/>
20781                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20782                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20783                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20784                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20785                   </form>
20786                 </file>
20787                 <file name="protractor.js" type="protractor">
20788                   var text = element(by.binding('example.text'));
20789                   var valid = element(by.binding('myForm.input.$valid'));
20790                   var input = element(by.model('example.text'));
20791
20792                   it('should initialize to model', function() {
20793                     expect(text.getText()).toContain('guest');
20794                     expect(valid.getText()).toContain('true');
20795                   });
20796
20797                   it('should be invalid if empty', function() {
20798                     input.clear();
20799                     input.sendKeys('');
20800
20801                     expect(text.getText()).toEqual('text =');
20802                     expect(valid.getText()).toContain('false');
20803                   });
20804
20805                   it('should be invalid if multi word', function() {
20806                     input.clear();
20807                     input.sendKeys('hello world');
20808
20809                     expect(valid.getText()).toContain('false');
20810                   });
20811                 </file>
20812               </example>
20813            */
20814           'text': textInputType,
20815
20816             /**
20817              * @ngdoc input
20818              * @name input[date]
20819              *
20820              * @description
20821              * Input with date validation and transformation. In browsers that do not yet support
20822              * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
20823              * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
20824              * modern browsers do not yet support this input type, it is important to provide cues to users on the
20825              * expected input format via a placeholder or label.
20826              *
20827              * The model must always be a Date object, otherwise Angular will throw an error.
20828              * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20829              *
20830              * The timezone to be used to read/write the `Date` instance in the model can be defined using
20831              * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20832              *
20833              * @param {string} ngModel Assignable angular expression to data-bind to.
20834              * @param {string=} name Property name of the form under which the control is published.
20835              * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20836              *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20837              *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
20838              *   constraint validation.
20839              * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20840              *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
20841              *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
20842              *   constraint validation.
20843              * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
20844              *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20845              * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
20846              *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20847              * @param {string=} required Sets `required` validation error key if the value is not entered.
20848              * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20849              *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20850              *    `required` when you want to data-bind to the `required` attribute.
20851              * @param {string=} ngChange Angular expression to be executed when input changes due to user
20852              *    interaction with the input element.
20853              *
20854              * @example
20855              <example name="date-input-directive" module="dateInputExample">
20856              <file name="index.html">
20857                <script>
20858                   angular.module('dateInputExample', [])
20859                     .controller('DateController', ['$scope', function($scope) {
20860                       $scope.example = {
20861                         value: new Date(2013, 9, 22)
20862                       };
20863                     }]);
20864                </script>
20865                <form name="myForm" ng-controller="DateController as dateCtrl">
20866                   <label for="exampleInput">Pick a date in 2013:</label>
20867                   <input type="date" id="exampleInput" name="input" ng-model="example.value"
20868                       placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
20869                   <div role="alert">
20870                     <span class="error" ng-show="myForm.input.$error.required">
20871                         Required!</span>
20872                     <span class="error" ng-show="myForm.input.$error.date">
20873                         Not a valid date!</span>
20874                    </div>
20875                    <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
20876                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20877                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20878                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20879                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20880                </form>
20881              </file>
20882              <file name="protractor.js" type="protractor">
20883                 var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
20884                 var valid = element(by.binding('myForm.input.$valid'));
20885                 var input = element(by.model('example.value'));
20886
20887                 // currently protractor/webdriver does not support
20888                 // sending keys to all known HTML5 input controls
20889                 // for various browsers (see https://github.com/angular/protractor/issues/562).
20890                 function setInput(val) {
20891                   // set the value of the element and force validation.
20892                   var scr = "var ipt = document.getElementById('exampleInput'); " +
20893                   "ipt.value = '" + val + "';" +
20894                   "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20895                   browser.executeScript(scr);
20896                 }
20897
20898                 it('should initialize to model', function() {
20899                   expect(value.getText()).toContain('2013-10-22');
20900                   expect(valid.getText()).toContain('myForm.input.$valid = true');
20901                 });
20902
20903                 it('should be invalid if empty', function() {
20904                   setInput('');
20905                   expect(value.getText()).toEqual('value =');
20906                   expect(valid.getText()).toContain('myForm.input.$valid = false');
20907                 });
20908
20909                 it('should be invalid if over max', function() {
20910                   setInput('2015-01-01');
20911                   expect(value.getText()).toContain('');
20912                   expect(valid.getText()).toContain('myForm.input.$valid = false');
20913                 });
20914              </file>
20915              </example>
20916              */
20917           'date': createDateInputType('date', DATE_REGEXP,
20918                  createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
20919                  'yyyy-MM-dd'),
20920
20921            /**
20922             * @ngdoc input
20923             * @name input[datetime-local]
20924             *
20925             * @description
20926             * Input with datetime validation and transformation. In browsers that do not yet support
20927             * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20928             * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
20929             *
20930             * The model must always be a Date object, otherwise Angular will throw an error.
20931             * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20932             *
20933             * The timezone to be used to read/write the `Date` instance in the model can be defined using
20934             * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20935             *
20936             * @param {string} ngModel Assignable angular expression to data-bind to.
20937             * @param {string=} name Property name of the form under which the control is published.
20938             * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20939             *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20940             *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20941             *   Note that `min` will also add native HTML5 constraint validation.
20942             * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20943             *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
20944             *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
20945             *   Note that `max` will also add native HTML5 constraint validation.
20946             * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
20947             *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
20948             * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
20949             *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
20950             * @param {string=} required Sets `required` validation error key if the value is not entered.
20951             * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20952             *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20953             *    `required` when you want to data-bind to the `required` attribute.
20954             * @param {string=} ngChange Angular expression to be executed when input changes due to user
20955             *    interaction with the input element.
20956             *
20957             * @example
20958             <example name="datetimelocal-input-directive" module="dateExample">
20959             <file name="index.html">
20960               <script>
20961                 angular.module('dateExample', [])
20962                   .controller('DateController', ['$scope', function($scope) {
20963                     $scope.example = {
20964                       value: new Date(2010, 11, 28, 14, 57)
20965                     };
20966                   }]);
20967               </script>
20968               <form name="myForm" ng-controller="DateController as dateCtrl">
20969                 <label for="exampleInput">Pick a date between in 2013:</label>
20970                 <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
20971                     placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
20972                 <div role="alert">
20973                   <span class="error" ng-show="myForm.input.$error.required">
20974                       Required!</span>
20975                   <span class="error" ng-show="myForm.input.$error.datetimelocal">
20976                       Not a valid date!</span>
20977                 </div>
20978                 <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
20979                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20980                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20981                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20982                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20983               </form>
20984             </file>
20985             <file name="protractor.js" type="protractor">
20986               var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
20987               var valid = element(by.binding('myForm.input.$valid'));
20988               var input = element(by.model('example.value'));
20989
20990               // currently protractor/webdriver does not support
20991               // sending keys to all known HTML5 input controls
20992               // for various browsers (https://github.com/angular/protractor/issues/562).
20993               function setInput(val) {
20994                 // set the value of the element and force validation.
20995                 var scr = "var ipt = document.getElementById('exampleInput'); " +
20996                 "ipt.value = '" + val + "';" +
20997                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20998                 browser.executeScript(scr);
20999               }
21000
21001               it('should initialize to model', function() {
21002                 expect(value.getText()).toContain('2010-12-28T14:57:00');
21003                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21004               });
21005
21006               it('should be invalid if empty', function() {
21007                 setInput('');
21008                 expect(value.getText()).toEqual('value =');
21009                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21010               });
21011
21012               it('should be invalid if over max', function() {
21013                 setInput('2015-01-01T23:59:00');
21014                 expect(value.getText()).toContain('');
21015                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21016               });
21017             </file>
21018             </example>
21019             */
21020           'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
21021               createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
21022               'yyyy-MM-ddTHH:mm:ss.sss'),
21023
21024           /**
21025            * @ngdoc input
21026            * @name input[time]
21027            *
21028            * @description
21029            * Input with time validation and transformation. In browsers that do not yet support
21030            * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21031            * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
21032            * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
21033            *
21034            * The model must always be a Date object, otherwise Angular will throw an error.
21035            * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21036            *
21037            * The timezone to be used to read/write the `Date` instance in the model can be defined using
21038            * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21039            *
21040            * @param {string} ngModel Assignable angular expression to data-bind to.
21041            * @param {string=} name Property name of the form under which the control is published.
21042            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21043            *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
21044            *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
21045            *   native HTML5 constraint validation.
21046            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21047            *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
21048            *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
21049            *   native HTML5 constraint validation.
21050            * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
21051            *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21052            * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
21053            *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21054            * @param {string=} required Sets `required` validation error key if the value is not entered.
21055            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21056            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21057            *    `required` when you want to data-bind to the `required` attribute.
21058            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21059            *    interaction with the input element.
21060            *
21061            * @example
21062            <example name="time-input-directive" module="timeExample">
21063            <file name="index.html">
21064              <script>
21065               angular.module('timeExample', [])
21066                 .controller('DateController', ['$scope', function($scope) {
21067                   $scope.example = {
21068                     value: new Date(1970, 0, 1, 14, 57, 0)
21069                   };
21070                 }]);
21071              </script>
21072              <form name="myForm" ng-controller="DateController as dateCtrl">
21073                 <label for="exampleInput">Pick a between 8am and 5pm:</label>
21074                 <input type="time" id="exampleInput" name="input" ng-model="example.value"
21075                     placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
21076                 <div role="alert">
21077                   <span class="error" ng-show="myForm.input.$error.required">
21078                       Required!</span>
21079                   <span class="error" ng-show="myForm.input.$error.time">
21080                       Not a valid date!</span>
21081                 </div>
21082                 <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
21083                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21084                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21085                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21086                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21087              </form>
21088            </file>
21089            <file name="protractor.js" type="protractor">
21090               var value = element(by.binding('example.value | date: "HH:mm:ss"'));
21091               var valid = element(by.binding('myForm.input.$valid'));
21092               var input = element(by.model('example.value'));
21093
21094               // currently protractor/webdriver does not support
21095               // sending keys to all known HTML5 input controls
21096               // for various browsers (https://github.com/angular/protractor/issues/562).
21097               function setInput(val) {
21098                 // set the value of the element and force validation.
21099                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21100                 "ipt.value = '" + val + "';" +
21101                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21102                 browser.executeScript(scr);
21103               }
21104
21105               it('should initialize to model', function() {
21106                 expect(value.getText()).toContain('14:57:00');
21107                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21108               });
21109
21110               it('should be invalid if empty', function() {
21111                 setInput('');
21112                 expect(value.getText()).toEqual('value =');
21113                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21114               });
21115
21116               it('should be invalid if over max', function() {
21117                 setInput('23:59:00');
21118                 expect(value.getText()).toContain('');
21119                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21120               });
21121            </file>
21122            </example>
21123            */
21124           'time': createDateInputType('time', TIME_REGEXP,
21125               createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
21126              'HH:mm:ss.sss'),
21127
21128            /**
21129             * @ngdoc input
21130             * @name input[week]
21131             *
21132             * @description
21133             * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
21134             * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21135             * week format (yyyy-W##), for example: `2013-W02`.
21136             *
21137             * The model must always be a Date object, otherwise Angular will throw an error.
21138             * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21139             *
21140             * The timezone to be used to read/write the `Date` instance in the model can be defined using
21141             * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21142             *
21143             * @param {string} ngModel Assignable angular expression to data-bind to.
21144             * @param {string=} name Property name of the form under which the control is published.
21145             * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21146             *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21147             *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
21148             *   native HTML5 constraint validation.
21149             * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21150             *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
21151             *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
21152             *   native HTML5 constraint validation.
21153             * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21154             *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21155             * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21156             *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21157             * @param {string=} required Sets `required` validation error key if the value is not entered.
21158             * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21159             *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21160             *    `required` when you want to data-bind to the `required` attribute.
21161             * @param {string=} ngChange Angular expression to be executed when input changes due to user
21162             *    interaction with the input element.
21163             *
21164             * @example
21165             <example name="week-input-directive" module="weekExample">
21166             <file name="index.html">
21167               <script>
21168               angular.module('weekExample', [])
21169                 .controller('DateController', ['$scope', function($scope) {
21170                   $scope.example = {
21171                     value: new Date(2013, 0, 3)
21172                   };
21173                 }]);
21174               </script>
21175               <form name="myForm" ng-controller="DateController as dateCtrl">
21176                 <label>Pick a date between in 2013:
21177                   <input id="exampleInput" type="week" name="input" ng-model="example.value"
21178                          placeholder="YYYY-W##" min="2012-W32"
21179                          max="2013-W52" required />
21180                 </label>
21181                 <div role="alert">
21182                   <span class="error" ng-show="myForm.input.$error.required">
21183                       Required!</span>
21184                   <span class="error" ng-show="myForm.input.$error.week">
21185                       Not a valid date!</span>
21186                 </div>
21187                 <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
21188                 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21189                 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21190                 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21191                 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21192               </form>
21193             </file>
21194             <file name="protractor.js" type="protractor">
21195               var value = element(by.binding('example.value | date: "yyyy-Www"'));
21196               var valid = element(by.binding('myForm.input.$valid'));
21197               var input = element(by.model('example.value'));
21198
21199               // currently protractor/webdriver does not support
21200               // sending keys to all known HTML5 input controls
21201               // for various browsers (https://github.com/angular/protractor/issues/562).
21202               function setInput(val) {
21203                 // set the value of the element and force validation.
21204                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21205                 "ipt.value = '" + val + "';" +
21206                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21207                 browser.executeScript(scr);
21208               }
21209
21210               it('should initialize to model', function() {
21211                 expect(value.getText()).toContain('2013-W01');
21212                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21213               });
21214
21215               it('should be invalid if empty', function() {
21216                 setInput('');
21217                 expect(value.getText()).toEqual('value =');
21218                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21219               });
21220
21221               it('should be invalid if over max', function() {
21222                 setInput('2015-W01');
21223                 expect(value.getText()).toContain('');
21224                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21225               });
21226             </file>
21227             </example>
21228             */
21229           'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
21230
21231           /**
21232            * @ngdoc input
21233            * @name input[month]
21234            *
21235            * @description
21236            * Input with month validation and transformation. In browsers that do not yet support
21237            * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
21238            * month format (yyyy-MM), for example: `2009-01`.
21239            *
21240            * The model must always be a Date object, otherwise Angular will throw an error.
21241            * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
21242            * If the model is not set to the first of the month, the next view to model update will set it
21243            * to the first of the month.
21244            *
21245            * The timezone to be used to read/write the `Date` instance in the model can be defined using
21246            * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
21247            *
21248            * @param {string} ngModel Assignable angular expression to data-bind to.
21249            * @param {string=} name Property name of the form under which the control is published.
21250            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21251            *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21252            *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
21253            *   native HTML5 constraint validation.
21254            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21255            *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
21256            *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
21257            *   native HTML5 constraint validation.
21258            * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
21259            *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
21260            * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
21261            *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
21262
21263            * @param {string=} required Sets `required` validation error key if the value is not entered.
21264            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21265            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21266            *    `required` when you want to data-bind to the `required` attribute.
21267            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21268            *    interaction with the input element.
21269            *
21270            * @example
21271            <example name="month-input-directive" module="monthExample">
21272            <file name="index.html">
21273              <script>
21274               angular.module('monthExample', [])
21275                 .controller('DateController', ['$scope', function($scope) {
21276                   $scope.example = {
21277                     value: new Date(2013, 9, 1)
21278                   };
21279                 }]);
21280              </script>
21281              <form name="myForm" ng-controller="DateController as dateCtrl">
21282                <label for="exampleInput">Pick a month in 2013:</label>
21283                <input id="exampleInput" type="month" name="input" ng-model="example.value"
21284                   placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
21285                <div role="alert">
21286                  <span class="error" ng-show="myForm.input.$error.required">
21287                     Required!</span>
21288                  <span class="error" ng-show="myForm.input.$error.month">
21289                     Not a valid month!</span>
21290                </div>
21291                <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
21292                <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21293                <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21294                <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21295                <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21296              </form>
21297            </file>
21298            <file name="protractor.js" type="protractor">
21299               var value = element(by.binding('example.value | date: "yyyy-MM"'));
21300               var valid = element(by.binding('myForm.input.$valid'));
21301               var input = element(by.model('example.value'));
21302
21303               // currently protractor/webdriver does not support
21304               // sending keys to all known HTML5 input controls
21305               // for various browsers (https://github.com/angular/protractor/issues/562).
21306               function setInput(val) {
21307                 // set the value of the element and force validation.
21308                 var scr = "var ipt = document.getElementById('exampleInput'); " +
21309                 "ipt.value = '" + val + "';" +
21310                 "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
21311                 browser.executeScript(scr);
21312               }
21313
21314               it('should initialize to model', function() {
21315                 expect(value.getText()).toContain('2013-10');
21316                 expect(valid.getText()).toContain('myForm.input.$valid = true');
21317               });
21318
21319               it('should be invalid if empty', function() {
21320                 setInput('');
21321                 expect(value.getText()).toEqual('value =');
21322                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21323               });
21324
21325               it('should be invalid if over max', function() {
21326                 setInput('2015-01');
21327                 expect(value.getText()).toContain('');
21328                 expect(valid.getText()).toContain('myForm.input.$valid = false');
21329               });
21330            </file>
21331            </example>
21332            */
21333           'month': createDateInputType('month', MONTH_REGEXP,
21334              createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
21335              'yyyy-MM'),
21336
21337           /**
21338            * @ngdoc input
21339            * @name input[number]
21340            *
21341            * @description
21342            * Text input with number validation and transformation. Sets the `number` validation
21343            * error if not a valid number.
21344            *
21345            * <div class="alert alert-warning">
21346            * The model must always be of type `number` otherwise Angular will throw an error.
21347            * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
21348            * error docs for more information and an example of how to convert your model if necessary.
21349            * </div>
21350            *
21351            * ## Issues with HTML5 constraint validation
21352            *
21353            * In browsers that follow the
21354            * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
21355            * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
21356            * If a non-number is entered in the input, the browser will report the value as an empty string,
21357            * which means the view / model values in `ngModel` and subsequently the scope value
21358            * will also be an empty string.
21359            *
21360            *
21361            * @param {string} ngModel Assignable angular expression to data-bind to.
21362            * @param {string=} name Property name of the form under which the control is published.
21363            * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
21364            * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
21365            * @param {string=} required Sets `required` validation error key if the value is not entered.
21366            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21367            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21368            *    `required` when you want to data-bind to the `required` attribute.
21369            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21370            *    minlength.
21371            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21372            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21373            *    any length.
21374            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21375            *    that contains the regular expression body that will be converted to a regular expression
21376            *    as in the ngPattern directive.
21377            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21378            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21379            *    If the expression evaluates to a RegExp object, then this is used directly.
21380            *    If the expression evaluates to a string, then it will be converted to a RegExp
21381            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21382            *    `new RegExp('^abc$')`.<br />
21383            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21384            *    start at the index of the last search's match, thus not taking the whole input value into
21385            *    account.
21386            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21387            *    interaction with the input element.
21388            *
21389            * @example
21390               <example name="number-input-directive" module="numberExample">
21391                 <file name="index.html">
21392                  <script>
21393                    angular.module('numberExample', [])
21394                      .controller('ExampleController', ['$scope', function($scope) {
21395                        $scope.example = {
21396                          value: 12
21397                        };
21398                      }]);
21399                  </script>
21400                  <form name="myForm" ng-controller="ExampleController">
21401                    <label>Number:
21402                      <input type="number" name="input" ng-model="example.value"
21403                             min="0" max="99" required>
21404                   </label>
21405                    <div role="alert">
21406                      <span class="error" ng-show="myForm.input.$error.required">
21407                        Required!</span>
21408                      <span class="error" ng-show="myForm.input.$error.number">
21409                        Not valid number!</span>
21410                    </div>
21411                    <tt>value = {{example.value}}</tt><br/>
21412                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21413                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21414                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21415                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21416                   </form>
21417                 </file>
21418                 <file name="protractor.js" type="protractor">
21419                   var value = element(by.binding('example.value'));
21420                   var valid = element(by.binding('myForm.input.$valid'));
21421                   var input = element(by.model('example.value'));
21422
21423                   it('should initialize to model', function() {
21424                     expect(value.getText()).toContain('12');
21425                     expect(valid.getText()).toContain('true');
21426                   });
21427
21428                   it('should be invalid if empty', function() {
21429                     input.clear();
21430                     input.sendKeys('');
21431                     expect(value.getText()).toEqual('value =');
21432                     expect(valid.getText()).toContain('false');
21433                   });
21434
21435                   it('should be invalid if over max', function() {
21436                     input.clear();
21437                     input.sendKeys('123');
21438                     expect(value.getText()).toEqual('value =');
21439                     expect(valid.getText()).toContain('false');
21440                   });
21441                 </file>
21442               </example>
21443            */
21444           'number': numberInputType,
21445
21446
21447           /**
21448            * @ngdoc input
21449            * @name input[url]
21450            *
21451            * @description
21452            * Text input with URL validation. Sets the `url` validation error key if the content is not a
21453            * valid URL.
21454            *
21455            * <div class="alert alert-warning">
21456            * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
21457            * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
21458            * the built-in validators (see the {@link guide/forms Forms guide})
21459            * </div>
21460            *
21461            * @param {string} ngModel Assignable angular expression to data-bind to.
21462            * @param {string=} name Property name of the form under which the control is published.
21463            * @param {string=} required Sets `required` validation error key if the value is not entered.
21464            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21465            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21466            *    `required` when you want to data-bind to the `required` attribute.
21467            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21468            *    minlength.
21469            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21470            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21471            *    any length.
21472            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21473            *    that contains the regular expression body that will be converted to a regular expression
21474            *    as in the ngPattern directive.
21475            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21476            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21477            *    If the expression evaluates to a RegExp object, then this is used directly.
21478            *    If the expression evaluates to a string, then it will be converted to a RegExp
21479            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21480            *    `new RegExp('^abc$')`.<br />
21481            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21482            *    start at the index of the last search's match, thus not taking the whole input value into
21483            *    account.
21484            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21485            *    interaction with the input element.
21486            *
21487            * @example
21488               <example name="url-input-directive" module="urlExample">
21489                 <file name="index.html">
21490                  <script>
21491                    angular.module('urlExample', [])
21492                      .controller('ExampleController', ['$scope', function($scope) {
21493                        $scope.url = {
21494                          text: 'http://google.com'
21495                        };
21496                      }]);
21497                  </script>
21498                  <form name="myForm" ng-controller="ExampleController">
21499                    <label>URL:
21500                      <input type="url" name="input" ng-model="url.text" required>
21501                    <label>
21502                    <div role="alert">
21503                      <span class="error" ng-show="myForm.input.$error.required">
21504                        Required!</span>
21505                      <span class="error" ng-show="myForm.input.$error.url">
21506                        Not valid url!</span>
21507                    </div>
21508                    <tt>text = {{url.text}}</tt><br/>
21509                    <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21510                    <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21511                    <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21512                    <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21513                    <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
21514                   </form>
21515                 </file>
21516                 <file name="protractor.js" type="protractor">
21517                   var text = element(by.binding('url.text'));
21518                   var valid = element(by.binding('myForm.input.$valid'));
21519                   var input = element(by.model('url.text'));
21520
21521                   it('should initialize to model', function() {
21522                     expect(text.getText()).toContain('http://google.com');
21523                     expect(valid.getText()).toContain('true');
21524                   });
21525
21526                   it('should be invalid if empty', function() {
21527                     input.clear();
21528                     input.sendKeys('');
21529
21530                     expect(text.getText()).toEqual('text =');
21531                     expect(valid.getText()).toContain('false');
21532                   });
21533
21534                   it('should be invalid if not url', function() {
21535                     input.clear();
21536                     input.sendKeys('box');
21537
21538                     expect(valid.getText()).toContain('false');
21539                   });
21540                 </file>
21541               </example>
21542            */
21543           'url': urlInputType,
21544
21545
21546           /**
21547            * @ngdoc input
21548            * @name input[email]
21549            *
21550            * @description
21551            * Text input with email validation. Sets the `email` validation error key if not a valid email
21552            * address.
21553            *
21554            * <div class="alert alert-warning">
21555            * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
21556            * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
21557            * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
21558            * </div>
21559            *
21560            * @param {string} ngModel Assignable angular expression to data-bind to.
21561            * @param {string=} name Property name of the form under which the control is published.
21562            * @param {string=} required Sets `required` validation error key if the value is not entered.
21563            * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21564            *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21565            *    `required` when you want to data-bind to the `required` attribute.
21566            * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21567            *    minlength.
21568            * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21569            *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21570            *    any length.
21571            * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21572            *    that contains the regular expression body that will be converted to a regular expression
21573            *    as in the ngPattern directive.
21574            * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21575            *    a RegExp found by evaluating the Angular expression given in the attribute value.
21576            *    If the expression evaluates to a RegExp object, then this is used directly.
21577            *    If the expression evaluates to a string, then it will be converted to a RegExp
21578            *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21579            *    `new RegExp('^abc$')`.<br />
21580            *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21581            *    start at the index of the last search's match, thus not taking the whole input value into
21582            *    account.
21583            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21584            *    interaction with the input element.
21585            *
21586            * @example
21587               <example name="email-input-directive" module="emailExample">
21588                 <file name="index.html">
21589                  <script>
21590                    angular.module('emailExample', [])
21591                      .controller('ExampleController', ['$scope', function($scope) {
21592                        $scope.email = {
21593                          text: 'me@example.com'
21594                        };
21595                      }]);
21596                  </script>
21597                    <form name="myForm" ng-controller="ExampleController">
21598                      <label>Email:
21599                        <input type="email" name="input" ng-model="email.text" required>
21600                      </label>
21601                      <div role="alert">
21602                        <span class="error" ng-show="myForm.input.$error.required">
21603                          Required!</span>
21604                        <span class="error" ng-show="myForm.input.$error.email">
21605                          Not valid email!</span>
21606                      </div>
21607                      <tt>text = {{email.text}}</tt><br/>
21608                      <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21609                      <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21610                      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21611                      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21612                      <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
21613                    </form>
21614                  </file>
21615                 <file name="protractor.js" type="protractor">
21616                   var text = element(by.binding('email.text'));
21617                   var valid = element(by.binding('myForm.input.$valid'));
21618                   var input = element(by.model('email.text'));
21619
21620                   it('should initialize to model', function() {
21621                     expect(text.getText()).toContain('me@example.com');
21622                     expect(valid.getText()).toContain('true');
21623                   });
21624
21625                   it('should be invalid if empty', function() {
21626                     input.clear();
21627                     input.sendKeys('');
21628                     expect(text.getText()).toEqual('text =');
21629                     expect(valid.getText()).toContain('false');
21630                   });
21631
21632                   it('should be invalid if not email', function() {
21633                     input.clear();
21634                     input.sendKeys('xxx');
21635
21636                     expect(valid.getText()).toContain('false');
21637                   });
21638                 </file>
21639               </example>
21640            */
21641           'email': emailInputType,
21642
21643
21644           /**
21645            * @ngdoc input
21646            * @name input[radio]
21647            *
21648            * @description
21649            * HTML radio button.
21650            *
21651            * @param {string} ngModel Assignable angular expression to data-bind to.
21652            * @param {string} value The value to which the `ngModel` expression should be set when selected.
21653            *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
21654            *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
21655            * @param {string=} name Property name of the form under which the control is published.
21656            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21657            *    interaction with the input element.
21658            * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
21659            *    is selected. Should be used instead of the `value` attribute if you need
21660            *    a non-string `ngModel` (`boolean`, `array`, ...).
21661            *
21662            * @example
21663               <example name="radio-input-directive" module="radioExample">
21664                 <file name="index.html">
21665                  <script>
21666                    angular.module('radioExample', [])
21667                      .controller('ExampleController', ['$scope', function($scope) {
21668                        $scope.color = {
21669                          name: 'blue'
21670                        };
21671                        $scope.specialValue = {
21672                          "id": "12345",
21673                          "value": "green"
21674                        };
21675                      }]);
21676                  </script>
21677                  <form name="myForm" ng-controller="ExampleController">
21678                    <label>
21679                      <input type="radio" ng-model="color.name" value="red">
21680                      Red
21681                    </label><br/>
21682                    <label>
21683                      <input type="radio" ng-model="color.name" ng-value="specialValue">
21684                      Green
21685                    </label><br/>
21686                    <label>
21687                      <input type="radio" ng-model="color.name" value="blue">
21688                      Blue
21689                    </label><br/>
21690                    <tt>color = {{color.name | json}}</tt><br/>
21691                   </form>
21692                   Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
21693                 </file>
21694                 <file name="protractor.js" type="protractor">
21695                   it('should change state', function() {
21696                     var color = element(by.binding('color.name'));
21697
21698                     expect(color.getText()).toContain('blue');
21699
21700                     element.all(by.model('color.name')).get(0).click();
21701
21702                     expect(color.getText()).toContain('red');
21703                   });
21704                 </file>
21705               </example>
21706            */
21707           'radio': radioInputType,
21708
21709
21710           /**
21711            * @ngdoc input
21712            * @name input[checkbox]
21713            *
21714            * @description
21715            * HTML checkbox.
21716            *
21717            * @param {string} ngModel Assignable angular expression to data-bind to.
21718            * @param {string=} name Property name of the form under which the control is published.
21719            * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
21720            * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
21721            * @param {string=} ngChange Angular expression to be executed when input changes due to user
21722            *    interaction with the input element.
21723            *
21724            * @example
21725               <example name="checkbox-input-directive" module="checkboxExample">
21726                 <file name="index.html">
21727                  <script>
21728                    angular.module('checkboxExample', [])
21729                      .controller('ExampleController', ['$scope', function($scope) {
21730                        $scope.checkboxModel = {
21731                         value1 : true,
21732                         value2 : 'YES'
21733                       };
21734                      }]);
21735                  </script>
21736                  <form name="myForm" ng-controller="ExampleController">
21737                    <label>Value1:
21738                      <input type="checkbox" ng-model="checkboxModel.value1">
21739                    </label><br/>
21740                    <label>Value2:
21741                      <input type="checkbox" ng-model="checkboxModel.value2"
21742                             ng-true-value="'YES'" ng-false-value="'NO'">
21743                     </label><br/>
21744                    <tt>value1 = {{checkboxModel.value1}}</tt><br/>
21745                    <tt>value2 = {{checkboxModel.value2}}</tt><br/>
21746                   </form>
21747                 </file>
21748                 <file name="protractor.js" type="protractor">
21749                   it('should change state', function() {
21750                     var value1 = element(by.binding('checkboxModel.value1'));
21751                     var value2 = element(by.binding('checkboxModel.value2'));
21752
21753                     expect(value1.getText()).toContain('true');
21754                     expect(value2.getText()).toContain('YES');
21755
21756                     element(by.model('checkboxModel.value1')).click();
21757                     element(by.model('checkboxModel.value2')).click();
21758
21759                     expect(value1.getText()).toContain('false');
21760                     expect(value2.getText()).toContain('NO');
21761                   });
21762                 </file>
21763               </example>
21764            */
21765           'checkbox': checkboxInputType,
21766
21767           'hidden': noop,
21768           'button': noop,
21769           'submit': noop,
21770           'reset': noop,
21771           'file': noop
21772         };
21773
21774         function stringBasedInputType(ctrl) {
21775           ctrl.$formatters.push(function(value) {
21776             return ctrl.$isEmpty(value) ? value : value.toString();
21777           });
21778         }
21779
21780         function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21781           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21782           stringBasedInputType(ctrl);
21783         }
21784
21785         function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21786           var type = lowercase(element[0].type);
21787
21788           // In composition mode, users are still inputing intermediate text buffer,
21789           // hold the listener until composition is done.
21790           // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
21791           if (!$sniffer.android) {
21792             var composing = false;
21793
21794             element.on('compositionstart', function(data) {
21795               composing = true;
21796             });
21797
21798             element.on('compositionend', function() {
21799               composing = false;
21800               listener();
21801             });
21802           }
21803
21804           var listener = function(ev) {
21805             if (timeout) {
21806               $browser.defer.cancel(timeout);
21807               timeout = null;
21808             }
21809             if (composing) return;
21810             var value = element.val(),
21811                 event = ev && ev.type;
21812
21813             // By default we will trim the value
21814             // If the attribute ng-trim exists we will avoid trimming
21815             // If input type is 'password', the value is never trimmed
21816             if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
21817               value = trim(value);
21818             }
21819
21820             // If a control is suffering from bad input (due to native validators), browsers discard its
21821             // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
21822             // control's value is the same empty value twice in a row.
21823             if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
21824               ctrl.$setViewValue(value, event);
21825             }
21826           };
21827
21828           // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
21829           // input event on backspace, delete or cut
21830           if ($sniffer.hasEvent('input')) {
21831             element.on('input', listener);
21832           } else {
21833             var timeout;
21834
21835             var deferListener = function(ev, input, origValue) {
21836               if (!timeout) {
21837                 timeout = $browser.defer(function() {
21838                   timeout = null;
21839                   if (!input || input.value !== origValue) {
21840                     listener(ev);
21841                   }
21842                 });
21843               }
21844             };
21845
21846             element.on('keydown', function(event) {
21847               var key = event.keyCode;
21848
21849               // ignore
21850               //    command            modifiers                   arrows
21851               if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
21852
21853               deferListener(event, this, this.value);
21854             });
21855
21856             // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
21857             if ($sniffer.hasEvent('paste')) {
21858               element.on('paste cut', deferListener);
21859             }
21860           }
21861
21862           // if user paste into input using mouse on older browser
21863           // or form autocomplete on newer browser, we need "change" event to catch it
21864           element.on('change', listener);
21865
21866           ctrl.$render = function() {
21867             // Workaround for Firefox validation #12102.
21868             var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
21869             if (element.val() !== value) {
21870               element.val(value);
21871             }
21872           };
21873         }
21874
21875         function weekParser(isoWeek, existingDate) {
21876           if (isDate(isoWeek)) {
21877             return isoWeek;
21878           }
21879
21880           if (isString(isoWeek)) {
21881             WEEK_REGEXP.lastIndex = 0;
21882             var parts = WEEK_REGEXP.exec(isoWeek);
21883             if (parts) {
21884               var year = +parts[1],
21885                   week = +parts[2],
21886                   hours = 0,
21887                   minutes = 0,
21888                   seconds = 0,
21889                   milliseconds = 0,
21890                   firstThurs = getFirstThursdayOfYear(year),
21891                   addDays = (week - 1) * 7;
21892
21893               if (existingDate) {
21894                 hours = existingDate.getHours();
21895                 minutes = existingDate.getMinutes();
21896                 seconds = existingDate.getSeconds();
21897                 milliseconds = existingDate.getMilliseconds();
21898               }
21899
21900               return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
21901             }
21902           }
21903
21904           return NaN;
21905         }
21906
21907         function createDateParser(regexp, mapping) {
21908           return function(iso, date) {
21909             var parts, map;
21910
21911             if (isDate(iso)) {
21912               return iso;
21913             }
21914
21915             if (isString(iso)) {
21916               // When a date is JSON'ified to wraps itself inside of an extra
21917               // set of double quotes. This makes the date parsing code unable
21918               // to match the date string and parse it as a date.
21919               if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
21920                 iso = iso.substring(1, iso.length - 1);
21921               }
21922               if (ISO_DATE_REGEXP.test(iso)) {
21923                 return new Date(iso);
21924               }
21925               regexp.lastIndex = 0;
21926               parts = regexp.exec(iso);
21927
21928               if (parts) {
21929                 parts.shift();
21930                 if (date) {
21931                   map = {
21932                     yyyy: date.getFullYear(),
21933                     MM: date.getMonth() + 1,
21934                     dd: date.getDate(),
21935                     HH: date.getHours(),
21936                     mm: date.getMinutes(),
21937                     ss: date.getSeconds(),
21938                     sss: date.getMilliseconds() / 1000
21939                   };
21940                 } else {
21941                   map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
21942                 }
21943
21944                 forEach(parts, function(part, index) {
21945                   if (index < mapping.length) {
21946                     map[mapping[index]] = +part;
21947                   }
21948                 });
21949                 return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
21950               }
21951             }
21952
21953             return NaN;
21954           };
21955         }
21956
21957         function createDateInputType(type, regexp, parseDate, format) {
21958           return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
21959             badInputChecker(scope, element, attr, ctrl);
21960             baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21961             var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
21962             var previousDate;
21963
21964             ctrl.$$parserName = type;
21965             ctrl.$parsers.push(function(value) {
21966               if (ctrl.$isEmpty(value)) return null;
21967               if (regexp.test(value)) {
21968                 // Note: We cannot read ctrl.$modelValue, as there might be a different
21969                 // parser/formatter in the processing chain so that the model
21970                 // contains some different data format!
21971                 var parsedDate = parseDate(value, previousDate);
21972                 if (timezone) {
21973                   parsedDate = convertTimezoneToLocal(parsedDate, timezone);
21974                 }
21975                 return parsedDate;
21976               }
21977               return undefined;
21978             });
21979
21980             ctrl.$formatters.push(function(value) {
21981               if (value && !isDate(value)) {
21982                 throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
21983               }
21984               if (isValidDate(value)) {
21985                 previousDate = value;
21986                 if (previousDate && timezone) {
21987                   previousDate = convertTimezoneToLocal(previousDate, timezone, true);
21988                 }
21989                 return $filter('date')(value, format, timezone);
21990               } else {
21991                 previousDate = null;
21992                 return '';
21993               }
21994             });
21995
21996             if (isDefined(attr.min) || attr.ngMin) {
21997               var minVal;
21998               ctrl.$validators.min = function(value) {
21999                 return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
22000               };
22001               attr.$observe('min', function(val) {
22002                 minVal = parseObservedDateValue(val);
22003                 ctrl.$validate();
22004               });
22005             }
22006
22007             if (isDefined(attr.max) || attr.ngMax) {
22008               var maxVal;
22009               ctrl.$validators.max = function(value) {
22010                 return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
22011               };
22012               attr.$observe('max', function(val) {
22013                 maxVal = parseObservedDateValue(val);
22014                 ctrl.$validate();
22015               });
22016             }
22017
22018             function isValidDate(value) {
22019               // Invalid Date: getTime() returns NaN
22020               return value && !(value.getTime && value.getTime() !== value.getTime());
22021             }
22022
22023             function parseObservedDateValue(val) {
22024               return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
22025             }
22026           };
22027         }
22028
22029         function badInputChecker(scope, element, attr, ctrl) {
22030           var node = element[0];
22031           var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
22032           if (nativeValidation) {
22033             ctrl.$parsers.push(function(value) {
22034               var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
22035               // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
22036               // - also sets validity.badInput (should only be validity.typeMismatch).
22037               // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
22038               // - can ignore this case as we can still read out the erroneous email...
22039               return validity.badInput && !validity.typeMismatch ? undefined : value;
22040             });
22041           }
22042         }
22043
22044         function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22045           badInputChecker(scope, element, attr, ctrl);
22046           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22047
22048           ctrl.$$parserName = 'number';
22049           ctrl.$parsers.push(function(value) {
22050             if (ctrl.$isEmpty(value))      return null;
22051             if (NUMBER_REGEXP.test(value)) return parseFloat(value);
22052             return undefined;
22053           });
22054
22055           ctrl.$formatters.push(function(value) {
22056             if (!ctrl.$isEmpty(value)) {
22057               if (!isNumber(value)) {
22058                 throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
22059               }
22060               value = value.toString();
22061             }
22062             return value;
22063           });
22064
22065           if (isDefined(attr.min) || attr.ngMin) {
22066             var minVal;
22067             ctrl.$validators.min = function(value) {
22068               return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
22069             };
22070
22071             attr.$observe('min', function(val) {
22072               if (isDefined(val) && !isNumber(val)) {
22073                 val = parseFloat(val, 10);
22074               }
22075               minVal = isNumber(val) && !isNaN(val) ? val : undefined;
22076               // TODO(matsko): implement validateLater to reduce number of validations
22077               ctrl.$validate();
22078             });
22079           }
22080
22081           if (isDefined(attr.max) || attr.ngMax) {
22082             var maxVal;
22083             ctrl.$validators.max = function(value) {
22084               return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
22085             };
22086
22087             attr.$observe('max', function(val) {
22088               if (isDefined(val) && !isNumber(val)) {
22089                 val = parseFloat(val, 10);
22090               }
22091               maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
22092               // TODO(matsko): implement validateLater to reduce number of validations
22093               ctrl.$validate();
22094             });
22095           }
22096         }
22097
22098         function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22099           // Note: no badInputChecker here by purpose as `url` is only a validation
22100           // in browsers, i.e. we can always read out input.value even if it is not valid!
22101           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22102           stringBasedInputType(ctrl);
22103
22104           ctrl.$$parserName = 'url';
22105           ctrl.$validators.url = function(modelValue, viewValue) {
22106             var value = modelValue || viewValue;
22107             return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
22108           };
22109         }
22110
22111         function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
22112           // Note: no badInputChecker here by purpose as `url` is only a validation
22113           // in browsers, i.e. we can always read out input.value even if it is not valid!
22114           baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
22115           stringBasedInputType(ctrl);
22116
22117           ctrl.$$parserName = 'email';
22118           ctrl.$validators.email = function(modelValue, viewValue) {
22119             var value = modelValue || viewValue;
22120             return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
22121           };
22122         }
22123
22124         function radioInputType(scope, element, attr, ctrl) {
22125           // make the name unique, if not defined
22126           if (isUndefined(attr.name)) {
22127             element.attr('name', nextUid());
22128           }
22129
22130           var listener = function(ev) {
22131             if (element[0].checked) {
22132               ctrl.$setViewValue(attr.value, ev && ev.type);
22133             }
22134           };
22135
22136           element.on('click', listener);
22137
22138           ctrl.$render = function() {
22139             var value = attr.value;
22140             element[0].checked = (value == ctrl.$viewValue);
22141           };
22142
22143           attr.$observe('value', ctrl.$render);
22144         }
22145
22146         function parseConstantExpr($parse, context, name, expression, fallback) {
22147           var parseFn;
22148           if (isDefined(expression)) {
22149             parseFn = $parse(expression);
22150             if (!parseFn.constant) {
22151               throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
22152                                            '`{1}`.', name, expression);
22153             }
22154             return parseFn(context);
22155           }
22156           return fallback;
22157         }
22158
22159         function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
22160           var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
22161           var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
22162
22163           var listener = function(ev) {
22164             ctrl.$setViewValue(element[0].checked, ev && ev.type);
22165           };
22166
22167           element.on('click', listener);
22168
22169           ctrl.$render = function() {
22170             element[0].checked = ctrl.$viewValue;
22171           };
22172
22173           // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
22174           // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
22175           // it to a boolean.
22176           ctrl.$isEmpty = function(value) {
22177             return value === false;
22178           };
22179
22180           ctrl.$formatters.push(function(value) {
22181             return equals(value, trueValue);
22182           });
22183
22184           ctrl.$parsers.push(function(value) {
22185             return value ? trueValue : falseValue;
22186           });
22187         }
22188
22189
22190         /**
22191          * @ngdoc directive
22192          * @name textarea
22193          * @restrict E
22194          *
22195          * @description
22196          * HTML textarea element control with angular data-binding. The data-binding and validation
22197          * properties of this element are exactly the same as those of the
22198          * {@link ng.directive:input input element}.
22199          *
22200          * @param {string} ngModel Assignable angular expression to data-bind to.
22201          * @param {string=} name Property name of the form under which the control is published.
22202          * @param {string=} required Sets `required` validation error key if the value is not entered.
22203          * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
22204          *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
22205          *    `required` when you want to data-bind to the `required` attribute.
22206          * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22207          *    minlength.
22208          * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22209          *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22210          *    length.
22211          * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22212          *    a RegExp found by evaluating the Angular expression given in the attribute value.
22213          *    If the expression evaluates to a RegExp object, then this is used directly.
22214          *    If the expression evaluates to a string, then it will be converted to a RegExp
22215          *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22216          *    `new RegExp('^abc$')`.<br />
22217          *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22218          *    start at the index of the last search's match, thus not taking the whole input value into
22219          *    account.
22220          * @param {string=} ngChange Angular expression to be executed when input changes due to user
22221          *    interaction with the input element.
22222          * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22223          */
22224
22225
22226         /**
22227          * @ngdoc directive
22228          * @name input
22229          * @restrict E
22230          *
22231          * @description
22232          * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
22233          * input state control, and validation.
22234          * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
22235          *
22236          * <div class="alert alert-warning">
22237          * **Note:** Not every feature offered is available for all input types.
22238          * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
22239          * </div>
22240          *
22241          * @param {string} ngModel Assignable angular expression to data-bind to.
22242          * @param {string=} name Property name of the form under which the control is published.
22243          * @param {string=} required Sets `required` validation error key if the value is not entered.
22244          * @param {boolean=} ngRequired Sets `required` attribute if set to true
22245          * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
22246          *    minlength.
22247          * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
22248          *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
22249          *    length.
22250          * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
22251          *    a RegExp found by evaluating the Angular expression given in the attribute value.
22252          *    If the expression evaluates to a RegExp object, then this is used directly.
22253          *    If the expression evaluates to a string, then it will be converted to a RegExp
22254          *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
22255          *    `new RegExp('^abc$')`.<br />
22256          *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
22257          *    start at the index of the last search's match, thus not taking the whole input value into
22258          *    account.
22259          * @param {string=} ngChange Angular expression to be executed when input changes due to user
22260          *    interaction with the input element.
22261          * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
22262          *    This parameter is ignored for input[type=password] controls, which will never trim the
22263          *    input.
22264          *
22265          * @example
22266             <example name="input-directive" module="inputExample">
22267               <file name="index.html">
22268                <script>
22269                   angular.module('inputExample', [])
22270                     .controller('ExampleController', ['$scope', function($scope) {
22271                       $scope.user = {name: 'guest', last: 'visitor'};
22272                     }]);
22273                </script>
22274                <div ng-controller="ExampleController">
22275                  <form name="myForm">
22276                    <label>
22277                       User name:
22278                       <input type="text" name="userName" ng-model="user.name" required>
22279                    </label>
22280                    <div role="alert">
22281                      <span class="error" ng-show="myForm.userName.$error.required">
22282                       Required!</span>
22283                    </div>
22284                    <label>
22285                       Last name:
22286                       <input type="text" name="lastName" ng-model="user.last"
22287                       ng-minlength="3" ng-maxlength="10">
22288                    </label>
22289                    <div role="alert">
22290                      <span class="error" ng-show="myForm.lastName.$error.minlength">
22291                        Too short!</span>
22292                      <span class="error" ng-show="myForm.lastName.$error.maxlength">
22293                        Too long!</span>
22294                    </div>
22295                  </form>
22296                  <hr>
22297                  <tt>user = {{user}}</tt><br/>
22298                  <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
22299                  <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
22300                  <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
22301                  <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
22302                  <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22303                  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22304                  <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
22305                  <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
22306                </div>
22307               </file>
22308               <file name="protractor.js" type="protractor">
22309                 var user = element(by.exactBinding('user'));
22310                 var userNameValid = element(by.binding('myForm.userName.$valid'));
22311                 var lastNameValid = element(by.binding('myForm.lastName.$valid'));
22312                 var lastNameError = element(by.binding('myForm.lastName.$error'));
22313                 var formValid = element(by.binding('myForm.$valid'));
22314                 var userNameInput = element(by.model('user.name'));
22315                 var userLastInput = element(by.model('user.last'));
22316
22317                 it('should initialize to model', function() {
22318                   expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
22319                   expect(userNameValid.getText()).toContain('true');
22320                   expect(formValid.getText()).toContain('true');
22321                 });
22322
22323                 it('should be invalid if empty when required', function() {
22324                   userNameInput.clear();
22325                   userNameInput.sendKeys('');
22326
22327                   expect(user.getText()).toContain('{"last":"visitor"}');
22328                   expect(userNameValid.getText()).toContain('false');
22329                   expect(formValid.getText()).toContain('false');
22330                 });
22331
22332                 it('should be valid if empty when min length is set', function() {
22333                   userLastInput.clear();
22334                   userLastInput.sendKeys('');
22335
22336                   expect(user.getText()).toContain('{"name":"guest","last":""}');
22337                   expect(lastNameValid.getText()).toContain('true');
22338                   expect(formValid.getText()).toContain('true');
22339                 });
22340
22341                 it('should be invalid if less than required min length', function() {
22342                   userLastInput.clear();
22343                   userLastInput.sendKeys('xx');
22344
22345                   expect(user.getText()).toContain('{"name":"guest"}');
22346                   expect(lastNameValid.getText()).toContain('false');
22347                   expect(lastNameError.getText()).toContain('minlength');
22348                   expect(formValid.getText()).toContain('false');
22349                 });
22350
22351                 it('should be invalid if longer than max length', function() {
22352                   userLastInput.clear();
22353                   userLastInput.sendKeys('some ridiculously long name');
22354
22355                   expect(user.getText()).toContain('{"name":"guest"}');
22356                   expect(lastNameValid.getText()).toContain('false');
22357                   expect(lastNameError.getText()).toContain('maxlength');
22358                   expect(formValid.getText()).toContain('false');
22359                 });
22360               </file>
22361             </example>
22362          */
22363         var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
22364             function($browser, $sniffer, $filter, $parse) {
22365           return {
22366             restrict: 'E',
22367             require: ['?ngModel'],
22368             link: {
22369               pre: function(scope, element, attr, ctrls) {
22370                 if (ctrls[0]) {
22371                   (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
22372                                                                       $browser, $filter, $parse);
22373                 }
22374               }
22375             }
22376           };
22377         }];
22378
22379
22380
22381         var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
22382         /**
22383          * @ngdoc directive
22384          * @name ngValue
22385          *
22386          * @description
22387          * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
22388          * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
22389          * the bound value.
22390          *
22391          * `ngValue` is useful when dynamically generating lists of radio buttons using
22392          * {@link ngRepeat `ngRepeat`}, as shown below.
22393          *
22394          * Likewise, `ngValue` can be used to generate `<option>` elements for
22395          * the {@link select `select`} element. In that case however, only strings are supported
22396          * for the `value `attribute, so the resulting `ngModel` will always be a string.
22397          * Support for `select` models with non-string values is available via `ngOptions`.
22398          *
22399          * @element input
22400          * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
22401          *   of the `input` element
22402          *
22403          * @example
22404             <example name="ngValue-directive" module="valueExample">
22405               <file name="index.html">
22406                <script>
22407                   angular.module('valueExample', [])
22408                     .controller('ExampleController', ['$scope', function($scope) {
22409                       $scope.names = ['pizza', 'unicorns', 'robots'];
22410                       $scope.my = { favorite: 'unicorns' };
22411                     }]);
22412                </script>
22413                 <form ng-controller="ExampleController">
22414                   <h2>Which is your favorite?</h2>
22415                     <label ng-repeat="name in names" for="{{name}}">
22416                       {{name}}
22417                       <input type="radio"
22418                              ng-model="my.favorite"
22419                              ng-value="name"
22420                              id="{{name}}"
22421                              name="favorite">
22422                     </label>
22423                   <div>You chose {{my.favorite}}</div>
22424                 </form>
22425               </file>
22426               <file name="protractor.js" type="protractor">
22427                 var favorite = element(by.binding('my.favorite'));
22428
22429                 it('should initialize to model', function() {
22430                   expect(favorite.getText()).toContain('unicorns');
22431                 });
22432                 it('should bind the values to the inputs', function() {
22433                   element.all(by.model('my.favorite')).get(0).click();
22434                   expect(favorite.getText()).toContain('pizza');
22435                 });
22436               </file>
22437             </example>
22438          */
22439         var ngValueDirective = function() {
22440           return {
22441             restrict: 'A',
22442             priority: 100,
22443             compile: function(tpl, tplAttr) {
22444               if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
22445                 return function ngValueConstantLink(scope, elm, attr) {
22446                   attr.$set('value', scope.$eval(attr.ngValue));
22447                 };
22448               } else {
22449                 return function ngValueLink(scope, elm, attr) {
22450                   scope.$watch(attr.ngValue, function valueWatchAction(value) {
22451                     attr.$set('value', value);
22452                   });
22453                 };
22454               }
22455             }
22456           };
22457         };
22458
22459         /**
22460          * @ngdoc directive
22461          * @name ngBind
22462          * @restrict AC
22463          *
22464          * @description
22465          * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
22466          * with the value of a given expression, and to update the text content when the value of that
22467          * expression changes.
22468          *
22469          * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
22470          * `{{ expression }}` which is similar but less verbose.
22471          *
22472          * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
22473          * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
22474          * element attribute, it makes the bindings invisible to the user while the page is loading.
22475          *
22476          * An alternative solution to this problem would be using the
22477          * {@link ng.directive:ngCloak ngCloak} directive.
22478          *
22479          *
22480          * @element ANY
22481          * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
22482          *
22483          * @example
22484          * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
22485            <example module="bindExample">
22486              <file name="index.html">
22487                <script>
22488                  angular.module('bindExample', [])
22489                    .controller('ExampleController', ['$scope', function($scope) {
22490                      $scope.name = 'Whirled';
22491                    }]);
22492                </script>
22493                <div ng-controller="ExampleController">
22494                  <label>Enter name: <input type="text" ng-model="name"></label><br>
22495                  Hello <span ng-bind="name"></span>!
22496                </div>
22497              </file>
22498              <file name="protractor.js" type="protractor">
22499                it('should check ng-bind', function() {
22500                  var nameInput = element(by.model('name'));
22501
22502                  expect(element(by.binding('name')).getText()).toBe('Whirled');
22503                  nameInput.clear();
22504                  nameInput.sendKeys('world');
22505                  expect(element(by.binding('name')).getText()).toBe('world');
22506                });
22507              </file>
22508            </example>
22509          */
22510         var ngBindDirective = ['$compile', function($compile) {
22511           return {
22512             restrict: 'AC',
22513             compile: function ngBindCompile(templateElement) {
22514               $compile.$$addBindingClass(templateElement);
22515               return function ngBindLink(scope, element, attr) {
22516                 $compile.$$addBindingInfo(element, attr.ngBind);
22517                 element = element[0];
22518                 scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
22519                   element.textContent = isUndefined(value) ? '' : value;
22520                 });
22521               };
22522             }
22523           };
22524         }];
22525
22526
22527         /**
22528          * @ngdoc directive
22529          * @name ngBindTemplate
22530          *
22531          * @description
22532          * The `ngBindTemplate` directive specifies that the element
22533          * text content should be replaced with the interpolation of the template
22534          * in the `ngBindTemplate` attribute.
22535          * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
22536          * expressions. This directive is needed since some HTML elements
22537          * (such as TITLE and OPTION) cannot contain SPAN elements.
22538          *
22539          * @element ANY
22540          * @param {string} ngBindTemplate template of form
22541          *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
22542          *
22543          * @example
22544          * Try it here: enter text in text box and watch the greeting change.
22545            <example module="bindExample">
22546              <file name="index.html">
22547                <script>
22548                  angular.module('bindExample', [])
22549                    .controller('ExampleController', ['$scope', function($scope) {
22550                      $scope.salutation = 'Hello';
22551                      $scope.name = 'World';
22552                    }]);
22553                </script>
22554                <div ng-controller="ExampleController">
22555                 <label>Salutation: <input type="text" ng-model="salutation"></label><br>
22556                 <label>Name: <input type="text" ng-model="name"></label><br>
22557                 <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
22558                </div>
22559              </file>
22560              <file name="protractor.js" type="protractor">
22561                it('should check ng-bind', function() {
22562                  var salutationElem = element(by.binding('salutation'));
22563                  var salutationInput = element(by.model('salutation'));
22564                  var nameInput = element(by.model('name'));
22565
22566                  expect(salutationElem.getText()).toBe('Hello World!');
22567
22568                  salutationInput.clear();
22569                  salutationInput.sendKeys('Greetings');
22570                  nameInput.clear();
22571                  nameInput.sendKeys('user');
22572
22573                  expect(salutationElem.getText()).toBe('Greetings user!');
22574                });
22575              </file>
22576            </example>
22577          */
22578         var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
22579           return {
22580             compile: function ngBindTemplateCompile(templateElement) {
22581               $compile.$$addBindingClass(templateElement);
22582               return function ngBindTemplateLink(scope, element, attr) {
22583                 var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
22584                 $compile.$$addBindingInfo(element, interpolateFn.expressions);
22585                 element = element[0];
22586                 attr.$observe('ngBindTemplate', function(value) {
22587                   element.textContent = isUndefined(value) ? '' : value;
22588                 });
22589               };
22590             }
22591           };
22592         }];
22593
22594
22595         /**
22596          * @ngdoc directive
22597          * @name ngBindHtml
22598          *
22599          * @description
22600          * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
22601          * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
22602          * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
22603          * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
22604          * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
22605          *
22606          * You may also bypass sanitization for values you know are safe. To do so, bind to
22607          * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
22608          * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
22609          *
22610          * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
22611          * will have an exception (instead of an exploit.)
22612          *
22613          * @element ANY
22614          * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
22615          *
22616          * @example
22617
22618            <example module="bindHtmlExample" deps="angular-sanitize.js">
22619              <file name="index.html">
22620                <div ng-controller="ExampleController">
22621                 <p ng-bind-html="myHTML"></p>
22622                </div>
22623              </file>
22624
22625              <file name="script.js">
22626                angular.module('bindHtmlExample', ['ngSanitize'])
22627                  .controller('ExampleController', ['$scope', function($scope) {
22628                    $scope.myHTML =
22629                       'I am an <code>HTML</code>string with ' +
22630                       '<a href="#">links!</a> and other <em>stuff</em>';
22631                  }]);
22632              </file>
22633
22634              <file name="protractor.js" type="protractor">
22635                it('should check ng-bind-html', function() {
22636                  expect(element(by.binding('myHTML')).getText()).toBe(
22637                      'I am an HTMLstring with links! and other stuff');
22638                });
22639              </file>
22640            </example>
22641          */
22642         var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
22643           return {
22644             restrict: 'A',
22645             compile: function ngBindHtmlCompile(tElement, tAttrs) {
22646               var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
22647               var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
22648                 return (value || '').toString();
22649               });
22650               $compile.$$addBindingClass(tElement);
22651
22652               return function ngBindHtmlLink(scope, element, attr) {
22653                 $compile.$$addBindingInfo(element, attr.ngBindHtml);
22654
22655                 scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
22656                   // we re-evaluate the expr because we want a TrustedValueHolderType
22657                   // for $sce, not a string
22658                   element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
22659                 });
22660               };
22661             }
22662           };
22663         }];
22664
22665         /**
22666          * @ngdoc directive
22667          * @name ngChange
22668          *
22669          * @description
22670          * Evaluate the given expression when the user changes the input.
22671          * The expression is evaluated immediately, unlike the JavaScript onchange event
22672          * which only triggers at the end of a change (usually, when the user leaves the
22673          * form element or presses the return key).
22674          *
22675          * The `ngChange` expression is only evaluated when a change in the input value causes
22676          * a new value to be committed to the model.
22677          *
22678          * It will not be evaluated:
22679          * * if the value returned from the `$parsers` transformation pipeline has not changed
22680          * * if the input has continued to be invalid since the model will stay `null`
22681          * * if the model is changed programmatically and not by a change to the input value
22682          *
22683          *
22684          * Note, this directive requires `ngModel` to be present.
22685          *
22686          * @element input
22687          * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
22688          * in input value.
22689          *
22690          * @example
22691          * <example name="ngChange-directive" module="changeExample">
22692          *   <file name="index.html">
22693          *     <script>
22694          *       angular.module('changeExample', [])
22695          *         .controller('ExampleController', ['$scope', function($scope) {
22696          *           $scope.counter = 0;
22697          *           $scope.change = function() {
22698          *             $scope.counter++;
22699          *           };
22700          *         }]);
22701          *     </script>
22702          *     <div ng-controller="ExampleController">
22703          *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
22704          *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
22705          *       <label for="ng-change-example2">Confirmed</label><br />
22706          *       <tt>debug = {{confirmed}}</tt><br/>
22707          *       <tt>counter = {{counter}}</tt><br/>
22708          *     </div>
22709          *   </file>
22710          *   <file name="protractor.js" type="protractor">
22711          *     var counter = element(by.binding('counter'));
22712          *     var debug = element(by.binding('confirmed'));
22713          *
22714          *     it('should evaluate the expression if changing from view', function() {
22715          *       expect(counter.getText()).toContain('0');
22716          *
22717          *       element(by.id('ng-change-example1')).click();
22718          *
22719          *       expect(counter.getText()).toContain('1');
22720          *       expect(debug.getText()).toContain('true');
22721          *     });
22722          *
22723          *     it('should not evaluate the expression if changing from model', function() {
22724          *       element(by.id('ng-change-example2')).click();
22725
22726          *       expect(counter.getText()).toContain('0');
22727          *       expect(debug.getText()).toContain('true');
22728          *     });
22729          *   </file>
22730          * </example>
22731          */
22732         var ngChangeDirective = valueFn({
22733           restrict: 'A',
22734           require: 'ngModel',
22735           link: function(scope, element, attr, ctrl) {
22736             ctrl.$viewChangeListeners.push(function() {
22737               scope.$eval(attr.ngChange);
22738             });
22739           }
22740         });
22741
22742         function classDirective(name, selector) {
22743           name = 'ngClass' + name;
22744           return ['$animate', function($animate) {
22745             return {
22746               restrict: 'AC',
22747               link: function(scope, element, attr) {
22748                 var oldVal;
22749
22750                 scope.$watch(attr[name], ngClassWatchAction, true);
22751
22752                 attr.$observe('class', function(value) {
22753                   ngClassWatchAction(scope.$eval(attr[name]));
22754                 });
22755
22756
22757                 if (name !== 'ngClass') {
22758                   scope.$watch('$index', function($index, old$index) {
22759                     // jshint bitwise: false
22760                     var mod = $index & 1;
22761                     if (mod !== (old$index & 1)) {
22762                       var classes = arrayClasses(scope.$eval(attr[name]));
22763                       mod === selector ?
22764                         addClasses(classes) :
22765                         removeClasses(classes);
22766                     }
22767                   });
22768                 }
22769
22770                 function addClasses(classes) {
22771                   var newClasses = digestClassCounts(classes, 1);
22772                   attr.$addClass(newClasses);
22773                 }
22774
22775                 function removeClasses(classes) {
22776                   var newClasses = digestClassCounts(classes, -1);
22777                   attr.$removeClass(newClasses);
22778                 }
22779
22780                 function digestClassCounts(classes, count) {
22781                   // Use createMap() to prevent class assumptions involving property
22782                   // names in Object.prototype
22783                   var classCounts = element.data('$classCounts') || createMap();
22784                   var classesToUpdate = [];
22785                   forEach(classes, function(className) {
22786                     if (count > 0 || classCounts[className]) {
22787                       classCounts[className] = (classCounts[className] || 0) + count;
22788                       if (classCounts[className] === +(count > 0)) {
22789                         classesToUpdate.push(className);
22790                       }
22791                     }
22792                   });
22793                   element.data('$classCounts', classCounts);
22794                   return classesToUpdate.join(' ');
22795                 }
22796
22797                 function updateClasses(oldClasses, newClasses) {
22798                   var toAdd = arrayDifference(newClasses, oldClasses);
22799                   var toRemove = arrayDifference(oldClasses, newClasses);
22800                   toAdd = digestClassCounts(toAdd, 1);
22801                   toRemove = digestClassCounts(toRemove, -1);
22802                   if (toAdd && toAdd.length) {
22803                     $animate.addClass(element, toAdd);
22804                   }
22805                   if (toRemove && toRemove.length) {
22806                     $animate.removeClass(element, toRemove);
22807                   }
22808                 }
22809
22810                 function ngClassWatchAction(newVal) {
22811                   if (selector === true || scope.$index % 2 === selector) {
22812                     var newClasses = arrayClasses(newVal || []);
22813                     if (!oldVal) {
22814                       addClasses(newClasses);
22815                     } else if (!equals(newVal,oldVal)) {
22816                       var oldClasses = arrayClasses(oldVal);
22817                       updateClasses(oldClasses, newClasses);
22818                     }
22819                   }
22820                   oldVal = shallowCopy(newVal);
22821                 }
22822               }
22823             };
22824
22825             function arrayDifference(tokens1, tokens2) {
22826               var values = [];
22827
22828               outer:
22829               for (var i = 0; i < tokens1.length; i++) {
22830                 var token = tokens1[i];
22831                 for (var j = 0; j < tokens2.length; j++) {
22832                   if (token == tokens2[j]) continue outer;
22833                 }
22834                 values.push(token);
22835               }
22836               return values;
22837             }
22838
22839             function arrayClasses(classVal) {
22840               var classes = [];
22841               if (isArray(classVal)) {
22842                 forEach(classVal, function(v) {
22843                   classes = classes.concat(arrayClasses(v));
22844                 });
22845                 return classes;
22846               } else if (isString(classVal)) {
22847                 return classVal.split(' ');
22848               } else if (isObject(classVal)) {
22849                 forEach(classVal, function(v, k) {
22850                   if (v) {
22851                     classes = classes.concat(k.split(' '));
22852                   }
22853                 });
22854                 return classes;
22855               }
22856               return classVal;
22857             }
22858           }];
22859         }
22860
22861         /**
22862          * @ngdoc directive
22863          * @name ngClass
22864          * @restrict AC
22865          *
22866          * @description
22867          * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
22868          * an expression that represents all classes to be added.
22869          *
22870          * The directive operates in three different ways, depending on which of three types the expression
22871          * evaluates to:
22872          *
22873          * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
22874          * names.
22875          *
22876          * 2. If the expression evaluates to an object, then for each key-value pair of the
22877          * object with a truthy value the corresponding key is used as a class name.
22878          *
22879          * 3. If the expression evaluates to an array, each element of the array should either be a string as in
22880          * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
22881          * to give you more control over what CSS classes appear. See the code below for an example of this.
22882          *
22883          *
22884          * The directive won't add duplicate classes if a particular class was already set.
22885          *
22886          * When the expression changes, the previously added classes are removed and only then are the
22887          * new classes added.
22888          *
22889          * @animations
22890          * **add** - happens just before the class is applied to the elements
22891          *
22892          * **remove** - happens just before the class is removed from the element
22893          *
22894          * @element ANY
22895          * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
22896          *   of the evaluation can be a string representing space delimited class
22897          *   names, an array, or a map of class names to boolean values. In the case of a map, the
22898          *   names of the properties whose values are truthy will be added as css classes to the
22899          *   element.
22900          *
22901          * @example Example that demonstrates basic bindings via ngClass directive.
22902            <example>
22903              <file name="index.html">
22904                <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
22905                <label>
22906                   <input type="checkbox" ng-model="deleted">
22907                   deleted (apply "strike" class)
22908                </label><br>
22909                <label>
22910                   <input type="checkbox" ng-model="important">
22911                   important (apply "bold" class)
22912                </label><br>
22913                <label>
22914                   <input type="checkbox" ng-model="error">
22915                   error (apply "has-error" class)
22916                </label>
22917                <hr>
22918                <p ng-class="style">Using String Syntax</p>
22919                <input type="text" ng-model="style"
22920                       placeholder="Type: bold strike red" aria-label="Type: bold strike red">
22921                <hr>
22922                <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
22923                <input ng-model="style1"
22924                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
22925                <input ng-model="style2"
22926                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
22927                <input ng-model="style3"
22928                       placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
22929                <hr>
22930                <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
22931                <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
22932                <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
22933              </file>
22934              <file name="style.css">
22935                .strike {
22936                    text-decoration: line-through;
22937                }
22938                .bold {
22939                    font-weight: bold;
22940                }
22941                .red {
22942                    color: red;
22943                }
22944                .has-error {
22945                    color: red;
22946                    background-color: yellow;
22947                }
22948                .orange {
22949                    color: orange;
22950                }
22951              </file>
22952              <file name="protractor.js" type="protractor">
22953                var ps = element.all(by.css('p'));
22954
22955                it('should let you toggle the class', function() {
22956
22957                  expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
22958                  expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
22959
22960                  element(by.model('important')).click();
22961                  expect(ps.first().getAttribute('class')).toMatch(/bold/);
22962
22963                  element(by.model('error')).click();
22964                  expect(ps.first().getAttribute('class')).toMatch(/has-error/);
22965                });
22966
22967                it('should let you toggle string example', function() {
22968                  expect(ps.get(1).getAttribute('class')).toBe('');
22969                  element(by.model('style')).clear();
22970                  element(by.model('style')).sendKeys('red');
22971                  expect(ps.get(1).getAttribute('class')).toBe('red');
22972                });
22973
22974                it('array example should have 3 classes', function() {
22975                  expect(ps.get(2).getAttribute('class')).toBe('');
22976                  element(by.model('style1')).sendKeys('bold');
22977                  element(by.model('style2')).sendKeys('strike');
22978                  element(by.model('style3')).sendKeys('red');
22979                  expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
22980                });
22981
22982                it('array with map example should have 2 classes', function() {
22983                  expect(ps.last().getAttribute('class')).toBe('');
22984                  element(by.model('style4')).sendKeys('bold');
22985                  element(by.model('warning')).click();
22986                  expect(ps.last().getAttribute('class')).toBe('bold orange');
22987                });
22988              </file>
22989            </example>
22990
22991            ## Animations
22992
22993            The example below demonstrates how to perform animations using ngClass.
22994
22995            <example module="ngAnimate" deps="angular-animate.js" animations="true">
22996              <file name="index.html">
22997               <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
22998               <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
22999               <br>
23000               <span class="base-class" ng-class="myVar">Sample Text</span>
23001              </file>
23002              <file name="style.css">
23003                .base-class {
23004                  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23005                }
23006
23007                .base-class.my-class {
23008                  color: red;
23009                  font-size:3em;
23010                }
23011              </file>
23012              <file name="protractor.js" type="protractor">
23013                it('should check ng-class', function() {
23014                  expect(element(by.css('.base-class')).getAttribute('class')).not.
23015                    toMatch(/my-class/);
23016
23017                  element(by.id('setbtn')).click();
23018
23019                  expect(element(by.css('.base-class')).getAttribute('class')).
23020                    toMatch(/my-class/);
23021
23022                  element(by.id('clearbtn')).click();
23023
23024                  expect(element(by.css('.base-class')).getAttribute('class')).not.
23025                    toMatch(/my-class/);
23026                });
23027              </file>
23028            </example>
23029
23030
23031            ## ngClass and pre-existing CSS3 Transitions/Animations
23032            The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
23033            Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
23034            any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
23035            to view the step by step details of {@link $animate#addClass $animate.addClass} and
23036            {@link $animate#removeClass $animate.removeClass}.
23037          */
23038         var ngClassDirective = classDirective('', true);
23039
23040         /**
23041          * @ngdoc directive
23042          * @name ngClassOdd
23043          * @restrict AC
23044          *
23045          * @description
23046          * The `ngClassOdd` and `ngClassEven` directives work exactly as
23047          * {@link ng.directive:ngClass ngClass}, except they work in
23048          * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23049          *
23050          * This directive can be applied only within the scope of an
23051          * {@link ng.directive:ngRepeat ngRepeat}.
23052          *
23053          * @element ANY
23054          * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
23055          *   of the evaluation can be a string representing space delimited class names or an array.
23056          *
23057          * @example
23058            <example>
23059              <file name="index.html">
23060                 <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23061                   <li ng-repeat="name in names">
23062                    <span ng-class-odd="'odd'" ng-class-even="'even'">
23063                      {{name}}
23064                    </span>
23065                   </li>
23066                 </ol>
23067              </file>
23068              <file name="style.css">
23069                .odd {
23070                  color: red;
23071                }
23072                .even {
23073                  color: blue;
23074                }
23075              </file>
23076              <file name="protractor.js" type="protractor">
23077                it('should check ng-class-odd and ng-class-even', function() {
23078                  expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23079                    toMatch(/odd/);
23080                  expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23081                    toMatch(/even/);
23082                });
23083              </file>
23084            </example>
23085          */
23086         var ngClassOddDirective = classDirective('Odd', 0);
23087
23088         /**
23089          * @ngdoc directive
23090          * @name ngClassEven
23091          * @restrict AC
23092          *
23093          * @description
23094          * The `ngClassOdd` and `ngClassEven` directives work exactly as
23095          * {@link ng.directive:ngClass ngClass}, except they work in
23096          * conjunction with `ngRepeat` and take effect only on odd (even) rows.
23097          *
23098          * This directive can be applied only within the scope of an
23099          * {@link ng.directive:ngRepeat ngRepeat}.
23100          *
23101          * @element ANY
23102          * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
23103          *   result of the evaluation can be a string representing space delimited class names or an array.
23104          *
23105          * @example
23106            <example>
23107              <file name="index.html">
23108                 <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
23109                   <li ng-repeat="name in names">
23110                    <span ng-class-odd="'odd'" ng-class-even="'even'">
23111                      {{name}} &nbsp; &nbsp; &nbsp;
23112                    </span>
23113                   </li>
23114                 </ol>
23115              </file>
23116              <file name="style.css">
23117                .odd {
23118                  color: red;
23119                }
23120                .even {
23121                  color: blue;
23122                }
23123              </file>
23124              <file name="protractor.js" type="protractor">
23125                it('should check ng-class-odd and ng-class-even', function() {
23126                  expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
23127                    toMatch(/odd/);
23128                  expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
23129                    toMatch(/even/);
23130                });
23131              </file>
23132            </example>
23133          */
23134         var ngClassEvenDirective = classDirective('Even', 1);
23135
23136         /**
23137          * @ngdoc directive
23138          * @name ngCloak
23139          * @restrict AC
23140          *
23141          * @description
23142          * The `ngCloak` directive is used to prevent the Angular html template from being briefly
23143          * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
23144          * directive to avoid the undesirable flicker effect caused by the html template display.
23145          *
23146          * The directive can be applied to the `<body>` element, but the preferred usage is to apply
23147          * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
23148          * of the browser view.
23149          *
23150          * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
23151          * `angular.min.js`.
23152          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
23153          *
23154          * ```css
23155          * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
23156          *   display: none !important;
23157          * }
23158          * ```
23159          *
23160          * When this css rule is loaded by the browser, all html elements (including their children) that
23161          * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
23162          * during the compilation of the template it deletes the `ngCloak` element attribute, making
23163          * the compiled element visible.
23164          *
23165          * For the best result, the `angular.js` script must be loaded in the head section of the html
23166          * document; alternatively, the css rule above must be included in the external stylesheet of the
23167          * application.
23168          *
23169          * @element ANY
23170          *
23171          * @example
23172            <example>
23173              <file name="index.html">
23174                 <div id="template1" ng-cloak>{{ 'hello' }}</div>
23175                 <div id="template2" class="ng-cloak">{{ 'world' }}</div>
23176              </file>
23177              <file name="protractor.js" type="protractor">
23178                it('should remove the template directive and css class', function() {
23179                  expect($('#template1').getAttribute('ng-cloak')).
23180                    toBeNull();
23181                  expect($('#template2').getAttribute('ng-cloak')).
23182                    toBeNull();
23183                });
23184              </file>
23185            </example>
23186          *
23187          */
23188         var ngCloakDirective = ngDirective({
23189           compile: function(element, attr) {
23190             attr.$set('ngCloak', undefined);
23191             element.removeClass('ng-cloak');
23192           }
23193         });
23194
23195         /**
23196          * @ngdoc directive
23197          * @name ngController
23198          *
23199          * @description
23200          * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
23201          * supports the principles behind the Model-View-Controller design pattern.
23202          *
23203          * MVC components in angular:
23204          *
23205          * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
23206          *   are accessed through bindings.
23207          * * View — The template (HTML with data bindings) that is rendered into the View.
23208          * * Controller — The `ngController` directive specifies a Controller class; the class contains business
23209          *   logic behind the application to decorate the scope with functions and values
23210          *
23211          * Note that you can also attach controllers to the DOM by declaring it in a route definition
23212          * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
23213          * again using `ng-controller` in the template itself.  This will cause the controller to be attached
23214          * and executed twice.
23215          *
23216          * @element ANY
23217          * @scope
23218          * @priority 500
23219          * @param {expression} ngController Name of a constructor function registered with the current
23220          * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
23221          * that on the current scope evaluates to a constructor function.
23222          *
23223          * The controller instance can be published into a scope property by specifying
23224          * `ng-controller="as propertyName"`.
23225          *
23226          * If the current `$controllerProvider` is configured to use globals (via
23227          * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
23228          * also be the name of a globally accessible constructor function (not recommended).
23229          *
23230          * @example
23231          * Here is a simple form for editing user contact information. Adding, removing, clearing, and
23232          * greeting are methods declared on the controller (see source tab). These methods can
23233          * easily be called from the angular markup. Any changes to the data are automatically reflected
23234          * in the View without the need for a manual update.
23235          *
23236          * Two different declaration styles are included below:
23237          *
23238          * * one binds methods and properties directly onto the controller using `this`:
23239          * `ng-controller="SettingsController1 as settings"`
23240          * * one injects `$scope` into the controller:
23241          * `ng-controller="SettingsController2"`
23242          *
23243          * The second option is more common in the Angular community, and is generally used in boilerplates
23244          * and in this guide. However, there are advantages to binding properties directly to the controller
23245          * and avoiding scope.
23246          *
23247          * * Using `controller as` makes it obvious which controller you are accessing in the template when
23248          * multiple controllers apply to an element.
23249          * * If you are writing your controllers as classes you have easier access to the properties and
23250          * methods, which will appear on the scope, from inside the controller code.
23251          * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
23252          * inheritance masking primitives.
23253          *
23254          * This example demonstrates the `controller as` syntax.
23255          *
23256          * <example name="ngControllerAs" module="controllerAsExample">
23257          *   <file name="index.html">
23258          *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
23259          *      <label>Name: <input type="text" ng-model="settings.name"/></label>
23260          *      <button ng-click="settings.greet()">greet</button><br/>
23261          *      Contact:
23262          *      <ul>
23263          *        <li ng-repeat="contact in settings.contacts">
23264          *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
23265          *             <option>phone</option>
23266          *             <option>email</option>
23267          *          </select>
23268          *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23269          *          <button ng-click="settings.clearContact(contact)">clear</button>
23270          *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
23271          *        </li>
23272          *        <li><button ng-click="settings.addContact()">add</button></li>
23273          *     </ul>
23274          *    </div>
23275          *   </file>
23276          *   <file name="app.js">
23277          *    angular.module('controllerAsExample', [])
23278          *      .controller('SettingsController1', SettingsController1);
23279          *
23280          *    function SettingsController1() {
23281          *      this.name = "John Smith";
23282          *      this.contacts = [
23283          *        {type: 'phone', value: '408 555 1212'},
23284          *        {type: 'email', value: 'john.smith@example.org'} ];
23285          *    }
23286          *
23287          *    SettingsController1.prototype.greet = function() {
23288          *      alert(this.name);
23289          *    };
23290          *
23291          *    SettingsController1.prototype.addContact = function() {
23292          *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
23293          *    };
23294          *
23295          *    SettingsController1.prototype.removeContact = function(contactToRemove) {
23296          *     var index = this.contacts.indexOf(contactToRemove);
23297          *      this.contacts.splice(index, 1);
23298          *    };
23299          *
23300          *    SettingsController1.prototype.clearContact = function(contact) {
23301          *      contact.type = 'phone';
23302          *      contact.value = '';
23303          *    };
23304          *   </file>
23305          *   <file name="protractor.js" type="protractor">
23306          *     it('should check controller as', function() {
23307          *       var container = element(by.id('ctrl-as-exmpl'));
23308          *         expect(container.element(by.model('settings.name'))
23309          *           .getAttribute('value')).toBe('John Smith');
23310          *
23311          *       var firstRepeat =
23312          *           container.element(by.repeater('contact in settings.contacts').row(0));
23313          *       var secondRepeat =
23314          *           container.element(by.repeater('contact in settings.contacts').row(1));
23315          *
23316          *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23317          *           .toBe('408 555 1212');
23318          *
23319          *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23320          *           .toBe('john.smith@example.org');
23321          *
23322          *       firstRepeat.element(by.buttonText('clear')).click();
23323          *
23324          *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23325          *           .toBe('');
23326          *
23327          *       container.element(by.buttonText('add')).click();
23328          *
23329          *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
23330          *           .element(by.model('contact.value'))
23331          *           .getAttribute('value'))
23332          *           .toBe('yourname@example.org');
23333          *     });
23334          *   </file>
23335          * </example>
23336          *
23337          * This example demonstrates the "attach to `$scope`" style of controller.
23338          *
23339          * <example name="ngController" module="controllerExample">
23340          *  <file name="index.html">
23341          *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
23342          *     <label>Name: <input type="text" ng-model="name"/></label>
23343          *     <button ng-click="greet()">greet</button><br/>
23344          *     Contact:
23345          *     <ul>
23346          *       <li ng-repeat="contact in contacts">
23347          *         <select ng-model="contact.type" id="select_{{$index}}">
23348          *            <option>phone</option>
23349          *            <option>email</option>
23350          *         </select>
23351          *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
23352          *         <button ng-click="clearContact(contact)">clear</button>
23353          *         <button ng-click="removeContact(contact)">X</button>
23354          *       </li>
23355          *       <li>[ <button ng-click="addContact()">add</button> ]</li>
23356          *    </ul>
23357          *   </div>
23358          *  </file>
23359          *  <file name="app.js">
23360          *   angular.module('controllerExample', [])
23361          *     .controller('SettingsController2', ['$scope', SettingsController2]);
23362          *
23363          *   function SettingsController2($scope) {
23364          *     $scope.name = "John Smith";
23365          *     $scope.contacts = [
23366          *       {type:'phone', value:'408 555 1212'},
23367          *       {type:'email', value:'john.smith@example.org'} ];
23368          *
23369          *     $scope.greet = function() {
23370          *       alert($scope.name);
23371          *     };
23372          *
23373          *     $scope.addContact = function() {
23374          *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
23375          *     };
23376          *
23377          *     $scope.removeContact = function(contactToRemove) {
23378          *       var index = $scope.contacts.indexOf(contactToRemove);
23379          *       $scope.contacts.splice(index, 1);
23380          *     };
23381          *
23382          *     $scope.clearContact = function(contact) {
23383          *       contact.type = 'phone';
23384          *       contact.value = '';
23385          *     };
23386          *   }
23387          *  </file>
23388          *  <file name="protractor.js" type="protractor">
23389          *    it('should check controller', function() {
23390          *      var container = element(by.id('ctrl-exmpl'));
23391          *
23392          *      expect(container.element(by.model('name'))
23393          *          .getAttribute('value')).toBe('John Smith');
23394          *
23395          *      var firstRepeat =
23396          *          container.element(by.repeater('contact in contacts').row(0));
23397          *      var secondRepeat =
23398          *          container.element(by.repeater('contact in contacts').row(1));
23399          *
23400          *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23401          *          .toBe('408 555 1212');
23402          *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
23403          *          .toBe('john.smith@example.org');
23404          *
23405          *      firstRepeat.element(by.buttonText('clear')).click();
23406          *
23407          *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
23408          *          .toBe('');
23409          *
23410          *      container.element(by.buttonText('add')).click();
23411          *
23412          *      expect(container.element(by.repeater('contact in contacts').row(2))
23413          *          .element(by.model('contact.value'))
23414          *          .getAttribute('value'))
23415          *          .toBe('yourname@example.org');
23416          *    });
23417          *  </file>
23418          *</example>
23419
23420          */
23421         var ngControllerDirective = [function() {
23422           return {
23423             restrict: 'A',
23424             scope: true,
23425             controller: '@',
23426             priority: 500
23427           };
23428         }];
23429
23430         /**
23431          * @ngdoc directive
23432          * @name ngCsp
23433          *
23434          * @element html
23435          * @description
23436          *
23437          * Angular has some features that can break certain
23438          * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
23439          *
23440          * If you intend to implement these rules then you must tell Angular not to use these features.
23441          *
23442          * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
23443          *
23444          *
23445          * The following rules affect Angular:
23446          *
23447          * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
23448          * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
23449          * increase in the speed of evaluating Angular expressions.
23450          *
23451          * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
23452          * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
23453          * To make these directives work when a CSP rule is blocking inline styles, you must link to the
23454          * `angular-csp.css` in your HTML manually.
23455          *
23456          * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
23457          * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
23458          * however, triggers a CSP error to be logged in the console:
23459          *
23460          * ```
23461          * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
23462          * script in the following Content Security Policy directive: "default-src 'self'". Note that
23463          * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
23464          * ```
23465          *
23466          * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
23467          * directive on an element of the HTML document that appears before the `<script>` tag that loads
23468          * the `angular.js` file.
23469          *
23470          * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
23471          *
23472          * You can specify which of the CSP related Angular features should be deactivated by providing
23473          * a value for the `ng-csp` attribute. The options are as follows:
23474          *
23475          * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
23476          *
23477          * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
23478          *
23479          * You can use these values in the following combinations:
23480          *
23481          *
23482          * * No declaration means that Angular will assume that you can do inline styles, but it will do
23483          * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
23484          * of Angular.
23485          *
23486          * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
23487          * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
23488          * of Angular.
23489          *
23490          * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
23491          * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
23492          *
23493          * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
23494          * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
23495          *
23496          * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
23497          * styles nor use eval, which is the same as an empty: ng-csp.
23498          * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
23499          *
23500          * @example
23501          * This example shows how to apply the `ngCsp` directive to the `html` tag.
23502            ```html
23503              <!doctype html>
23504              <html ng-app ng-csp>
23505              ...
23506              ...
23507              </html>
23508            ```
23509           * @example
23510               // Note: the suffix `.csp` in the example name triggers
23511               // csp mode in our http server!
23512               <example name="example.csp" module="cspExample" ng-csp="true">
23513                 <file name="index.html">
23514                   <div ng-controller="MainController as ctrl">
23515                     <div>
23516                       <button ng-click="ctrl.inc()" id="inc">Increment</button>
23517                       <span id="counter">
23518                         {{ctrl.counter}}
23519                       </span>
23520                     </div>
23521
23522                     <div>
23523                       <button ng-click="ctrl.evil()" id="evil">Evil</button>
23524                       <span id="evilError">
23525                         {{ctrl.evilError}}
23526                       </span>
23527                     </div>
23528                   </div>
23529                 </file>
23530                 <file name="script.js">
23531                    angular.module('cspExample', [])
23532                      .controller('MainController', function() {
23533                         this.counter = 0;
23534                         this.inc = function() {
23535                           this.counter++;
23536                         };
23537                         this.evil = function() {
23538                           // jshint evil:true
23539                           try {
23540                             eval('1+2');
23541                           } catch (e) {
23542                             this.evilError = e.message;
23543                           }
23544                         };
23545                       });
23546                 </file>
23547                 <file name="protractor.js" type="protractor">
23548                   var util, webdriver;
23549
23550                   var incBtn = element(by.id('inc'));
23551                   var counter = element(by.id('counter'));
23552                   var evilBtn = element(by.id('evil'));
23553                   var evilError = element(by.id('evilError'));
23554
23555                   function getAndClearSevereErrors() {
23556                     return browser.manage().logs().get('browser').then(function(browserLog) {
23557                       return browserLog.filter(function(logEntry) {
23558                         return logEntry.level.value > webdriver.logging.Level.WARNING.value;
23559                       });
23560                     });
23561                   }
23562
23563                   function clearErrors() {
23564                     getAndClearSevereErrors();
23565                   }
23566
23567                   function expectNoErrors() {
23568                     getAndClearSevereErrors().then(function(filteredLog) {
23569                       expect(filteredLog.length).toEqual(0);
23570                       if (filteredLog.length) {
23571                         console.log('browser console errors: ' + util.inspect(filteredLog));
23572                       }
23573                     });
23574                   }
23575
23576                   function expectError(regex) {
23577                     getAndClearSevereErrors().then(function(filteredLog) {
23578                       var found = false;
23579                       filteredLog.forEach(function(log) {
23580                         if (log.message.match(regex)) {
23581                           found = true;
23582                         }
23583                       });
23584                       if (!found) {
23585                         throw new Error('expected an error that matches ' + regex);
23586                       }
23587                     });
23588                   }
23589
23590                   beforeEach(function() {
23591                     util = require('util');
23592                     webdriver = require('protractor/node_modules/selenium-webdriver');
23593                   });
23594
23595                   // For now, we only test on Chrome,
23596                   // as Safari does not load the page with Protractor's injected scripts,
23597                   // and Firefox webdriver always disables content security policy (#6358)
23598                   if (browser.params.browser !== 'chrome') {
23599                     return;
23600                   }
23601
23602                   it('should not report errors when the page is loaded', function() {
23603                     // clear errors so we are not dependent on previous tests
23604                     clearErrors();
23605                     // Need to reload the page as the page is already loaded when
23606                     // we come here
23607                     browser.driver.getCurrentUrl().then(function(url) {
23608                       browser.get(url);
23609                     });
23610                     expectNoErrors();
23611                   });
23612
23613                   it('should evaluate expressions', function() {
23614                     expect(counter.getText()).toEqual('0');
23615                     incBtn.click();
23616                     expect(counter.getText()).toEqual('1');
23617                     expectNoErrors();
23618                   });
23619
23620                   it('should throw and report an error when using "eval"', function() {
23621                     evilBtn.click();
23622                     expect(evilError.getText()).toMatch(/Content Security Policy/);
23623                     expectError(/Content Security Policy/);
23624                   });
23625                 </file>
23626               </example>
23627           */
23628
23629         // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
23630         // bootstrap the system (before $parse is instantiated), for this reason we just have
23631         // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
23632
23633         /**
23634          * @ngdoc directive
23635          * @name ngClick
23636          *
23637          * @description
23638          * The ngClick directive allows you to specify custom behavior when
23639          * an element is clicked.
23640          *
23641          * @element ANY
23642          * @priority 0
23643          * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
23644          * click. ({@link guide/expression#-event- Event object is available as `$event`})
23645          *
23646          * @example
23647            <example>
23648              <file name="index.html">
23649               <button ng-click="count = count + 1" ng-init="count=0">
23650                 Increment
23651               </button>
23652               <span>
23653                 count: {{count}}
23654               </span>
23655              </file>
23656              <file name="protractor.js" type="protractor">
23657                it('should check ng-click', function() {
23658                  expect(element(by.binding('count')).getText()).toMatch('0');
23659                  element(by.css('button')).click();
23660                  expect(element(by.binding('count')).getText()).toMatch('1');
23661                });
23662              </file>
23663            </example>
23664          */
23665         /*
23666          * A collection of directives that allows creation of custom event handlers that are defined as
23667          * angular expressions and are compiled and executed within the current scope.
23668          */
23669         var ngEventDirectives = {};
23670
23671         // For events that might fire synchronously during DOM manipulation
23672         // we need to execute their event handlers asynchronously using $evalAsync,
23673         // so that they are not executed in an inconsistent state.
23674         var forceAsyncEvents = {
23675           'blur': true,
23676           'focus': true
23677         };
23678         forEach(
23679           'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
23680           function(eventName) {
23681             var directiveName = directiveNormalize('ng-' + eventName);
23682             ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
23683               return {
23684                 restrict: 'A',
23685                 compile: function($element, attr) {
23686                   // We expose the powerful $event object on the scope that provides access to the Window,
23687                   // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
23688                   // checks at the cost of speed since event handler expressions are not executed as
23689                   // frequently as regular change detection.
23690                   var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
23691                   return function ngEventHandler(scope, element) {
23692                     element.on(eventName, function(event) {
23693                       var callback = function() {
23694                         fn(scope, {$event:event});
23695                       };
23696                       if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
23697                         scope.$evalAsync(callback);
23698                       } else {
23699                         scope.$apply(callback);
23700                       }
23701                     });
23702                   };
23703                 }
23704               };
23705             }];
23706           }
23707         );
23708
23709         /**
23710          * @ngdoc directive
23711          * @name ngDblclick
23712          *
23713          * @description
23714          * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
23715          *
23716          * @element ANY
23717          * @priority 0
23718          * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
23719          * a dblclick. (The Event object is available as `$event`)
23720          *
23721          * @example
23722            <example>
23723              <file name="index.html">
23724               <button ng-dblclick="count = count + 1" ng-init="count=0">
23725                 Increment (on double click)
23726               </button>
23727               count: {{count}}
23728              </file>
23729            </example>
23730          */
23731
23732
23733         /**
23734          * @ngdoc directive
23735          * @name ngMousedown
23736          *
23737          * @description
23738          * The ngMousedown directive allows you to specify custom behavior on mousedown event.
23739          *
23740          * @element ANY
23741          * @priority 0
23742          * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
23743          * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
23744          *
23745          * @example
23746            <example>
23747              <file name="index.html">
23748               <button ng-mousedown="count = count + 1" ng-init="count=0">
23749                 Increment (on mouse down)
23750               </button>
23751               count: {{count}}
23752              </file>
23753            </example>
23754          */
23755
23756
23757         /**
23758          * @ngdoc directive
23759          * @name ngMouseup
23760          *
23761          * @description
23762          * Specify custom behavior on mouseup event.
23763          *
23764          * @element ANY
23765          * @priority 0
23766          * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
23767          * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
23768          *
23769          * @example
23770            <example>
23771              <file name="index.html">
23772               <button ng-mouseup="count = count + 1" ng-init="count=0">
23773                 Increment (on mouse up)
23774               </button>
23775               count: {{count}}
23776              </file>
23777            </example>
23778          */
23779
23780         /**
23781          * @ngdoc directive
23782          * @name ngMouseover
23783          *
23784          * @description
23785          * Specify custom behavior on mouseover event.
23786          *
23787          * @element ANY
23788          * @priority 0
23789          * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
23790          * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
23791          *
23792          * @example
23793            <example>
23794              <file name="index.html">
23795               <button ng-mouseover="count = count + 1" ng-init="count=0">
23796                 Increment (when mouse is over)
23797               </button>
23798               count: {{count}}
23799              </file>
23800            </example>
23801          */
23802
23803
23804         /**
23805          * @ngdoc directive
23806          * @name ngMouseenter
23807          *
23808          * @description
23809          * Specify custom behavior on mouseenter event.
23810          *
23811          * @element ANY
23812          * @priority 0
23813          * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
23814          * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
23815          *
23816          * @example
23817            <example>
23818              <file name="index.html">
23819               <button ng-mouseenter="count = count + 1" ng-init="count=0">
23820                 Increment (when mouse enters)
23821               </button>
23822               count: {{count}}
23823              </file>
23824            </example>
23825          */
23826
23827
23828         /**
23829          * @ngdoc directive
23830          * @name ngMouseleave
23831          *
23832          * @description
23833          * Specify custom behavior on mouseleave event.
23834          *
23835          * @element ANY
23836          * @priority 0
23837          * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
23838          * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
23839          *
23840          * @example
23841            <example>
23842              <file name="index.html">
23843               <button ng-mouseleave="count = count + 1" ng-init="count=0">
23844                 Increment (when mouse leaves)
23845               </button>
23846               count: {{count}}
23847              </file>
23848            </example>
23849          */
23850
23851
23852         /**
23853          * @ngdoc directive
23854          * @name ngMousemove
23855          *
23856          * @description
23857          * Specify custom behavior on mousemove event.
23858          *
23859          * @element ANY
23860          * @priority 0
23861          * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
23862          * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
23863          *
23864          * @example
23865            <example>
23866              <file name="index.html">
23867               <button ng-mousemove="count = count + 1" ng-init="count=0">
23868                 Increment (when mouse moves)
23869               </button>
23870               count: {{count}}
23871              </file>
23872            </example>
23873          */
23874
23875
23876         /**
23877          * @ngdoc directive
23878          * @name ngKeydown
23879          *
23880          * @description
23881          * Specify custom behavior on keydown event.
23882          *
23883          * @element ANY
23884          * @priority 0
23885          * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
23886          * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23887          *
23888          * @example
23889            <example>
23890              <file name="index.html">
23891               <input ng-keydown="count = count + 1" ng-init="count=0">
23892               key down count: {{count}}
23893              </file>
23894            </example>
23895          */
23896
23897
23898         /**
23899          * @ngdoc directive
23900          * @name ngKeyup
23901          *
23902          * @description
23903          * Specify custom behavior on keyup event.
23904          *
23905          * @element ANY
23906          * @priority 0
23907          * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
23908          * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23909          *
23910          * @example
23911            <example>
23912              <file name="index.html">
23913                <p>Typing in the input box below updates the key count</p>
23914                <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
23915
23916                <p>Typing in the input box below updates the keycode</p>
23917                <input ng-keyup="event=$event">
23918                <p>event keyCode: {{ event.keyCode }}</p>
23919                <p>event altKey: {{ event.altKey }}</p>
23920              </file>
23921            </example>
23922          */
23923
23924
23925         /**
23926          * @ngdoc directive
23927          * @name ngKeypress
23928          *
23929          * @description
23930          * Specify custom behavior on keypress event.
23931          *
23932          * @element ANY
23933          * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
23934          * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
23935          * and can be interrogated for keyCode, altKey, etc.)
23936          *
23937          * @example
23938            <example>
23939              <file name="index.html">
23940               <input ng-keypress="count = count + 1" ng-init="count=0">
23941               key press count: {{count}}
23942              </file>
23943            </example>
23944          */
23945
23946
23947         /**
23948          * @ngdoc directive
23949          * @name ngSubmit
23950          *
23951          * @description
23952          * Enables binding angular expressions to onsubmit events.
23953          *
23954          * Additionally it prevents the default action (which for form means sending the request to the
23955          * server and reloading the current page), but only if the form does not contain `action`,
23956          * `data-action`, or `x-action` attributes.
23957          *
23958          * <div class="alert alert-warning">
23959          * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
23960          * `ngSubmit` handlers together. See the
23961          * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
23962          * for a detailed discussion of when `ngSubmit` may be triggered.
23963          * </div>
23964          *
23965          * @element form
23966          * @priority 0
23967          * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
23968          * ({@link guide/expression#-event- Event object is available as `$event`})
23969          *
23970          * @example
23971            <example module="submitExample">
23972              <file name="index.html">
23973               <script>
23974                 angular.module('submitExample', [])
23975                   .controller('ExampleController', ['$scope', function($scope) {
23976                     $scope.list = [];
23977                     $scope.text = 'hello';
23978                     $scope.submit = function() {
23979                       if ($scope.text) {
23980                         $scope.list.push(this.text);
23981                         $scope.text = '';
23982                       }
23983                     };
23984                   }]);
23985               </script>
23986               <form ng-submit="submit()" ng-controller="ExampleController">
23987                 Enter text and hit enter:
23988                 <input type="text" ng-model="text" name="text" />
23989                 <input type="submit" id="submit" value="Submit" />
23990                 <pre>list={{list}}</pre>
23991               </form>
23992              </file>
23993              <file name="protractor.js" type="protractor">
23994                it('should check ng-submit', function() {
23995                  expect(element(by.binding('list')).getText()).toBe('list=[]');
23996                  element(by.css('#submit')).click();
23997                  expect(element(by.binding('list')).getText()).toContain('hello');
23998                  expect(element(by.model('text')).getAttribute('value')).toBe('');
23999                });
24000                it('should ignore empty strings', function() {
24001                  expect(element(by.binding('list')).getText()).toBe('list=[]');
24002                  element(by.css('#submit')).click();
24003                  element(by.css('#submit')).click();
24004                  expect(element(by.binding('list')).getText()).toContain('hello');
24005                 });
24006              </file>
24007            </example>
24008          */
24009
24010         /**
24011          * @ngdoc directive
24012          * @name ngFocus
24013          *
24014          * @description
24015          * Specify custom behavior on focus event.
24016          *
24017          * Note: As the `focus` event is executed synchronously when calling `input.focus()`
24018          * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24019          * during an `$apply` to ensure a consistent state.
24020          *
24021          * @element window, input, select, textarea, a
24022          * @priority 0
24023          * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
24024          * focus. ({@link guide/expression#-event- Event object is available as `$event`})
24025          *
24026          * @example
24027          * See {@link ng.directive:ngClick ngClick}
24028          */
24029
24030         /**
24031          * @ngdoc directive
24032          * @name ngBlur
24033          *
24034          * @description
24035          * Specify custom behavior on blur event.
24036          *
24037          * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
24038          * an element has lost focus.
24039          *
24040          * Note: As the `blur` event is executed synchronously also during DOM manipulations
24041          * (e.g. removing a focussed input),
24042          * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
24043          * during an `$apply` to ensure a consistent state.
24044          *
24045          * @element window, input, select, textarea, a
24046          * @priority 0
24047          * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
24048          * blur. ({@link guide/expression#-event- Event object is available as `$event`})
24049          *
24050          * @example
24051          * See {@link ng.directive:ngClick ngClick}
24052          */
24053
24054         /**
24055          * @ngdoc directive
24056          * @name ngCopy
24057          *
24058          * @description
24059          * Specify custom behavior on copy event.
24060          *
24061          * @element window, input, select, textarea, a
24062          * @priority 0
24063          * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
24064          * copy. ({@link guide/expression#-event- Event object is available as `$event`})
24065          *
24066          * @example
24067            <example>
24068              <file name="index.html">
24069               <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
24070               copied: {{copied}}
24071              </file>
24072            </example>
24073          */
24074
24075         /**
24076          * @ngdoc directive
24077          * @name ngCut
24078          *
24079          * @description
24080          * Specify custom behavior on cut event.
24081          *
24082          * @element window, input, select, textarea, a
24083          * @priority 0
24084          * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
24085          * cut. ({@link guide/expression#-event- Event object is available as `$event`})
24086          *
24087          * @example
24088            <example>
24089              <file name="index.html">
24090               <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
24091               cut: {{cut}}
24092              </file>
24093            </example>
24094          */
24095
24096         /**
24097          * @ngdoc directive
24098          * @name ngPaste
24099          *
24100          * @description
24101          * Specify custom behavior on paste event.
24102          *
24103          * @element window, input, select, textarea, a
24104          * @priority 0
24105          * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
24106          * paste. ({@link guide/expression#-event- Event object is available as `$event`})
24107          *
24108          * @example
24109            <example>
24110              <file name="index.html">
24111               <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
24112               pasted: {{paste}}
24113              </file>
24114            </example>
24115          */
24116
24117         /**
24118          * @ngdoc directive
24119          * @name ngIf
24120          * @restrict A
24121          * @multiElement
24122          *
24123          * @description
24124          * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
24125          * {expression}. If the expression assigned to `ngIf` evaluates to a false
24126          * value then the element is removed from the DOM, otherwise a clone of the
24127          * element is reinserted into the DOM.
24128          *
24129          * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
24130          * element in the DOM rather than changing its visibility via the `display` css property.  A common
24131          * case when this difference is significant is when using css selectors that rely on an element's
24132          * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
24133          *
24134          * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
24135          * is created when the element is restored.  The scope created within `ngIf` inherits from
24136          * its parent scope using
24137          * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
24138          * An important implication of this is if `ngModel` is used within `ngIf` to bind to
24139          * a javascript primitive defined in the parent scope. In this case any modifications made to the
24140          * variable within the child scope will override (hide) the value in the parent scope.
24141          *
24142          * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
24143          * is if an element's class attribute is directly modified after it's compiled, using something like
24144          * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
24145          * the added class will be lost because the original compiled state is used to regenerate the element.
24146          *
24147          * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
24148          * and `leave` effects.
24149          *
24150          * @animations
24151          * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
24152          * leave - happens just before the `ngIf` contents are removed from the DOM
24153          *
24154          * @element ANY
24155          * @scope
24156          * @priority 600
24157          * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
24158          *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
24159          *     element is added to the DOM tree.
24160          *
24161          * @example
24162           <example module="ngAnimate" deps="angular-animate.js" animations="true">
24163             <file name="index.html">
24164               <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
24165               Show when checked:
24166               <span ng-if="checked" class="animate-if">
24167                 This is removed when the checkbox is unchecked.
24168               </span>
24169             </file>
24170             <file name="animations.css">
24171               .animate-if {
24172                 background:white;
24173                 border:1px solid black;
24174                 padding:10px;
24175               }
24176
24177               .animate-if.ng-enter, .animate-if.ng-leave {
24178                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24179               }
24180
24181               .animate-if.ng-enter,
24182               .animate-if.ng-leave.ng-leave-active {
24183                 opacity:0;
24184               }
24185
24186               .animate-if.ng-leave,
24187               .animate-if.ng-enter.ng-enter-active {
24188                 opacity:1;
24189               }
24190             </file>
24191           </example>
24192          */
24193         var ngIfDirective = ['$animate', function($animate) {
24194           return {
24195             multiElement: true,
24196             transclude: 'element',
24197             priority: 600,
24198             terminal: true,
24199             restrict: 'A',
24200             $$tlb: true,
24201             link: function($scope, $element, $attr, ctrl, $transclude) {
24202                 var block, childScope, previousElements;
24203                 $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
24204
24205                   if (value) {
24206                     if (!childScope) {
24207                       $transclude(function(clone, newScope) {
24208                         childScope = newScope;
24209                         clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
24210                         // Note: We only need the first/last node of the cloned nodes.
24211                         // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24212                         // by a directive with templateUrl when its template arrives.
24213                         block = {
24214                           clone: clone
24215                         };
24216                         $animate.enter(clone, $element.parent(), $element);
24217                       });
24218                     }
24219                   } else {
24220                     if (previousElements) {
24221                       previousElements.remove();
24222                       previousElements = null;
24223                     }
24224                     if (childScope) {
24225                       childScope.$destroy();
24226                       childScope = null;
24227                     }
24228                     if (block) {
24229                       previousElements = getBlockNodes(block.clone);
24230                       $animate.leave(previousElements).then(function() {
24231                         previousElements = null;
24232                       });
24233                       block = null;
24234                     }
24235                   }
24236                 });
24237             }
24238           };
24239         }];
24240
24241         /**
24242          * @ngdoc directive
24243          * @name ngInclude
24244          * @restrict ECA
24245          *
24246          * @description
24247          * Fetches, compiles and includes an external HTML fragment.
24248          *
24249          * By default, the template URL is restricted to the same domain and protocol as the
24250          * application document. This is done by calling {@link $sce#getTrustedResourceUrl
24251          * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
24252          * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
24253          * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
24254          * ng.$sce Strict Contextual Escaping}.
24255          *
24256          * In addition, the browser's
24257          * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
24258          * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
24259          * policy may further restrict whether the template is successfully loaded.
24260          * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
24261          * access on some browsers.
24262          *
24263          * @animations
24264          * enter - animation is used to bring new content into the browser.
24265          * leave - animation is used to animate existing content away.
24266          *
24267          * The enter and leave animation occur concurrently.
24268          *
24269          * @scope
24270          * @priority 400
24271          *
24272          * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
24273          *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
24274          * @param {string=} onload Expression to evaluate when a new partial is loaded.
24275          *                  <div class="alert alert-warning">
24276          *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
24277          *                  a function with the name on the window element, which will usually throw a
24278          *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
24279          *                  different form that {@link guide/directive#normalization matches} `onload`.
24280          *                  </div>
24281            *
24282          * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
24283          *                  $anchorScroll} to scroll the viewport after the content is loaded.
24284          *
24285          *                  - If the attribute is not set, disable scrolling.
24286          *                  - If the attribute is set without value, enable scrolling.
24287          *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
24288          *
24289          * @example
24290           <example module="includeExample" deps="angular-animate.js" animations="true">
24291             <file name="index.html">
24292              <div ng-controller="ExampleController">
24293                <select ng-model="template" ng-options="t.name for t in templates">
24294                 <option value="">(blank)</option>
24295                </select>
24296                url of the template: <code>{{template.url}}</code>
24297                <hr/>
24298                <div class="slide-animate-container">
24299                  <div class="slide-animate" ng-include="template.url"></div>
24300                </div>
24301              </div>
24302             </file>
24303             <file name="script.js">
24304               angular.module('includeExample', ['ngAnimate'])
24305                 .controller('ExampleController', ['$scope', function($scope) {
24306                   $scope.templates =
24307                     [ { name: 'template1.html', url: 'template1.html'},
24308                       { name: 'template2.html', url: 'template2.html'} ];
24309                   $scope.template = $scope.templates[0];
24310                 }]);
24311              </file>
24312             <file name="template1.html">
24313               Content of template1.html
24314             </file>
24315             <file name="template2.html">
24316               Content of template2.html
24317             </file>
24318             <file name="animations.css">
24319               .slide-animate-container {
24320                 position:relative;
24321                 background:white;
24322                 border:1px solid black;
24323                 height:40px;
24324                 overflow:hidden;
24325               }
24326
24327               .slide-animate {
24328                 padding:10px;
24329               }
24330
24331               .slide-animate.ng-enter, .slide-animate.ng-leave {
24332                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
24333
24334                 position:absolute;
24335                 top:0;
24336                 left:0;
24337                 right:0;
24338                 bottom:0;
24339                 display:block;
24340                 padding:10px;
24341               }
24342
24343               .slide-animate.ng-enter {
24344                 top:-50px;
24345               }
24346               .slide-animate.ng-enter.ng-enter-active {
24347                 top:0;
24348               }
24349
24350               .slide-animate.ng-leave {
24351                 top:0;
24352               }
24353               .slide-animate.ng-leave.ng-leave-active {
24354                 top:50px;
24355               }
24356             </file>
24357             <file name="protractor.js" type="protractor">
24358               var templateSelect = element(by.model('template'));
24359               var includeElem = element(by.css('[ng-include]'));
24360
24361               it('should load template1.html', function() {
24362                 expect(includeElem.getText()).toMatch(/Content of template1.html/);
24363               });
24364
24365               it('should load template2.html', function() {
24366                 if (browser.params.browser == 'firefox') {
24367                   // Firefox can't handle using selects
24368                   // See https://github.com/angular/protractor/issues/480
24369                   return;
24370                 }
24371                 templateSelect.click();
24372                 templateSelect.all(by.css('option')).get(2).click();
24373                 expect(includeElem.getText()).toMatch(/Content of template2.html/);
24374               });
24375
24376               it('should change to blank', function() {
24377                 if (browser.params.browser == 'firefox') {
24378                   // Firefox can't handle using selects
24379                   return;
24380                 }
24381                 templateSelect.click();
24382                 templateSelect.all(by.css('option')).get(0).click();
24383                 expect(includeElem.isPresent()).toBe(false);
24384               });
24385             </file>
24386           </example>
24387          */
24388
24389
24390         /**
24391          * @ngdoc event
24392          * @name ngInclude#$includeContentRequested
24393          * @eventType emit on the scope ngInclude was declared in
24394          * @description
24395          * Emitted every time the ngInclude content is requested.
24396          *
24397          * @param {Object} angularEvent Synthetic event object.
24398          * @param {String} src URL of content to load.
24399          */
24400
24401
24402         /**
24403          * @ngdoc event
24404          * @name ngInclude#$includeContentLoaded
24405          * @eventType emit on the current ngInclude scope
24406          * @description
24407          * Emitted every time the ngInclude content is reloaded.
24408          *
24409          * @param {Object} angularEvent Synthetic event object.
24410          * @param {String} src URL of content to load.
24411          */
24412
24413
24414         /**
24415          * @ngdoc event
24416          * @name ngInclude#$includeContentError
24417          * @eventType emit on the scope ngInclude was declared in
24418          * @description
24419          * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
24420          *
24421          * @param {Object} angularEvent Synthetic event object.
24422          * @param {String} src URL of content to load.
24423          */
24424         var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
24425                           function($templateRequest,   $anchorScroll,   $animate) {
24426           return {
24427             restrict: 'ECA',
24428             priority: 400,
24429             terminal: true,
24430             transclude: 'element',
24431             controller: angular.noop,
24432             compile: function(element, attr) {
24433               var srcExp = attr.ngInclude || attr.src,
24434                   onloadExp = attr.onload || '',
24435                   autoScrollExp = attr.autoscroll;
24436
24437               return function(scope, $element, $attr, ctrl, $transclude) {
24438                 var changeCounter = 0,
24439                     currentScope,
24440                     previousElement,
24441                     currentElement;
24442
24443                 var cleanupLastIncludeContent = function() {
24444                   if (previousElement) {
24445                     previousElement.remove();
24446                     previousElement = null;
24447                   }
24448                   if (currentScope) {
24449                     currentScope.$destroy();
24450                     currentScope = null;
24451                   }
24452                   if (currentElement) {
24453                     $animate.leave(currentElement).then(function() {
24454                       previousElement = null;
24455                     });
24456                     previousElement = currentElement;
24457                     currentElement = null;
24458                   }
24459                 };
24460
24461                 scope.$watch(srcExp, function ngIncludeWatchAction(src) {
24462                   var afterAnimation = function() {
24463                     if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
24464                       $anchorScroll();
24465                     }
24466                   };
24467                   var thisChangeId = ++changeCounter;
24468
24469                   if (src) {
24470                     //set the 2nd param to true to ignore the template request error so that the inner
24471                     //contents and scope can be cleaned up.
24472                     $templateRequest(src, true).then(function(response) {
24473                       if (thisChangeId !== changeCounter) return;
24474                       var newScope = scope.$new();
24475                       ctrl.template = response;
24476
24477                       // Note: This will also link all children of ng-include that were contained in the original
24478                       // html. If that content contains controllers, ... they could pollute/change the scope.
24479                       // However, using ng-include on an element with additional content does not make sense...
24480                       // Note: We can't remove them in the cloneAttchFn of $transclude as that
24481                       // function is called before linking the content, which would apply child
24482                       // directives to non existing elements.
24483                       var clone = $transclude(newScope, function(clone) {
24484                         cleanupLastIncludeContent();
24485                         $animate.enter(clone, null, $element).then(afterAnimation);
24486                       });
24487
24488                       currentScope = newScope;
24489                       currentElement = clone;
24490
24491                       currentScope.$emit('$includeContentLoaded', src);
24492                       scope.$eval(onloadExp);
24493                     }, function() {
24494                       if (thisChangeId === changeCounter) {
24495                         cleanupLastIncludeContent();
24496                         scope.$emit('$includeContentError', src);
24497                       }
24498                     });
24499                     scope.$emit('$includeContentRequested', src);
24500                   } else {
24501                     cleanupLastIncludeContent();
24502                     ctrl.template = null;
24503                   }
24504                 });
24505               };
24506             }
24507           };
24508         }];
24509
24510         // This directive is called during the $transclude call of the first `ngInclude` directive.
24511         // It will replace and compile the content of the element with the loaded template.
24512         // We need this directive so that the element content is already filled when
24513         // the link function of another directive on the same element as ngInclude
24514         // is called.
24515         var ngIncludeFillContentDirective = ['$compile',
24516           function($compile) {
24517             return {
24518               restrict: 'ECA',
24519               priority: -400,
24520               require: 'ngInclude',
24521               link: function(scope, $element, $attr, ctrl) {
24522                 if (/SVG/.test($element[0].toString())) {
24523                   // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
24524                   // support innerHTML, so detect this here and try to generate the contents
24525                   // specially.
24526                   $element.empty();
24527                   $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
24528                       function namespaceAdaptedClone(clone) {
24529                     $element.append(clone);
24530                   }, {futureParentElement: $element});
24531                   return;
24532                 }
24533
24534                 $element.html(ctrl.template);
24535                 $compile($element.contents())(scope);
24536               }
24537             };
24538           }];
24539
24540         /**
24541          * @ngdoc directive
24542          * @name ngInit
24543          * @restrict AC
24544          *
24545          * @description
24546          * The `ngInit` directive allows you to evaluate an expression in the
24547          * current scope.
24548          *
24549          * <div class="alert alert-danger">
24550          * This directive can be abused to add unnecessary amounts of logic into your templates.
24551          * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
24552          * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
24553          * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
24554          * rather than `ngInit` to initialize values on a scope.
24555          * </div>
24556          *
24557          * <div class="alert alert-warning">
24558          * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
24559          * sure you have parentheses to ensure correct operator precedence:
24560          * <pre class="prettyprint">
24561          * `<div ng-init="test1 = ($index | toString)"></div>`
24562          * </pre>
24563          * </div>
24564          *
24565          * @priority 450
24566          *
24567          * @element ANY
24568          * @param {expression} ngInit {@link guide/expression Expression} to eval.
24569          *
24570          * @example
24571            <example module="initExample">
24572              <file name="index.html">
24573            <script>
24574              angular.module('initExample', [])
24575                .controller('ExampleController', ['$scope', function($scope) {
24576                  $scope.list = [['a', 'b'], ['c', 'd']];
24577                }]);
24578            </script>
24579            <div ng-controller="ExampleController">
24580              <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
24581                <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
24582                   <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
24583                </div>
24584              </div>
24585            </div>
24586              </file>
24587              <file name="protractor.js" type="protractor">
24588                it('should alias index positions', function() {
24589                  var elements = element.all(by.css('.example-init'));
24590                  expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
24591                  expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
24592                  expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
24593                  expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
24594                });
24595              </file>
24596            </example>
24597          */
24598         var ngInitDirective = ngDirective({
24599           priority: 450,
24600           compile: function() {
24601             return {
24602               pre: function(scope, element, attrs) {
24603                 scope.$eval(attrs.ngInit);
24604               }
24605             };
24606           }
24607         });
24608
24609         /**
24610          * @ngdoc directive
24611          * @name ngList
24612          *
24613          * @description
24614          * Text input that converts between a delimited string and an array of strings. The default
24615          * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
24616          * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
24617          *
24618          * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
24619          * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
24620          *   list item is respected. This implies that the user of the directive is responsible for
24621          *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
24622          *   tab or newline character.
24623          * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
24624          *   when joining the list items back together) and whitespace around each list item is stripped
24625          *   before it is added to the model.
24626          *
24627          * ### Example with Validation
24628          *
24629          * <example name="ngList-directive" module="listExample">
24630          *   <file name="app.js">
24631          *      angular.module('listExample', [])
24632          *        .controller('ExampleController', ['$scope', function($scope) {
24633          *          $scope.names = ['morpheus', 'neo', 'trinity'];
24634          *        }]);
24635          *   </file>
24636          *   <file name="index.html">
24637          *    <form name="myForm" ng-controller="ExampleController">
24638          *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
24639          *      <span role="alert">
24640          *        <span class="error" ng-show="myForm.namesInput.$error.required">
24641          *        Required!</span>
24642          *      </span>
24643          *      <br>
24644          *      <tt>names = {{names}}</tt><br/>
24645          *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
24646          *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
24647          *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24648          *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24649          *     </form>
24650          *   </file>
24651          *   <file name="protractor.js" type="protractor">
24652          *     var listInput = element(by.model('names'));
24653          *     var names = element(by.exactBinding('names'));
24654          *     var valid = element(by.binding('myForm.namesInput.$valid'));
24655          *     var error = element(by.css('span.error'));
24656          *
24657          *     it('should initialize to model', function() {
24658          *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
24659          *       expect(valid.getText()).toContain('true');
24660          *       expect(error.getCssValue('display')).toBe('none');
24661          *     });
24662          *
24663          *     it('should be invalid if empty', function() {
24664          *       listInput.clear();
24665          *       listInput.sendKeys('');
24666          *
24667          *       expect(names.getText()).toContain('');
24668          *       expect(valid.getText()).toContain('false');
24669          *       expect(error.getCssValue('display')).not.toBe('none');
24670          *     });
24671          *   </file>
24672          * </example>
24673          *
24674          * ### Example - splitting on newline
24675          * <example name="ngList-directive-newlines">
24676          *   <file name="index.html">
24677          *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
24678          *    <pre>{{ list | json }}</pre>
24679          *   </file>
24680          *   <file name="protractor.js" type="protractor">
24681          *     it("should split the text by newlines", function() {
24682          *       var listInput = element(by.model('list'));
24683          *       var output = element(by.binding('list | json'));
24684          *       listInput.sendKeys('abc\ndef\nghi');
24685          *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
24686          *     });
24687          *   </file>
24688          * </example>
24689          *
24690          * @element input
24691          * @param {string=} ngList optional delimiter that should be used to split the value.
24692          */
24693         var ngListDirective = function() {
24694           return {
24695             restrict: 'A',
24696             priority: 100,
24697             require: 'ngModel',
24698             link: function(scope, element, attr, ctrl) {
24699               // We want to control whitespace trimming so we use this convoluted approach
24700               // to access the ngList attribute, which doesn't pre-trim the attribute
24701               var ngList = element.attr(attr.$attr.ngList) || ', ';
24702               var trimValues = attr.ngTrim !== 'false';
24703               var separator = trimValues ? trim(ngList) : ngList;
24704
24705               var parse = function(viewValue) {
24706                 // If the viewValue is invalid (say required but empty) it will be `undefined`
24707                 if (isUndefined(viewValue)) return;
24708
24709                 var list = [];
24710
24711                 if (viewValue) {
24712                   forEach(viewValue.split(separator), function(value) {
24713                     if (value) list.push(trimValues ? trim(value) : value);
24714                   });
24715                 }
24716
24717                 return list;
24718               };
24719
24720               ctrl.$parsers.push(parse);
24721               ctrl.$formatters.push(function(value) {
24722                 if (isArray(value)) {
24723                   return value.join(ngList);
24724                 }
24725
24726                 return undefined;
24727               });
24728
24729               // Override the standard $isEmpty because an empty array means the input is empty.
24730               ctrl.$isEmpty = function(value) {
24731                 return !value || !value.length;
24732               };
24733             }
24734           };
24735         };
24736
24737         /* global VALID_CLASS: true,
24738           INVALID_CLASS: true,
24739           PRISTINE_CLASS: true,
24740           DIRTY_CLASS: true,
24741           UNTOUCHED_CLASS: true,
24742           TOUCHED_CLASS: true,
24743         */
24744
24745         var VALID_CLASS = 'ng-valid',
24746             INVALID_CLASS = 'ng-invalid',
24747             PRISTINE_CLASS = 'ng-pristine',
24748             DIRTY_CLASS = 'ng-dirty',
24749             UNTOUCHED_CLASS = 'ng-untouched',
24750             TOUCHED_CLASS = 'ng-touched',
24751             PENDING_CLASS = 'ng-pending';
24752
24753         var ngModelMinErr = minErr('ngModel');
24754
24755         /**
24756          * @ngdoc type
24757          * @name ngModel.NgModelController
24758          *
24759          * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
24760          * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
24761          * is set.
24762          * @property {*} $modelValue The value in the model that the control is bound to.
24763          * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
24764                the control reads value from the DOM. The functions are called in array order, each passing
24765                its return value through to the next. The last return value is forwarded to the
24766                {@link ngModel.NgModelController#$validators `$validators`} collection.
24767
24768         Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
24769         `$viewValue`}.
24770
24771         Returning `undefined` from a parser means a parse error occurred. In that case,
24772         no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
24773         will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
24774         is set to `true`. The parse error is stored in `ngModel.$error.parse`.
24775
24776          *
24777          * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
24778                the model value changes. The functions are called in reverse array order, each passing the value through to the
24779                next. The last return value is used as the actual DOM value.
24780                Used to format / convert values for display in the control.
24781          * ```js
24782          * function formatter(value) {
24783          *   if (value) {
24784          *     return value.toUpperCase();
24785          *   }
24786          * }
24787          * ngModel.$formatters.push(formatter);
24788          * ```
24789          *
24790          * @property {Object.<string, function>} $validators A collection of validators that are applied
24791          *      whenever the model value changes. The key value within the object refers to the name of the
24792          *      validator while the function refers to the validation operation. The validation operation is
24793          *      provided with the model value as an argument and must return a true or false value depending
24794          *      on the response of that validation.
24795          *
24796          * ```js
24797          * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
24798          *   var value = modelValue || viewValue;
24799          *   return /[0-9]+/.test(value) &&
24800          *          /[a-z]+/.test(value) &&
24801          *          /[A-Z]+/.test(value) &&
24802          *          /\W+/.test(value);
24803          * };
24804          * ```
24805          *
24806          * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
24807          *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
24808          *      is expected to return a promise when it is run during the model validation process. Once the promise
24809          *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
24810          *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
24811          *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
24812          *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
24813          *      will only run once all synchronous validators have passed.
24814          *
24815          * Please note that if $http is used then it is important that the server returns a success HTTP response code
24816          * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
24817          *
24818          * ```js
24819          * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
24820          *   var value = modelValue || viewValue;
24821          *
24822          *   // Lookup user by username
24823          *   return $http.get('/api/users/' + value).
24824          *      then(function resolved() {
24825          *        //username exists, this means validation fails
24826          *        return $q.reject('exists');
24827          *      }, function rejected() {
24828          *        //username does not exist, therefore this validation passes
24829          *        return true;
24830          *      });
24831          * };
24832          * ```
24833          *
24834          * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
24835          *     view value has changed. It is called with no arguments, and its return value is ignored.
24836          *     This can be used in place of additional $watches against the model value.
24837          *
24838          * @property {Object} $error An object hash with all failing validator ids as keys.
24839          * @property {Object} $pending An object hash with all pending validator ids as keys.
24840          *
24841          * @property {boolean} $untouched True if control has not lost focus yet.
24842          * @property {boolean} $touched True if control has lost focus.
24843          * @property {boolean} $pristine True if user has not interacted with the control yet.
24844          * @property {boolean} $dirty True if user has already interacted with the control.
24845          * @property {boolean} $valid True if there is no error.
24846          * @property {boolean} $invalid True if at least one error on the control.
24847          * @property {string} $name The name attribute of the control.
24848          *
24849          * @description
24850          *
24851          * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
24852          * The controller contains services for data-binding, validation, CSS updates, and value formatting
24853          * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
24854          * listening to DOM events.
24855          * Such DOM related logic should be provided by other directives which make use of
24856          * `NgModelController` for data-binding to control elements.
24857          * Angular provides this DOM logic for most {@link input `input`} elements.
24858          * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
24859          * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
24860          *
24861          * @example
24862          * ### Custom Control Example
24863          * This example shows how to use `NgModelController` with a custom control to achieve
24864          * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
24865          * collaborate together to achieve the desired result.
24866          *
24867          * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
24868          * contents be edited in place by the user.
24869          *
24870          * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
24871          * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
24872          * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
24873          * that content using the `$sce` service.
24874          *
24875          * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
24876             <file name="style.css">
24877               [contenteditable] {
24878                 border: 1px solid black;
24879                 background-color: white;
24880                 min-height: 20px;
24881               }
24882
24883               .ng-invalid {
24884                 border: 1px solid red;
24885               }
24886
24887             </file>
24888             <file name="script.js">
24889               angular.module('customControl', ['ngSanitize']).
24890                 directive('contenteditable', ['$sce', function($sce) {
24891                   return {
24892                     restrict: 'A', // only activate on element attribute
24893                     require: '?ngModel', // get a hold of NgModelController
24894                     link: function(scope, element, attrs, ngModel) {
24895                       if (!ngModel) return; // do nothing if no ng-model
24896
24897                       // Specify how UI should be updated
24898                       ngModel.$render = function() {
24899                         element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
24900                       };
24901
24902                       // Listen for change events to enable binding
24903                       element.on('blur keyup change', function() {
24904                         scope.$evalAsync(read);
24905                       });
24906                       read(); // initialize
24907
24908                       // Write data to the model
24909                       function read() {
24910                         var html = element.html();
24911                         // When we clear the content editable the browser leaves a <br> behind
24912                         // If strip-br attribute is provided then we strip this out
24913                         if ( attrs.stripBr && html == '<br>' ) {
24914                           html = '';
24915                         }
24916                         ngModel.$setViewValue(html);
24917                       }
24918                     }
24919                   };
24920                 }]);
24921             </file>
24922             <file name="index.html">
24923               <form name="myForm">
24924                <div contenteditable
24925                     name="myWidget" ng-model="userContent"
24926                     strip-br="true"
24927                     required>Change me!</div>
24928                 <span ng-show="myForm.myWidget.$error.required">Required!</span>
24929                <hr>
24930                <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
24931               </form>
24932             </file>
24933             <file name="protractor.js" type="protractor">
24934             it('should data-bind and become invalid', function() {
24935               if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
24936                 // SafariDriver can't handle contenteditable
24937                 // and Firefox driver can't clear contenteditables very well
24938                 return;
24939               }
24940               var contentEditable = element(by.css('[contenteditable]'));
24941               var content = 'Change me!';
24942
24943               expect(contentEditable.getText()).toEqual(content);
24944
24945               contentEditable.clear();
24946               contentEditable.sendKeys(protractor.Key.BACK_SPACE);
24947               expect(contentEditable.getText()).toEqual('');
24948               expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
24949             });
24950             </file>
24951          * </example>
24952          *
24953          *
24954          */
24955         var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
24956             function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
24957           this.$viewValue = Number.NaN;
24958           this.$modelValue = Number.NaN;
24959           this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
24960           this.$validators = {};
24961           this.$asyncValidators = {};
24962           this.$parsers = [];
24963           this.$formatters = [];
24964           this.$viewChangeListeners = [];
24965           this.$untouched = true;
24966           this.$touched = false;
24967           this.$pristine = true;
24968           this.$dirty = false;
24969           this.$valid = true;
24970           this.$invalid = false;
24971           this.$error = {}; // keep invalid keys here
24972           this.$$success = {}; // keep valid keys here
24973           this.$pending = undefined; // keep pending keys here
24974           this.$name = $interpolate($attr.name || '', false)($scope);
24975           this.$$parentForm = nullFormCtrl;
24976
24977           var parsedNgModel = $parse($attr.ngModel),
24978               parsedNgModelAssign = parsedNgModel.assign,
24979               ngModelGet = parsedNgModel,
24980               ngModelSet = parsedNgModelAssign,
24981               pendingDebounce = null,
24982               parserValid,
24983               ctrl = this;
24984
24985           this.$$setOptions = function(options) {
24986             ctrl.$options = options;
24987             if (options && options.getterSetter) {
24988               var invokeModelGetter = $parse($attr.ngModel + '()'),
24989                   invokeModelSetter = $parse($attr.ngModel + '($$$p)');
24990
24991               ngModelGet = function($scope) {
24992                 var modelValue = parsedNgModel($scope);
24993                 if (isFunction(modelValue)) {
24994                   modelValue = invokeModelGetter($scope);
24995                 }
24996                 return modelValue;
24997               };
24998               ngModelSet = function($scope, newValue) {
24999                 if (isFunction(parsedNgModel($scope))) {
25000                   invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
25001                 } else {
25002                   parsedNgModelAssign($scope, ctrl.$modelValue);
25003                 }
25004               };
25005             } else if (!parsedNgModel.assign) {
25006               throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
25007                   $attr.ngModel, startingTag($element));
25008             }
25009           };
25010
25011           /**
25012            * @ngdoc method
25013            * @name ngModel.NgModelController#$render
25014            *
25015            * @description
25016            * Called when the view needs to be updated. It is expected that the user of the ng-model
25017            * directive will implement this method.
25018            *
25019            * The `$render()` method is invoked in the following situations:
25020            *
25021            * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
25022            *   committed value then `$render()` is called to update the input control.
25023            * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
25024            *   the `$viewValue` are different from last time.
25025            *
25026            * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
25027            * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
25028            * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
25029            * invoked if you only change a property on the objects.
25030            */
25031           this.$render = noop;
25032
25033           /**
25034            * @ngdoc method
25035            * @name ngModel.NgModelController#$isEmpty
25036            *
25037            * @description
25038            * This is called when we need to determine if the value of an input is empty.
25039            *
25040            * For instance, the required directive does this to work out if the input has data or not.
25041            *
25042            * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
25043            *
25044            * You can override this for input directives whose concept of being empty is different from the
25045            * default. The `checkboxInputType` directive does this because in its case a value of `false`
25046            * implies empty.
25047            *
25048            * @param {*} value The value of the input to check for emptiness.
25049            * @returns {boolean} True if `value` is "empty".
25050            */
25051           this.$isEmpty = function(value) {
25052             return isUndefined(value) || value === '' || value === null || value !== value;
25053           };
25054
25055           var currentValidationRunId = 0;
25056
25057           /**
25058            * @ngdoc method
25059            * @name ngModel.NgModelController#$setValidity
25060            *
25061            * @description
25062            * Change the validity state, and notify the form.
25063            *
25064            * This method can be called within $parsers/$formatters or a custom validation implementation.
25065            * However, in most cases it should be sufficient to use the `ngModel.$validators` and
25066            * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
25067            *
25068            * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
25069            *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
25070            *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
25071            *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
25072            *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
25073            *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
25074            * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
25075            *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
25076            *                          Skipped is used by Angular when validators do not run because of parse errors and
25077            *                          when `$asyncValidators` do not run because any of the `$validators` failed.
25078            */
25079           addSetValidityMethod({
25080             ctrl: this,
25081             $element: $element,
25082             set: function(object, property) {
25083               object[property] = true;
25084             },
25085             unset: function(object, property) {
25086               delete object[property];
25087             },
25088             $animate: $animate
25089           });
25090
25091           /**
25092            * @ngdoc method
25093            * @name ngModel.NgModelController#$setPristine
25094            *
25095            * @description
25096            * Sets the control to its pristine state.
25097            *
25098            * This method can be called to remove the `ng-dirty` class and set the control to its pristine
25099            * state (`ng-pristine` class). A model is considered to be pristine when the control
25100            * has not been changed from when first compiled.
25101            */
25102           this.$setPristine = function() {
25103             ctrl.$dirty = false;
25104             ctrl.$pristine = true;
25105             $animate.removeClass($element, DIRTY_CLASS);
25106             $animate.addClass($element, PRISTINE_CLASS);
25107           };
25108
25109           /**
25110            * @ngdoc method
25111            * @name ngModel.NgModelController#$setDirty
25112            *
25113            * @description
25114            * Sets the control to its dirty state.
25115            *
25116            * This method can be called to remove the `ng-pristine` class and set the control to its dirty
25117            * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
25118            * from when first compiled.
25119            */
25120           this.$setDirty = function() {
25121             ctrl.$dirty = true;
25122             ctrl.$pristine = false;
25123             $animate.removeClass($element, PRISTINE_CLASS);
25124             $animate.addClass($element, DIRTY_CLASS);
25125             ctrl.$$parentForm.$setDirty();
25126           };
25127
25128           /**
25129            * @ngdoc method
25130            * @name ngModel.NgModelController#$setUntouched
25131            *
25132            * @description
25133            * Sets the control to its untouched state.
25134            *
25135            * This method can be called to remove the `ng-touched` class and set the control to its
25136            * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
25137            * by default, however this function can be used to restore that state if the model has
25138            * already been touched by the user.
25139            */
25140           this.$setUntouched = function() {
25141             ctrl.$touched = false;
25142             ctrl.$untouched = true;
25143             $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
25144           };
25145
25146           /**
25147            * @ngdoc method
25148            * @name ngModel.NgModelController#$setTouched
25149            *
25150            * @description
25151            * Sets the control to its touched state.
25152            *
25153            * This method can be called to remove the `ng-untouched` class and set the control to its
25154            * touched state (`ng-touched` class). A model is considered to be touched when the user has
25155            * first focused the control element and then shifted focus away from the control (blur event).
25156            */
25157           this.$setTouched = function() {
25158             ctrl.$touched = true;
25159             ctrl.$untouched = false;
25160             $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
25161           };
25162
25163           /**
25164            * @ngdoc method
25165            * @name ngModel.NgModelController#$rollbackViewValue
25166            *
25167            * @description
25168            * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
25169            * which may be caused by a pending debounced event or because the input is waiting for a some
25170            * future event.
25171            *
25172            * If you have an input that uses `ng-model-options` to set up debounced events or events such
25173            * as blur you can have a situation where there is a period when the `$viewValue`
25174            * is out of synch with the ngModel's `$modelValue`.
25175            *
25176            * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
25177            * programmatically before these debounced/future events have resolved/occurred, because Angular's
25178            * dirty checking mechanism is not able to tell whether the model has actually changed or not.
25179            *
25180            * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
25181            * input which may have such events pending. This is important in order to make sure that the
25182            * input field will be updated with the new model value and any pending operations are cancelled.
25183            *
25184            * <example name="ng-model-cancel-update" module="cancel-update-example">
25185            *   <file name="app.js">
25186            *     angular.module('cancel-update-example', [])
25187            *
25188            *     .controller('CancelUpdateController', ['$scope', function($scope) {
25189            *       $scope.resetWithCancel = function(e) {
25190            *         if (e.keyCode == 27) {
25191            *           $scope.myForm.myInput1.$rollbackViewValue();
25192            *           $scope.myValue = '';
25193            *         }
25194            *       };
25195            *       $scope.resetWithoutCancel = function(e) {
25196            *         if (e.keyCode == 27) {
25197            *           $scope.myValue = '';
25198            *         }
25199            *       };
25200            *     }]);
25201            *   </file>
25202            *   <file name="index.html">
25203            *     <div ng-controller="CancelUpdateController">
25204            *       <p>Try typing something in each input.  See that the model only updates when you
25205            *          blur off the input.
25206            *        </p>
25207            *        <p>Now see what happens if you start typing then press the Escape key</p>
25208            *
25209            *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
25210            *         <p id="inputDescription1">With $rollbackViewValue()</p>
25211            *         <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
25212            *                ng-keydown="resetWithCancel($event)"><br/>
25213            *         myValue: "{{ myValue }}"
25214            *
25215            *         <p id="inputDescription2">Without $rollbackViewValue()</p>
25216            *         <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
25217            *                ng-keydown="resetWithoutCancel($event)"><br/>
25218            *         myValue: "{{ myValue }}"
25219            *       </form>
25220            *     </div>
25221            *   </file>
25222            * </example>
25223            */
25224           this.$rollbackViewValue = function() {
25225             $timeout.cancel(pendingDebounce);
25226             ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
25227             ctrl.$render();
25228           };
25229
25230           /**
25231            * @ngdoc method
25232            * @name ngModel.NgModelController#$validate
25233            *
25234            * @description
25235            * Runs each of the registered validators (first synchronous validators and then
25236            * asynchronous validators).
25237            * If the validity changes to invalid, the model will be set to `undefined`,
25238            * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
25239            * If the validity changes to valid, it will set the model to the last available valid
25240            * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
25241            */
25242           this.$validate = function() {
25243             // ignore $validate before model is initialized
25244             if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25245               return;
25246             }
25247
25248             var viewValue = ctrl.$$lastCommittedViewValue;
25249             // Note: we use the $$rawModelValue as $modelValue might have been
25250             // set to undefined during a view -> model update that found validation
25251             // errors. We can't parse the view here, since that could change
25252             // the model although neither viewValue nor the model on the scope changed
25253             var modelValue = ctrl.$$rawModelValue;
25254
25255             var prevValid = ctrl.$valid;
25256             var prevModelValue = ctrl.$modelValue;
25257
25258             var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25259
25260             ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
25261               // If there was no change in validity, don't update the model
25262               // This prevents changing an invalid modelValue to undefined
25263               if (!allowInvalid && prevValid !== allValid) {
25264                 // Note: Don't check ctrl.$valid here, as we could have
25265                 // external validators (e.g. calculated on the server),
25266                 // that just call $setValidity and need the model value
25267                 // to calculate their validity.
25268                 ctrl.$modelValue = allValid ? modelValue : undefined;
25269
25270                 if (ctrl.$modelValue !== prevModelValue) {
25271                   ctrl.$$writeModelToScope();
25272                 }
25273               }
25274             });
25275
25276           };
25277
25278           this.$$runValidators = function(modelValue, viewValue, doneCallback) {
25279             currentValidationRunId++;
25280             var localValidationRunId = currentValidationRunId;
25281
25282             // check parser error
25283             if (!processParseErrors()) {
25284               validationDone(false);
25285               return;
25286             }
25287             if (!processSyncValidators()) {
25288               validationDone(false);
25289               return;
25290             }
25291             processAsyncValidators();
25292
25293             function processParseErrors() {
25294               var errorKey = ctrl.$$parserName || 'parse';
25295               if (isUndefined(parserValid)) {
25296                 setValidity(errorKey, null);
25297               } else {
25298                 if (!parserValid) {
25299                   forEach(ctrl.$validators, function(v, name) {
25300                     setValidity(name, null);
25301                   });
25302                   forEach(ctrl.$asyncValidators, function(v, name) {
25303                     setValidity(name, null);
25304                   });
25305                 }
25306                 // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
25307                 setValidity(errorKey, parserValid);
25308                 return parserValid;
25309               }
25310               return true;
25311             }
25312
25313             function processSyncValidators() {
25314               var syncValidatorsValid = true;
25315               forEach(ctrl.$validators, function(validator, name) {
25316                 var result = validator(modelValue, viewValue);
25317                 syncValidatorsValid = syncValidatorsValid && result;
25318                 setValidity(name, result);
25319               });
25320               if (!syncValidatorsValid) {
25321                 forEach(ctrl.$asyncValidators, function(v, name) {
25322                   setValidity(name, null);
25323                 });
25324                 return false;
25325               }
25326               return true;
25327             }
25328
25329             function processAsyncValidators() {
25330               var validatorPromises = [];
25331               var allValid = true;
25332               forEach(ctrl.$asyncValidators, function(validator, name) {
25333                 var promise = validator(modelValue, viewValue);
25334                 if (!isPromiseLike(promise)) {
25335                   throw ngModelMinErr("$asyncValidators",
25336                     "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
25337                 }
25338                 setValidity(name, undefined);
25339                 validatorPromises.push(promise.then(function() {
25340                   setValidity(name, true);
25341                 }, function(error) {
25342                   allValid = false;
25343                   setValidity(name, false);
25344                 }));
25345               });
25346               if (!validatorPromises.length) {
25347                 validationDone(true);
25348               } else {
25349                 $q.all(validatorPromises).then(function() {
25350                   validationDone(allValid);
25351                 }, noop);
25352               }
25353             }
25354
25355             function setValidity(name, isValid) {
25356               if (localValidationRunId === currentValidationRunId) {
25357                 ctrl.$setValidity(name, isValid);
25358               }
25359             }
25360
25361             function validationDone(allValid) {
25362               if (localValidationRunId === currentValidationRunId) {
25363
25364                 doneCallback(allValid);
25365               }
25366             }
25367           };
25368
25369           /**
25370            * @ngdoc method
25371            * @name ngModel.NgModelController#$commitViewValue
25372            *
25373            * @description
25374            * Commit a pending update to the `$modelValue`.
25375            *
25376            * Updates may be pending by a debounced event or because the input is waiting for a some future
25377            * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
25378            * usually handles calling this in response to input events.
25379            */
25380           this.$commitViewValue = function() {
25381             var viewValue = ctrl.$viewValue;
25382
25383             $timeout.cancel(pendingDebounce);
25384
25385             // If the view value has not changed then we should just exit, except in the case where there is
25386             // a native validator on the element. In this case the validation state may have changed even though
25387             // the viewValue has stayed empty.
25388             if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
25389               return;
25390             }
25391             ctrl.$$lastCommittedViewValue = viewValue;
25392
25393             // change to dirty
25394             if (ctrl.$pristine) {
25395               this.$setDirty();
25396             }
25397             this.$$parseAndValidate();
25398           };
25399
25400           this.$$parseAndValidate = function() {
25401             var viewValue = ctrl.$$lastCommittedViewValue;
25402             var modelValue = viewValue;
25403             parserValid = isUndefined(modelValue) ? undefined : true;
25404
25405             if (parserValid) {
25406               for (var i = 0; i < ctrl.$parsers.length; i++) {
25407                 modelValue = ctrl.$parsers[i](modelValue);
25408                 if (isUndefined(modelValue)) {
25409                   parserValid = false;
25410                   break;
25411                 }
25412               }
25413             }
25414             if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
25415               // ctrl.$modelValue has not been touched yet...
25416               ctrl.$modelValue = ngModelGet($scope);
25417             }
25418             var prevModelValue = ctrl.$modelValue;
25419             var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
25420             ctrl.$$rawModelValue = modelValue;
25421
25422             if (allowInvalid) {
25423               ctrl.$modelValue = modelValue;
25424               writeToModelIfNeeded();
25425             }
25426
25427             // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
25428             // This can happen if e.g. $setViewValue is called from inside a parser
25429             ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
25430               if (!allowInvalid) {
25431                 // Note: Don't check ctrl.$valid here, as we could have
25432                 // external validators (e.g. calculated on the server),
25433                 // that just call $setValidity and need the model value
25434                 // to calculate their validity.
25435                 ctrl.$modelValue = allValid ? modelValue : undefined;
25436                 writeToModelIfNeeded();
25437               }
25438             });
25439
25440             function writeToModelIfNeeded() {
25441               if (ctrl.$modelValue !== prevModelValue) {
25442                 ctrl.$$writeModelToScope();
25443               }
25444             }
25445           };
25446
25447           this.$$writeModelToScope = function() {
25448             ngModelSet($scope, ctrl.$modelValue);
25449             forEach(ctrl.$viewChangeListeners, function(listener) {
25450               try {
25451                 listener();
25452               } catch (e) {
25453                 $exceptionHandler(e);
25454               }
25455             });
25456           };
25457
25458           /**
25459            * @ngdoc method
25460            * @name ngModel.NgModelController#$setViewValue
25461            *
25462            * @description
25463            * Update the view value.
25464            *
25465            * This method should be called when a control wants to change the view value; typically,
25466            * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
25467            * directive calls it when the value of the input changes and {@link ng.directive:select select}
25468            * calls it when an option is selected.
25469            *
25470            * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
25471            * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
25472            * value sent directly for processing, finally to be applied to `$modelValue` and then the
25473            * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
25474            * in the `$viewChangeListeners` list, are called.
25475            *
25476            * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
25477            * and the `default` trigger is not listed, all those actions will remain pending until one of the
25478            * `updateOn` events is triggered on the DOM element.
25479            * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
25480            * directive is used with a custom debounce for this particular event.
25481            * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
25482            * is specified, once the timer runs out.
25483            *
25484            * When used with standard inputs, the view value will always be a string (which is in some cases
25485            * parsed into another type, such as a `Date` object for `input[date]`.)
25486            * However, custom controls might also pass objects to this method. In this case, we should make
25487            * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
25488            * perform a deep watch of objects, it only looks for a change of identity. If you only change
25489            * the property of the object then ngModel will not realise that the object has changed and
25490            * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
25491            * not change properties of the copy once it has been passed to `$setViewValue`.
25492            * Otherwise you may cause the model value on the scope to change incorrectly.
25493            *
25494            * <div class="alert alert-info">
25495            * In any case, the value passed to the method should always reflect the current value
25496            * of the control. For example, if you are calling `$setViewValue` for an input element,
25497            * you should pass the input DOM value. Otherwise, the control and the scope model become
25498            * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
25499            * the control's DOM value in any way. If we want to change the control's DOM value
25500            * programmatically, we should update the `ngModel` scope expression. Its new value will be
25501            * picked up by the model controller, which will run it through the `$formatters`, `$render` it
25502            * to update the DOM, and finally call `$validate` on it.
25503            * </div>
25504            *
25505            * @param {*} value value from the view.
25506            * @param {string} trigger Event that triggered the update.
25507            */
25508           this.$setViewValue = function(value, trigger) {
25509             ctrl.$viewValue = value;
25510             if (!ctrl.$options || ctrl.$options.updateOnDefault) {
25511               ctrl.$$debounceViewValueCommit(trigger);
25512             }
25513           };
25514
25515           this.$$debounceViewValueCommit = function(trigger) {
25516             var debounceDelay = 0,
25517                 options = ctrl.$options,
25518                 debounce;
25519
25520             if (options && isDefined(options.debounce)) {
25521               debounce = options.debounce;
25522               if (isNumber(debounce)) {
25523                 debounceDelay = debounce;
25524               } else if (isNumber(debounce[trigger])) {
25525                 debounceDelay = debounce[trigger];
25526               } else if (isNumber(debounce['default'])) {
25527                 debounceDelay = debounce['default'];
25528               }
25529             }
25530
25531             $timeout.cancel(pendingDebounce);
25532             if (debounceDelay) {
25533               pendingDebounce = $timeout(function() {
25534                 ctrl.$commitViewValue();
25535               }, debounceDelay);
25536             } else if ($rootScope.$$phase) {
25537               ctrl.$commitViewValue();
25538             } else {
25539               $scope.$apply(function() {
25540                 ctrl.$commitViewValue();
25541               });
25542             }
25543           };
25544
25545           // model -> value
25546           // Note: we cannot use a normal scope.$watch as we want to detect the following:
25547           // 1. scope value is 'a'
25548           // 2. user enters 'b'
25549           // 3. ng-change kicks in and reverts scope value to 'a'
25550           //    -> scope value did not change since the last digest as
25551           //       ng-change executes in apply phase
25552           // 4. view should be changed back to 'a'
25553           $scope.$watch(function ngModelWatch() {
25554             var modelValue = ngModelGet($scope);
25555
25556             // if scope model value and ngModel value are out of sync
25557             // TODO(perf): why not move this to the action fn?
25558             if (modelValue !== ctrl.$modelValue &&
25559                // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
25560                (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
25561             ) {
25562               ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
25563               parserValid = undefined;
25564
25565               var formatters = ctrl.$formatters,
25566                   idx = formatters.length;
25567
25568               var viewValue = modelValue;
25569               while (idx--) {
25570                 viewValue = formatters[idx](viewValue);
25571               }
25572               if (ctrl.$viewValue !== viewValue) {
25573                 ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
25574                 ctrl.$render();
25575
25576                 ctrl.$$runValidators(modelValue, viewValue, noop);
25577               }
25578             }
25579
25580             return modelValue;
25581           });
25582         }];
25583
25584
25585         /**
25586          * @ngdoc directive
25587          * @name ngModel
25588          *
25589          * @element input
25590          * @priority 1
25591          *
25592          * @description
25593          * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
25594          * property on the scope using {@link ngModel.NgModelController NgModelController},
25595          * which is created and exposed by this directive.
25596          *
25597          * `ngModel` is responsible for:
25598          *
25599          * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
25600          *   require.
25601          * - Providing validation behavior (i.e. required, number, email, url).
25602          * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
25603          * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
25604          * - Registering the control with its parent {@link ng.directive:form form}.
25605          *
25606          * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
25607          * current scope. If the property doesn't already exist on this scope, it will be created
25608          * implicitly and added to the scope.
25609          *
25610          * For best practices on using `ngModel`, see:
25611          *
25612          *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
25613          *
25614          * For basic examples, how to use `ngModel`, see:
25615          *
25616          *  - {@link ng.directive:input input}
25617          *    - {@link input[text] text}
25618          *    - {@link input[checkbox] checkbox}
25619          *    - {@link input[radio] radio}
25620          *    - {@link input[number] number}
25621          *    - {@link input[email] email}
25622          *    - {@link input[url] url}
25623          *    - {@link input[date] date}
25624          *    - {@link input[datetime-local] datetime-local}
25625          *    - {@link input[time] time}
25626          *    - {@link input[month] month}
25627          *    - {@link input[week] week}
25628          *  - {@link ng.directive:select select}
25629          *  - {@link ng.directive:textarea textarea}
25630          *
25631          * # CSS classes
25632          * The following CSS classes are added and removed on the associated input/select/textarea element
25633          * depending on the validity of the model.
25634          *
25635          *  - `ng-valid`: the model is valid
25636          *  - `ng-invalid`: the model is invalid
25637          *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
25638          *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
25639          *  - `ng-pristine`: the control hasn't been interacted with yet
25640          *  - `ng-dirty`: the control has been interacted with
25641          *  - `ng-touched`: the control has been blurred
25642          *  - `ng-untouched`: the control hasn't been blurred
25643          *  - `ng-pending`: any `$asyncValidators` are unfulfilled
25644          *
25645          * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25646          *
25647          * ## Animation Hooks
25648          *
25649          * Animations within models are triggered when any of the associated CSS classes are added and removed
25650          * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
25651          * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
25652          * The animations that are triggered within ngModel are similar to how they work in ngClass and
25653          * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
25654          *
25655          * The following example shows a simple way to utilize CSS transitions to style an input element
25656          * that has been rendered as invalid after it has been validated:
25657          *
25658          * <pre>
25659          * //be sure to include ngAnimate as a module to hook into more
25660          * //advanced animations
25661          * .my-input {
25662          *   transition:0.5s linear all;
25663          *   background: white;
25664          * }
25665          * .my-input.ng-invalid {
25666          *   background: red;
25667          *   color:white;
25668          * }
25669          * </pre>
25670          *
25671          * @example
25672          * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
25673              <file name="index.html">
25674                <script>
25675                 angular.module('inputExample', [])
25676                   .controller('ExampleController', ['$scope', function($scope) {
25677                     $scope.val = '1';
25678                   }]);
25679                </script>
25680                <style>
25681                  .my-input {
25682                    transition:all linear 0.5s;
25683                    background: transparent;
25684                  }
25685                  .my-input.ng-invalid {
25686                    color:white;
25687                    background: red;
25688                  }
25689                </style>
25690                <p id="inputDescription">
25691                 Update input to see transitions when valid/invalid.
25692                 Integer is a valid value.
25693                </p>
25694                <form name="testForm" ng-controller="ExampleController">
25695                  <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
25696                         aria-describedby="inputDescription" />
25697                </form>
25698              </file>
25699          * </example>
25700          *
25701          * ## Binding to a getter/setter
25702          *
25703          * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
25704          * function that returns a representation of the model when called with zero arguments, and sets
25705          * the internal state of a model when called with an argument. It's sometimes useful to use this
25706          * for models that have an internal representation that's different from what the model exposes
25707          * to the view.
25708          *
25709          * <div class="alert alert-success">
25710          * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
25711          * frequently than other parts of your code.
25712          * </div>
25713          *
25714          * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
25715          * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
25716          * a `<form>`, which will enable this behavior for all `<input>`s within it. See
25717          * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
25718          *
25719          * The following example shows how to use `ngModel` with a getter/setter:
25720          *
25721          * @example
25722          * <example name="ngModel-getter-setter" module="getterSetterExample">
25723              <file name="index.html">
25724                <div ng-controller="ExampleController">
25725                  <form name="userForm">
25726                    <label>Name:
25727                      <input type="text" name="userName"
25728                             ng-model="user.name"
25729                             ng-model-options="{ getterSetter: true }" />
25730                    </label>
25731                  </form>
25732                  <pre>user.name = <span ng-bind="user.name()"></span></pre>
25733                </div>
25734              </file>
25735              <file name="app.js">
25736                angular.module('getterSetterExample', [])
25737                  .controller('ExampleController', ['$scope', function($scope) {
25738                    var _name = 'Brian';
25739                    $scope.user = {
25740                      name: function(newName) {
25741                       // Note that newName can be undefined for two reasons:
25742                       // 1. Because it is called as a getter and thus called with no arguments
25743                       // 2. Because the property should actually be set to undefined. This happens e.g. if the
25744                       //    input is invalid
25745                       return arguments.length ? (_name = newName) : _name;
25746                      }
25747                    };
25748                  }]);
25749              </file>
25750          * </example>
25751          */
25752         var ngModelDirective = ['$rootScope', function($rootScope) {
25753           return {
25754             restrict: 'A',
25755             require: ['ngModel', '^?form', '^?ngModelOptions'],
25756             controller: NgModelController,
25757             // Prelink needs to run before any input directive
25758             // so that we can set the NgModelOptions in NgModelController
25759             // before anyone else uses it.
25760             priority: 1,
25761             compile: function ngModelCompile(element) {
25762               // Setup initial state of the control
25763               element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
25764
25765               return {
25766                 pre: function ngModelPreLink(scope, element, attr, ctrls) {
25767                   var modelCtrl = ctrls[0],
25768                       formCtrl = ctrls[1] || modelCtrl.$$parentForm;
25769
25770                   modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
25771
25772                   // notify others, especially parent forms
25773                   formCtrl.$addControl(modelCtrl);
25774
25775                   attr.$observe('name', function(newValue) {
25776                     if (modelCtrl.$name !== newValue) {
25777                       modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
25778                     }
25779                   });
25780
25781                   scope.$on('$destroy', function() {
25782                     modelCtrl.$$parentForm.$removeControl(modelCtrl);
25783                   });
25784                 },
25785                 post: function ngModelPostLink(scope, element, attr, ctrls) {
25786                   var modelCtrl = ctrls[0];
25787                   if (modelCtrl.$options && modelCtrl.$options.updateOn) {
25788                     element.on(modelCtrl.$options.updateOn, function(ev) {
25789                       modelCtrl.$$debounceViewValueCommit(ev && ev.type);
25790                     });
25791                   }
25792
25793                   element.on('blur', function(ev) {
25794                     if (modelCtrl.$touched) return;
25795
25796                     if ($rootScope.$$phase) {
25797                       scope.$evalAsync(modelCtrl.$setTouched);
25798                     } else {
25799                       scope.$apply(modelCtrl.$setTouched);
25800                     }
25801                   });
25802                 }
25803               };
25804             }
25805           };
25806         }];
25807
25808         var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25809
25810         /**
25811          * @ngdoc directive
25812          * @name ngModelOptions
25813          *
25814          * @description
25815          * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
25816          * events that will trigger a model update and/or a debouncing delay so that the actual update only
25817          * takes place when a timer expires; this timer will be reset after another change takes place.
25818          *
25819          * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
25820          * be different from the value in the actual model. This means that if you update the model you
25821          * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
25822          * order to make sure it is synchronized with the model and that any debounced action is canceled.
25823          *
25824          * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
25825          * method is by making sure the input is placed inside a form that has a `name` attribute. This is
25826          * important because `form` controllers are published to the related scope under the name in their
25827          * `name` attribute.
25828          *
25829          * Any pending changes will take place immediately when an enclosing form is submitted via the
25830          * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
25831          * to have access to the updated model.
25832          *
25833          * `ngModelOptions` has an effect on the element it's declared on and its descendants.
25834          *
25835          * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
25836          *   - `updateOn`: string specifying which event should the input be bound to. You can set several
25837          *     events using an space delimited list. There is a special event called `default` that
25838          *     matches the default events belonging of the control.
25839          *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
25840          *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
25841          *     custom value for each event. For example:
25842          *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
25843          *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
25844          *     not validate correctly instead of the default behavior of setting the model to undefined.
25845          *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
25846                `ngModel` as getters/setters.
25847          *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
25848          *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
25849          *     continental US time zone abbreviations, but for general use, use a time zone offset, for
25850          *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
25851          *     If not specified, the timezone of the browser will be used.
25852          *
25853          * @example
25854
25855           The following example shows how to override immediate updates. Changes on the inputs within the
25856           form will update the model only when the control loses focus (blur event). If `escape` key is
25857           pressed while the input field is focused, the value is reset to the value in the current model.
25858
25859           <example name="ngModelOptions-directive-blur" module="optionsExample">
25860             <file name="index.html">
25861               <div ng-controller="ExampleController">
25862                 <form name="userForm">
25863                   <label>Name:
25864                     <input type="text" name="userName"
25865                            ng-model="user.name"
25866                            ng-model-options="{ updateOn: 'blur' }"
25867                            ng-keyup="cancel($event)" />
25868                   </label><br />
25869                   <label>Other data:
25870                     <input type="text" ng-model="user.data" />
25871                   </label><br />
25872                 </form>
25873                 <pre>user.name = <span ng-bind="user.name"></span></pre>
25874                 <pre>user.data = <span ng-bind="user.data"></span></pre>
25875               </div>
25876             </file>
25877             <file name="app.js">
25878               angular.module('optionsExample', [])
25879                 .controller('ExampleController', ['$scope', function($scope) {
25880                   $scope.user = { name: 'John', data: '' };
25881
25882                   $scope.cancel = function(e) {
25883                     if (e.keyCode == 27) {
25884                       $scope.userForm.userName.$rollbackViewValue();
25885                     }
25886                   };
25887                 }]);
25888             </file>
25889             <file name="protractor.js" type="protractor">
25890               var model = element(by.binding('user.name'));
25891               var input = element(by.model('user.name'));
25892               var other = element(by.model('user.data'));
25893
25894               it('should allow custom events', function() {
25895                 input.sendKeys(' Doe');
25896                 input.click();
25897                 expect(model.getText()).toEqual('John');
25898                 other.click();
25899                 expect(model.getText()).toEqual('John Doe');
25900               });
25901
25902               it('should $rollbackViewValue when model changes', function() {
25903                 input.sendKeys(' Doe');
25904                 expect(input.getAttribute('value')).toEqual('John Doe');
25905                 input.sendKeys(protractor.Key.ESCAPE);
25906                 expect(input.getAttribute('value')).toEqual('John');
25907                 other.click();
25908                 expect(model.getText()).toEqual('John');
25909               });
25910             </file>
25911           </example>
25912
25913           This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
25914           If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
25915
25916           <example name="ngModelOptions-directive-debounce" module="optionsExample">
25917             <file name="index.html">
25918               <div ng-controller="ExampleController">
25919                 <form name="userForm">
25920                   <label>Name:
25921                     <input type="text" name="userName"
25922                            ng-model="user.name"
25923                            ng-model-options="{ debounce: 1000 }" />
25924                   </label>
25925                   <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
25926                   <br />
25927                 </form>
25928                 <pre>user.name = <span ng-bind="user.name"></span></pre>
25929               </div>
25930             </file>
25931             <file name="app.js">
25932               angular.module('optionsExample', [])
25933                 .controller('ExampleController', ['$scope', function($scope) {
25934                   $scope.user = { name: 'Igor' };
25935                 }]);
25936             </file>
25937           </example>
25938
25939           This one shows how to bind to getter/setters:
25940
25941           <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
25942             <file name="index.html">
25943               <div ng-controller="ExampleController">
25944                 <form name="userForm">
25945                   <label>Name:
25946                     <input type="text" name="userName"
25947                            ng-model="user.name"
25948                            ng-model-options="{ getterSetter: true }" />
25949                   </label>
25950                 </form>
25951                 <pre>user.name = <span ng-bind="user.name()"></span></pre>
25952               </div>
25953             </file>
25954             <file name="app.js">
25955               angular.module('getterSetterExample', [])
25956                 .controller('ExampleController', ['$scope', function($scope) {
25957                   var _name = 'Brian';
25958                   $scope.user = {
25959                     name: function(newName) {
25960                       // Note that newName can be undefined for two reasons:
25961                       // 1. Because it is called as a getter and thus called with no arguments
25962                       // 2. Because the property should actually be set to undefined. This happens e.g. if the
25963                       //    input is invalid
25964                       return arguments.length ? (_name = newName) : _name;
25965                     }
25966                   };
25967                 }]);
25968             </file>
25969           </example>
25970          */
25971         var ngModelOptionsDirective = function() {
25972           return {
25973             restrict: 'A',
25974             controller: ['$scope', '$attrs', function($scope, $attrs) {
25975               var that = this;
25976               this.$options = copy($scope.$eval($attrs.ngModelOptions));
25977               // Allow adding/overriding bound events
25978               if (isDefined(this.$options.updateOn)) {
25979                 this.$options.updateOnDefault = false;
25980                 // extract "default" pseudo-event from list of events that can trigger a model update
25981                 this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
25982                   that.$options.updateOnDefault = true;
25983                   return ' ';
25984                 }));
25985               } else {
25986                 this.$options.updateOnDefault = true;
25987               }
25988             }]
25989           };
25990         };
25991
25992
25993
25994         // helper methods
25995         function addSetValidityMethod(context) {
25996           var ctrl = context.ctrl,
25997               $element = context.$element,
25998               classCache = {},
25999               set = context.set,
26000               unset = context.unset,
26001               $animate = context.$animate;
26002
26003           classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
26004
26005           ctrl.$setValidity = setValidity;
26006
26007           function setValidity(validationErrorKey, state, controller) {
26008             if (isUndefined(state)) {
26009               createAndSet('$pending', validationErrorKey, controller);
26010             } else {
26011               unsetAndCleanup('$pending', validationErrorKey, controller);
26012             }
26013             if (!isBoolean(state)) {
26014               unset(ctrl.$error, validationErrorKey, controller);
26015               unset(ctrl.$$success, validationErrorKey, controller);
26016             } else {
26017               if (state) {
26018                 unset(ctrl.$error, validationErrorKey, controller);
26019                 set(ctrl.$$success, validationErrorKey, controller);
26020               } else {
26021                 set(ctrl.$error, validationErrorKey, controller);
26022                 unset(ctrl.$$success, validationErrorKey, controller);
26023               }
26024             }
26025             if (ctrl.$pending) {
26026               cachedToggleClass(PENDING_CLASS, true);
26027               ctrl.$valid = ctrl.$invalid = undefined;
26028               toggleValidationCss('', null);
26029             } else {
26030               cachedToggleClass(PENDING_CLASS, false);
26031               ctrl.$valid = isObjectEmpty(ctrl.$error);
26032               ctrl.$invalid = !ctrl.$valid;
26033               toggleValidationCss('', ctrl.$valid);
26034             }
26035
26036             // re-read the state as the set/unset methods could have
26037             // combined state in ctrl.$error[validationError] (used for forms),
26038             // where setting/unsetting only increments/decrements the value,
26039             // and does not replace it.
26040             var combinedState;
26041             if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
26042               combinedState = undefined;
26043             } else if (ctrl.$error[validationErrorKey]) {
26044               combinedState = false;
26045             } else if (ctrl.$$success[validationErrorKey]) {
26046               combinedState = true;
26047             } else {
26048               combinedState = null;
26049             }
26050
26051             toggleValidationCss(validationErrorKey, combinedState);
26052             ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
26053           }
26054
26055           function createAndSet(name, value, controller) {
26056             if (!ctrl[name]) {
26057               ctrl[name] = {};
26058             }
26059             set(ctrl[name], value, controller);
26060           }
26061
26062           function unsetAndCleanup(name, value, controller) {
26063             if (ctrl[name]) {
26064               unset(ctrl[name], value, controller);
26065             }
26066             if (isObjectEmpty(ctrl[name])) {
26067               ctrl[name] = undefined;
26068             }
26069           }
26070
26071           function cachedToggleClass(className, switchValue) {
26072             if (switchValue && !classCache[className]) {
26073               $animate.addClass($element, className);
26074               classCache[className] = true;
26075             } else if (!switchValue && classCache[className]) {
26076               $animate.removeClass($element, className);
26077               classCache[className] = false;
26078             }
26079           }
26080
26081           function toggleValidationCss(validationErrorKey, isValid) {
26082             validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
26083
26084             cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
26085             cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
26086           }
26087         }
26088
26089         function isObjectEmpty(obj) {
26090           if (obj) {
26091             for (var prop in obj) {
26092               if (obj.hasOwnProperty(prop)) {
26093                 return false;
26094               }
26095             }
26096           }
26097           return true;
26098         }
26099
26100         /**
26101          * @ngdoc directive
26102          * @name ngNonBindable
26103          * @restrict AC
26104          * @priority 1000
26105          *
26106          * @description
26107          * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
26108          * DOM element. This is useful if the element contains what appears to be Angular directives and
26109          * bindings but which should be ignored by Angular. This could be the case if you have a site that
26110          * displays snippets of code, for instance.
26111          *
26112          * @element ANY
26113          *
26114          * @example
26115          * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
26116          * but the one wrapped in `ngNonBindable` is left alone.
26117          *
26118          * @example
26119             <example>
26120               <file name="index.html">
26121                 <div>Normal: {{1 + 2}}</div>
26122                 <div ng-non-bindable>Ignored: {{1 + 2}}</div>
26123               </file>
26124               <file name="protractor.js" type="protractor">
26125                it('should check ng-non-bindable', function() {
26126                  expect(element(by.binding('1 + 2')).getText()).toContain('3');
26127                  expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
26128                });
26129               </file>
26130             </example>
26131          */
26132         var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
26133
26134         /* global jqLiteRemove */
26135
26136         var ngOptionsMinErr = minErr('ngOptions');
26137
26138         /**
26139          * @ngdoc directive
26140          * @name ngOptions
26141          * @restrict A
26142          *
26143          * @description
26144          *
26145          * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
26146          * elements for the `<select>` element using the array or object obtained by evaluating the
26147          * `ngOptions` comprehension expression.
26148          *
26149          * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
26150          * similar result. However, `ngOptions` provides some benefits such as reducing memory and
26151          * increasing speed by not creating a new scope for each repeated instance, as well as providing
26152          * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
26153          * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
26154          *  to a non-string value. This is because an option element can only be bound to string values at
26155          * present.
26156          *
26157          * When an item in the `<select>` menu is selected, the array element or object property
26158          * represented by the selected option will be bound to the model identified by the `ngModel`
26159          * directive.
26160          *
26161          * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
26162          * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
26163          * option. See example below for demonstration.
26164          *
26165          * ## Complex Models (objects or collections)
26166          *
26167          * By default, `ngModel` watches the model by reference, not value. This is important to know when
26168          * binding the select to a model that is an object or a collection.
26169          *
26170          * One issue occurs if you want to preselect an option. For example, if you set
26171          * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
26172          * because the objects are not identical. So by default, you should always reference the item in your collection
26173          * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
26174          *
26175          * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
26176          * of the item not by reference, but by the result of the `track by` expression. For example, if your
26177          * collection items have an id property, you would `track by item.id`.
26178          *
26179          * A different issue with objects or collections is that ngModel won't detect if an object property or
26180          * a collection item changes. For that reason, `ngOptions` additionally watches the model using
26181          * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
26182          * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
26183          * has not changed identity, but only a property on the object or an item in the collection changes.
26184          *
26185          * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
26186          * if the model is an array). This means that changing a property deeper than the first level inside the
26187          * object/collection will not trigger a re-rendering.
26188          *
26189          * ## `select` **`as`**
26190          *
26191          * Using `select` **`as`** will bind the result of the `select` expression to the model, but
26192          * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
26193          * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
26194          * is used, the result of that expression will be set as the value of the `option` and `select` elements.
26195          *
26196          *
26197          * ### `select` **`as`** and **`track by`**
26198          *
26199          * <div class="alert alert-warning">
26200          * Be careful when using `select` **`as`** and **`track by`** in the same expression.
26201          * </div>
26202          *
26203          * Given this array of items on the $scope:
26204          *
26205          * ```js
26206          * $scope.items = [{
26207          *   id: 1,
26208          *   label: 'aLabel',
26209          *   subItem: { name: 'aSubItem' }
26210          * }, {
26211          *   id: 2,
26212          *   label: 'bLabel',
26213          *   subItem: { name: 'bSubItem' }
26214          * }];
26215          * ```
26216          *
26217          * This will work:
26218          *
26219          * ```html
26220          * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
26221          * ```
26222          * ```js
26223          * $scope.selected = $scope.items[0];
26224          * ```
26225          *
26226          * but this will not work:
26227          *
26228          * ```html
26229          * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
26230          * ```
26231          * ```js
26232          * $scope.selected = $scope.items[0].subItem;
26233          * ```
26234          *
26235          * In both examples, the **`track by`** expression is applied successfully to each `item` in the
26236          * `items` array. Because the selected option has been set programmatically in the controller, the
26237          * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
26238          * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
26239          * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
26240          * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
26241          * is not matched against any `<option>` and the `<select>` appears as having no selected value.
26242          *
26243          *
26244          * @param {string} ngModel Assignable angular expression to data-bind to.
26245          * @param {string=} name Property name of the form under which the control is published.
26246          * @param {string=} required The control is considered valid only if value is entered.
26247          * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26248          *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26249          *    `required` when you want to data-bind to the `required` attribute.
26250          * @param {comprehension_expression=} ngOptions in one of the following forms:
26251          *
26252          *   * for array data sources:
26253          *     * `label` **`for`** `value` **`in`** `array`
26254          *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
26255          *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
26256          *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
26257          *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26258          *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
26259          *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
26260          *        (for including a filter with `track by`)
26261          *   * for object data sources:
26262          *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26263          *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
26264          *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
26265          *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
26266          *     * `select` **`as`** `label` **`group by`** `group`
26267          *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26268          *     * `select` **`as`** `label` **`disable when`** `disable`
26269          *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
26270          *
26271          * Where:
26272          *
26273          *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
26274          *   * `value`: local variable which will refer to each item in the `array` or each property value
26275          *      of `object` during iteration.
26276          *   * `key`: local variable which will refer to a property name in `object` during iteration.
26277          *   * `label`: The result of this expression will be the label for `<option>` element. The
26278          *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
26279          *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
26280          *      element. If not specified, `select` expression will default to `value`.
26281          *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
26282          *      DOM element.
26283          *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
26284          *      element. Return `true` to disable.
26285          *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
26286          *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
26287          *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
26288          *      even when the options are recreated (e.g. reloaded from the server).
26289          *
26290          * @example
26291             <example module="selectExample">
26292               <file name="index.html">
26293                 <script>
26294                 angular.module('selectExample', [])
26295                   .controller('ExampleController', ['$scope', function($scope) {
26296                     $scope.colors = [
26297                       {name:'black', shade:'dark'},
26298                       {name:'white', shade:'light', notAnOption: true},
26299                       {name:'red', shade:'dark'},
26300                       {name:'blue', shade:'dark', notAnOption: true},
26301                       {name:'yellow', shade:'light', notAnOption: false}
26302                     ];
26303                     $scope.myColor = $scope.colors[2]; // red
26304                   }]);
26305                 </script>
26306                 <div ng-controller="ExampleController">
26307                   <ul>
26308                     <li ng-repeat="color in colors">
26309                       <label>Name: <input ng-model="color.name"></label>
26310                       <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
26311                       <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
26312                     </li>
26313                     <li>
26314                       <button ng-click="colors.push({})">add</button>
26315                     </li>
26316                   </ul>
26317                   <hr/>
26318                   <label>Color (null not allowed):
26319                     <select ng-model="myColor" ng-options="color.name for color in colors"></select>
26320                   </label><br/>
26321                   <label>Color (null allowed):
26322                   <span  class="nullable">
26323                     <select ng-model="myColor" ng-options="color.name for color in colors">
26324                       <option value="">-- choose color --</option>
26325                     </select>
26326                   </span></label><br/>
26327
26328                   <label>Color grouped by shade:
26329                     <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
26330                     </select>
26331                   </label><br/>
26332
26333                   <label>Color grouped by shade, with some disabled:
26334                     <select ng-model="myColor"
26335                           ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
26336                     </select>
26337                   </label><br/>
26338
26339
26340
26341                   Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
26342                   <br/>
26343                   <hr/>
26344                   Currently selected: {{ {selected_color:myColor} }}
26345                   <div style="border:solid 1px black; height:20px"
26346                        ng-style="{'background-color':myColor.name}">
26347                   </div>
26348                 </div>
26349               </file>
26350               <file name="protractor.js" type="protractor">
26351                  it('should check ng-options', function() {
26352                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
26353                    element.all(by.model('myColor')).first().click();
26354                    element.all(by.css('select[ng-model="myColor"] option')).first().click();
26355                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
26356                    element(by.css('.nullable select[ng-model="myColor"]')).click();
26357                    element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
26358                    expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
26359                  });
26360               </file>
26361             </example>
26362          */
26363
26364         // jshint maxlen: false
26365         //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
26366         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]+?))?$/;
26367                                 // 1: value expression (valueFn)
26368                                 // 2: label expression (displayFn)
26369                                 // 3: group by expression (groupByFn)
26370                                 // 4: disable when expression (disableWhenFn)
26371                                 // 5: array item variable name
26372                                 // 6: object item key variable name
26373                                 // 7: object item value variable name
26374                                 // 8: collection expression
26375                                 // 9: track by expression
26376         // jshint maxlen: 100
26377
26378
26379         var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26380
26381           function parseOptionsExpression(optionsExp, selectElement, scope) {
26382
26383             var match = optionsExp.match(NG_OPTIONS_REGEXP);
26384             if (!(match)) {
26385               throw ngOptionsMinErr('iexp',
26386                 "Expected expression in form of " +
26387                 "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
26388                 " but got '{0}'. Element: {1}",
26389                 optionsExp, startingTag(selectElement));
26390             }
26391
26392             // Extract the parts from the ngOptions expression
26393
26394             // The variable name for the value of the item in the collection
26395             var valueName = match[5] || match[7];
26396             // The variable name for the key of the item in the collection
26397             var keyName = match[6];
26398
26399             // An expression that generates the viewValue for an option if there is a label expression
26400             var selectAs = / as /.test(match[0]) && match[1];
26401             // An expression that is used to track the id of each object in the options collection
26402             var trackBy = match[9];
26403             // An expression that generates the viewValue for an option if there is no label expression
26404             var valueFn = $parse(match[2] ? match[1] : valueName);
26405             var selectAsFn = selectAs && $parse(selectAs);
26406             var viewValueFn = selectAsFn || valueFn;
26407             var trackByFn = trackBy && $parse(trackBy);
26408
26409             // Get the value by which we are going to track the option
26410             // if we have a trackFn then use that (passing scope and locals)
26411             // otherwise just hash the given viewValue
26412             var getTrackByValueFn = trackBy ?
26413                                       function(value, locals) { return trackByFn(scope, locals); } :
26414                                       function getHashOfValue(value) { return hashKey(value); };
26415             var getTrackByValue = function(value, key) {
26416               return getTrackByValueFn(value, getLocals(value, key));
26417             };
26418
26419             var displayFn = $parse(match[2] || match[1]);
26420             var groupByFn = $parse(match[3] || '');
26421             var disableWhenFn = $parse(match[4] || '');
26422             var valuesFn = $parse(match[8]);
26423
26424             var locals = {};
26425             var getLocals = keyName ? function(value, key) {
26426               locals[keyName] = key;
26427               locals[valueName] = value;
26428               return locals;
26429             } : function(value) {
26430               locals[valueName] = value;
26431               return locals;
26432             };
26433
26434
26435             function Option(selectValue, viewValue, label, group, disabled) {
26436               this.selectValue = selectValue;
26437               this.viewValue = viewValue;
26438               this.label = label;
26439               this.group = group;
26440               this.disabled = disabled;
26441             }
26442
26443             function getOptionValuesKeys(optionValues) {
26444               var optionValuesKeys;
26445
26446               if (!keyName && isArrayLike(optionValues)) {
26447                 optionValuesKeys = optionValues;
26448               } else {
26449                 // if object, extract keys, in enumeration order, unsorted
26450                 optionValuesKeys = [];
26451                 for (var itemKey in optionValues) {
26452                   if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
26453                     optionValuesKeys.push(itemKey);
26454                   }
26455                 }
26456               }
26457               return optionValuesKeys;
26458             }
26459
26460             return {
26461               trackBy: trackBy,
26462               getTrackByValue: getTrackByValue,
26463               getWatchables: $parse(valuesFn, function(optionValues) {
26464                 // Create a collection of things that we would like to watch (watchedArray)
26465                 // so that they can all be watched using a single $watchCollection
26466                 // that only runs the handler once if anything changes
26467                 var watchedArray = [];
26468                 optionValues = optionValues || [];
26469
26470                 var optionValuesKeys = getOptionValuesKeys(optionValues);
26471                 var optionValuesLength = optionValuesKeys.length;
26472                 for (var index = 0; index < optionValuesLength; index++) {
26473                   var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26474                   var value = optionValues[key];
26475
26476                   var locals = getLocals(optionValues[key], key);
26477                   var selectValue = getTrackByValueFn(optionValues[key], locals);
26478                   watchedArray.push(selectValue);
26479
26480                   // Only need to watch the displayFn if there is a specific label expression
26481                   if (match[2] || match[1]) {
26482                     var label = displayFn(scope, locals);
26483                     watchedArray.push(label);
26484                   }
26485
26486                   // Only need to watch the disableWhenFn if there is a specific disable expression
26487                   if (match[4]) {
26488                     var disableWhen = disableWhenFn(scope, locals);
26489                     watchedArray.push(disableWhen);
26490                   }
26491                 }
26492                 return watchedArray;
26493               }),
26494
26495               getOptions: function() {
26496
26497                 var optionItems = [];
26498                 var selectValueMap = {};
26499
26500                 // The option values were already computed in the `getWatchables` fn,
26501                 // which must have been called to trigger `getOptions`
26502                 var optionValues = valuesFn(scope) || [];
26503                 var optionValuesKeys = getOptionValuesKeys(optionValues);
26504                 var optionValuesLength = optionValuesKeys.length;
26505
26506                 for (var index = 0; index < optionValuesLength; index++) {
26507                   var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
26508                   var value = optionValues[key];
26509                   var locals = getLocals(value, key);
26510                   var viewValue = viewValueFn(scope, locals);
26511                   var selectValue = getTrackByValueFn(viewValue, locals);
26512                   var label = displayFn(scope, locals);
26513                   var group = groupByFn(scope, locals);
26514                   var disabled = disableWhenFn(scope, locals);
26515                   var optionItem = new Option(selectValue, viewValue, label, group, disabled);
26516
26517                   optionItems.push(optionItem);
26518                   selectValueMap[selectValue] = optionItem;
26519                 }
26520
26521                 return {
26522                   items: optionItems,
26523                   selectValueMap: selectValueMap,
26524                   getOptionFromViewValue: function(value) {
26525                     return selectValueMap[getTrackByValue(value)];
26526                   },
26527                   getViewValueFromOption: function(option) {
26528                     // If the viewValue could be an object that may be mutated by the application,
26529                     // we need to make a copy and not return the reference to the value on the option.
26530                     return trackBy ? angular.copy(option.viewValue) : option.viewValue;
26531                   }
26532                 };
26533               }
26534             };
26535           }
26536
26537
26538           // we can't just jqLite('<option>') since jqLite is not smart enough
26539           // to create it in <select> and IE barfs otherwise.
26540           var optionTemplate = document.createElement('option'),
26541               optGroupTemplate = document.createElement('optgroup');
26542
26543
26544             function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
26545
26546               // if ngModel is not defined, we don't need to do anything
26547               var ngModelCtrl = ctrls[1];
26548               if (!ngModelCtrl) return;
26549
26550               var selectCtrl = ctrls[0];
26551               var multiple = attr.multiple;
26552
26553               // The emptyOption allows the application developer to provide their own custom "empty"
26554               // option when the viewValue does not match any of the option values.
26555               var emptyOption;
26556               for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
26557                 if (children[i].value === '') {
26558                   emptyOption = children.eq(i);
26559                   break;
26560                 }
26561               }
26562
26563               var providedEmptyOption = !!emptyOption;
26564
26565               var unknownOption = jqLite(optionTemplate.cloneNode(false));
26566               unknownOption.val('?');
26567
26568               var options;
26569               var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
26570
26571
26572               var renderEmptyOption = function() {
26573                 if (!providedEmptyOption) {
26574                   selectElement.prepend(emptyOption);
26575                 }
26576                 selectElement.val('');
26577                 emptyOption.prop('selected', true); // needed for IE
26578                 emptyOption.attr('selected', true);
26579               };
26580
26581               var removeEmptyOption = function() {
26582                 if (!providedEmptyOption) {
26583                   emptyOption.remove();
26584                 }
26585               };
26586
26587
26588               var renderUnknownOption = function() {
26589                 selectElement.prepend(unknownOption);
26590                 selectElement.val('?');
26591                 unknownOption.prop('selected', true); // needed for IE
26592                 unknownOption.attr('selected', true);
26593               };
26594
26595               var removeUnknownOption = function() {
26596                 unknownOption.remove();
26597               };
26598
26599               // Update the controller methods for multiple selectable options
26600               if (!multiple) {
26601
26602                 selectCtrl.writeValue = function writeNgOptionsValue(value) {
26603                   var option = options.getOptionFromViewValue(value);
26604
26605                   if (option && !option.disabled) {
26606                     if (selectElement[0].value !== option.selectValue) {
26607                       removeUnknownOption();
26608                       removeEmptyOption();
26609
26610                       selectElement[0].value = option.selectValue;
26611                       option.element.selected = true;
26612                       option.element.setAttribute('selected', 'selected');
26613                     }
26614                   } else {
26615                     if (value === null || providedEmptyOption) {
26616                       removeUnknownOption();
26617                       renderEmptyOption();
26618                     } else {
26619                       removeEmptyOption();
26620                       renderUnknownOption();
26621                     }
26622                   }
26623                 };
26624
26625                 selectCtrl.readValue = function readNgOptionsValue() {
26626
26627                   var selectedOption = options.selectValueMap[selectElement.val()];
26628
26629                   if (selectedOption && !selectedOption.disabled) {
26630                     removeEmptyOption();
26631                     removeUnknownOption();
26632                     return options.getViewValueFromOption(selectedOption);
26633                   }
26634                   return null;
26635                 };
26636
26637                 // If we are using `track by` then we must watch the tracked value on the model
26638                 // since ngModel only watches for object identity change
26639                 if (ngOptions.trackBy) {
26640                   scope.$watch(
26641                     function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
26642                     function() { ngModelCtrl.$render(); }
26643                   );
26644                 }
26645
26646               } else {
26647
26648                 ngModelCtrl.$isEmpty = function(value) {
26649                   return !value || value.length === 0;
26650                 };
26651
26652
26653                 selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
26654                   options.items.forEach(function(option) {
26655                     option.element.selected = false;
26656                   });
26657
26658                   if (value) {
26659                     value.forEach(function(item) {
26660                       var option = options.getOptionFromViewValue(item);
26661                       if (option && !option.disabled) option.element.selected = true;
26662                     });
26663                   }
26664                 };
26665
26666
26667                 selectCtrl.readValue = function readNgOptionsMultiple() {
26668                   var selectedValues = selectElement.val() || [],
26669                       selections = [];
26670
26671                   forEach(selectedValues, function(value) {
26672                     var option = options.selectValueMap[value];
26673                     if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
26674                   });
26675
26676                   return selections;
26677                 };
26678
26679                 // If we are using `track by` then we must watch these tracked values on the model
26680                 // since ngModel only watches for object identity change
26681                 if (ngOptions.trackBy) {
26682
26683                   scope.$watchCollection(function() {
26684                     if (isArray(ngModelCtrl.$viewValue)) {
26685                       return ngModelCtrl.$viewValue.map(function(value) {
26686                         return ngOptions.getTrackByValue(value);
26687                       });
26688                     }
26689                   }, function() {
26690                     ngModelCtrl.$render();
26691                   });
26692
26693                 }
26694               }
26695
26696
26697               if (providedEmptyOption) {
26698
26699                 // we need to remove it before calling selectElement.empty() because otherwise IE will
26700                 // remove the label from the element. wtf?
26701                 emptyOption.remove();
26702
26703                 // compile the element since there might be bindings in it
26704                 $compile(emptyOption)(scope);
26705
26706                 // remove the class, which is added automatically because we recompile the element and it
26707                 // becomes the compilation root
26708                 emptyOption.removeClass('ng-scope');
26709               } else {
26710                 emptyOption = jqLite(optionTemplate.cloneNode(false));
26711               }
26712
26713               // We need to do this here to ensure that the options object is defined
26714               // when we first hit it in writeNgOptionsValue
26715               updateOptions();
26716
26717               // We will re-render the option elements if the option values or labels change
26718               scope.$watchCollection(ngOptions.getWatchables, updateOptions);
26719
26720               // ------------------------------------------------------------------ //
26721
26722
26723               function updateOptionElement(option, element) {
26724                 option.element = element;
26725                 element.disabled = option.disabled;
26726                 // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
26727                 // selects in certain circumstances when multiple selects are next to each other and display
26728                 // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
26729                 // See https://github.com/angular/angular.js/issues/11314 for more info.
26730                 // This is unfortunately untestable with unit / e2e tests
26731                 if (option.label !== element.label) {
26732                   element.label = option.label;
26733                   element.textContent = option.label;
26734                 }
26735                 if (option.value !== element.value) element.value = option.selectValue;
26736               }
26737
26738               function addOrReuseElement(parent, current, type, templateElement) {
26739                 var element;
26740                 // Check whether we can reuse the next element
26741                 if (current && lowercase(current.nodeName) === type) {
26742                   // The next element is the right type so reuse it
26743                   element = current;
26744                 } else {
26745                   // The next element is not the right type so create a new one
26746                   element = templateElement.cloneNode(false);
26747                   if (!current) {
26748                     // There are no more elements so just append it to the select
26749                     parent.appendChild(element);
26750                   } else {
26751                     // The next element is not a group so insert the new one
26752                     parent.insertBefore(element, current);
26753                   }
26754                 }
26755                 return element;
26756               }
26757
26758
26759               function removeExcessElements(current) {
26760                 var next;
26761                 while (current) {
26762                   next = current.nextSibling;
26763                   jqLiteRemove(current);
26764                   current = next;
26765                 }
26766               }
26767
26768
26769               function skipEmptyAndUnknownOptions(current) {
26770                 var emptyOption_ = emptyOption && emptyOption[0];
26771                 var unknownOption_ = unknownOption && unknownOption[0];
26772
26773                 // We cannot rely on the extracted empty option being the same as the compiled empty option,
26774                 // because the compiled empty option might have been replaced by a comment because
26775                 // it had an "element" transclusion directive on it (such as ngIf)
26776                 if (emptyOption_ || unknownOption_) {
26777                   while (current &&
26778                         (current === emptyOption_ ||
26779                         current === unknownOption_ ||
26780                         current.nodeType === NODE_TYPE_COMMENT ||
26781                         current.value === '')) {
26782                     current = current.nextSibling;
26783                   }
26784                 }
26785                 return current;
26786               }
26787
26788
26789               function updateOptions() {
26790
26791                 var previousValue = options && selectCtrl.readValue();
26792
26793                 options = ngOptions.getOptions();
26794
26795                 var groupMap = {};
26796                 var currentElement = selectElement[0].firstChild;
26797
26798                 // Ensure that the empty option is always there if it was explicitly provided
26799                 if (providedEmptyOption) {
26800                   selectElement.prepend(emptyOption);
26801                 }
26802
26803                 currentElement = skipEmptyAndUnknownOptions(currentElement);
26804
26805                 options.items.forEach(function updateOption(option) {
26806                   var group;
26807                   var groupElement;
26808                   var optionElement;
26809
26810                   if (option.group) {
26811
26812                     // This option is to live in a group
26813                     // See if we have already created this group
26814                     group = groupMap[option.group];
26815
26816                     if (!group) {
26817
26818                       // We have not already created this group
26819                       groupElement = addOrReuseElement(selectElement[0],
26820                                                        currentElement,
26821                                                        'optgroup',
26822                                                        optGroupTemplate);
26823                       // Move to the next element
26824                       currentElement = groupElement.nextSibling;
26825
26826                       // Update the label on the group element
26827                       groupElement.label = option.group;
26828
26829                       // Store it for use later
26830                       group = groupMap[option.group] = {
26831                         groupElement: groupElement,
26832                         currentOptionElement: groupElement.firstChild
26833                       };
26834
26835                     }
26836
26837                     // So now we have a group for this option we add the option to the group
26838                     optionElement = addOrReuseElement(group.groupElement,
26839                                                       group.currentOptionElement,
26840                                                       'option',
26841                                                       optionTemplate);
26842                     updateOptionElement(option, optionElement);
26843                     // Move to the next element
26844                     group.currentOptionElement = optionElement.nextSibling;
26845
26846                   } else {
26847
26848                     // This option is not in a group
26849                     optionElement = addOrReuseElement(selectElement[0],
26850                                                       currentElement,
26851                                                       'option',
26852                                                       optionTemplate);
26853                     updateOptionElement(option, optionElement);
26854                     // Move to the next element
26855                     currentElement = optionElement.nextSibling;
26856                   }
26857                 });
26858
26859
26860                 // Now remove all excess options and group
26861                 Object.keys(groupMap).forEach(function(key) {
26862                   removeExcessElements(groupMap[key].currentOptionElement);
26863                 });
26864                 removeExcessElements(currentElement);
26865
26866                 ngModelCtrl.$render();
26867
26868                 // Check to see if the value has changed due to the update to the options
26869                 if (!ngModelCtrl.$isEmpty(previousValue)) {
26870                   var nextValue = selectCtrl.readValue();
26871                   if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
26872                     ngModelCtrl.$setViewValue(nextValue);
26873                     ngModelCtrl.$render();
26874                   }
26875                 }
26876
26877               }
26878           }
26879
26880           return {
26881             restrict: 'A',
26882             terminal: true,
26883             require: ['select', '?ngModel'],
26884             link: {
26885               pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
26886                 // Deactivate the SelectController.register method to prevent
26887                 // option directives from accidentally registering themselves
26888                 // (and unwanted $destroy handlers etc.)
26889                 ctrls[0].registerOption = noop;
26890               },
26891               post: ngOptionsPostLink
26892             }
26893           };
26894         }];
26895
26896         /**
26897          * @ngdoc directive
26898          * @name ngPluralize
26899          * @restrict EA
26900          *
26901          * @description
26902          * `ngPluralize` is a directive that displays messages according to en-US localization rules.
26903          * These rules are bundled with angular.js, but can be overridden
26904          * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
26905          * by specifying the mappings between
26906          * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26907          * and the strings to be displayed.
26908          *
26909          * # Plural categories and explicit number rules
26910          * There are two
26911          * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26912          * in Angular's default en-US locale: "one" and "other".
26913          *
26914          * While a plural category may match many numbers (for example, in en-US locale, "other" can match
26915          * any number that is not 1), an explicit number rule can only match one number. For example, the
26916          * explicit number rule for "3" matches the number 3. There are examples of plural categories
26917          * and explicit number rules throughout the rest of this documentation.
26918          *
26919          * # Configuring ngPluralize
26920          * You configure ngPluralize by providing 2 attributes: `count` and `when`.
26921          * You can also provide an optional attribute, `offset`.
26922          *
26923          * The value of the `count` attribute can be either a string or an {@link guide/expression
26924          * Angular expression}; these are evaluated on the current scope for its bound value.
26925          *
26926          * The `when` attribute specifies the mappings between plural categories and the actual
26927          * string to be displayed. The value of the attribute should be a JSON object.
26928          *
26929          * The following example shows how to configure ngPluralize:
26930          *
26931          * ```html
26932          * <ng-pluralize count="personCount"
26933                          when="{'0': 'Nobody is viewing.',
26934          *                      'one': '1 person is viewing.',
26935          *                      'other': '{} people are viewing.'}">
26936          * </ng-pluralize>
26937          *```
26938          *
26939          * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
26940          * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
26941          * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
26942          * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
26943          * show "a dozen people are viewing".
26944          *
26945          * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
26946          * into pluralized strings. In the previous example, Angular will replace `{}` with
26947          * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
26948          * for <span ng-non-bindable>{{numberExpression}}</span>.
26949          *
26950          * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
26951          * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
26952          *
26953          * # Configuring ngPluralize with offset
26954          * The `offset` attribute allows further customization of pluralized text, which can result in
26955          * a better user experience. For example, instead of the message "4 people are viewing this document",
26956          * you might display "John, Kate and 2 others are viewing this document".
26957          * The offset attribute allows you to offset a number by any desired value.
26958          * Let's take a look at an example:
26959          *
26960          * ```html
26961          * <ng-pluralize count="personCount" offset=2
26962          *               when="{'0': 'Nobody is viewing.',
26963          *                      '1': '{{person1}} is viewing.',
26964          *                      '2': '{{person1}} and {{person2}} are viewing.',
26965          *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
26966          *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26967          * </ng-pluralize>
26968          * ```
26969          *
26970          * Notice that we are still using two plural categories(one, other), but we added
26971          * three explicit number rules 0, 1 and 2.
26972          * When one person, perhaps John, views the document, "John is viewing" will be shown.
26973          * When three people view the document, no explicit number rule is found, so
26974          * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
26975          * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
26976          * is shown.
26977          *
26978          * Note that when you specify offsets, you must provide explicit number rules for
26979          * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
26980          * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
26981          * plural categories "one" and "other".
26982          *
26983          * @param {string|expression} count The variable to be bound to.
26984          * @param {string} when The mapping between plural category to its corresponding strings.
26985          * @param {number=} offset Offset to deduct from the total number.
26986          *
26987          * @example
26988             <example module="pluralizeExample">
26989               <file name="index.html">
26990                 <script>
26991                   angular.module('pluralizeExample', [])
26992                     .controller('ExampleController', ['$scope', function($scope) {
26993                       $scope.person1 = 'Igor';
26994                       $scope.person2 = 'Misko';
26995                       $scope.personCount = 1;
26996                     }]);
26997                 </script>
26998                 <div ng-controller="ExampleController">
26999                   <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
27000                   <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
27001                   <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
27002
27003                   <!--- Example with simple pluralization rules for en locale --->
27004                   Without Offset:
27005                   <ng-pluralize count="personCount"
27006                                 when="{'0': 'Nobody is viewing.',
27007                                        'one': '1 person is viewing.',
27008                                        'other': '{} people are viewing.'}">
27009                   </ng-pluralize><br>
27010
27011                   <!--- Example with offset --->
27012                   With Offset(2):
27013                   <ng-pluralize count="personCount" offset=2
27014                                 when="{'0': 'Nobody is viewing.',
27015                                        '1': '{{person1}} is viewing.',
27016                                        '2': '{{person1}} and {{person2}} are viewing.',
27017                                        'one': '{{person1}}, {{person2}} and one other person are viewing.',
27018                                        'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
27019                   </ng-pluralize>
27020                 </div>
27021               </file>
27022               <file name="protractor.js" type="protractor">
27023                 it('should show correct pluralized string', function() {
27024                   var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
27025                   var withOffset = element.all(by.css('ng-pluralize')).get(1);
27026                   var countInput = element(by.model('personCount'));
27027
27028                   expect(withoutOffset.getText()).toEqual('1 person is viewing.');
27029                   expect(withOffset.getText()).toEqual('Igor is viewing.');
27030
27031                   countInput.clear();
27032                   countInput.sendKeys('0');
27033
27034                   expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
27035                   expect(withOffset.getText()).toEqual('Nobody is viewing.');
27036
27037                   countInput.clear();
27038                   countInput.sendKeys('2');
27039
27040                   expect(withoutOffset.getText()).toEqual('2 people are viewing.');
27041                   expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
27042
27043                   countInput.clear();
27044                   countInput.sendKeys('3');
27045
27046                   expect(withoutOffset.getText()).toEqual('3 people are viewing.');
27047                   expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
27048
27049                   countInput.clear();
27050                   countInput.sendKeys('4');
27051
27052                   expect(withoutOffset.getText()).toEqual('4 people are viewing.');
27053                   expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
27054                 });
27055                 it('should show data-bound names', function() {
27056                   var withOffset = element.all(by.css('ng-pluralize')).get(1);
27057                   var personCount = element(by.model('personCount'));
27058                   var person1 = element(by.model('person1'));
27059                   var person2 = element(by.model('person2'));
27060                   personCount.clear();
27061                   personCount.sendKeys('4');
27062                   person1.clear();
27063                   person1.sendKeys('Di');
27064                   person2.clear();
27065                   person2.sendKeys('Vojta');
27066                   expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
27067                 });
27068               </file>
27069             </example>
27070          */
27071         var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
27072           var BRACE = /{}/g,
27073               IS_WHEN = /^when(Minus)?(.+)$/;
27074
27075           return {
27076             link: function(scope, element, attr) {
27077               var numberExp = attr.count,
27078                   whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
27079                   offset = attr.offset || 0,
27080                   whens = scope.$eval(whenExp) || {},
27081                   whensExpFns = {},
27082                   startSymbol = $interpolate.startSymbol(),
27083                   endSymbol = $interpolate.endSymbol(),
27084                   braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
27085                   watchRemover = angular.noop,
27086                   lastCount;
27087
27088               forEach(attr, function(expression, attributeName) {
27089                 var tmpMatch = IS_WHEN.exec(attributeName);
27090                 if (tmpMatch) {
27091                   var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
27092                   whens[whenKey] = element.attr(attr.$attr[attributeName]);
27093                 }
27094               });
27095               forEach(whens, function(expression, key) {
27096                 whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
27097
27098               });
27099
27100               scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
27101                 var count = parseFloat(newVal);
27102                 var countIsNaN = isNaN(count);
27103
27104                 if (!countIsNaN && !(count in whens)) {
27105                   // If an explicit number rule such as 1, 2, 3... is defined, just use it.
27106                   // Otherwise, check it against pluralization rules in $locale service.
27107                   count = $locale.pluralCat(count - offset);
27108                 }
27109
27110                 // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
27111                 // In JS `NaN !== NaN`, so we have to exlicitly check.
27112                 if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
27113                   watchRemover();
27114                   var whenExpFn = whensExpFns[count];
27115                   if (isUndefined(whenExpFn)) {
27116                     if (newVal != null) {
27117                       $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
27118                     }
27119                     watchRemover = noop;
27120                     updateElementText();
27121                   } else {
27122                     watchRemover = scope.$watch(whenExpFn, updateElementText);
27123                   }
27124                   lastCount = count;
27125                 }
27126               });
27127
27128               function updateElementText(newText) {
27129                 element.text(newText || '');
27130               }
27131             }
27132           };
27133         }];
27134
27135         /**
27136          * @ngdoc directive
27137          * @name ngRepeat
27138          * @multiElement
27139          *
27140          * @description
27141          * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
27142          * instance gets its own scope, where the given loop variable is set to the current collection item,
27143          * and `$index` is set to the item index or key.
27144          *
27145          * Special properties are exposed on the local scope of each template instance, including:
27146          *
27147          * | Variable  | Type            | Details                                                                     |
27148          * |-----------|-----------------|-----------------------------------------------------------------------------|
27149          * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
27150          * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
27151          * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
27152          * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
27153          * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
27154          * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
27155          *
27156          * <div class="alert alert-info">
27157          *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
27158          *   This may be useful when, for instance, nesting ngRepeats.
27159          * </div>
27160          *
27161          *
27162          * # Iterating over object properties
27163          *
27164          * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
27165          * syntax:
27166          *
27167          * ```js
27168          * <div ng-repeat="(key, value) in myObj"> ... </div>
27169          * ```
27170          *
27171          * You need to be aware that the JavaScript specification does not define the order of keys
27172          * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
27173          * used to sort the keys alphabetically.)
27174          *
27175          * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
27176          * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
27177          * keys in the order in which they were defined, although there are exceptions when keys are deleted
27178          * 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).
27179          *
27180          * If this is not desired, the recommended workaround is to convert your object into an array
27181          * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
27182          * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
27183          * or implement a `$watch` on the object yourself.
27184          *
27185          *
27186          * # Tracking and Duplicates
27187          *
27188          * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
27189          * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
27190          *
27191          * * When an item is added, a new instance of the template is added to the DOM.
27192          * * When an item is removed, its template instance is removed from the DOM.
27193          * * When items are reordered, their respective templates are reordered in the DOM.
27194          *
27195          * To minimize creation of DOM elements, `ngRepeat` uses a function
27196          * to "keep track" of all items in the collection and their corresponding DOM elements.
27197          * For example, if an item is added to the collection, ngRepeat will know that all other items
27198          * already have DOM elements, and will not re-render them.
27199          *
27200          * The default tracking function (which tracks items by their identity) does not allow
27201          * duplicate items in arrays. This is because when there are duplicates, it is not possible
27202          * to maintain a one-to-one mapping between collection items and DOM elements.
27203          *
27204          * If you do need to repeat duplicate items, you can substitute the default tracking behavior
27205          * with your own using the `track by` expression.
27206          *
27207          * For example, you may track items by the index of each item in the collection, using the
27208          * special scope property `$index`:
27209          * ```html
27210          *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
27211          *      {{n}}
27212          *    </div>
27213          * ```
27214          *
27215          * You may also use arbitrary expressions in `track by`, including references to custom functions
27216          * on the scope:
27217          * ```html
27218          *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
27219          *      {{n}}
27220          *    </div>
27221          * ```
27222          *
27223          * <div class="alert alert-success">
27224          * If you are working with objects that have an identifier property, you should track
27225          * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
27226          * will not have to rebuild the DOM elements for items it has already rendered, even if the
27227          * JavaScript objects in the collection have been substituted for new ones. For large collections,
27228          * this signifincantly improves rendering performance. If you don't have a unique identifier,
27229          * `track by $index` can also provide a performance boost.
27230          * </div>
27231          * ```html
27232          *    <div ng-repeat="model in collection track by model.id">
27233          *      {{model.name}}
27234          *    </div>
27235          * ```
27236          *
27237          * When no `track by` expression is provided, it is equivalent to tracking by the built-in
27238          * `$id` function, which tracks items by their identity:
27239          * ```html
27240          *    <div ng-repeat="obj in collection track by $id(obj)">
27241          *      {{obj.prop}}
27242          *    </div>
27243          * ```
27244          *
27245          * <div class="alert alert-warning">
27246          * **Note:** `track by` must always be the last expression:
27247          * </div>
27248          * ```
27249          * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
27250          *     {{model.name}}
27251          * </div>
27252          * ```
27253          *
27254          * # Special repeat start and end points
27255          * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
27256          * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
27257          * 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)
27258          * up to and including the ending HTML tag where **ng-repeat-end** is placed.
27259          *
27260          * The example below makes use of this feature:
27261          * ```html
27262          *   <header ng-repeat-start="item in items">
27263          *     Header {{ item }}
27264          *   </header>
27265          *   <div class="body">
27266          *     Body {{ item }}
27267          *   </div>
27268          *   <footer ng-repeat-end>
27269          *     Footer {{ item }}
27270          *   </footer>
27271          * ```
27272          *
27273          * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
27274          * ```html
27275          *   <header>
27276          *     Header A
27277          *   </header>
27278          *   <div class="body">
27279          *     Body A
27280          *   </div>
27281          *   <footer>
27282          *     Footer A
27283          *   </footer>
27284          *   <header>
27285          *     Header B
27286          *   </header>
27287          *   <div class="body">
27288          *     Body B
27289          *   </div>
27290          *   <footer>
27291          *     Footer B
27292          *   </footer>
27293          * ```
27294          *
27295          * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
27296          * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
27297          *
27298          * @animations
27299          * **.enter** - when a new item is added to the list or when an item is revealed after a filter
27300          *
27301          * **.leave** - when an item is removed from the list or when an item is filtered out
27302          *
27303          * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
27304          *
27305          * @element ANY
27306          * @scope
27307          * @priority 1000
27308          * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
27309          *   formats are currently supported:
27310          *
27311          *   * `variable in expression` – where variable is the user defined loop variable and `expression`
27312          *     is a scope expression giving the collection to enumerate.
27313          *
27314          *     For example: `album in artist.albums`.
27315          *
27316          *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
27317          *     and `expression` is the scope expression giving the collection to enumerate.
27318          *
27319          *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
27320          *
27321          *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
27322          *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
27323          *     is specified, ng-repeat associates elements by identity. It is an error to have
27324          *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
27325          *     mapped to the same DOM element, which is not possible.)
27326          *
27327          *     Note that the tracking expression must come last, after any filters, and the alias expression.
27328          *
27329          *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
27330          *     will be associated by item identity in the array.
27331          *
27332          *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
27333          *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
27334          *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
27335          *     element in the same way in the DOM.
27336          *
27337          *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
27338          *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
27339          *     property is same.
27340          *
27341          *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
27342          *     to items in conjunction with a tracking expression.
27343          *
27344          *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
27345          *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
27346          *     when a filter is active on the repeater, but the filtered result set is empty.
27347          *
27348          *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
27349          *     the items have been processed through the filter.
27350          *
27351          *     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
27352          *     (and not as operator, inside an expression).
27353          *
27354          *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
27355          *
27356          * @example
27357          * This example initializes the scope to a list of names and
27358          * then uses `ngRepeat` to display every person:
27359           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27360             <file name="index.html">
27361               <div ng-init="friends = [
27362                 {name:'John', age:25, gender:'boy'},
27363                 {name:'Jessie', age:30, gender:'girl'},
27364                 {name:'Johanna', age:28, gender:'girl'},
27365                 {name:'Joy', age:15, gender:'girl'},
27366                 {name:'Mary', age:28, gender:'girl'},
27367                 {name:'Peter', age:95, gender:'boy'},
27368                 {name:'Sebastian', age:50, gender:'boy'},
27369                 {name:'Erika', age:27, gender:'girl'},
27370                 {name:'Patrick', age:40, gender:'boy'},
27371                 {name:'Samantha', age:60, gender:'girl'}
27372               ]">
27373                 I have {{friends.length}} friends. They are:
27374                 <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
27375                 <ul class="example-animate-container">
27376                   <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
27377                     [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
27378                   </li>
27379                   <li class="animate-repeat" ng-if="results.length == 0">
27380                     <strong>No results found...</strong>
27381                   </li>
27382                 </ul>
27383               </div>
27384             </file>
27385             <file name="animations.css">
27386               .example-animate-container {
27387                 background:white;
27388                 border:1px solid black;
27389                 list-style:none;
27390                 margin:0;
27391                 padding:0 10px;
27392               }
27393
27394               .animate-repeat {
27395                 line-height:40px;
27396                 list-style:none;
27397                 box-sizing:border-box;
27398               }
27399
27400               .animate-repeat.ng-move,
27401               .animate-repeat.ng-enter,
27402               .animate-repeat.ng-leave {
27403                 transition:all linear 0.5s;
27404               }
27405
27406               .animate-repeat.ng-leave.ng-leave-active,
27407               .animate-repeat.ng-move,
27408               .animate-repeat.ng-enter {
27409                 opacity:0;
27410                 max-height:0;
27411               }
27412
27413               .animate-repeat.ng-leave,
27414               .animate-repeat.ng-move.ng-move-active,
27415               .animate-repeat.ng-enter.ng-enter-active {
27416                 opacity:1;
27417                 max-height:40px;
27418               }
27419             </file>
27420             <file name="protractor.js" type="protractor">
27421               var friends = element.all(by.repeater('friend in friends'));
27422
27423               it('should render initial data set', function() {
27424                 expect(friends.count()).toBe(10);
27425                 expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
27426                 expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
27427                 expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
27428                 expect(element(by.binding('friends.length')).getText())
27429                     .toMatch("I have 10 friends. They are:");
27430               });
27431
27432                it('should update repeater when filter predicate changes', function() {
27433                  expect(friends.count()).toBe(10);
27434
27435                  element(by.model('q')).sendKeys('ma');
27436
27437                  expect(friends.count()).toBe(2);
27438                  expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
27439                  expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
27440                });
27441               </file>
27442             </example>
27443          */
27444         var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
27445           var NG_REMOVED = '$$NG_REMOVED';
27446           var ngRepeatMinErr = minErr('ngRepeat');
27447
27448           var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
27449             // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
27450             scope[valueIdentifier] = value;
27451             if (keyIdentifier) scope[keyIdentifier] = key;
27452             scope.$index = index;
27453             scope.$first = (index === 0);
27454             scope.$last = (index === (arrayLength - 1));
27455             scope.$middle = !(scope.$first || scope.$last);
27456             // jshint bitwise: false
27457             scope.$odd = !(scope.$even = (index&1) === 0);
27458             // jshint bitwise: true
27459           };
27460
27461           var getBlockStart = function(block) {
27462             return block.clone[0];
27463           };
27464
27465           var getBlockEnd = function(block) {
27466             return block.clone[block.clone.length - 1];
27467           };
27468
27469
27470           return {
27471             restrict: 'A',
27472             multiElement: true,
27473             transclude: 'element',
27474             priority: 1000,
27475             terminal: true,
27476             $$tlb: true,
27477             compile: function ngRepeatCompile($element, $attr) {
27478               var expression = $attr.ngRepeat;
27479               var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
27480
27481               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*$/);
27482
27483               if (!match) {
27484                 throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
27485                     expression);
27486               }
27487
27488               var lhs = match[1];
27489               var rhs = match[2];
27490               var aliasAs = match[3];
27491               var trackByExp = match[4];
27492
27493               match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
27494
27495               if (!match) {
27496                 throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
27497                     lhs);
27498               }
27499               var valueIdentifier = match[3] || match[1];
27500               var keyIdentifier = match[2];
27501
27502               if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
27503                   /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
27504                 throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
27505                   aliasAs);
27506               }
27507
27508               var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
27509               var hashFnLocals = {$id: hashKey};
27510
27511               if (trackByExp) {
27512                 trackByExpGetter = $parse(trackByExp);
27513               } else {
27514                 trackByIdArrayFn = function(key, value) {
27515                   return hashKey(value);
27516                 };
27517                 trackByIdObjFn = function(key) {
27518                   return key;
27519                 };
27520               }
27521
27522               return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
27523
27524                 if (trackByExpGetter) {
27525                   trackByIdExpFn = function(key, value, index) {
27526                     // assign key, value, and $index to the locals so that they can be used in hash functions
27527                     if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
27528                     hashFnLocals[valueIdentifier] = value;
27529                     hashFnLocals.$index = index;
27530                     return trackByExpGetter($scope, hashFnLocals);
27531                   };
27532                 }
27533
27534                 // Store a list of elements from previous run. This is a hash where key is the item from the
27535                 // iterator, and the value is objects with following properties.
27536                 //   - scope: bound scope
27537                 //   - element: previous element.
27538                 //   - index: position
27539                 //
27540                 // We are using no-proto object so that we don't need to guard against inherited props via
27541                 // hasOwnProperty.
27542                 var lastBlockMap = createMap();
27543
27544                 //watch props
27545                 $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
27546                   var index, length,
27547                       previousNode = $element[0],     // node that cloned nodes should be inserted after
27548                                                       // initialized to the comment node anchor
27549                       nextNode,
27550                       // Same as lastBlockMap but it has the current state. It will become the
27551                       // lastBlockMap on the next iteration.
27552                       nextBlockMap = createMap(),
27553                       collectionLength,
27554                       key, value, // key/value of iteration
27555                       trackById,
27556                       trackByIdFn,
27557                       collectionKeys,
27558                       block,       // last object information {scope, element, id}
27559                       nextBlockOrder,
27560                       elementsToRemove;
27561
27562                   if (aliasAs) {
27563                     $scope[aliasAs] = collection;
27564                   }
27565
27566                   if (isArrayLike(collection)) {
27567                     collectionKeys = collection;
27568                     trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
27569                   } else {
27570                     trackByIdFn = trackByIdExpFn || trackByIdObjFn;
27571                     // if object, extract keys, in enumeration order, unsorted
27572                     collectionKeys = [];
27573                     for (var itemKey in collection) {
27574                       if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
27575                         collectionKeys.push(itemKey);
27576                       }
27577                     }
27578                   }
27579
27580                   collectionLength = collectionKeys.length;
27581                   nextBlockOrder = new Array(collectionLength);
27582
27583                   // locate existing items
27584                   for (index = 0; index < collectionLength; index++) {
27585                     key = (collection === collectionKeys) ? index : collectionKeys[index];
27586                     value = collection[key];
27587                     trackById = trackByIdFn(key, value, index);
27588                     if (lastBlockMap[trackById]) {
27589                       // found previously seen block
27590                       block = lastBlockMap[trackById];
27591                       delete lastBlockMap[trackById];
27592                       nextBlockMap[trackById] = block;
27593                       nextBlockOrder[index] = block;
27594                     } else if (nextBlockMap[trackById]) {
27595                       // if collision detected. restore lastBlockMap and throw an error
27596                       forEach(nextBlockOrder, function(block) {
27597                         if (block && block.scope) lastBlockMap[block.id] = block;
27598                       });
27599                       throw ngRepeatMinErr('dupes',
27600                           "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
27601                           expression, trackById, value);
27602                     } else {
27603                       // new never before seen block
27604                       nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
27605                       nextBlockMap[trackById] = true;
27606                     }
27607                   }
27608
27609                   // remove leftover items
27610                   for (var blockKey in lastBlockMap) {
27611                     block = lastBlockMap[blockKey];
27612                     elementsToRemove = getBlockNodes(block.clone);
27613                     $animate.leave(elementsToRemove);
27614                     if (elementsToRemove[0].parentNode) {
27615                       // if the element was not removed yet because of pending animation, mark it as deleted
27616                       // so that we can ignore it later
27617                       for (index = 0, length = elementsToRemove.length; index < length; index++) {
27618                         elementsToRemove[index][NG_REMOVED] = true;
27619                       }
27620                     }
27621                     block.scope.$destroy();
27622                   }
27623
27624                   // we are not using forEach for perf reasons (trying to avoid #call)
27625                   for (index = 0; index < collectionLength; index++) {
27626                     key = (collection === collectionKeys) ? index : collectionKeys[index];
27627                     value = collection[key];
27628                     block = nextBlockOrder[index];
27629
27630                     if (block.scope) {
27631                       // if we have already seen this object, then we need to reuse the
27632                       // associated scope/element
27633
27634                       nextNode = previousNode;
27635
27636                       // skip nodes that are already pending removal via leave animation
27637                       do {
27638                         nextNode = nextNode.nextSibling;
27639                       } while (nextNode && nextNode[NG_REMOVED]);
27640
27641                       if (getBlockStart(block) != nextNode) {
27642                         // existing item which got moved
27643                         $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
27644                       }
27645                       previousNode = getBlockEnd(block);
27646                       updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27647                     } else {
27648                       // new item which we don't know about
27649                       $transclude(function ngRepeatTransclude(clone, scope) {
27650                         block.scope = scope;
27651                         // http://jsperf.com/clone-vs-createcomment
27652                         var endNode = ngRepeatEndComment.cloneNode(false);
27653                         clone[clone.length++] = endNode;
27654
27655                         // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
27656                         $animate.enter(clone, null, jqLite(previousNode));
27657                         previousNode = endNode;
27658                         // Note: We only need the first/last node of the cloned nodes.
27659                         // However, we need to keep the reference to the jqlite wrapper as it might be changed later
27660                         // by a directive with templateUrl when its template arrives.
27661                         block.clone = clone;
27662                         nextBlockMap[block.id] = block;
27663                         updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
27664                       });
27665                     }
27666                   }
27667                   lastBlockMap = nextBlockMap;
27668                 });
27669               };
27670             }
27671           };
27672         }];
27673
27674         var NG_HIDE_CLASS = 'ng-hide';
27675         var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
27676         /**
27677          * @ngdoc directive
27678          * @name ngShow
27679          * @multiElement
27680          *
27681          * @description
27682          * The `ngShow` directive shows or hides the given HTML element based on the expression
27683          * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
27684          * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27685          * in AngularJS and sets the display style to none (using an !important flag).
27686          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27687          *
27688          * ```html
27689          * <!-- when $scope.myValue is truthy (element is visible) -->
27690          * <div ng-show="myValue"></div>
27691          *
27692          * <!-- when $scope.myValue is falsy (element is hidden) -->
27693          * <div ng-show="myValue" class="ng-hide"></div>
27694          * ```
27695          *
27696          * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
27697          * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
27698          * from the element causing the element not to appear hidden.
27699          *
27700          * ## Why is !important used?
27701          *
27702          * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27703          * can be easily overridden by heavier selectors. For example, something as simple
27704          * as changing the display style on a HTML list item would make hidden elements appear visible.
27705          * This also becomes a bigger issue when dealing with CSS frameworks.
27706          *
27707          * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27708          * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27709          * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27710          *
27711          * ### Overriding `.ng-hide`
27712          *
27713          * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27714          * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27715          * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
27716          * with extra animation classes that can be added.
27717          *
27718          * ```css
27719          * .ng-hide:not(.ng-hide-animate) {
27720          *   /&#42; this is just another form of hiding an element &#42;/
27721          *   display: block!important;
27722          *   position: absolute;
27723          *   top: -9999px;
27724          *   left: -9999px;
27725          * }
27726          * ```
27727          *
27728          * By default you don't need to override in CSS anything and the animations will work around the display style.
27729          *
27730          * ## A note about animations with `ngShow`
27731          *
27732          * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27733          * is true and false. This system works like the animation system present with ngClass except that
27734          * you must also include the !important flag to override the display property
27735          * so that you can perform an animation when the element is hidden during the time of the animation.
27736          *
27737          * ```css
27738          * //
27739          * //a working example can be found at the bottom of this page
27740          * //
27741          * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27742          *   /&#42; this is required as of 1.3x to properly
27743          *      apply all styling in a show/hide animation &#42;/
27744          *   transition: 0s linear all;
27745          * }
27746          *
27747          * .my-element.ng-hide-add-active,
27748          * .my-element.ng-hide-remove-active {
27749          *   /&#42; the transition is defined in the active class &#42;/
27750          *   transition: 1s linear all;
27751          * }
27752          *
27753          * .my-element.ng-hide-add { ... }
27754          * .my-element.ng-hide-add.ng-hide-add-active { ... }
27755          * .my-element.ng-hide-remove { ... }
27756          * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27757          * ```
27758          *
27759          * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27760          * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27761          *
27762          * @animations
27763          * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
27764          * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
27765          *
27766          * @element ANY
27767          * @param {expression} ngShow If the {@link guide/expression expression} is truthy
27768          *     then the element is shown or hidden respectively.
27769          *
27770          * @example
27771           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27772             <file name="index.html">
27773               Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
27774               <div>
27775                 Show:
27776                 <div class="check-element animate-show" ng-show="checked">
27777                   <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27778                 </div>
27779               </div>
27780               <div>
27781                 Hide:
27782                 <div class="check-element animate-show" ng-hide="checked">
27783                   <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27784                 </div>
27785               </div>
27786             </file>
27787             <file name="glyphicons.css">
27788               @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27789             </file>
27790             <file name="animations.css">
27791               .animate-show {
27792                 line-height: 20px;
27793                 opacity: 1;
27794                 padding: 10px;
27795                 border: 1px solid black;
27796                 background: white;
27797               }
27798
27799               .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
27800                 transition: all linear 0.5s;
27801               }
27802
27803               .animate-show.ng-hide {
27804                 line-height: 0;
27805                 opacity: 0;
27806                 padding: 0 10px;
27807               }
27808
27809               .check-element {
27810                 padding: 10px;
27811                 border: 1px solid black;
27812                 background: white;
27813               }
27814             </file>
27815             <file name="protractor.js" type="protractor">
27816               var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27817               var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27818
27819               it('should check ng-show / ng-hide', function() {
27820                 expect(thumbsUp.isDisplayed()).toBeFalsy();
27821                 expect(thumbsDown.isDisplayed()).toBeTruthy();
27822
27823                 element(by.model('checked')).click();
27824
27825                 expect(thumbsUp.isDisplayed()).toBeTruthy();
27826                 expect(thumbsDown.isDisplayed()).toBeFalsy();
27827               });
27828             </file>
27829           </example>
27830          */
27831         var ngShowDirective = ['$animate', function($animate) {
27832           return {
27833             restrict: 'A',
27834             multiElement: true,
27835             link: function(scope, element, attr) {
27836               scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
27837                 // we're adding a temporary, animation-specific class for ng-hide since this way
27838                 // we can control when the element is actually displayed on screen without having
27839                 // to have a global/greedy CSS selector that breaks when other animations are run.
27840                 // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
27841                 $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
27842                   tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27843                 });
27844               });
27845             }
27846           };
27847         }];
27848
27849
27850         /**
27851          * @ngdoc directive
27852          * @name ngHide
27853          * @multiElement
27854          *
27855          * @description
27856          * The `ngHide` directive shows or hides the given HTML element based on the expression
27857          * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
27858          * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27859          * in AngularJS and sets the display style to none (using an !important flag).
27860          * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27861          *
27862          * ```html
27863          * <!-- when $scope.myValue is truthy (element is hidden) -->
27864          * <div ng-hide="myValue" class="ng-hide"></div>
27865          *
27866          * <!-- when $scope.myValue is falsy (element is visible) -->
27867          * <div ng-hide="myValue"></div>
27868          * ```
27869          *
27870          * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
27871          * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
27872          * from the element causing the element not to appear hidden.
27873          *
27874          * ## Why is !important used?
27875          *
27876          * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27877          * can be easily overridden by heavier selectors. For example, something as simple
27878          * as changing the display style on a HTML list item would make hidden elements appear visible.
27879          * This also becomes a bigger issue when dealing with CSS frameworks.
27880          *
27881          * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27882          * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27883          * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27884          *
27885          * ### Overriding `.ng-hide`
27886          *
27887          * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27888          * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27889          * class in CSS:
27890          *
27891          * ```css
27892          * .ng-hide {
27893          *   /&#42; this is just another form of hiding an element &#42;/
27894          *   display: block!important;
27895          *   position: absolute;
27896          *   top: -9999px;
27897          *   left: -9999px;
27898          * }
27899          * ```
27900          *
27901          * By default you don't need to override in CSS anything and the animations will work around the display style.
27902          *
27903          * ## A note about animations with `ngHide`
27904          *
27905          * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27906          * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
27907          * CSS class is added and removed for you instead of your own CSS class.
27908          *
27909          * ```css
27910          * //
27911          * //a working example can be found at the bottom of this page
27912          * //
27913          * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27914          *   transition: 0.5s linear all;
27915          * }
27916          *
27917          * .my-element.ng-hide-add { ... }
27918          * .my-element.ng-hide-add.ng-hide-add-active { ... }
27919          * .my-element.ng-hide-remove { ... }
27920          * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27921          * ```
27922          *
27923          * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27924          * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27925          *
27926          * @animations
27927          * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
27928          * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
27929          *
27930          * @element ANY
27931          * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
27932          *     the element is shown or hidden respectively.
27933          *
27934          * @example
27935           <example module="ngAnimate" deps="angular-animate.js" animations="true">
27936             <file name="index.html">
27937               Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
27938               <div>
27939                 Show:
27940                 <div class="check-element animate-hide" ng-show="checked">
27941                   <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27942                 </div>
27943               </div>
27944               <div>
27945                 Hide:
27946                 <div class="check-element animate-hide" ng-hide="checked">
27947                   <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27948                 </div>
27949               </div>
27950             </file>
27951             <file name="glyphicons.css">
27952               @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27953             </file>
27954             <file name="animations.css">
27955               .animate-hide {
27956                 transition: all linear 0.5s;
27957                 line-height: 20px;
27958                 opacity: 1;
27959                 padding: 10px;
27960                 border: 1px solid black;
27961                 background: white;
27962               }
27963
27964               .animate-hide.ng-hide {
27965                 line-height: 0;
27966                 opacity: 0;
27967                 padding: 0 10px;
27968               }
27969
27970               .check-element {
27971                 padding: 10px;
27972                 border: 1px solid black;
27973                 background: white;
27974               }
27975             </file>
27976             <file name="protractor.js" type="protractor">
27977               var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27978               var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27979
27980               it('should check ng-show / ng-hide', function() {
27981                 expect(thumbsUp.isDisplayed()).toBeFalsy();
27982                 expect(thumbsDown.isDisplayed()).toBeTruthy();
27983
27984                 element(by.model('checked')).click();
27985
27986                 expect(thumbsUp.isDisplayed()).toBeTruthy();
27987                 expect(thumbsDown.isDisplayed()).toBeFalsy();
27988               });
27989             </file>
27990           </example>
27991          */
27992         var ngHideDirective = ['$animate', function($animate) {
27993           return {
27994             restrict: 'A',
27995             multiElement: true,
27996             link: function(scope, element, attr) {
27997               scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
27998                 // The comment inside of the ngShowDirective explains why we add and
27999                 // remove a temporary class for the show/hide animation
28000                 $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
28001                   tempClasses: NG_HIDE_IN_PROGRESS_CLASS
28002                 });
28003               });
28004             }
28005           };
28006         }];
28007
28008         /**
28009          * @ngdoc directive
28010          * @name ngStyle
28011          * @restrict AC
28012          *
28013          * @description
28014          * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
28015          *
28016          * @element ANY
28017          * @param {expression} ngStyle
28018          *
28019          * {@link guide/expression Expression} which evals to an
28020          * object whose keys are CSS style names and values are corresponding values for those CSS
28021          * keys.
28022          *
28023          * Since some CSS style names are not valid keys for an object, they must be quoted.
28024          * See the 'background-color' style in the example below.
28025          *
28026          * @example
28027            <example>
28028              <file name="index.html">
28029                 <input type="button" value="set color" ng-click="myStyle={color:'red'}">
28030                 <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
28031                 <input type="button" value="clear" ng-click="myStyle={}">
28032                 <br/>
28033                 <span ng-style="myStyle">Sample Text</span>
28034                 <pre>myStyle={{myStyle}}</pre>
28035              </file>
28036              <file name="style.css">
28037                span {
28038                  color: black;
28039                }
28040              </file>
28041              <file name="protractor.js" type="protractor">
28042                var colorSpan = element(by.css('span'));
28043
28044                it('should check ng-style', function() {
28045                  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
28046                  element(by.css('input[value=\'set color\']')).click();
28047                  expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
28048                  element(by.css('input[value=clear]')).click();
28049                  expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
28050                });
28051              </file>
28052            </example>
28053          */
28054         var ngStyleDirective = ngDirective(function(scope, element, attr) {
28055           scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
28056             if (oldStyles && (newStyles !== oldStyles)) {
28057               forEach(oldStyles, function(val, style) { element.css(style, '');});
28058             }
28059             if (newStyles) element.css(newStyles);
28060           }, true);
28061         });
28062
28063         /**
28064          * @ngdoc directive
28065          * @name ngSwitch
28066          * @restrict EA
28067          *
28068          * @description
28069          * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
28070          * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
28071          * as specified in the template.
28072          *
28073          * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
28074          * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
28075          * matches the value obtained from the evaluated expression. In other words, you define a container element
28076          * (where you place the directive), place an expression on the **`on="..."` attribute**
28077          * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
28078          * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
28079          * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
28080          * attribute is displayed.
28081          *
28082          * <div class="alert alert-info">
28083          * Be aware that the attribute values to match against cannot be expressions. They are interpreted
28084          * as literal string values to match against.
28085          * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
28086          * value of the expression `$scope.someVal`.
28087          * </div>
28088
28089          * @animations
28090          * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
28091          * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
28092          *
28093          * @usage
28094          *
28095          * ```
28096          * <ANY ng-switch="expression">
28097          *   <ANY ng-switch-when="matchValue1">...</ANY>
28098          *   <ANY ng-switch-when="matchValue2">...</ANY>
28099          *   <ANY ng-switch-default>...</ANY>
28100          * </ANY>
28101          * ```
28102          *
28103          *
28104          * @scope
28105          * @priority 1200
28106          * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
28107          * On child elements add:
28108          *
28109          * * `ngSwitchWhen`: the case statement to match against. If match then this
28110          *   case will be displayed. If the same match appears multiple times, all the
28111          *   elements will be displayed.
28112          * * `ngSwitchDefault`: the default case when no other case match. If there
28113          *   are multiple default cases, all of them will be displayed when no other
28114          *   case match.
28115          *
28116          *
28117          * @example
28118           <example module="switchExample" deps="angular-animate.js" animations="true">
28119             <file name="index.html">
28120               <div ng-controller="ExampleController">
28121                 <select ng-model="selection" ng-options="item for item in items">
28122                 </select>
28123                 <code>selection={{selection}}</code>
28124                 <hr/>
28125                 <div class="animate-switch-container"
28126                   ng-switch on="selection">
28127                     <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
28128                     <div class="animate-switch" ng-switch-when="home">Home Span</div>
28129                     <div class="animate-switch" ng-switch-default>default</div>
28130                 </div>
28131               </div>
28132             </file>
28133             <file name="script.js">
28134               angular.module('switchExample', ['ngAnimate'])
28135                 .controller('ExampleController', ['$scope', function($scope) {
28136                   $scope.items = ['settings', 'home', 'other'];
28137                   $scope.selection = $scope.items[0];
28138                 }]);
28139             </file>
28140             <file name="animations.css">
28141               .animate-switch-container {
28142                 position:relative;
28143                 background:white;
28144                 border:1px solid black;
28145                 height:40px;
28146                 overflow:hidden;
28147               }
28148
28149               .animate-switch {
28150                 padding:10px;
28151               }
28152
28153               .animate-switch.ng-animate {
28154                 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
28155
28156                 position:absolute;
28157                 top:0;
28158                 left:0;
28159                 right:0;
28160                 bottom:0;
28161               }
28162
28163               .animate-switch.ng-leave.ng-leave-active,
28164               .animate-switch.ng-enter {
28165                 top:-50px;
28166               }
28167               .animate-switch.ng-leave,
28168               .animate-switch.ng-enter.ng-enter-active {
28169                 top:0;
28170               }
28171             </file>
28172             <file name="protractor.js" type="protractor">
28173               var switchElem = element(by.css('[ng-switch]'));
28174               var select = element(by.model('selection'));
28175
28176               it('should start in settings', function() {
28177                 expect(switchElem.getText()).toMatch(/Settings Div/);
28178               });
28179               it('should change to home', function() {
28180                 select.all(by.css('option')).get(1).click();
28181                 expect(switchElem.getText()).toMatch(/Home Span/);
28182               });
28183               it('should select default', function() {
28184                 select.all(by.css('option')).get(2).click();
28185                 expect(switchElem.getText()).toMatch(/default/);
28186               });
28187             </file>
28188           </example>
28189          */
28190         var ngSwitchDirective = ['$animate', function($animate) {
28191           return {
28192             require: 'ngSwitch',
28193
28194             // asks for $scope to fool the BC controller module
28195             controller: ['$scope', function ngSwitchController() {
28196              this.cases = {};
28197             }],
28198             link: function(scope, element, attr, ngSwitchController) {
28199               var watchExpr = attr.ngSwitch || attr.on,
28200                   selectedTranscludes = [],
28201                   selectedElements = [],
28202                   previousLeaveAnimations = [],
28203                   selectedScopes = [];
28204
28205               var spliceFactory = function(array, index) {
28206                   return function() { array.splice(index, 1); };
28207               };
28208
28209               scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
28210                 var i, ii;
28211                 for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
28212                   $animate.cancel(previousLeaveAnimations[i]);
28213                 }
28214                 previousLeaveAnimations.length = 0;
28215
28216                 for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
28217                   var selected = getBlockNodes(selectedElements[i].clone);
28218                   selectedScopes[i].$destroy();
28219                   var promise = previousLeaveAnimations[i] = $animate.leave(selected);
28220                   promise.then(spliceFactory(previousLeaveAnimations, i));
28221                 }
28222
28223                 selectedElements.length = 0;
28224                 selectedScopes.length = 0;
28225
28226                 if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
28227                   forEach(selectedTranscludes, function(selectedTransclude) {
28228                     selectedTransclude.transclude(function(caseElement, selectedScope) {
28229                       selectedScopes.push(selectedScope);
28230                       var anchor = selectedTransclude.element;
28231                       caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
28232                       var block = { clone: caseElement };
28233
28234                       selectedElements.push(block);
28235                       $animate.enter(caseElement, anchor.parent(), anchor);
28236                     });
28237                   });
28238                 }
28239               });
28240             }
28241           };
28242         }];
28243
28244         var ngSwitchWhenDirective = ngDirective({
28245           transclude: 'element',
28246           priority: 1200,
28247           require: '^ngSwitch',
28248           multiElement: true,
28249           link: function(scope, element, attrs, ctrl, $transclude) {
28250             ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
28251             ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
28252           }
28253         });
28254
28255         var ngSwitchDefaultDirective = ngDirective({
28256           transclude: 'element',
28257           priority: 1200,
28258           require: '^ngSwitch',
28259           multiElement: true,
28260           link: function(scope, element, attr, ctrl, $transclude) {
28261             ctrl.cases['?'] = (ctrl.cases['?'] || []);
28262             ctrl.cases['?'].push({ transclude: $transclude, element: element });
28263            }
28264         });
28265
28266         /**
28267          * @ngdoc directive
28268          * @name ngTransclude
28269          * @restrict EAC
28270          *
28271          * @description
28272          * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
28273          *
28274          * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
28275          *
28276          * @element ANY
28277          *
28278          * @example
28279            <example module="transcludeExample">
28280              <file name="index.html">
28281                <script>
28282                  angular.module('transcludeExample', [])
28283                   .directive('pane', function(){
28284                      return {
28285                        restrict: 'E',
28286                        transclude: true,
28287                        scope: { title:'@' },
28288                        template: '<div style="border: 1px solid black;">' +
28289                                    '<div style="background-color: gray">{{title}}</div>' +
28290                                    '<ng-transclude></ng-transclude>' +
28291                                  '</div>'
28292                      };
28293                  })
28294                  .controller('ExampleController', ['$scope', function($scope) {
28295                    $scope.title = 'Lorem Ipsum';
28296                    $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
28297                  }]);
28298                </script>
28299                <div ng-controller="ExampleController">
28300                  <input ng-model="title" aria-label="title"> <br/>
28301                  <textarea ng-model="text" aria-label="text"></textarea> <br/>
28302                  <pane title="{{title}}">{{text}}</pane>
28303                </div>
28304              </file>
28305              <file name="protractor.js" type="protractor">
28306                 it('should have transcluded', function() {
28307                   var titleElement = element(by.model('title'));
28308                   titleElement.clear();
28309                   titleElement.sendKeys('TITLE');
28310                   var textElement = element(by.model('text'));
28311                   textElement.clear();
28312                   textElement.sendKeys('TEXT');
28313                   expect(element(by.binding('title')).getText()).toEqual('TITLE');
28314                   expect(element(by.binding('text')).getText()).toEqual('TEXT');
28315                 });
28316              </file>
28317            </example>
28318          *
28319          */
28320         var ngTranscludeDirective = ngDirective({
28321           restrict: 'EAC',
28322           link: function($scope, $element, $attrs, controller, $transclude) {
28323             if (!$transclude) {
28324               throw minErr('ngTransclude')('orphan',
28325                'Illegal use of ngTransclude directive in the template! ' +
28326                'No parent directive that requires a transclusion found. ' +
28327                'Element: {0}',
28328                startingTag($element));
28329             }
28330
28331             $transclude(function(clone) {
28332               $element.empty();
28333               $element.append(clone);
28334             });
28335           }
28336         });
28337
28338         /**
28339          * @ngdoc directive
28340          * @name script
28341          * @restrict E
28342          *
28343          * @description
28344          * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
28345          * template can be used by {@link ng.directive:ngInclude `ngInclude`},
28346          * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
28347          * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
28348          * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
28349          *
28350          * @param {string} type Must be set to `'text/ng-template'`.
28351          * @param {string} id Cache name of the template.
28352          *
28353          * @example
28354           <example>
28355             <file name="index.html">
28356               <script type="text/ng-template" id="/tpl.html">
28357                 Content of the template.
28358               </script>
28359
28360               <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
28361               <div id="tpl-content" ng-include src="currentTpl"></div>
28362             </file>
28363             <file name="protractor.js" type="protractor">
28364               it('should load template defined inside script tag', function() {
28365                 element(by.css('#tpl-link')).click();
28366                 expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
28367               });
28368             </file>
28369           </example>
28370          */
28371         var scriptDirective = ['$templateCache', function($templateCache) {
28372           return {
28373             restrict: 'E',
28374             terminal: true,
28375             compile: function(element, attr) {
28376               if (attr.type == 'text/ng-template') {
28377                 var templateUrl = attr.id,
28378                     text = element[0].text;
28379
28380                 $templateCache.put(templateUrl, text);
28381               }
28382             }
28383           };
28384         }];
28385
28386         var noopNgModelController = { $setViewValue: noop, $render: noop };
28387
28388         function chromeHack(optionElement) {
28389           // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
28390           // Adding an <option selected="selected"> element to a <select required="required"> should
28391           // automatically select the new element
28392           if (optionElement[0].hasAttribute('selected')) {
28393             optionElement[0].selected = true;
28394           }
28395         }
28396
28397         /**
28398          * @ngdoc type
28399          * @name  select.SelectController
28400          * @description
28401          * The controller for the `<select>` directive. This provides support for reading
28402          * and writing the selected value(s) of the control and also coordinates dynamically
28403          * added `<option>` elements, perhaps by an `ngRepeat` directive.
28404          */
28405         var SelectController =
28406                 ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
28407
28408           var self = this,
28409               optionsMap = new HashMap();
28410
28411           // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
28412           self.ngModelCtrl = noopNgModelController;
28413
28414           // The "unknown" option is one that is prepended to the list if the viewValue
28415           // does not match any of the options. When it is rendered the value of the unknown
28416           // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
28417           //
28418           // We can't just jqLite('<option>') since jqLite is not smart enough
28419           // to create it in <select> and IE barfs otherwise.
28420           self.unknownOption = jqLite(document.createElement('option'));
28421           self.renderUnknownOption = function(val) {
28422             var unknownVal = '? ' + hashKey(val) + ' ?';
28423             self.unknownOption.val(unknownVal);
28424             $element.prepend(self.unknownOption);
28425             $element.val(unknownVal);
28426           };
28427
28428           $scope.$on('$destroy', function() {
28429             // disable unknown option so that we don't do work when the whole select is being destroyed
28430             self.renderUnknownOption = noop;
28431           });
28432
28433           self.removeUnknownOption = function() {
28434             if (self.unknownOption.parent()) self.unknownOption.remove();
28435           };
28436
28437
28438           // Read the value of the select control, the implementation of this changes depending
28439           // upon whether the select can have multiple values and whether ngOptions is at work.
28440           self.readValue = function readSingleValue() {
28441             self.removeUnknownOption();
28442             return $element.val();
28443           };
28444
28445
28446           // Write the value to the select control, the implementation of this changes depending
28447           // upon whether the select can have multiple values and whether ngOptions is at work.
28448           self.writeValue = function writeSingleValue(value) {
28449             if (self.hasOption(value)) {
28450               self.removeUnknownOption();
28451               $element.val(value);
28452               if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
28453             } else {
28454               if (value == null && self.emptyOption) {
28455                 self.removeUnknownOption();
28456                 $element.val('');
28457               } else {
28458                 self.renderUnknownOption(value);
28459               }
28460             }
28461           };
28462
28463
28464           // Tell the select control that an option, with the given value, has been added
28465           self.addOption = function(value, element) {
28466             assertNotHasOwnProperty(value, '"option value"');
28467             if (value === '') {
28468               self.emptyOption = element;
28469             }
28470             var count = optionsMap.get(value) || 0;
28471             optionsMap.put(value, count + 1);
28472             self.ngModelCtrl.$render();
28473             chromeHack(element);
28474           };
28475
28476           // Tell the select control that an option, with the given value, has been removed
28477           self.removeOption = function(value) {
28478             var count = optionsMap.get(value);
28479             if (count) {
28480               if (count === 1) {
28481                 optionsMap.remove(value);
28482                 if (value === '') {
28483                   self.emptyOption = undefined;
28484                 }
28485               } else {
28486                 optionsMap.put(value, count - 1);
28487               }
28488             }
28489           };
28490
28491           // Check whether the select control has an option matching the given value
28492           self.hasOption = function(value) {
28493             return !!optionsMap.get(value);
28494           };
28495
28496
28497           self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
28498
28499             if (interpolateValueFn) {
28500               // The value attribute is interpolated
28501               var oldVal;
28502               optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
28503                 if (isDefined(oldVal)) {
28504                   self.removeOption(oldVal);
28505                 }
28506                 oldVal = newVal;
28507                 self.addOption(newVal, optionElement);
28508               });
28509             } else if (interpolateTextFn) {
28510               // The text content is interpolated
28511               optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
28512                 optionAttrs.$set('value', newVal);
28513                 if (oldVal !== newVal) {
28514                   self.removeOption(oldVal);
28515                 }
28516                 self.addOption(newVal, optionElement);
28517               });
28518             } else {
28519               // The value attribute is static
28520               self.addOption(optionAttrs.value, optionElement);
28521             }
28522
28523             optionElement.on('$destroy', function() {
28524               self.removeOption(optionAttrs.value);
28525               self.ngModelCtrl.$render();
28526             });
28527           };
28528         }];
28529
28530         /**
28531          * @ngdoc directive
28532          * @name select
28533          * @restrict E
28534          *
28535          * @description
28536          * HTML `SELECT` element with angular data-binding.
28537          *
28538          * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
28539          * between the scope and the `<select>` control (including setting default values).
28540          * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
28541          * {@link ngOptions `ngOptions`} directives.
28542          *
28543          * When an item in the `<select>` menu is selected, the value of the selected option will be bound
28544          * to the model identified by the `ngModel` directive. With static or repeated options, this is
28545          * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
28546          * If you want dynamic value attributes, you can use interpolation inside the value attribute.
28547          *
28548          * <div class="alert alert-warning">
28549          * Note that the value of a `select` directive used without `ngOptions` is always a string.
28550          * When the model needs to be bound to a non-string value, you must either explictly convert it
28551          * using a directive (see example below) or use `ngOptions` to specify the set of options.
28552          * This is because an option element can only be bound to string values at present.
28553          * </div>
28554          *
28555          * If the viewValue of `ngModel` does not match any of the options, then the control
28556          * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
28557          *
28558          * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
28559          * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
28560          * option. See example below for demonstration.
28561          *
28562          * <div class="alert alert-info">
28563          * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
28564          * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
28565          * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
28566          * comprehension expression, and additionally in reducing memory and increasing speed by not creating
28567          * a new scope for each repeated instance.
28568          * </div>
28569          *
28570          *
28571          * @param {string} ngModel Assignable angular expression to data-bind to.
28572          * @param {string=} name Property name of the form under which the control is published.
28573          * @param {string=} multiple Allows multiple options to be selected. The selected values will be
28574          *     bound to the model as an array.
28575          * @param {string=} required Sets `required` validation error key if the value is not entered.
28576          * @param {string=} ngRequired Adds required attribute and required validation constraint to
28577          * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
28578          * when you want to data-bind to the required attribute.
28579          * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
28580          *    interaction with the select element.
28581          * @param {string=} ngOptions sets the options that the select is populated with and defines what is
28582          * set on the model on selection. See {@link ngOptions `ngOptions`}.
28583          *
28584          * @example
28585          * ### Simple `select` elements with static options
28586          *
28587          * <example name="static-select" module="staticSelect">
28588          * <file name="index.html">
28589          * <div ng-controller="ExampleController">
28590          *   <form name="myForm">
28591          *     <label for="singleSelect"> Single select: </label><br>
28592          *     <select name="singleSelect" ng-model="data.singleSelect">
28593          *       <option value="option-1">Option 1</option>
28594          *       <option value="option-2">Option 2</option>
28595          *     </select><br>
28596          *
28597          *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
28598          *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
28599          *       <option value="">---Please select---</option> <!-- not selected / blank option -->
28600          *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
28601          *       <option value="option-2">Option 2</option>
28602          *     </select><br>
28603          *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
28604          *     <tt>singleSelect = {{data.singleSelect}}</tt>
28605          *
28606          *     <hr>
28607          *     <label for="multipleSelect"> Multiple select: </label><br>
28608          *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
28609          *       <option value="option-1">Option 1</option>
28610          *       <option value="option-2">Option 2</option>
28611          *       <option value="option-3">Option 3</option>
28612          *     </select><br>
28613          *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
28614          *   </form>
28615          * </div>
28616          * </file>
28617          * <file name="app.js">
28618          *  angular.module('staticSelect', [])
28619          *    .controller('ExampleController', ['$scope', function($scope) {
28620          *      $scope.data = {
28621          *       singleSelect: null,
28622          *       multipleSelect: [],
28623          *       option1: 'option-1',
28624          *      };
28625          *
28626          *      $scope.forceUnknownOption = function() {
28627          *        $scope.data.singleSelect = 'nonsense';
28628          *      };
28629          *   }]);
28630          * </file>
28631          *</example>
28632          *
28633          * ### Using `ngRepeat` to generate `select` options
28634          * <example name="ngrepeat-select" module="ngrepeatSelect">
28635          * <file name="index.html">
28636          * <div ng-controller="ExampleController">
28637          *   <form name="myForm">
28638          *     <label for="repeatSelect"> Repeat select: </label>
28639          *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
28640          *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
28641          *     </select>
28642          *   </form>
28643          *   <hr>
28644          *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
28645          * </div>
28646          * </file>
28647          * <file name="app.js">
28648          *  angular.module('ngrepeatSelect', [])
28649          *    .controller('ExampleController', ['$scope', function($scope) {
28650          *      $scope.data = {
28651          *       repeatSelect: null,
28652          *       availableOptions: [
28653          *         {id: '1', name: 'Option A'},
28654          *         {id: '2', name: 'Option B'},
28655          *         {id: '3', name: 'Option C'}
28656          *       ],
28657          *      };
28658          *   }]);
28659          * </file>
28660          *</example>
28661          *
28662          *
28663          * ### Using `select` with `ngOptions` and setting a default value
28664          * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
28665          *
28666          * <example name="select-with-default-values" module="defaultValueSelect">
28667          * <file name="index.html">
28668          * <div ng-controller="ExampleController">
28669          *   <form name="myForm">
28670          *     <label for="mySelect">Make a choice:</label>
28671          *     <select name="mySelect" id="mySelect"
28672          *       ng-options="option.name for option in data.availableOptions track by option.id"
28673          *       ng-model="data.selectedOption"></select>
28674          *   </form>
28675          *   <hr>
28676          *   <tt>option = {{data.selectedOption}}</tt><br/>
28677          * </div>
28678          * </file>
28679          * <file name="app.js">
28680          *  angular.module('defaultValueSelect', [])
28681          *    .controller('ExampleController', ['$scope', function($scope) {
28682          *      $scope.data = {
28683          *       availableOptions: [
28684          *         {id: '1', name: 'Option A'},
28685          *         {id: '2', name: 'Option B'},
28686          *         {id: '3', name: 'Option C'}
28687          *       ],
28688          *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
28689          *       };
28690          *   }]);
28691          * </file>
28692          *</example>
28693          *
28694          *
28695          * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
28696          *
28697          * <example name="select-with-non-string-options" module="nonStringSelect">
28698          *   <file name="index.html">
28699          *     <select ng-model="model.id" convert-to-number>
28700          *       <option value="0">Zero</option>
28701          *       <option value="1">One</option>
28702          *       <option value="2">Two</option>
28703          *     </select>
28704          *     {{ model }}
28705          *   </file>
28706          *   <file name="app.js">
28707          *     angular.module('nonStringSelect', [])
28708          *       .run(function($rootScope) {
28709          *         $rootScope.model = { id: 2 };
28710          *       })
28711          *       .directive('convertToNumber', function() {
28712          *         return {
28713          *           require: 'ngModel',
28714          *           link: function(scope, element, attrs, ngModel) {
28715          *             ngModel.$parsers.push(function(val) {
28716          *               return parseInt(val, 10);
28717          *             });
28718          *             ngModel.$formatters.push(function(val) {
28719          *               return '' + val;
28720          *             });
28721          *           }
28722          *         };
28723          *       });
28724          *   </file>
28725          *   <file name="protractor.js" type="protractor">
28726          *     it('should initialize to model', function() {
28727          *       var select = element(by.css('select'));
28728          *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
28729          *     });
28730          *   </file>
28731          * </example>
28732          *
28733          */
28734         var selectDirective = function() {
28735
28736           return {
28737             restrict: 'E',
28738             require: ['select', '?ngModel'],
28739             controller: SelectController,
28740             priority: 1,
28741             link: {
28742               pre: selectPreLink
28743             }
28744           };
28745
28746           function selectPreLink(scope, element, attr, ctrls) {
28747
28748               // if ngModel is not defined, we don't need to do anything
28749               var ngModelCtrl = ctrls[1];
28750               if (!ngModelCtrl) return;
28751
28752               var selectCtrl = ctrls[0];
28753
28754               selectCtrl.ngModelCtrl = ngModelCtrl;
28755
28756               // We delegate rendering to the `writeValue` method, which can be changed
28757               // if the select can have multiple selected values or if the options are being
28758               // generated by `ngOptions`
28759               ngModelCtrl.$render = function() {
28760                 selectCtrl.writeValue(ngModelCtrl.$viewValue);
28761               };
28762
28763               // When the selected item(s) changes we delegate getting the value of the select control
28764               // to the `readValue` method, which can be changed if the select can have multiple
28765               // selected values or if the options are being generated by `ngOptions`
28766               element.on('change', function() {
28767                 scope.$apply(function() {
28768                   ngModelCtrl.$setViewValue(selectCtrl.readValue());
28769                 });
28770               });
28771
28772               // If the select allows multiple values then we need to modify how we read and write
28773               // values from and to the control; also what it means for the value to be empty and
28774               // we have to add an extra watch since ngModel doesn't work well with arrays - it
28775               // doesn't trigger rendering if only an item in the array changes.
28776               if (attr.multiple) {
28777
28778                 // Read value now needs to check each option to see if it is selected
28779                 selectCtrl.readValue = function readMultipleValue() {
28780                   var array = [];
28781                   forEach(element.find('option'), function(option) {
28782                     if (option.selected) {
28783                       array.push(option.value);
28784                     }
28785                   });
28786                   return array;
28787                 };
28788
28789                 // Write value now needs to set the selected property of each matching option
28790                 selectCtrl.writeValue = function writeMultipleValue(value) {
28791                   var items = new HashMap(value);
28792                   forEach(element.find('option'), function(option) {
28793                     option.selected = isDefined(items.get(option.value));
28794                   });
28795                 };
28796
28797                 // we have to do it on each watch since ngModel watches reference, but
28798                 // we need to work of an array, so we need to see if anything was inserted/removed
28799                 var lastView, lastViewRef = NaN;
28800                 scope.$watch(function selectMultipleWatch() {
28801                   if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
28802                     lastView = shallowCopy(ngModelCtrl.$viewValue);
28803                     ngModelCtrl.$render();
28804                   }
28805                   lastViewRef = ngModelCtrl.$viewValue;
28806                 });
28807
28808                 // If we are a multiple select then value is now a collection
28809                 // so the meaning of $isEmpty changes
28810                 ngModelCtrl.$isEmpty = function(value) {
28811                   return !value || value.length === 0;
28812                 };
28813
28814               }
28815             }
28816         };
28817
28818
28819         // The option directive is purely designed to communicate the existence (or lack of)
28820         // of dynamically created (and destroyed) option elements to their containing select
28821         // directive via its controller.
28822         var optionDirective = ['$interpolate', function($interpolate) {
28823           return {
28824             restrict: 'E',
28825             priority: 100,
28826             compile: function(element, attr) {
28827
28828               if (isDefined(attr.value)) {
28829                 // If the value attribute is defined, check if it contains an interpolation
28830                 var interpolateValueFn = $interpolate(attr.value, true);
28831               } else {
28832                 // If the value attribute is not defined then we fall back to the
28833                 // text content of the option element, which may be interpolated
28834                 var interpolateTextFn = $interpolate(element.text(), true);
28835                 if (!interpolateTextFn) {
28836                   attr.$set('value', element.text());
28837                 }
28838               }
28839
28840               return function(scope, element, attr) {
28841
28842                 // This is an optimization over using ^^ since we don't want to have to search
28843                 // all the way to the root of the DOM for every single option element
28844                 var selectCtrlName = '$selectController',
28845                     parent = element.parent(),
28846                     selectCtrl = parent.data(selectCtrlName) ||
28847                       parent.parent().data(selectCtrlName); // in case we are in optgroup
28848
28849                 if (selectCtrl) {
28850                   selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
28851                 }
28852               };
28853             }
28854           };
28855         }];
28856
28857         var styleDirective = valueFn({
28858           restrict: 'E',
28859           terminal: false
28860         });
28861
28862         var requiredDirective = function() {
28863           return {
28864             restrict: 'A',
28865             require: '?ngModel',
28866             link: function(scope, elm, attr, ctrl) {
28867               if (!ctrl) return;
28868               attr.required = true; // force truthy in case we are on non input element
28869
28870               ctrl.$validators.required = function(modelValue, viewValue) {
28871                 return !attr.required || !ctrl.$isEmpty(viewValue);
28872               };
28873
28874               attr.$observe('required', function() {
28875                 ctrl.$validate();
28876               });
28877             }
28878           };
28879         };
28880
28881
28882         var patternDirective = function() {
28883           return {
28884             restrict: 'A',
28885             require: '?ngModel',
28886             link: function(scope, elm, attr, ctrl) {
28887               if (!ctrl) return;
28888
28889               var regexp, patternExp = attr.ngPattern || attr.pattern;
28890               attr.$observe('pattern', function(regex) {
28891                 if (isString(regex) && regex.length > 0) {
28892                   regex = new RegExp('^' + regex + '$');
28893                 }
28894
28895                 if (regex && !regex.test) {
28896                   throw minErr('ngPattern')('noregexp',
28897                     'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
28898                     regex, startingTag(elm));
28899                 }
28900
28901                 regexp = regex || undefined;
28902                 ctrl.$validate();
28903               });
28904
28905               ctrl.$validators.pattern = function(modelValue, viewValue) {
28906                 // HTML5 pattern constraint validates the input value, so we validate the viewValue
28907                 return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
28908               };
28909             }
28910           };
28911         };
28912
28913
28914         var maxlengthDirective = function() {
28915           return {
28916             restrict: 'A',
28917             require: '?ngModel',
28918             link: function(scope, elm, attr, ctrl) {
28919               if (!ctrl) return;
28920
28921               var maxlength = -1;
28922               attr.$observe('maxlength', function(value) {
28923                 var intVal = toInt(value);
28924                 maxlength = isNaN(intVal) ? -1 : intVal;
28925                 ctrl.$validate();
28926               });
28927               ctrl.$validators.maxlength = function(modelValue, viewValue) {
28928                 return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
28929               };
28930             }
28931           };
28932         };
28933
28934         var minlengthDirective = function() {
28935           return {
28936             restrict: 'A',
28937             require: '?ngModel',
28938             link: function(scope, elm, attr, ctrl) {
28939               if (!ctrl) return;
28940
28941               var minlength = 0;
28942               attr.$observe('minlength', function(value) {
28943                 minlength = toInt(value) || 0;
28944                 ctrl.$validate();
28945               });
28946               ctrl.$validators.minlength = function(modelValue, viewValue) {
28947                 return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
28948               };
28949             }
28950           };
28951         };
28952
28953         if (window.angular.bootstrap) {
28954           //AngularJS is already loaded, so we can return here...
28955           console.log('WARNING: Tried to load angular more than once.');
28956           return;
28957         }
28958
28959         //try to bind to jquery now so that one can write jqLite(document).ready()
28960         //but we will rebind on bootstrap again.
28961         bindJQuery();
28962
28963         publishExternalAPI(angular);
28964
28965         angular.module("ngLocale", [], ["$provide", function($provide) {
28966         var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
28967         function getDecimals(n) {
28968           n = n + '';
28969           var i = n.indexOf('.');
28970           return (i == -1) ? 0 : n.length - i - 1;
28971         }
28972
28973         function getVF(n, opt_precision) {
28974           var v = opt_precision;
28975
28976           if (undefined === v) {
28977             v = Math.min(getDecimals(n), 3);
28978           }
28979
28980           var base = Math.pow(10, v);
28981           var f = ((n * base) | 0) % base;
28982           return {v: v, f: f};
28983         }
28984
28985         $provide.value("$locale", {
28986           "DATETIME_FORMATS": {
28987             "AMPMS": [
28988               "AM",
28989               "PM"
28990             ],
28991             "DAY": [
28992               "Sunday",
28993               "Monday",
28994               "Tuesday",
28995               "Wednesday",
28996               "Thursday",
28997               "Friday",
28998               "Saturday"
28999             ],
29000             "ERANAMES": [
29001               "Before Christ",
29002               "Anno Domini"
29003             ],
29004             "ERAS": [
29005               "BC",
29006               "AD"
29007             ],
29008             "FIRSTDAYOFWEEK": 6,
29009             "MONTH": [
29010               "January",
29011               "February",
29012               "March",
29013               "April",
29014               "May",
29015               "June",
29016               "July",
29017               "August",
29018               "September",
29019               "October",
29020               "November",
29021               "December"
29022             ],
29023             "SHORTDAY": [
29024               "Sun",
29025               "Mon",
29026               "Tue",
29027               "Wed",
29028               "Thu",
29029               "Fri",
29030               "Sat"
29031             ],
29032             "SHORTMONTH": [
29033               "Jan",
29034               "Feb",
29035               "Mar",
29036               "Apr",
29037               "May",
29038               "Jun",
29039               "Jul",
29040               "Aug",
29041               "Sep",
29042               "Oct",
29043               "Nov",
29044               "Dec"
29045             ],
29046             "WEEKENDRANGE": [
29047               5,
29048               6
29049             ],
29050             "fullDate": "EEEE, MMMM d, y",
29051             "longDate": "MMMM d, y",
29052             "medium": "MMM d, y h:mm:ss a",
29053             "mediumDate": "MMM d, y",
29054             "mediumTime": "h:mm:ss a",
29055             "short": "M/d/yy h:mm a",
29056             "shortDate": "M/d/yy",
29057             "shortTime": "h:mm a"
29058           },
29059           "NUMBER_FORMATS": {
29060             "CURRENCY_SYM": "$",
29061             "DECIMAL_SEP": ".",
29062             "GROUP_SEP": ",",
29063             "PATTERNS": [
29064               {
29065                 "gSize": 3,
29066                 "lgSize": 3,
29067                 "maxFrac": 3,
29068                 "minFrac": 0,
29069                 "minInt": 1,
29070                 "negPre": "-",
29071                 "negSuf": "",
29072                 "posPre": "",
29073                 "posSuf": ""
29074               },
29075               {
29076                 "gSize": 3,
29077                 "lgSize": 3,
29078                 "maxFrac": 2,
29079                 "minFrac": 2,
29080                 "minInt": 1,
29081                 "negPre": "-\u00a4",
29082                 "negSuf": "",
29083                 "posPre": "\u00a4",
29084                 "posSuf": ""
29085               }
29086             ]
29087           },
29088           "id": "en-us",
29089           "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;}
29090         });
29091         }]);
29092
29093           jqLite(document).ready(function() {
29094             angularInit(document, bootstrap);
29095           });
29096
29097         })(window, document);
29098
29099         !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>');
29100
29101 /***/ },
29102 /* 3 */
29103 /***/ function(module, exports) {
29104
29105         /**
29106          * State-based routing for AngularJS
29107          * @version v0.2.18
29108          * @link http://angular-ui.github.com/
29109          * @license MIT License, http://www.opensource.org/licenses/MIT
29110          */
29111
29112         /* commonjs package manager support (eg componentjs) */
29113         if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
29114           module.exports = 'ui.router';
29115         }
29116
29117         (function (window, angular, undefined) {
29118         /*jshint globalstrict:true*/
29119         /*global angular:false*/
29120         'use strict';
29121
29122         var isDefined = angular.isDefined,
29123             isFunction = angular.isFunction,
29124             isString = angular.isString,
29125             isObject = angular.isObject,
29126             isArray = angular.isArray,
29127             forEach = angular.forEach,
29128             extend = angular.extend,
29129             copy = angular.copy,
29130             toJson = angular.toJson;
29131
29132         function inherit(parent, extra) {
29133           return extend(new (extend(function() {}, { prototype: parent }))(), extra);
29134         }
29135
29136         function merge(dst) {
29137           forEach(arguments, function(obj) {
29138             if (obj !== dst) {
29139               forEach(obj, function(value, key) {
29140                 if (!dst.hasOwnProperty(key)) dst[key] = value;
29141               });
29142             }
29143           });
29144           return dst;
29145         }
29146
29147         /**
29148          * Finds the common ancestor path between two states.
29149          *
29150          * @param {Object} first The first state.
29151          * @param {Object} second The second state.
29152          * @return {Array} Returns an array of state names in descending order, not including the root.
29153          */
29154         function ancestors(first, second) {
29155           var path = [];
29156
29157           for (var n in first.path) {
29158             if (first.path[n] !== second.path[n]) break;
29159             path.push(first.path[n]);
29160           }
29161           return path;
29162         }
29163
29164         /**
29165          * IE8-safe wrapper for `Object.keys()`.
29166          *
29167          * @param {Object} object A JavaScript object.
29168          * @return {Array} Returns the keys of the object as an array.
29169          */
29170         function objectKeys(object) {
29171           if (Object.keys) {
29172             return Object.keys(object);
29173           }
29174           var result = [];
29175
29176           forEach(object, function(val, key) {
29177             result.push(key);
29178           });
29179           return result;
29180         }
29181
29182         /**
29183          * IE8-safe wrapper for `Array.prototype.indexOf()`.
29184          *
29185          * @param {Array} array A JavaScript array.
29186          * @param {*} value A value to search the array for.
29187          * @return {Number} Returns the array index value of `value`, or `-1` if not present.
29188          */
29189         function indexOf(array, value) {
29190           if (Array.prototype.indexOf) {
29191             return array.indexOf(value, Number(arguments[2]) || 0);
29192           }
29193           var len = array.length >>> 0, from = Number(arguments[2]) || 0;
29194           from = (from < 0) ? Math.ceil(from) : Math.floor(from);
29195
29196           if (from < 0) from += len;
29197
29198           for (; from < len; from++) {
29199             if (from in array && array[from] === value) return from;
29200           }
29201           return -1;
29202         }
29203
29204         /**
29205          * Merges a set of parameters with all parameters inherited between the common parents of the
29206          * current state and a given destination state.
29207          *
29208          * @param {Object} currentParams The value of the current state parameters ($stateParams).
29209          * @param {Object} newParams The set of parameters which will be composited with inherited params.
29210          * @param {Object} $current Internal definition of object representing the current state.
29211          * @param {Object} $to Internal definition of object representing state to transition to.
29212          */
29213         function inheritParams(currentParams, newParams, $current, $to) {
29214           var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
29215
29216           for (var i in parents) {
29217             if (!parents[i] || !parents[i].params) continue;
29218             parentParams = objectKeys(parents[i].params);
29219             if (!parentParams.length) continue;
29220
29221             for (var j in parentParams) {
29222               if (indexOf(inheritList, parentParams[j]) >= 0) continue;
29223               inheritList.push(parentParams[j]);
29224               inherited[parentParams[j]] = currentParams[parentParams[j]];
29225             }
29226           }
29227           return extend({}, inherited, newParams);
29228         }
29229
29230         /**
29231          * Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
29232          *
29233          * @param {Object} a The first object.
29234          * @param {Object} b The second object.
29235          * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
29236          *                     it defaults to the list of keys in `a`.
29237          * @return {Boolean} Returns `true` if the keys match, otherwise `false`.
29238          */
29239         function equalForKeys(a, b, keys) {
29240           if (!keys) {
29241             keys = [];
29242             for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
29243           }
29244
29245           for (var i=0; i<keys.length; i++) {
29246             var k = keys[i];
29247             if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
29248           }
29249           return true;
29250         }
29251
29252         /**
29253          * Returns the subset of an object, based on a list of keys.
29254          *
29255          * @param {Array} keys
29256          * @param {Object} values
29257          * @return {Boolean} Returns a subset of `values`.
29258          */
29259         function filterByKeys(keys, values) {
29260           var filtered = {};
29261
29262           forEach(keys, function (name) {
29263             filtered[name] = values[name];
29264           });
29265           return filtered;
29266         }
29267
29268         // like _.indexBy
29269         // when you know that your index values will be unique, or you want last-one-in to win
29270         function indexBy(array, propName) {
29271           var result = {};
29272           forEach(array, function(item) {
29273             result[item[propName]] = item;
29274           });
29275           return result;
29276         }
29277
29278         // extracted from underscore.js
29279         // Return a copy of the object only containing the whitelisted properties.
29280         function pick(obj) {
29281           var copy = {};
29282           var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
29283           forEach(keys, function(key) {
29284             if (key in obj) copy[key] = obj[key];
29285           });
29286           return copy;
29287         }
29288
29289         // extracted from underscore.js
29290         // Return a copy of the object omitting the blacklisted properties.
29291         function omit(obj) {
29292           var copy = {};
29293           var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
29294           for (var key in obj) {
29295             if (indexOf(keys, key) == -1) copy[key] = obj[key];
29296           }
29297           return copy;
29298         }
29299
29300         function pluck(collection, key) {
29301           var result = isArray(collection) ? [] : {};
29302
29303           forEach(collection, function(val, i) {
29304             result[i] = isFunction(key) ? key(val) : val[key];
29305           });
29306           return result;
29307         }
29308
29309         function filter(collection, callback) {
29310           var array = isArray(collection);
29311           var result = array ? [] : {};
29312           forEach(collection, function(val, i) {
29313             if (callback(val, i)) {
29314               result[array ? result.length : i] = val;
29315             }
29316           });
29317           return result;
29318         }
29319
29320         function map(collection, callback) {
29321           var result = isArray(collection) ? [] : {};
29322
29323           forEach(collection, function(val, i) {
29324             result[i] = callback(val, i);
29325           });
29326           return result;
29327         }
29328
29329         /**
29330          * @ngdoc overview
29331          * @name ui.router.util
29332          *
29333          * @description
29334          * # ui.router.util sub-module
29335          *
29336          * This module is a dependency of other sub-modules. Do not include this module as a dependency
29337          * in your angular app (use {@link ui.router} module instead).
29338          *
29339          */
29340         angular.module('ui.router.util', ['ng']);
29341
29342         /**
29343          * @ngdoc overview
29344          * @name ui.router.router
29345          * 
29346          * @requires ui.router.util
29347          *
29348          * @description
29349          * # ui.router.router sub-module
29350          *
29351          * This module is a dependency of other sub-modules. Do not include this module as a dependency
29352          * in your angular app (use {@link ui.router} module instead).
29353          */
29354         angular.module('ui.router.router', ['ui.router.util']);
29355
29356         /**
29357          * @ngdoc overview
29358          * @name ui.router.state
29359          * 
29360          * @requires ui.router.router
29361          * @requires ui.router.util
29362          *
29363          * @description
29364          * # ui.router.state sub-module
29365          *
29366          * This module is a dependency of the main ui.router module. Do not include this module as a dependency
29367          * in your angular app (use {@link ui.router} module instead).
29368          * 
29369          */
29370         angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
29371
29372         /**
29373          * @ngdoc overview
29374          * @name ui.router
29375          *
29376          * @requires ui.router.state
29377          *
29378          * @description
29379          * # ui.router
29380          * 
29381          * ## The main module for ui.router 
29382          * There are several sub-modules included with the ui.router module, however only this module is needed
29383          * as a dependency within your angular app. The other modules are for organization purposes. 
29384          *
29385          * The modules are:
29386          * * ui.router - the main "umbrella" module
29387          * * ui.router.router - 
29388          * 
29389          * *You'll need to include **only** this module as the dependency within your angular app.*
29390          * 
29391          * <pre>
29392          * <!doctype html>
29393          * <html ng-app="myApp">
29394          * <head>
29395          *   <script src="js/angular.js"></script>
29396          *   <!-- Include the ui-router script -->
29397          *   <script src="js/angular-ui-router.min.js"></script>
29398          *   <script>
29399          *     // ...and add 'ui.router' as a dependency
29400          *     var myApp = angular.module('myApp', ['ui.router']);
29401          *   </script>
29402          * </head>
29403          * <body>
29404          * </body>
29405          * </html>
29406          * </pre>
29407          */
29408         angular.module('ui.router', ['ui.router.state']);
29409
29410         angular.module('ui.router.compat', ['ui.router']);
29411
29412         /**
29413          * @ngdoc object
29414          * @name ui.router.util.$resolve
29415          *
29416          * @requires $q
29417          * @requires $injector
29418          *
29419          * @description
29420          * Manages resolution of (acyclic) graphs of promises.
29421          */
29422         $Resolve.$inject = ['$q', '$injector'];
29423         function $Resolve(  $q,    $injector) {
29424           
29425           var VISIT_IN_PROGRESS = 1,
29426               VISIT_DONE = 2,
29427               NOTHING = {},
29428               NO_DEPENDENCIES = [],
29429               NO_LOCALS = NOTHING,
29430               NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
29431           
29432
29433           /**
29434            * @ngdoc function
29435            * @name ui.router.util.$resolve#study
29436            * @methodOf ui.router.util.$resolve
29437            *
29438            * @description
29439            * Studies a set of invocables that are likely to be used multiple times.
29440            * <pre>
29441            * $resolve.study(invocables)(locals, parent, self)
29442            * </pre>
29443            * is equivalent to
29444            * <pre>
29445            * $resolve.resolve(invocables, locals, parent, self)
29446            * </pre>
29447            * but the former is more efficient (in fact `resolve` just calls `study` 
29448            * internally).
29449            *
29450            * @param {object} invocables Invocable objects
29451            * @return {function} a function to pass in locals, parent and self
29452            */
29453           this.study = function (invocables) {
29454             if (!isObject(invocables)) throw new Error("'invocables' must be an object");
29455             var invocableKeys = objectKeys(invocables || {});
29456             
29457             // Perform a topological sort of invocables to build an ordered plan
29458             var plan = [], cycle = [], visited = {};
29459             function visit(value, key) {
29460               if (visited[key] === VISIT_DONE) return;
29461               
29462               cycle.push(key);
29463               if (visited[key] === VISIT_IN_PROGRESS) {
29464                 cycle.splice(0, indexOf(cycle, key));
29465                 throw new Error("Cyclic dependency: " + cycle.join(" -> "));
29466               }
29467               visited[key] = VISIT_IN_PROGRESS;
29468               
29469               if (isString(value)) {
29470                 plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
29471               } else {
29472                 var params = $injector.annotate(value);
29473                 forEach(params, function (param) {
29474                   if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
29475                 });
29476                 plan.push(key, value, params);
29477               }
29478               
29479               cycle.pop();
29480               visited[key] = VISIT_DONE;
29481             }
29482             forEach(invocables, visit);
29483             invocables = cycle = visited = null; // plan is all that's required
29484             
29485             function isResolve(value) {
29486               return isObject(value) && value.then && value.$$promises;
29487             }
29488             
29489             return function (locals, parent, self) {
29490               if (isResolve(locals) && self === undefined) {
29491                 self = parent; parent = locals; locals = null;
29492               }
29493               if (!locals) locals = NO_LOCALS;
29494               else if (!isObject(locals)) {
29495                 throw new Error("'locals' must be an object");
29496               }       
29497               if (!parent) parent = NO_PARENT;
29498               else if (!isResolve(parent)) {
29499                 throw new Error("'parent' must be a promise returned by $resolve.resolve()");
29500               }
29501               
29502               // To complete the overall resolution, we have to wait for the parent
29503               // promise and for the promise for each invokable in our plan.
29504               var resolution = $q.defer(),
29505                   result = resolution.promise,
29506                   promises = result.$$promises = {},
29507                   values = extend({}, locals),
29508                   wait = 1 + plan.length/3,
29509                   merged = false;
29510                   
29511               function done() {
29512                 // Merge parent values we haven't got yet and publish our own $$values
29513                 if (!--wait) {
29514                   if (!merged) merge(values, parent.$$values); 
29515                   result.$$values = values;
29516                   result.$$promises = result.$$promises || true; // keep for isResolve()
29517                   delete result.$$inheritedValues;
29518                   resolution.resolve(values);
29519                 }
29520               }
29521               
29522               function fail(reason) {
29523                 result.$$failure = reason;
29524                 resolution.reject(reason);
29525               }
29526
29527               // Short-circuit if parent has already failed
29528               if (isDefined(parent.$$failure)) {
29529                 fail(parent.$$failure);
29530                 return result;
29531               }
29532               
29533               if (parent.$$inheritedValues) {
29534                 merge(values, omit(parent.$$inheritedValues, invocableKeys));
29535               }
29536
29537               // Merge parent values if the parent has already resolved, or merge
29538               // parent promises and wait if the parent resolve is still in progress.
29539               extend(promises, parent.$$promises);
29540               if (parent.$$values) {
29541                 merged = merge(values, omit(parent.$$values, invocableKeys));
29542                 result.$$inheritedValues = omit(parent.$$values, invocableKeys);
29543                 done();
29544               } else {
29545                 if (parent.$$inheritedValues) {
29546                   result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys);
29547                 }        
29548                 parent.then(done, fail);
29549               }
29550               
29551               // Process each invocable in the plan, but ignore any where a local of the same name exists.
29552               for (var i=0, ii=plan.length; i<ii; i+=3) {
29553                 if (locals.hasOwnProperty(plan[i])) done();
29554                 else invoke(plan[i], plan[i+1], plan[i+2]);
29555               }
29556               
29557               function invoke(key, invocable, params) {
29558                 // Create a deferred for this invocation. Failures will propagate to the resolution as well.
29559                 var invocation = $q.defer(), waitParams = 0;
29560                 function onfailure(reason) {
29561                   invocation.reject(reason);
29562                   fail(reason);
29563                 }
29564                 // Wait for any parameter that we have a promise for (either from parent or from this
29565                 // resolve; in that case study() will have made sure it's ordered before us in the plan).
29566                 forEach(params, function (dep) {
29567                   if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
29568                     waitParams++;
29569                     promises[dep].then(function (result) {
29570                       values[dep] = result;
29571                       if (!(--waitParams)) proceed();
29572                     }, onfailure);
29573                   }
29574                 });
29575                 if (!waitParams) proceed();
29576                 function proceed() {
29577                   if (isDefined(result.$$failure)) return;
29578                   try {
29579                     invocation.resolve($injector.invoke(invocable, self, values));
29580                     invocation.promise.then(function (result) {
29581                       values[key] = result;
29582                       done();
29583                     }, onfailure);
29584                   } catch (e) {
29585                     onfailure(e);
29586                   }
29587                 }
29588                 // Publish promise synchronously; invocations further down in the plan may depend on it.
29589                 promises[key] = invocation.promise;
29590               }
29591               
29592               return result;
29593             };
29594           };
29595           
29596           /**
29597            * @ngdoc function
29598            * @name ui.router.util.$resolve#resolve
29599            * @methodOf ui.router.util.$resolve
29600            *
29601            * @description
29602            * Resolves a set of invocables. An invocable is a function to be invoked via 
29603            * `$injector.invoke()`, and can have an arbitrary number of dependencies. 
29604            * An invocable can either return a value directly,
29605            * or a `$q` promise. If a promise is returned it will be resolved and the 
29606            * resulting value will be used instead. Dependencies of invocables are resolved 
29607            * (in this order of precedence)
29608            *
29609            * - from the specified `locals`
29610            * - from another invocable that is part of this `$resolve` call
29611            * - from an invocable that is inherited from a `parent` call to `$resolve` 
29612            *   (or recursively
29613            * - from any ancestor `$resolve` of that parent).
29614            *
29615            * The return value of `$resolve` is a promise for an object that contains 
29616            * (in this order of precedence)
29617            *
29618            * - any `locals` (if specified)
29619            * - the resolved return values of all injectables
29620            * - any values inherited from a `parent` call to `$resolve` (if specified)
29621            *
29622            * The promise will resolve after the `parent` promise (if any) and all promises 
29623            * returned by injectables have been resolved. If any invocable 
29624            * (or `$injector.invoke`) throws an exception, or if a promise returned by an 
29625            * invocable is rejected, the `$resolve` promise is immediately rejected with the 
29626            * same error. A rejection of a `parent` promise (if specified) will likewise be 
29627            * propagated immediately. Once the `$resolve` promise has been rejected, no 
29628            * further invocables will be called.
29629            * 
29630            * Cyclic dependencies between invocables are not permitted and will cause `$resolve`
29631            * to throw an error. As a special case, an injectable can depend on a parameter 
29632            * with the same name as the injectable, which will be fulfilled from the `parent` 
29633            * injectable of the same name. This allows inherited values to be decorated. 
29634            * Note that in this case any other injectable in the same `$resolve` with the same
29635            * dependency would see the decorated value, not the inherited value.
29636            *
29637            * Note that missing dependencies -- unlike cyclic dependencies -- will cause an 
29638            * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous) 
29639            * exception.
29640            *
29641            * Invocables are invoked eagerly as soon as all dependencies are available. 
29642            * This is true even for dependencies inherited from a `parent` call to `$resolve`.
29643            *
29644            * As a special case, an invocable can be a string, in which case it is taken to 
29645            * be a service name to be passed to `$injector.get()`. This is supported primarily 
29646            * for backwards-compatibility with the `resolve` property of `$routeProvider` 
29647            * routes.
29648            *
29649            * @param {object} invocables functions to invoke or 
29650            * `$injector` services to fetch.
29651            * @param {object} locals  values to make available to the injectables
29652            * @param {object} parent  a promise returned by another call to `$resolve`.
29653            * @param {object} self  the `this` for the invoked methods
29654            * @return {object} Promise for an object that contains the resolved return value
29655            * of all invocables, as well as any inherited and local values.
29656            */
29657           this.resolve = function (invocables, locals, parent, self) {
29658             return this.study(invocables)(locals, parent, self);
29659           };
29660         }
29661
29662         angular.module('ui.router.util').service('$resolve', $Resolve);
29663
29664
29665         /**
29666          * @ngdoc object
29667          * @name ui.router.util.$templateFactory
29668          *
29669          * @requires $http
29670          * @requires $templateCache
29671          * @requires $injector
29672          *
29673          * @description
29674          * Service. Manages loading of templates.
29675          */
29676         $TemplateFactory.$inject = ['$http', '$templateCache', '$injector'];
29677         function $TemplateFactory(  $http,   $templateCache,   $injector) {
29678
29679           /**
29680            * @ngdoc function
29681            * @name ui.router.util.$templateFactory#fromConfig
29682            * @methodOf ui.router.util.$templateFactory
29683            *
29684            * @description
29685            * Creates a template from a configuration object. 
29686            *
29687            * @param {object} config Configuration object for which to load a template. 
29688            * The following properties are search in the specified order, and the first one 
29689            * that is defined is used to create the template:
29690            *
29691            * @param {string|object} config.template html string template or function to 
29692            * load via {@link ui.router.util.$templateFactory#fromString fromString}.
29693            * @param {string|object} config.templateUrl url to load or a function returning 
29694            * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}.
29695            * @param {Function} config.templateProvider function to invoke via 
29696            * {@link ui.router.util.$templateFactory#fromProvider fromProvider}.
29697            * @param {object} params  Parameters to pass to the template function.
29698            * @param {object} locals Locals to pass to `invoke` if the template is loaded 
29699            * via a `templateProvider`. Defaults to `{ params: params }`.
29700            *
29701            * @return {string|object}  The template html as a string, or a promise for 
29702            * that string,or `null` if no template is configured.
29703            */
29704           this.fromConfig = function (config, params, locals) {
29705             return (
29706               isDefined(config.template) ? this.fromString(config.template, params) :
29707               isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
29708               isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
29709               null
29710             );
29711           };
29712
29713           /**
29714            * @ngdoc function
29715            * @name ui.router.util.$templateFactory#fromString
29716            * @methodOf ui.router.util.$templateFactory
29717            *
29718            * @description
29719            * Creates a template from a string or a function returning a string.
29720            *
29721            * @param {string|object} template html template as a string or function that 
29722            * returns an html template as a string.
29723            * @param {object} params Parameters to pass to the template function.
29724            *
29725            * @return {string|object} The template html as a string, or a promise for that 
29726            * string.
29727            */
29728           this.fromString = function (template, params) {
29729             return isFunction(template) ? template(params) : template;
29730           };
29731
29732           /**
29733            * @ngdoc function
29734            * @name ui.router.util.$templateFactory#fromUrl
29735            * @methodOf ui.router.util.$templateFactory
29736            * 
29737            * @description
29738            * Loads a template from the a URL via `$http` and `$templateCache`.
29739            *
29740            * @param {string|Function} url url of the template to load, or a function 
29741            * that returns a url.
29742            * @param {Object} params Parameters to pass to the url function.
29743            * @return {string|Promise.<string>} The template html as a string, or a promise 
29744            * for that string.
29745            */
29746           this.fromUrl = function (url, params) {
29747             if (isFunction(url)) url = url(params);
29748             if (url == null) return null;
29749             else return $http
29750                 .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }})
29751                 .then(function(response) { return response.data; });
29752           };
29753
29754           /**
29755            * @ngdoc function
29756            * @name ui.router.util.$templateFactory#fromProvider
29757            * @methodOf ui.router.util.$templateFactory
29758            *
29759            * @description
29760            * Creates a template by invoking an injectable provider function.
29761            *
29762            * @param {Function} provider Function to invoke via `$injector.invoke`
29763            * @param {Object} params Parameters for the template.
29764            * @param {Object} locals Locals to pass to `invoke`. Defaults to 
29765            * `{ params: params }`.
29766            * @return {string|Promise.<string>} The template html as a string, or a promise 
29767            * for that string.
29768            */
29769           this.fromProvider = function (provider, params, locals) {
29770             return $injector.invoke(provider, null, locals || { params: params });
29771           };
29772         }
29773
29774         angular.module('ui.router.util').service('$templateFactory', $TemplateFactory);
29775
29776         var $$UMFP; // reference to $UrlMatcherFactoryProvider
29777
29778         /**
29779          * @ngdoc object
29780          * @name ui.router.util.type:UrlMatcher
29781          *
29782          * @description
29783          * Matches URLs against patterns and extracts named parameters from the path or the search
29784          * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
29785          * of search parameters. Multiple search parameter names are separated by '&'. Search parameters
29786          * do not influence whether or not a URL is matched, but their values are passed through into
29787          * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.
29788          *
29789          * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
29790          * syntax, which optionally allows a regular expression for the parameter to be specified:
29791          *
29792          * * `':'` name - colon placeholder
29793          * * `'*'` name - catch-all placeholder
29794          * * `'{' name '}'` - curly placeholder
29795          * * `'{' name ':' regexp|type '}'` - curly placeholder with regexp or type name. Should the
29796          *   regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.
29797          *
29798          * Parameter names may contain only word characters (latin letters, digits, and underscore) and
29799          * must be unique within the pattern (across both path and search parameters). For colon
29800          * placeholders or curly placeholders without an explicit regexp, a path parameter matches any
29801          * number of characters other than '/'. For catch-all placeholders the path parameter matches
29802          * any number of characters.
29803          *
29804          * Examples:
29805          *
29806          * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
29807          *   trailing slashes, and patterns have to match the entire path, not just a prefix.
29808          * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
29809          *   '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
29810          * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
29811          * * `'/user/{id:[^/]*}'` - Same as the previous example.
29812          * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
29813          *   parameter consists of 1 to 8 hex digits.
29814          * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
29815          *   path into the parameter 'path'.
29816          * * `'/files/*path'` - ditto.
29817          * * `'/calendar/{start:date}'` - Matches "/calendar/2014-11-12" (because the pattern defined
29818          *   in the built-in  `date` Type matches `2014-11-12`) and provides a Date object in $stateParams.start
29819          *
29820          * @param {string} pattern  The pattern to compile into a matcher.
29821          * @param {Object} config  A configuration object hash:
29822          * @param {Object=} parentMatcher Used to concatenate the pattern/config onto
29823          *   an existing UrlMatcher
29824          *
29825          * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
29826          * * `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`.
29827          *
29828          * @property {string} prefix  A static prefix of this pattern. The matcher guarantees that any
29829          *   URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns
29830          *   non-null) will start with this prefix.
29831          *
29832          * @property {string} source  The pattern that was passed into the constructor
29833          *
29834          * @property {string} sourcePath  The path portion of the source property
29835          *
29836          * @property {string} sourceSearch  The search portion of the source property
29837          *
29838          * @property {string} regex  The constructed regex that will be used to match against the url when
29839          *   it is time to determine which url will match.
29840          *
29841          * @returns {Object}  New `UrlMatcher` object
29842          */
29843         function UrlMatcher(pattern, config, parentMatcher) {
29844           config = extend({ params: {} }, isObject(config) ? config : {});
29845
29846           // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
29847           //   '*' name
29848           //   ':' name
29849           //   '{' name '}'
29850           //   '{' name ':' regexp '}'
29851           // The regular expression is somewhat complicated due to the need to allow curly braces
29852           // inside the regular expression. The placeholder regexp breaks down as follows:
29853           //    ([:*])([\w\[\]]+)              - classic placeholder ($1 / $2) (search version has - for snake-case)
29854           //    \{([\w\[\]]+)(?:\:\s*( ... ))?\}  - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case
29855           //    (?: ... | ... | ... )+         - the regexp consists of any number of atoms, an atom being either
29856           //    [^{}\\]+                       - anything other than curly braces or backslash
29857           //    \\.                            - a backslash escape
29858           //    \{(?:[^{}\\]+|\\.)*\}          - a matched set of curly braces containing other atoms
29859           var placeholder       = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:\s*((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
29860               searchPlaceholder = /([:]?)([\w\[\].-]+)|\{([\w\[\].-]+)(?:\:\s*((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
29861               compiled = '^', last = 0, m,
29862               segments = this.segments = [],
29863               parentParams = parentMatcher ? parentMatcher.params : {},
29864               params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(),
29865               paramNames = [];
29866
29867           function addParameter(id, type, config, location) {
29868             paramNames.push(id);
29869             if (parentParams[id]) return parentParams[id];
29870             if (!/^\w+([-.]+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
29871             if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
29872             params[id] = new $$UMFP.Param(id, type, config, location);
29873             return params[id];
29874           }
29875
29876           function quoteRegExp(string, pattern, squash, optional) {
29877             var surroundPattern = ['',''], result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
29878             if (!pattern) return result;
29879             switch(squash) {
29880               case false: surroundPattern = ['(', ')' + (optional ? "?" : "")]; break;
29881               case true:
29882                 result = result.replace(/\/$/, '');
29883                 surroundPattern = ['(?:\/(', ')|\/)?'];
29884               break;
29885               default:    surroundPattern = ['(' + squash + "|", ')?']; break;
29886             }
29887             return result + surroundPattern[0] + pattern + surroundPattern[1];
29888           }
29889
29890           this.source = pattern;
29891
29892           // Split into static segments separated by path parameter placeholders.
29893           // The number of segments is always 1 more than the number of parameters.
29894           function matchDetails(m, isSearch) {
29895             var id, regexp, segment, type, cfg, arrayMode;
29896             id          = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
29897             cfg         = config.params[id];
29898             segment     = pattern.substring(last, m.index);
29899             regexp      = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null);
29900
29901             if (regexp) {
29902               type      = $$UMFP.type(regexp) || inherit($$UMFP.type("string"), { pattern: new RegExp(regexp, config.caseInsensitive ? 'i' : undefined) });
29903             }
29904
29905             return {
29906               id: id, regexp: regexp, segment: segment, type: type, cfg: cfg
29907             };
29908           }
29909
29910           var p, param, segment;
29911           while ((m = placeholder.exec(pattern))) {
29912             p = matchDetails(m, false);
29913             if (p.segment.indexOf('?') >= 0) break; // we're into the search part
29914
29915             param = addParameter(p.id, p.type, p.cfg, "path");
29916             compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash, param.isOptional);
29917             segments.push(p.segment);
29918             last = placeholder.lastIndex;
29919           }
29920           segment = pattern.substring(last);
29921
29922           // Find any search parameter names and remove them from the last segment
29923           var i = segment.indexOf('?');
29924
29925           if (i >= 0) {
29926             var search = this.sourceSearch = segment.substring(i);
29927             segment = segment.substring(0, i);
29928             this.sourcePath = pattern.substring(0, last + i);
29929
29930             if (search.length > 0) {
29931               last = 0;
29932               while ((m = searchPlaceholder.exec(search))) {
29933                 p = matchDetails(m, true);
29934                 param = addParameter(p.id, p.type, p.cfg, "search");
29935                 last = placeholder.lastIndex;
29936                 // check if ?&
29937               }
29938             }
29939           } else {
29940             this.sourcePath = pattern;
29941             this.sourceSearch = '';
29942           }
29943
29944           compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$';
29945           segments.push(segment);
29946
29947           this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
29948           this.prefix = segments[0];
29949           this.$$paramNames = paramNames;
29950         }
29951
29952         /**
29953          * @ngdoc function
29954          * @name ui.router.util.type:UrlMatcher#concat
29955          * @methodOf ui.router.util.type:UrlMatcher
29956          *
29957          * @description
29958          * Returns a new matcher for a pattern constructed by appending the path part and adding the
29959          * search parameters of the specified pattern to this pattern. The current pattern is not
29960          * modified. This can be understood as creating a pattern for URLs that are relative to (or
29961          * suffixes of) the current pattern.
29962          *
29963          * @example
29964          * The following two matchers are equivalent:
29965          * <pre>
29966          * new UrlMatcher('/user/{id}?q').concat('/details?date');
29967          * new UrlMatcher('/user/{id}/details?q&date');
29968          * </pre>
29969          *
29970          * @param {string} pattern  The pattern to append.
29971          * @param {Object} config  An object hash of the configuration for the matcher.
29972          * @returns {UrlMatcher}  A matcher for the concatenated pattern.
29973          */
29974         UrlMatcher.prototype.concat = function (pattern, config) {
29975           // Because order of search parameters is irrelevant, we can add our own search
29976           // parameters to the end of the new pattern. Parse the new pattern by itself
29977           // and then join the bits together, but it's much easier to do this on a string level.
29978           var defaultConfig = {
29979             caseInsensitive: $$UMFP.caseInsensitive(),
29980             strict: $$UMFP.strictMode(),
29981             squash: $$UMFP.defaultSquashPolicy()
29982           };
29983           return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this);
29984         };
29985
29986         UrlMatcher.prototype.toString = function () {
29987           return this.source;
29988         };
29989
29990         /**
29991          * @ngdoc function
29992          * @name ui.router.util.type:UrlMatcher#exec
29993          * @methodOf ui.router.util.type:UrlMatcher
29994          *
29995          * @description
29996          * Tests the specified path against this matcher, and returns an object containing the captured
29997          * parameter values, or null if the path does not match. The returned object contains the values
29998          * of any search parameters that are mentioned in the pattern, but their value may be null if
29999          * they are not present in `searchParams`. This means that search parameters are always treated
30000          * as optional.
30001          *
30002          * @example
30003          * <pre>
30004          * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
30005          *   x: '1', q: 'hello'
30006          * });
30007          * // returns { id: 'bob', q: 'hello', r: null }
30008          * </pre>
30009          *
30010          * @param {string} path  The URL path to match, e.g. `$location.path()`.
30011          * @param {Object} searchParams  URL search parameters, e.g. `$location.search()`.
30012          * @returns {Object}  The captured parameter values.
30013          */
30014         UrlMatcher.prototype.exec = function (path, searchParams) {
30015           var m = this.regexp.exec(path);
30016           if (!m) return null;
30017           searchParams = searchParams || {};
30018
30019           var paramNames = this.parameters(), nTotal = paramNames.length,
30020             nPath = this.segments.length - 1,
30021             values = {}, i, j, cfg, paramName;
30022
30023           if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
30024
30025           function decodePathArray(string) {
30026             function reverseString(str) { return str.split("").reverse().join(""); }
30027             function unquoteDashes(str) { return str.replace(/\\-/g, "-"); }
30028
30029             var split = reverseString(string).split(/-(?!\\)/);
30030             var allReversed = map(split, reverseString);
30031             return map(allReversed, unquoteDashes).reverse();
30032           }
30033
30034           var param, paramVal;
30035           for (i = 0; i < nPath; i++) {
30036             paramName = paramNames[i];
30037             param = this.params[paramName];
30038             paramVal = m[i+1];
30039             // if the param value matches a pre-replace pair, replace the value before decoding.
30040             for (j = 0; j < param.replace.length; j++) {
30041               if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;
30042             }
30043             if (paramVal && param.array === true) paramVal = decodePathArray(paramVal);
30044             if (isDefined(paramVal)) paramVal = param.type.decode(paramVal);
30045             values[paramName] = param.value(paramVal);
30046           }
30047           for (/**/; i < nTotal; i++) {
30048             paramName = paramNames[i];
30049             values[paramName] = this.params[paramName].value(searchParams[paramName]);
30050             param = this.params[paramName];
30051             paramVal = searchParams[paramName];
30052             for (j = 0; j < param.replace.length; j++) {
30053               if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;
30054             }
30055             if (isDefined(paramVal)) paramVal = param.type.decode(paramVal);
30056             values[paramName] = param.value(paramVal);
30057           }
30058
30059           return values;
30060         };
30061
30062         /**
30063          * @ngdoc function
30064          * @name ui.router.util.type:UrlMatcher#parameters
30065          * @methodOf ui.router.util.type:UrlMatcher
30066          *
30067          * @description
30068          * Returns the names of all path and search parameters of this pattern in an unspecified order.
30069          *
30070          * @returns {Array.<string>}  An array of parameter names. Must be treated as read-only. If the
30071          *    pattern has no parameters, an empty array is returned.
30072          */
30073         UrlMatcher.prototype.parameters = function (param) {
30074           if (!isDefined(param)) return this.$$paramNames;
30075           return this.params[param] || null;
30076         };
30077
30078         /**
30079          * @ngdoc function
30080          * @name ui.router.util.type:UrlMatcher#validates
30081          * @methodOf ui.router.util.type:UrlMatcher
30082          *
30083          * @description
30084          * Checks an object hash of parameters to validate their correctness according to the parameter
30085          * types of this `UrlMatcher`.
30086          *
30087          * @param {Object} params The object hash of parameters to validate.
30088          * @returns {boolean} Returns `true` if `params` validates, otherwise `false`.
30089          */
30090         UrlMatcher.prototype.validates = function (params) {
30091           return this.params.$$validates(params);
30092         };
30093
30094         /**
30095          * @ngdoc function
30096          * @name ui.router.util.type:UrlMatcher#format
30097          * @methodOf ui.router.util.type:UrlMatcher
30098          *
30099          * @description
30100          * Creates a URL that matches this pattern by substituting the specified values
30101          * for the path and search parameters. Null values for path parameters are
30102          * treated as empty strings.
30103          *
30104          * @example
30105          * <pre>
30106          * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
30107          * // returns '/user/bob?q=yes'
30108          * </pre>
30109          *
30110          * @param {Object} values  the values to substitute for the parameters in this pattern.
30111          * @returns {string}  the formatted URL (path and optionally search part).
30112          */
30113         UrlMatcher.prototype.format = function (values) {
30114           values = values || {};
30115           var segments = this.segments, params = this.parameters(), paramset = this.params;
30116           if (!this.validates(values)) return null;
30117
30118           var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0];
30119
30120           function encodeDashes(str) { // Replace dashes with encoded "\-"
30121             return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCodeAt(0).toString(16).toUpperCase(); });
30122           }
30123
30124           for (i = 0; i < nTotal; i++) {
30125             var isPathParam = i < nPath;
30126             var name = params[i], param = paramset[name], value = param.value(values[name]);
30127             var isDefaultValue = param.isOptional && param.type.equals(param.value(), value);
30128             var squash = isDefaultValue ? param.squash : false;
30129             var encoded = param.type.encode(value);
30130
30131             if (isPathParam) {
30132               var nextSegment = segments[i + 1];
30133               var isFinalPathParam = i + 1 === nPath;
30134
30135               if (squash === false) {
30136                 if (encoded != null) {
30137                   if (isArray(encoded)) {
30138                     result += map(encoded, encodeDashes).join("-");
30139                   } else {
30140                     result += encodeURIComponent(encoded);
30141                   }
30142                 }
30143                 result += nextSegment;
30144               } else if (squash === true) {
30145                 var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/;
30146                 result += nextSegment.match(capture)[1];
30147               } else if (isString(squash)) {
30148                 result += squash + nextSegment;
30149               }
30150
30151               if (isFinalPathParam && param.squash === true && result.slice(-1) === '/') result = result.slice(0, -1);
30152             } else {
30153               if (encoded == null || (isDefaultValue && squash !== false)) continue;
30154               if (!isArray(encoded)) encoded = [ encoded ];
30155               if (encoded.length === 0) continue;
30156               encoded = map(encoded, encodeURIComponent).join('&' + name + '=');
30157               result += (search ? '&' : '?') + (name + '=' + encoded);
30158               search = true;
30159             }
30160           }
30161
30162           return result;
30163         };
30164
30165         /**
30166          * @ngdoc object
30167          * @name ui.router.util.type:Type
30168          *
30169          * @description
30170          * Implements an interface to define custom parameter types that can be decoded from and encoded to
30171          * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`}
30172          * objects when matching or formatting URLs, or comparing or validating parameter values.
30173          *
30174          * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more
30175          * information on registering custom types.
30176          *
30177          * @param {Object} config  A configuration object which contains the custom type definition.  The object's
30178          *        properties will override the default methods and/or pattern in `Type`'s public interface.
30179          * @example
30180          * <pre>
30181          * {
30182          *   decode: function(val) { return parseInt(val, 10); },
30183          *   encode: function(val) { return val && val.toString(); },
30184          *   equals: function(a, b) { return this.is(a) && a === b; },
30185          *   is: function(val) { return angular.isNumber(val) isFinite(val) && val % 1 === 0; },
30186          *   pattern: /\d+/
30187          * }
30188          * </pre>
30189          *
30190          * @property {RegExp} pattern The regular expression pattern used to match values of this type when
30191          *           coming from a substring of a URL.
30192          *
30193          * @returns {Object}  Returns a new `Type` object.
30194          */
30195         function Type(config) {
30196           extend(this, config);
30197         }
30198
30199         /**
30200          * @ngdoc function
30201          * @name ui.router.util.type:Type#is
30202          * @methodOf ui.router.util.type:Type
30203          *
30204          * @description
30205          * Detects whether a value is of a particular type. Accepts a native (decoded) value
30206          * and determines whether it matches the current `Type` object.
30207          *
30208          * @param {*} val  The value to check.
30209          * @param {string} key  Optional. If the type check is happening in the context of a specific
30210          *        {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the
30211          *        parameter in which `val` is stored. Can be used for meta-programming of `Type` objects.
30212          * @returns {Boolean}  Returns `true` if the value matches the type, otherwise `false`.
30213          */
30214         Type.prototype.is = function(val, key) {
30215           return true;
30216         };
30217
30218         /**
30219          * @ngdoc function
30220          * @name ui.router.util.type:Type#encode
30221          * @methodOf ui.router.util.type:Type
30222          *
30223          * @description
30224          * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the
30225          * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it
30226          * only needs to be a representation of `val` that has been coerced to a string.
30227          *
30228          * @param {*} val  The value to encode.
30229          * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
30230          *        meta-programming of `Type` objects.
30231          * @returns {string}  Returns a string representation of `val` that can be encoded in a URL.
30232          */
30233         Type.prototype.encode = function(val, key) {
30234           return val;
30235         };
30236
30237         /**
30238          * @ngdoc function
30239          * @name ui.router.util.type:Type#decode
30240          * @methodOf ui.router.util.type:Type
30241          *
30242          * @description
30243          * Converts a parameter value (from URL string or transition param) to a custom/native value.
30244          *
30245          * @param {string} val  The URL parameter value to decode.
30246          * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
30247          *        meta-programming of `Type` objects.
30248          * @returns {*}  Returns a custom representation of the URL parameter value.
30249          */
30250         Type.prototype.decode = function(val, key) {
30251           return val;
30252         };
30253
30254         /**
30255          * @ngdoc function
30256          * @name ui.router.util.type:Type#equals
30257          * @methodOf ui.router.util.type:Type
30258          *
30259          * @description
30260          * Determines whether two decoded values are equivalent.
30261          *
30262          * @param {*} a  A value to compare against.
30263          * @param {*} b  A value to compare against.
30264          * @returns {Boolean}  Returns `true` if the values are equivalent/equal, otherwise `false`.
30265          */
30266         Type.prototype.equals = function(a, b) {
30267           return a == b;
30268         };
30269
30270         Type.prototype.$subPattern = function() {
30271           var sub = this.pattern.toString();
30272           return sub.substr(1, sub.length - 2);
30273         };
30274
30275         Type.prototype.pattern = /.*/;
30276
30277         Type.prototype.toString = function() { return "{Type:" + this.name + "}"; };
30278
30279         /** Given an encoded string, or a decoded object, returns a decoded object */
30280         Type.prototype.$normalize = function(val) {
30281           return this.is(val) ? val : this.decode(val);
30282         };
30283
30284         /*
30285          * Wraps an existing custom Type as an array of Type, depending on 'mode'.
30286          * e.g.:
30287          * - urlmatcher pattern "/path?{queryParam[]:int}"
30288          * - url: "/path?queryParam=1&queryParam=2
30289          * - $stateParams.queryParam will be [1, 2]
30290          * if `mode` is "auto", then
30291          * - url: "/path?queryParam=1 will create $stateParams.queryParam: 1
30292          * - url: "/path?queryParam=1&queryParam=2 will create $stateParams.queryParam: [1, 2]
30293          */
30294         Type.prototype.$asArray = function(mode, isSearch) {
30295           if (!mode) return this;
30296           if (mode === "auto" && !isSearch) throw new Error("'auto' array mode is for query parameters only");
30297
30298           function ArrayType(type, mode) {
30299             function bindTo(type, callbackName) {
30300               return function() {
30301                 return type[callbackName].apply(type, arguments);
30302               };
30303             }
30304
30305             // Wrap non-array value as array
30306             function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); }
30307             // Unwrap array value for "auto" mode. Return undefined for empty array.
30308             function arrayUnwrap(val) {
30309               switch(val.length) {
30310                 case 0: return undefined;
30311                 case 1: return mode === "auto" ? val[0] : val;
30312                 default: return val;
30313               }
30314             }
30315             function falsey(val) { return !val; }
30316
30317             // Wraps type (.is/.encode/.decode) functions to operate on each value of an array
30318             function arrayHandler(callback, allTruthyMode) {
30319               return function handleArray(val) {
30320                 if (isArray(val) && val.length === 0) return val;
30321                 val = arrayWrap(val);
30322                 var result = map(val, callback);
30323                 if (allTruthyMode === true)
30324                   return filter(result, falsey).length === 0;
30325                 return arrayUnwrap(result);
30326               };
30327             }
30328
30329             // Wraps type (.equals) functions to operate on each value of an array
30330             function arrayEqualsHandler(callback) {
30331               return function handleArray(val1, val2) {
30332                 var left = arrayWrap(val1), right = arrayWrap(val2);
30333                 if (left.length !== right.length) return false;
30334                 for (var i = 0; i < left.length; i++) {
30335                   if (!callback(left[i], right[i])) return false;
30336                 }
30337                 return true;
30338               };
30339             }
30340
30341             this.encode = arrayHandler(bindTo(type, 'encode'));
30342             this.decode = arrayHandler(bindTo(type, 'decode'));
30343             this.is     = arrayHandler(bindTo(type, 'is'), true);
30344             this.equals = arrayEqualsHandler(bindTo(type, 'equals'));
30345             this.pattern = type.pattern;
30346             this.$normalize = arrayHandler(bindTo(type, '$normalize'));
30347             this.name = type.name;
30348             this.$arrayMode = mode;
30349           }
30350
30351           return new ArrayType(this, mode);
30352         };
30353
30354
30355
30356         /**
30357          * @ngdoc object
30358          * @name ui.router.util.$urlMatcherFactory
30359          *
30360          * @description
30361          * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory
30362          * is also available to providers under the name `$urlMatcherFactoryProvider`.
30363          */
30364         function $UrlMatcherFactory() {
30365           $$UMFP = this;
30366
30367           var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false;
30368
30369           // Use tildes to pre-encode slashes.
30370           // If the slashes are simply URLEncoded, the browser can choose to pre-decode them,
30371           // and bidirectional encoding/decoding fails.
30372           // Tilde was chosen because it's not a RFC 3986 section 2.2 Reserved Character
30373           function valToString(val) { return val != null ? val.toString().replace(/~/g, "~~").replace(/\//g, "~2F") : val; }
30374           function valFromString(val) { return val != null ? val.toString().replace(/~2F/g, "/").replace(/~~/g, "~") : val; }
30375
30376           var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = {
30377             "string": {
30378               encode: valToString,
30379               decode: valFromString,
30380               // TODO: in 1.0, make string .is() return false if value is undefined/null by default.
30381               // In 0.2.x, string params are optional by default for backwards compat
30382               is: function(val) { return val == null || !isDefined(val) || typeof val === "string"; },
30383               pattern: /[^/]*/
30384             },
30385             "int": {
30386               encode: valToString,
30387               decode: function(val) { return parseInt(val, 10); },
30388               is: function(val) { return isDefined(val) && this.decode(val.toString()) === val; },
30389               pattern: /\d+/
30390             },
30391             "bool": {
30392               encode: function(val) { return val ? 1 : 0; },
30393               decode: function(val) { return parseInt(val, 10) !== 0; },
30394               is: function(val) { return val === true || val === false; },
30395               pattern: /0|1/
30396             },
30397             "date": {
30398               encode: function (val) {
30399                 if (!this.is(val))
30400                   return undefined;
30401                 return [ val.getFullYear(),
30402                   ('0' + (val.getMonth() + 1)).slice(-2),
30403                   ('0' + val.getDate()).slice(-2)
30404                 ].join("-");
30405               },
30406               decode: function (val) {
30407                 if (this.is(val)) return val;
30408                 var match = this.capture.exec(val);
30409                 return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;
30410               },
30411               is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); },
30412               equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); },
30413               pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,
30414               capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
30415             },
30416             "json": {
30417               encode: angular.toJson,
30418               decode: angular.fromJson,
30419               is: angular.isObject,
30420               equals: angular.equals,
30421               pattern: /[^/]*/
30422             },
30423             "any": { // does not encode/decode
30424               encode: angular.identity,
30425               decode: angular.identity,
30426               equals: angular.equals,
30427               pattern: /.*/
30428             }
30429           };
30430
30431           function getDefaultConfig() {
30432             return {
30433               strict: isStrictMode,
30434               caseInsensitive: isCaseInsensitive
30435             };
30436           }
30437
30438           function isInjectable(value) {
30439             return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));
30440           }
30441
30442           /**
30443            * [Internal] Get the default value of a parameter, which may be an injectable function.
30444            */
30445           $UrlMatcherFactory.$$getDefaultValue = function(config) {
30446             if (!isInjectable(config.value)) return config.value;
30447             if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
30448             return injector.invoke(config.value);
30449           };
30450
30451           /**
30452            * @ngdoc function
30453            * @name ui.router.util.$urlMatcherFactory#caseInsensitive
30454            * @methodOf ui.router.util.$urlMatcherFactory
30455            *
30456            * @description
30457            * Defines whether URL matching should be case sensitive (the default behavior), or not.
30458            *
30459            * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`;
30460            * @returns {boolean} the current value of caseInsensitive
30461            */
30462           this.caseInsensitive = function(value) {
30463             if (isDefined(value))
30464               isCaseInsensitive = value;
30465             return isCaseInsensitive;
30466           };
30467
30468           /**
30469            * @ngdoc function
30470            * @name ui.router.util.$urlMatcherFactory#strictMode
30471            * @methodOf ui.router.util.$urlMatcherFactory
30472            *
30473            * @description
30474            * Defines whether URLs should match trailing slashes, or not (the default behavior).
30475            *
30476            * @param {boolean=} value `false` to match trailing slashes in URLs, otherwise `true`.
30477            * @returns {boolean} the current value of strictMode
30478            */
30479           this.strictMode = function(value) {
30480             if (isDefined(value))
30481               isStrictMode = value;
30482             return isStrictMode;
30483           };
30484
30485           /**
30486            * @ngdoc function
30487            * @name ui.router.util.$urlMatcherFactory#defaultSquashPolicy
30488            * @methodOf ui.router.util.$urlMatcherFactory
30489            *
30490            * @description
30491            * Sets the default behavior when generating or matching URLs with default parameter values.
30492            *
30493            * @param {string} value A string that defines the default parameter URL squashing behavior.
30494            *    `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL
30495            *    `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the
30496            *             parameter is surrounded by slashes, squash (remove) one slash from the URL
30497            *    any other string, e.g. "~": When generating an href with a default parameter value, squash (remove)
30498            *             the parameter value from the URL and replace it with this string.
30499            */
30500           this.defaultSquashPolicy = function(value) {
30501             if (!isDefined(value)) return defaultSquashPolicy;
30502             if (value !== true && value !== false && !isString(value))
30503               throw new Error("Invalid squash policy: " + value + ". Valid policies: false, true, arbitrary-string");
30504             defaultSquashPolicy = value;
30505             return value;
30506           };
30507
30508           /**
30509            * @ngdoc function
30510            * @name ui.router.util.$urlMatcherFactory#compile
30511            * @methodOf ui.router.util.$urlMatcherFactory
30512            *
30513            * @description
30514            * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern.
30515            *
30516            * @param {string} pattern  The URL pattern.
30517            * @param {Object} config  The config object hash.
30518            * @returns {UrlMatcher}  The UrlMatcher.
30519            */
30520           this.compile = function (pattern, config) {
30521             return new UrlMatcher(pattern, extend(getDefaultConfig(), config));
30522           };
30523
30524           /**
30525            * @ngdoc function
30526            * @name ui.router.util.$urlMatcherFactory#isMatcher
30527            * @methodOf ui.router.util.$urlMatcherFactory
30528            *
30529            * @description
30530            * Returns true if the specified object is a `UrlMatcher`, or false otherwise.
30531            *
30532            * @param {Object} object  The object to perform the type check against.
30533            * @returns {Boolean}  Returns `true` if the object matches the `UrlMatcher` interface, by
30534            *          implementing all the same methods.
30535            */
30536           this.isMatcher = function (o) {
30537             if (!isObject(o)) return false;
30538             var result = true;
30539
30540             forEach(UrlMatcher.prototype, function(val, name) {
30541               if (isFunction(val)) {
30542                 result = result && (isDefined(o[name]) && isFunction(o[name]));
30543               }
30544             });
30545             return result;
30546           };
30547
30548           /**
30549            * @ngdoc function
30550            * @name ui.router.util.$urlMatcherFactory#type
30551            * @methodOf ui.router.util.$urlMatcherFactory
30552            *
30553            * @description
30554            * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to
30555            * generate URLs with typed parameters.
30556            *
30557            * @param {string} name  The type name.
30558            * @param {Object|Function} definition   The type definition. See
30559            *        {@link ui.router.util.type:Type `Type`} for information on the values accepted.
30560            * @param {Object|Function} definitionFn (optional) A function that is injected before the app
30561            *        runtime starts.  The result of this function is merged into the existing `definition`.
30562            *        See {@link ui.router.util.type:Type `Type`} for information on the values accepted.
30563            *
30564            * @returns {Object}  Returns `$urlMatcherFactoryProvider`.
30565            *
30566            * @example
30567            * This is a simple example of a custom type that encodes and decodes items from an
30568            * array, using the array index as the URL-encoded value:
30569            *
30570            * <pre>
30571            * var list = ['John', 'Paul', 'George', 'Ringo'];
30572            *
30573            * $urlMatcherFactoryProvider.type('listItem', {
30574            *   encode: function(item) {
30575            *     // Represent the list item in the URL using its corresponding index
30576            *     return list.indexOf(item);
30577            *   },
30578            *   decode: function(item) {
30579            *     // Look up the list item by index
30580            *     return list[parseInt(item, 10)];
30581            *   },
30582            *   is: function(item) {
30583            *     // Ensure the item is valid by checking to see that it appears
30584            *     // in the list
30585            *     return list.indexOf(item) > -1;
30586            *   }
30587            * });
30588            *
30589            * $stateProvider.state('list', {
30590            *   url: "/list/{item:listItem}",
30591            *   controller: function($scope, $stateParams) {
30592            *     console.log($stateParams.item);
30593            *   }
30594            * });
30595            *
30596            * // ...
30597            *
30598            * // Changes URL to '/list/3', logs "Ringo" to the console
30599            * $state.go('list', { item: "Ringo" });
30600            * </pre>
30601            *
30602            * This is a more complex example of a type that relies on dependency injection to
30603            * interact with services, and uses the parameter name from the URL to infer how to
30604            * handle encoding and decoding parameter values:
30605            *
30606            * <pre>
30607            * // Defines a custom type that gets a value from a service,
30608            * // where each service gets different types of values from
30609            * // a backend API:
30610            * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) {
30611            *
30612            *   // Matches up services to URL parameter names
30613            *   var services = {
30614            *     user: Users,
30615            *     post: Posts
30616            *   };
30617            *
30618            *   return {
30619            *     encode: function(object) {
30620            *       // Represent the object in the URL using its unique ID
30621            *       return object.id;
30622            *     },
30623            *     decode: function(value, key) {
30624            *       // Look up the object by ID, using the parameter
30625            *       // name (key) to call the correct service
30626            *       return services[key].findById(value);
30627            *     },
30628            *     is: function(object, key) {
30629            *       // Check that object is a valid dbObject
30630            *       return angular.isObject(object) && object.id && services[key];
30631            *     }
30632            *     equals: function(a, b) {
30633            *       // Check the equality of decoded objects by comparing
30634            *       // their unique IDs
30635            *       return a.id === b.id;
30636            *     }
30637            *   };
30638            * });
30639            *
30640            * // In a config() block, you can then attach URLs with
30641            * // type-annotated parameters:
30642            * $stateProvider.state('users', {
30643            *   url: "/users",
30644            *   // ...
30645            * }).state('users.item', {
30646            *   url: "/{user:dbObject}",
30647            *   controller: function($scope, $stateParams) {
30648            *     // $stateParams.user will now be an object returned from
30649            *     // the Users service
30650            *   },
30651            *   // ...
30652            * });
30653            * </pre>
30654            */
30655           this.type = function (name, definition, definitionFn) {
30656             if (!isDefined(definition)) return $types[name];
30657             if ($types.hasOwnProperty(name)) throw new Error("A type named '" + name + "' has already been defined.");
30658
30659             $types[name] = new Type(extend({ name: name }, definition));
30660             if (definitionFn) {
30661               typeQueue.push({ name: name, def: definitionFn });
30662               if (!enqueue) flushTypeQueue();
30663             }
30664             return this;
30665           };
30666
30667           // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s
30668           function flushTypeQueue() {
30669             while(typeQueue.length) {
30670               var type = typeQueue.shift();
30671               if (type.pattern) throw new Error("You cannot override a type's .pattern at runtime.");
30672               angular.extend($types[type.name], injector.invoke(type.def));
30673             }
30674           }
30675
30676           // Register default types. Store them in the prototype of $types.
30677           forEach(defaultTypes, function(type, name) { $types[name] = new Type(extend({name: name}, type)); });
30678           $types = inherit($types, {});
30679
30680           /* No need to document $get, since it returns this */
30681           this.$get = ['$injector', function ($injector) {
30682             injector = $injector;
30683             enqueue = false;
30684             flushTypeQueue();
30685
30686             forEach(defaultTypes, function(type, name) {
30687               if (!$types[name]) $types[name] = new Type(type);
30688             });
30689             return this;
30690           }];
30691
30692           this.Param = function Param(id, type, config, location) {
30693             var self = this;
30694             config = unwrapShorthand(config);
30695             type = getType(config, type, location);
30696             var arrayMode = getArrayMode();
30697             type = arrayMode ? type.$asArray(arrayMode, location === "search") : type;
30698             if (type.name === "string" && !arrayMode && location === "path" && config.value === undefined)
30699               config.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to ""
30700             var isOptional = config.value !== undefined;
30701             var squash = getSquashPolicy(config, isOptional);
30702             var replace = getReplace(config, arrayMode, isOptional, squash);
30703
30704             function unwrapShorthand(config) {
30705               var keys = isObject(config) ? objectKeys(config) : [];
30706               var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 &&
30707                                 indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1;
30708               if (isShorthand) config = { value: config };
30709               config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; };
30710               return config;
30711             }
30712
30713             function getType(config, urlType, location) {
30714               if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations.");
30715               if (urlType) return urlType;
30716               if (!config.type) return (location === "config" ? $types.any : $types.string);
30717
30718               if (angular.isString(config.type))
30719                 return $types[config.type];
30720               if (config.type instanceof Type)
30721                 return config.type;
30722               return new Type(config.type);
30723             }
30724
30725             // array config: param name (param[]) overrides default settings.  explicit config overrides param name.
30726             function getArrayMode() {
30727               var arrayDefaults = { array: (location === "search" ? "auto" : false) };
30728               var arrayParamNomenclature = id.match(/\[\]$/) ? { array: true } : {};
30729               return extend(arrayDefaults, arrayParamNomenclature, config).array;
30730             }
30731
30732             /**
30733              * returns false, true, or the squash value to indicate the "default parameter url squash policy".
30734              */
30735             function getSquashPolicy(config, isOptional) {
30736               var squash = config.squash;
30737               if (!isOptional || squash === false) return false;
30738               if (!isDefined(squash) || squash == null) return defaultSquashPolicy;
30739               if (squash === true || isString(squash)) return squash;
30740               throw new Error("Invalid squash policy: '" + squash + "'. Valid policies: false, true, or arbitrary string");
30741             }
30742
30743             function getReplace(config, arrayMode, isOptional, squash) {
30744               var replace, configuredKeys, defaultPolicy = [
30745                 { from: "",   to: (isOptional || arrayMode ? undefined : "") },
30746                 { from: null, to: (isOptional || arrayMode ? undefined : "") }
30747               ];
30748               replace = isArray(config.replace) ? config.replace : [];
30749               if (isString(squash))
30750                 replace.push({ from: squash, to: undefined });
30751               configuredKeys = map(replace, function(item) { return item.from; } );
30752               return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace);
30753             }
30754
30755             /**
30756              * [Internal] Get the default value of a parameter, which may be an injectable function.
30757              */
30758             function $$getDefaultValue() {
30759               if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
30760               var defaultValue = injector.invoke(config.$$fn);
30761               if (defaultValue !== null && defaultValue !== undefined && !self.type.is(defaultValue))
30762                 throw new Error("Default value (" + defaultValue + ") for parameter '" + self.id + "' is not an instance of Type (" + self.type.name + ")");
30763               return defaultValue;
30764             }
30765
30766             /**
30767              * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the
30768              * default value, which may be the result of an injectable function.
30769              */
30770             function $value(value) {
30771               function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; }
30772               function $replace(value) {
30773                 var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; });
30774                 return replacement.length ? replacement[0] : value;
30775               }
30776               value = $replace(value);
30777               return !isDefined(value) ? $$getDefaultValue() : self.type.$normalize(value);
30778             }
30779
30780             function toString() { return "{Param:" + id + " " + type + " squash: '" + squash + "' optional: " + isOptional + "}"; }
30781
30782             extend(this, {
30783               id: id,
30784               type: type,
30785               location: location,
30786               array: arrayMode,
30787               squash: squash,
30788               replace: replace,
30789               isOptional: isOptional,
30790               value: $value,
30791               dynamic: undefined,
30792               config: config,
30793               toString: toString
30794             });
30795           };
30796
30797           function ParamSet(params) {
30798             extend(this, params || {});
30799           }
30800
30801           ParamSet.prototype = {
30802             $$new: function() {
30803               return inherit(this, extend(new ParamSet(), { $$parent: this}));
30804             },
30805             $$keys: function () {
30806               var keys = [], chain = [], parent = this,
30807                 ignore = objectKeys(ParamSet.prototype);
30808               while (parent) { chain.push(parent); parent = parent.$$parent; }
30809               chain.reverse();
30810               forEach(chain, function(paramset) {
30811                 forEach(objectKeys(paramset), function(key) {
30812                     if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key);
30813                 });
30814               });
30815               return keys;
30816             },
30817             $$values: function(paramValues) {
30818               var values = {}, self = this;
30819               forEach(self.$$keys(), function(key) {
30820                 values[key] = self[key].value(paramValues && paramValues[key]);
30821               });
30822               return values;
30823             },
30824             $$equals: function(paramValues1, paramValues2) {
30825               var equal = true, self = this;
30826               forEach(self.$$keys(), function(key) {
30827                 var left = paramValues1 && paramValues1[key], right = paramValues2 && paramValues2[key];
30828                 if (!self[key].type.equals(left, right)) equal = false;
30829               });
30830               return equal;
30831             },
30832             $$validates: function $$validate(paramValues) {
30833               var keys = this.$$keys(), i, param, rawVal, normalized, encoded;
30834               for (i = 0; i < keys.length; i++) {
30835                 param = this[keys[i]];
30836                 rawVal = paramValues[keys[i]];
30837                 if ((rawVal === undefined || rawVal === null) && param.isOptional)
30838                   break; // There was no parameter value, but the param is optional
30839                 normalized = param.type.$normalize(rawVal);
30840                 if (!param.type.is(normalized))
30841                   return false; // The value was not of the correct Type, and could not be decoded to the correct Type
30842                 encoded = param.type.encode(normalized);
30843                 if (angular.isString(encoded) && !param.type.pattern.exec(encoded))
30844                   return false; // The value was of the correct type, but when encoded, did not match the Type's regexp
30845               }
30846               return true;
30847             },
30848             $$parent: undefined
30849           };
30850
30851           this.ParamSet = ParamSet;
30852         }
30853
30854         // Register as a provider so it's available to other providers
30855         angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
30856         angular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]);
30857
30858         /**
30859          * @ngdoc object
30860          * @name ui.router.router.$urlRouterProvider
30861          *
30862          * @requires ui.router.util.$urlMatcherFactoryProvider
30863          * @requires $locationProvider
30864          *
30865          * @description
30866          * `$urlRouterProvider` has the responsibility of watching `$location`. 
30867          * When `$location` changes it runs through a list of rules one by one until a 
30868          * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify 
30869          * a url in a state configuration. All urls are compiled into a UrlMatcher object.
30870          *
30871          * There are several methods on `$urlRouterProvider` that make it useful to use directly
30872          * in your module config.
30873          */
30874         $UrlRouterProvider.$inject = ['$locationProvider', '$urlMatcherFactoryProvider'];
30875         function $UrlRouterProvider(   $locationProvider,   $urlMatcherFactory) {
30876           var rules = [], otherwise = null, interceptDeferred = false, listener;
30877
30878           // Returns a string that is a prefix of all strings matching the RegExp
30879           function regExpPrefix(re) {
30880             var prefix = /^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(re.source);
30881             return (prefix != null) ? prefix[1].replace(/\\(.)/g, "$1") : '';
30882           }
30883
30884           // Interpolates matched values into a String.replace()-style pattern
30885           function interpolate(pattern, match) {
30886             return pattern.replace(/\$(\$|\d{1,2})/, function (m, what) {
30887               return match[what === '$' ? 0 : Number(what)];
30888             });
30889           }
30890
30891           /**
30892            * @ngdoc function
30893            * @name ui.router.router.$urlRouterProvider#rule
30894            * @methodOf ui.router.router.$urlRouterProvider
30895            *
30896            * @description
30897            * Defines rules that are used by `$urlRouterProvider` to find matches for
30898            * specific URLs.
30899            *
30900            * @example
30901            * <pre>
30902            * var app = angular.module('app', ['ui.router.router']);
30903            *
30904            * app.config(function ($urlRouterProvider) {
30905            *   // Here's an example of how you might allow case insensitive urls
30906            *   $urlRouterProvider.rule(function ($injector, $location) {
30907            *     var path = $location.path(),
30908            *         normalized = path.toLowerCase();
30909            *
30910            *     if (path !== normalized) {
30911            *       return normalized;
30912            *     }
30913            *   });
30914            * });
30915            * </pre>
30916            *
30917            * @param {function} rule Handler function that takes `$injector` and `$location`
30918            * services as arguments. You can use them to return a valid path as a string.
30919            *
30920            * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
30921            */
30922           this.rule = function (rule) {
30923             if (!isFunction(rule)) throw new Error("'rule' must be a function");
30924             rules.push(rule);
30925             return this;
30926           };
30927
30928           /**
30929            * @ngdoc object
30930            * @name ui.router.router.$urlRouterProvider#otherwise
30931            * @methodOf ui.router.router.$urlRouterProvider
30932            *
30933            * @description
30934            * Defines a path that is used when an invalid route is requested.
30935            *
30936            * @example
30937            * <pre>
30938            * var app = angular.module('app', ['ui.router.router']);
30939            *
30940            * app.config(function ($urlRouterProvider) {
30941            *   // if the path doesn't match any of the urls you configured
30942            *   // otherwise will take care of routing the user to the
30943            *   // specified url
30944            *   $urlRouterProvider.otherwise('/index');
30945            *
30946            *   // Example of using function rule as param
30947            *   $urlRouterProvider.otherwise(function ($injector, $location) {
30948            *     return '/a/valid/url';
30949            *   });
30950            * });
30951            * </pre>
30952            *
30953            * @param {string|function} rule The url path you want to redirect to or a function 
30954            * rule that returns the url path. The function version is passed two params: 
30955            * `$injector` and `$location` services, and must return a url string.
30956            *
30957            * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
30958            */
30959           this.otherwise = function (rule) {
30960             if (isString(rule)) {
30961               var redirect = rule;
30962               rule = function () { return redirect; };
30963             }
30964             else if (!isFunction(rule)) throw new Error("'rule' must be a function");
30965             otherwise = rule;
30966             return this;
30967           };
30968
30969
30970           function handleIfMatch($injector, handler, match) {
30971             if (!match) return false;
30972             var result = $injector.invoke(handler, handler, { $match: match });
30973             return isDefined(result) ? result : true;
30974           }
30975
30976           /**
30977            * @ngdoc function
30978            * @name ui.router.router.$urlRouterProvider#when
30979            * @methodOf ui.router.router.$urlRouterProvider
30980            *
30981            * @description
30982            * Registers a handler for a given url matching. 
30983            * 
30984            * If the handler is a string, it is
30985            * treated as a redirect, and is interpolated according to the syntax of match
30986            * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise).
30987            *
30988            * If the handler is a function, it is injectable. It gets invoked if `$location`
30989            * matches. You have the option of inject the match object as `$match`.
30990            *
30991            * The handler can return
30992            *
30993            * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter`
30994            *   will continue trying to find another one that matches.
30995            * - **string** which is treated as a redirect and passed to `$location.url()`
30996            * - **void** or any **truthy** value tells `$urlRouter` that the url was handled.
30997            *
30998            * @example
30999            * <pre>
31000            * var app = angular.module('app', ['ui.router.router']);
31001            *
31002            * app.config(function ($urlRouterProvider) {
31003            *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
31004            *     if ($state.$current.navigable !== state ||
31005            *         !equalForKeys($match, $stateParams) {
31006            *      $state.transitionTo(state, $match, false);
31007            *     }
31008            *   });
31009            * });
31010            * </pre>
31011            *
31012            * @param {string|object} what The incoming path that you want to redirect.
31013            * @param {string|function} handler The path you want to redirect your user to.
31014            */
31015           this.when = function (what, handler) {
31016             var redirect, handlerIsString = isString(handler);
31017             if (isString(what)) what = $urlMatcherFactory.compile(what);
31018
31019             if (!handlerIsString && !isFunction(handler) && !isArray(handler))
31020               throw new Error("invalid 'handler' in when()");
31021
31022             var strategies = {
31023               matcher: function (what, handler) {
31024                 if (handlerIsString) {
31025                   redirect = $urlMatcherFactory.compile(handler);
31026                   handler = ['$match', function ($match) { return redirect.format($match); }];
31027                 }
31028                 return extend(function ($injector, $location) {
31029                   return handleIfMatch($injector, handler, what.exec($location.path(), $location.search()));
31030                 }, {
31031                   prefix: isString(what.prefix) ? what.prefix : ''
31032                 });
31033               },
31034               regex: function (what, handler) {
31035                 if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky");
31036
31037                 if (handlerIsString) {
31038                   redirect = handler;
31039                   handler = ['$match', function ($match) { return interpolate(redirect, $match); }];
31040                 }
31041                 return extend(function ($injector, $location) {
31042                   return handleIfMatch($injector, handler, what.exec($location.path()));
31043                 }, {
31044                   prefix: regExpPrefix(what)
31045                 });
31046               }
31047             };
31048
31049             var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp };
31050
31051             for (var n in check) {
31052               if (check[n]) return this.rule(strategies[n](what, handler));
31053             }
31054
31055             throw new Error("invalid 'what' in when()");
31056           };
31057
31058           /**
31059            * @ngdoc function
31060            * @name ui.router.router.$urlRouterProvider#deferIntercept
31061            * @methodOf ui.router.router.$urlRouterProvider
31062            *
31063            * @description
31064            * Disables (or enables) deferring location change interception.
31065            *
31066            * If you wish to customize the behavior of syncing the URL (for example, if you wish to
31067            * defer a transition but maintain the current URL), call this method at configuration time.
31068            * Then, at run time, call `$urlRouter.listen()` after you have configured your own
31069            * `$locationChangeSuccess` event handler.
31070            *
31071            * @example
31072            * <pre>
31073            * var app = angular.module('app', ['ui.router.router']);
31074            *
31075            * app.config(function ($urlRouterProvider) {
31076            *
31077            *   // Prevent $urlRouter from automatically intercepting URL changes;
31078            *   // this allows you to configure custom behavior in between
31079            *   // location changes and route synchronization:
31080            *   $urlRouterProvider.deferIntercept();
31081            *
31082            * }).run(function ($rootScope, $urlRouter, UserService) {
31083            *
31084            *   $rootScope.$on('$locationChangeSuccess', function(e) {
31085            *     // UserService is an example service for managing user state
31086            *     if (UserService.isLoggedIn()) return;
31087            *
31088            *     // Prevent $urlRouter's default handler from firing
31089            *     e.preventDefault();
31090            *
31091            *     UserService.handleLogin().then(function() {
31092            *       // Once the user has logged in, sync the current URL
31093            *       // to the router:
31094            *       $urlRouter.sync();
31095            *     });
31096            *   });
31097            *
31098            *   // Configures $urlRouter's listener *after* your custom listener
31099            *   $urlRouter.listen();
31100            * });
31101            * </pre>
31102            *
31103            * @param {boolean} defer Indicates whether to defer location change interception. Passing
31104                     no parameter is equivalent to `true`.
31105            */
31106           this.deferIntercept = function (defer) {
31107             if (defer === undefined) defer = true;
31108             interceptDeferred = defer;
31109           };
31110
31111           /**
31112            * @ngdoc object
31113            * @name ui.router.router.$urlRouter
31114            *
31115            * @requires $location
31116            * @requires $rootScope
31117            * @requires $injector
31118            * @requires $browser
31119            *
31120            * @description
31121            *
31122            */
31123           this.$get = $get;
31124           $get.$inject = ['$location', '$rootScope', '$injector', '$browser', '$sniffer'];
31125           function $get(   $location,   $rootScope,   $injector,   $browser,   $sniffer) {
31126
31127             var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl;
31128
31129             function appendBasePath(url, isHtml5, absolute) {
31130               if (baseHref === '/') return url;
31131               if (isHtml5) return baseHref.slice(0, -1) + url;
31132               if (absolute) return baseHref.slice(1) + url;
31133               return url;
31134             }
31135
31136             // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree
31137             function update(evt) {
31138               if (evt && evt.defaultPrevented) return;
31139               var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl;
31140               lastPushedUrl = undefined;
31141               // TODO: Re-implement this in 1.0 for https://github.com/angular-ui/ui-router/issues/1573
31142               //if (ignoreUpdate) return true;
31143
31144               function check(rule) {
31145                 var handled = rule($injector, $location);
31146
31147                 if (!handled) return false;
31148                 if (isString(handled)) $location.replace().url(handled);
31149                 return true;
31150               }
31151               var n = rules.length, i;
31152
31153               for (i = 0; i < n; i++) {
31154                 if (check(rules[i])) return;
31155               }
31156               // always check otherwise last to allow dynamic updates to the set of rules
31157               if (otherwise) check(otherwise);
31158             }
31159
31160             function listen() {
31161               listener = listener || $rootScope.$on('$locationChangeSuccess', update);
31162               return listener;
31163             }
31164
31165             if (!interceptDeferred) listen();
31166
31167             return {
31168               /**
31169                * @ngdoc function
31170                * @name ui.router.router.$urlRouter#sync
31171                * @methodOf ui.router.router.$urlRouter
31172                *
31173                * @description
31174                * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`.
31175                * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event,
31176                * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed
31177                * with the transition by calling `$urlRouter.sync()`.
31178                *
31179                * @example
31180                * <pre>
31181                * angular.module('app', ['ui.router'])
31182                *   .run(function($rootScope, $urlRouter) {
31183                *     $rootScope.$on('$locationChangeSuccess', function(evt) {
31184                *       // Halt state change from even starting
31185                *       evt.preventDefault();
31186                *       // Perform custom logic
31187                *       var meetsRequirement = ...
31188                *       // Continue with the update and state transition if logic allows
31189                *       if (meetsRequirement) $urlRouter.sync();
31190                *     });
31191                * });
31192                * </pre>
31193                */
31194               sync: function() {
31195                 update();
31196               },
31197
31198               listen: function() {
31199                 return listen();
31200               },
31201
31202               update: function(read) {
31203                 if (read) {
31204                   location = $location.url();
31205                   return;
31206                 }
31207                 if ($location.url() === location) return;
31208
31209                 $location.url(location);
31210                 $location.replace();
31211               },
31212
31213               push: function(urlMatcher, params, options) {
31214                  var url = urlMatcher.format(params || {});
31215
31216                 // Handle the special hash param, if needed
31217                 if (url !== null && params && params['#']) {
31218                     url += '#' + params['#'];
31219                 }
31220
31221                 $location.url(url);
31222                 lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined;
31223                 if (options && options.replace) $location.replace();
31224               },
31225
31226               /**
31227                * @ngdoc function
31228                * @name ui.router.router.$urlRouter#href
31229                * @methodOf ui.router.router.$urlRouter
31230                *
31231                * @description
31232                * A URL generation method that returns the compiled URL for a given
31233                * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters.
31234                *
31235                * @example
31236                * <pre>
31237                * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), {
31238                *   person: "bob"
31239                * });
31240                * // $bob == "/about/bob";
31241                * </pre>
31242                *
31243                * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate.
31244                * @param {object=} params An object of parameter values to fill the matcher's required parameters.
31245                * @param {object=} options Options object. The options are:
31246                *
31247                * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
31248                *
31249                * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher`
31250                */
31251               href: function(urlMatcher, params, options) {
31252                 if (!urlMatcher.validates(params)) return null;
31253
31254                 var isHtml5 = $locationProvider.html5Mode();
31255                 if (angular.isObject(isHtml5)) {
31256                   isHtml5 = isHtml5.enabled;
31257                 }
31258
31259                 isHtml5 = isHtml5 && $sniffer.history;
31260                 
31261                 var url = urlMatcher.format(params);
31262                 options = options || {};
31263
31264                 if (!isHtml5 && url !== null) {
31265                   url = "#" + $locationProvider.hashPrefix() + url;
31266                 }
31267
31268                 // Handle special hash param, if needed
31269                 if (url !== null && params && params['#']) {
31270                   url += '#' + params['#'];
31271                 }
31272
31273                 url = appendBasePath(url, isHtml5, options.absolute);
31274
31275                 if (!options.absolute || !url) {
31276                   return url;
31277                 }
31278
31279                 var slash = (!isHtml5 && url ? '/' : ''), port = $location.port();
31280                 port = (port === 80 || port === 443 ? '' : ':' + port);
31281
31282                 return [$location.protocol(), '://', $location.host(), port, slash, url].join('');
31283               }
31284             };
31285           }
31286         }
31287
31288         angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);
31289
31290         /**
31291          * @ngdoc object
31292          * @name ui.router.state.$stateProvider
31293          *
31294          * @requires ui.router.router.$urlRouterProvider
31295          * @requires ui.router.util.$urlMatcherFactoryProvider
31296          *
31297          * @description
31298          * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely
31299          * on state.
31300          *
31301          * A state corresponds to a "place" in the application in terms of the overall UI and
31302          * navigation. A state describes (via the controller / template / view properties) what
31303          * the UI looks like and does at that place.
31304          *
31305          * States often have things in common, and the primary way of factoring out these
31306          * commonalities in this model is via the state hierarchy, i.e. parent/child states aka
31307          * nested states.
31308          *
31309          * The `$stateProvider` provides interfaces to declare these states for your app.
31310          */
31311         $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
31312         function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory) {
31313
31314           var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
31315
31316           // Builds state properties from definition passed to registerState()
31317           var stateBuilder = {
31318
31319             // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
31320             // state.children = [];
31321             // if (parent) parent.children.push(state);
31322             parent: function(state) {
31323               if (isDefined(state.parent) && state.parent) return findState(state.parent);
31324               // regex matches any valid composite state name
31325               // would match "contact.list" but not "contacts"
31326               var compositeName = /^(.+)\.[^.]+$/.exec(state.name);
31327               return compositeName ? findState(compositeName[1]) : root;
31328             },
31329
31330             // inherit 'data' from parent and override by own values (if any)
31331             data: function(state) {
31332               if (state.parent && state.parent.data) {
31333                 state.data = state.self.data = inherit(state.parent.data, state.data);
31334               }
31335               return state.data;
31336             },
31337
31338             // Build a URLMatcher if necessary, either via a relative or absolute URL
31339             url: function(state) {
31340               var url = state.url, config = { params: state.params || {} };
31341
31342               if (isString(url)) {
31343                 if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);
31344                 return (state.parent.navigable || root).url.concat(url, config);
31345               }
31346
31347               if (!url || $urlMatcherFactory.isMatcher(url)) return url;
31348               throw new Error("Invalid url '" + url + "' in state '" + state + "'");
31349             },
31350
31351             // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
31352             navigable: function(state) {
31353               return state.url ? state : (state.parent ? state.parent.navigable : null);
31354             },
31355
31356             // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params
31357             ownParams: function(state) {
31358               var params = state.url && state.url.params || new $$UMFP.ParamSet();
31359               forEach(state.params || {}, function(config, id) {
31360                 if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config");
31361               });
31362               return params;
31363             },
31364
31365             // Derive parameters for this state and ensure they're a super-set of parent's parameters
31366             params: function(state) {
31367               var ownParams = pick(state.ownParams, state.ownParams.$$keys());
31368               return state.parent && state.parent.params ? extend(state.parent.params.$$new(), ownParams) : new $$UMFP.ParamSet();
31369             },
31370
31371             // If there is no explicit multi-view configuration, make one up so we don't have
31372             // to handle both cases in the view directive later. Note that having an explicit
31373             // 'views' property will mean the default unnamed view properties are ignored. This
31374             // is also a good time to resolve view names to absolute names, so everything is a
31375             // straight lookup at link time.
31376             views: function(state) {
31377               var views = {};
31378
31379               forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {
31380                 if (name.indexOf('@') < 0) name += '@' + state.parent.name;
31381                 views[name] = view;
31382               });
31383               return views;
31384             },
31385
31386             // Keep a full path from the root down to this state as this is needed for state activation.
31387             path: function(state) {
31388               return state.parent ? state.parent.path.concat(state) : []; // exclude root from path
31389             },
31390
31391             // Speed up $state.contains() as it's used a lot
31392             includes: function(state) {
31393               var includes = state.parent ? extend({}, state.parent.includes) : {};
31394               includes[state.name] = true;
31395               return includes;
31396             },
31397
31398             $delegates: {}
31399           };
31400
31401           function isRelative(stateName) {
31402             return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
31403           }
31404
31405           function findState(stateOrName, base) {
31406             if (!stateOrName) return undefined;
31407
31408             var isStr = isString(stateOrName),
31409                 name  = isStr ? stateOrName : stateOrName.name,
31410                 path  = isRelative(name);
31411
31412             if (path) {
31413               if (!base) throw new Error("No reference point given for path '"  + name + "'");
31414               base = findState(base);
31415               
31416               var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
31417
31418               for (; i < pathLength; i++) {
31419                 if (rel[i] === "" && i === 0) {
31420                   current = base;
31421                   continue;
31422                 }
31423                 if (rel[i] === "^") {
31424                   if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
31425                   current = current.parent;
31426                   continue;
31427                 }
31428                 break;
31429               }
31430               rel = rel.slice(i).join(".");
31431               name = current.name + (current.name && rel ? "." : "") + rel;
31432             }
31433             var state = states[name];
31434
31435             if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {
31436               return state;
31437             }
31438             return undefined;
31439           }
31440
31441           function queueState(parentName, state) {
31442             if (!queue[parentName]) {
31443               queue[parentName] = [];
31444             }
31445             queue[parentName].push(state);
31446           }
31447
31448           function flushQueuedChildren(parentName) {
31449             var queued = queue[parentName] || [];
31450             while(queued.length) {
31451               registerState(queued.shift());
31452             }
31453           }
31454
31455           function registerState(state) {
31456             // Wrap a new object around the state so we can store our private details easily.
31457             state = inherit(state, {
31458               self: state,
31459               resolve: state.resolve || {},
31460               toString: function() { return this.name; }
31461             });
31462
31463             var name = state.name;
31464             if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name");
31465             if (states.hasOwnProperty(name)) throw new Error("State '" + name + "' is already defined");
31466
31467             // Get parent name
31468             var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))
31469                 : (isString(state.parent)) ? state.parent
31470                 : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name
31471                 : '';
31472
31473             // If parent is not registered yet, add state to queue and register later
31474             if (parentName && !states[parentName]) {
31475               return queueState(parentName, state.self);
31476             }
31477
31478             for (var key in stateBuilder) {
31479               if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);
31480             }
31481             states[name] = state;
31482
31483             // Register the state in the global state list and with $urlRouter if necessary.
31484             if (!state[abstractKey] && state.url) {
31485               $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
31486                 if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
31487                   $state.transitionTo(state, $match, { inherit: true, location: false });
31488                 }
31489               }]);
31490             }
31491
31492             // Register any queued children
31493             flushQueuedChildren(name);
31494
31495             return state;
31496           }
31497
31498           // Checks text to see if it looks like a glob.
31499           function isGlob (text) {
31500             return text.indexOf('*') > -1;
31501           }
31502
31503           // Returns true if glob matches current $state name.
31504           function doesStateMatchGlob (glob) {
31505             var globSegments = glob.split('.'),
31506                 segments = $state.$current.name.split('.');
31507
31508             //match single stars
31509             for (var i = 0, l = globSegments.length; i < l; i++) {
31510               if (globSegments[i] === '*') {
31511                 segments[i] = '*';
31512               }
31513             }
31514
31515             //match greedy starts
31516             if (globSegments[0] === '**') {
31517                segments = segments.slice(indexOf(segments, globSegments[1]));
31518                segments.unshift('**');
31519             }
31520             //match greedy ends
31521             if (globSegments[globSegments.length - 1] === '**') {
31522                segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
31523                segments.push('**');
31524             }
31525
31526             if (globSegments.length != segments.length) {
31527               return false;
31528             }
31529
31530             return segments.join('') === globSegments.join('');
31531           }
31532
31533
31534           // Implicit root state that is always active
31535           root = registerState({
31536             name: '',
31537             url: '^',
31538             views: null,
31539             'abstract': true
31540           });
31541           root.navigable = null;
31542
31543
31544           /**
31545            * @ngdoc function
31546            * @name ui.router.state.$stateProvider#decorator
31547            * @methodOf ui.router.state.$stateProvider
31548            *
31549            * @description
31550            * Allows you to extend (carefully) or override (at your own peril) the 
31551            * `stateBuilder` object used internally by `$stateProvider`. This can be used 
31552            * to add custom functionality to ui-router, for example inferring templateUrl 
31553            * based on the state name.
31554            *
31555            * When passing only a name, it returns the current (original or decorated) builder
31556            * function that matches `name`.
31557            *
31558            * The builder functions that can be decorated are listed below. Though not all
31559            * necessarily have a good use case for decoration, that is up to you to decide.
31560            *
31561            * In addition, users can attach custom decorators, which will generate new 
31562            * properties within the state's internal definition. There is currently no clear 
31563            * use-case for this beyond accessing internal states (i.e. $state.$current), 
31564            * however, expect this to become increasingly relevant as we introduce additional 
31565            * meta-programming features.
31566            *
31567            * **Warning**: Decorators should not be interdependent because the order of 
31568            * execution of the builder functions in non-deterministic. Builder functions 
31569            * should only be dependent on the state definition object and super function.
31570            *
31571            *
31572            * Existing builder functions and current return values:
31573            *
31574            * - **parent** `{object}` - returns the parent state object.
31575            * - **data** `{object}` - returns state data, including any inherited data that is not
31576            *   overridden by own values (if any).
31577            * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}
31578            *   or `null`.
31579            * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is 
31580            *   navigable).
31581            * - **params** `{object}` - returns an array of state params that are ensured to 
31582            *   be a super-set of parent's params.
31583            * - **views** `{object}` - returns a views object where each key is an absolute view 
31584            *   name (i.e. "viewName@stateName") and each value is the config object 
31585            *   (template, controller) for the view. Even when you don't use the views object 
31586            *   explicitly on a state config, one is still created for you internally.
31587            *   So by decorating this builder function you have access to decorating template 
31588            *   and controller properties.
31589            * - **ownParams** `{object}` - returns an array of params that belong to the state, 
31590            *   not including any params defined by ancestor states.
31591            * - **path** `{string}` - returns the full path from the root down to this state. 
31592            *   Needed for state activation.
31593            * - **includes** `{object}` - returns an object that includes every state that 
31594            *   would pass a `$state.includes()` test.
31595            *
31596            * @example
31597            * <pre>
31598            * // Override the internal 'views' builder with a function that takes the state
31599            * // definition, and a reference to the internal function being overridden:
31600            * $stateProvider.decorator('views', function (state, parent) {
31601            *   var result = {},
31602            *       views = parent(state);
31603            *
31604            *   angular.forEach(views, function (config, name) {
31605            *     var autoName = (state.name + '.' + name).replace('.', '/');
31606            *     config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
31607            *     result[name] = config;
31608            *   });
31609            *   return result;
31610            * });
31611            *
31612            * $stateProvider.state('home', {
31613            *   views: {
31614            *     'contact.list': { controller: 'ListController' },
31615            *     'contact.item': { controller: 'ItemController' }
31616            *   }
31617            * });
31618            *
31619            * // ...
31620            *
31621            * $state.go('home');
31622            * // Auto-populates list and item views with /partials/home/contact/list.html,
31623            * // and /partials/home/contact/item.html, respectively.
31624            * </pre>
31625            *
31626            * @param {string} name The name of the builder function to decorate. 
31627            * @param {object} func A function that is responsible for decorating the original 
31628            * builder function. The function receives two parameters:
31629            *
31630            *   - `{object}` - state - The state config object.
31631            *   - `{object}` - super - The original builder function.
31632            *
31633            * @return {object} $stateProvider - $stateProvider instance
31634            */
31635           this.decorator = decorator;
31636           function decorator(name, func) {
31637             /*jshint validthis: true */
31638             if (isString(name) && !isDefined(func)) {
31639               return stateBuilder[name];
31640             }
31641             if (!isFunction(func) || !isString(name)) {
31642               return this;
31643             }
31644             if (stateBuilder[name] && !stateBuilder.$delegates[name]) {
31645               stateBuilder.$delegates[name] = stateBuilder[name];
31646             }
31647             stateBuilder[name] = func;
31648             return this;
31649           }
31650
31651           /**
31652            * @ngdoc function
31653            * @name ui.router.state.$stateProvider#state
31654            * @methodOf ui.router.state.$stateProvider
31655            *
31656            * @description
31657            * Registers a state configuration under a given state name. The stateConfig object
31658            * has the following acceptable properties.
31659            *
31660            * @param {string} name A unique state name, e.g. "home", "about", "contacts".
31661            * To create a parent/child state use a dot, e.g. "about.sales", "home.newest".
31662            * @param {object} stateConfig State configuration object.
31663            * @param {string|function=} stateConfig.template
31664            * <a id='template'></a>
31665            *   html template as a string or a function that returns
31666            *   an html template as a string which should be used by the uiView directives. This property 
31667            *   takes precedence over templateUrl.
31668            *   
31669            *   If `template` is a function, it will be called with the following parameters:
31670            *
31671            *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
31672            *     applying the current state
31673            *
31674            * <pre>template:
31675            *   "<h1>inline template definition</h1>" +
31676            *   "<div ui-view></div>"</pre>
31677            * <pre>template: function(params) {
31678            *       return "<h1>generated template</h1>"; }</pre>
31679            * </div>
31680            *
31681            * @param {string|function=} stateConfig.templateUrl
31682            * <a id='templateUrl'></a>
31683            *
31684            *   path or function that returns a path to an html
31685            *   template that should be used by uiView.
31686            *   
31687            *   If `templateUrl` is a function, it will be called with the following parameters:
31688            *
31689            *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by 
31690            *     applying the current state
31691            *
31692            * <pre>templateUrl: "home.html"</pre>
31693            * <pre>templateUrl: function(params) {
31694            *     return myTemplates[params.pageId]; }</pre>
31695            *
31696            * @param {function=} stateConfig.templateProvider
31697            * <a id='templateProvider'></a>
31698            *    Provider function that returns HTML content string.
31699            * <pre> templateProvider:
31700            *       function(MyTemplateService, params) {
31701            *         return MyTemplateService.getTemplate(params.pageId);
31702            *       }</pre>
31703            *
31704            * @param {string|function=} stateConfig.controller
31705            * <a id='controller'></a>
31706            *
31707            *  Controller fn that should be associated with newly
31708            *   related scope or the name of a registered controller if passed as a string.
31709            *   Optionally, the ControllerAs may be declared here.
31710            * <pre>controller: "MyRegisteredController"</pre>
31711            * <pre>controller:
31712            *     "MyRegisteredController as fooCtrl"}</pre>
31713            * <pre>controller: function($scope, MyService) {
31714            *     $scope.data = MyService.getData(); }</pre>
31715            *
31716            * @param {function=} stateConfig.controllerProvider
31717            * <a id='controllerProvider'></a>
31718            *
31719            * Injectable provider function that returns the actual controller or string.
31720            * <pre>controllerProvider:
31721            *   function(MyResolveData) {
31722            *     if (MyResolveData.foo)
31723            *       return "FooCtrl"
31724            *     else if (MyResolveData.bar)
31725            *       return "BarCtrl";
31726            *     else return function($scope) {
31727            *       $scope.baz = "Qux";
31728            *     }
31729            *   }</pre>
31730            *
31731            * @param {string=} stateConfig.controllerAs
31732            * <a id='controllerAs'></a>
31733            * 
31734            * A controller alias name. If present the controller will be
31735            *   published to scope under the controllerAs name.
31736            * <pre>controllerAs: "myCtrl"</pre>
31737            *
31738            * @param {string|object=} stateConfig.parent
31739            * <a id='parent'></a>
31740            * Optionally specifies the parent state of this state.
31741            *
31742            * <pre>parent: 'parentState'</pre>
31743            * <pre>parent: parentState // JS variable</pre>
31744            *
31745            * @param {object=} stateConfig.resolve
31746            * <a id='resolve'></a>
31747            *
31748            * An optional map&lt;string, function&gt; of dependencies which
31749            *   should be injected into the controller. If any of these dependencies are promises, 
31750            *   the router will wait for them all to be resolved before the controller is instantiated.
31751            *   If all the promises are resolved successfully, the $stateChangeSuccess event is fired
31752            *   and the values of the resolved promises are injected into any controllers that reference them.
31753            *   If any  of the promises are rejected the $stateChangeError event is fired.
31754            *
31755            *   The map object is:
31756            *   
31757            *   - key - {string}: name of dependency to be injected into controller
31758            *   - factory - {string|function}: If string then it is alias for service. Otherwise if function, 
31759            *     it is injected and return value it treated as dependency. If result is a promise, it is 
31760            *     resolved before its value is injected into controller.
31761            *
31762            * <pre>resolve: {
31763            *     myResolve1:
31764            *       function($http, $stateParams) {
31765            *         return $http.get("/api/foos/"+stateParams.fooID);
31766            *       }
31767            *     }</pre>
31768            *
31769            * @param {string=} stateConfig.url
31770            * <a id='url'></a>
31771            *
31772            *   A url fragment with optional parameters. When a state is navigated or
31773            *   transitioned to, the `$stateParams` service will be populated with any 
31774            *   parameters that were passed.
31775            *
31776            *   (See {@link ui.router.util.type:UrlMatcher UrlMatcher} `UrlMatcher`} for
31777            *   more details on acceptable patterns )
31778            *
31779            * examples:
31780            * <pre>url: "/home"
31781            * url: "/users/:userid"
31782            * url: "/books/{bookid:[a-zA-Z_-]}"
31783            * url: "/books/{categoryid:int}"
31784            * url: "/books/{publishername:string}/{categoryid:int}"
31785            * url: "/messages?before&after"
31786            * url: "/messages?{before:date}&{after:date}"
31787            * url: "/messages/:mailboxid?{before:date}&{after:date}"
31788            * </pre>
31789            *
31790            * @param {object=} stateConfig.views
31791            * <a id='views'></a>
31792            * an optional map&lt;string, object&gt; which defined multiple views, or targets views
31793            * manually/explicitly.
31794            *
31795            * Examples:
31796            *
31797            * Targets three named `ui-view`s in the parent state's template
31798            * <pre>views: {
31799            *     header: {
31800            *       controller: "headerCtrl",
31801            *       templateUrl: "header.html"
31802            *     }, body: {
31803            *       controller: "bodyCtrl",
31804            *       templateUrl: "body.html"
31805            *     }, footer: {
31806            *       controller: "footCtrl",
31807            *       templateUrl: "footer.html"
31808            *     }
31809            *   }</pre>
31810            *
31811            * Targets named `ui-view="header"` from grandparent state 'top''s template, and named `ui-view="body" from parent state's template.
31812            * <pre>views: {
31813            *     'header@top': {
31814            *       controller: "msgHeaderCtrl",
31815            *       templateUrl: "msgHeader.html"
31816            *     }, 'body': {
31817            *       controller: "messagesCtrl",
31818            *       templateUrl: "messages.html"
31819            *     }
31820            *   }</pre>
31821            *
31822            * @param {boolean=} [stateConfig.abstract=false]
31823            * <a id='abstract'></a>
31824            * An abstract state will never be directly activated,
31825            *   but can provide inherited properties to its common children states.
31826            * <pre>abstract: true</pre>
31827            *
31828            * @param {function=} stateConfig.onEnter
31829            * <a id='onEnter'></a>
31830            *
31831            * Callback function for when a state is entered. Good way
31832            *   to trigger an action or dispatch an event, such as opening a dialog.
31833            * If minifying your scripts, make sure to explicitly annotate this function,
31834            * because it won't be automatically annotated by your build tools.
31835            *
31836            * <pre>onEnter: function(MyService, $stateParams) {
31837            *     MyService.foo($stateParams.myParam);
31838            * }</pre>
31839            *
31840            * @param {function=} stateConfig.onExit
31841            * <a id='onExit'></a>
31842            *
31843            * Callback function for when a state is exited. Good way to
31844            *   trigger an action or dispatch an event, such as opening a dialog.
31845            * If minifying your scripts, make sure to explicitly annotate this function,
31846            * because it won't be automatically annotated by your build tools.
31847            *
31848            * <pre>onExit: function(MyService, $stateParams) {
31849            *     MyService.cleanup($stateParams.myParam);
31850            * }</pre>
31851            *
31852            * @param {boolean=} [stateConfig.reloadOnSearch=true]
31853            * <a id='reloadOnSearch'></a>
31854            *
31855            * If `false`, will not retrigger the same state
31856            *   just because a search/query parameter has changed (via $location.search() or $location.hash()). 
31857            *   Useful for when you'd like to modify $location.search() without triggering a reload.
31858            * <pre>reloadOnSearch: false</pre>
31859            *
31860            * @param {object=} stateConfig.data
31861            * <a id='data'></a>
31862            *
31863            * Arbitrary data object, useful for custom configuration.  The parent state's `data` is
31864            *   prototypally inherited.  In other words, adding a data property to a state adds it to
31865            *   the entire subtree via prototypal inheritance.
31866            *
31867            * <pre>data: {
31868            *     requiredRole: 'foo'
31869            * } </pre>
31870            *
31871            * @param {object=} stateConfig.params
31872            * <a id='params'></a>
31873            *
31874            * A map which optionally configures parameters declared in the `url`, or
31875            *   defines additional non-url parameters.  For each parameter being
31876            *   configured, add a configuration object keyed to the name of the parameter.
31877            *
31878            *   Each parameter configuration object may contain the following properties:
31879            *
31880            *   - ** value ** - {object|function=}: specifies the default value for this
31881            *     parameter.  This implicitly sets this parameter as optional.
31882            *
31883            *     When UI-Router routes to a state and no value is
31884            *     specified for this parameter in the URL or transition, the
31885            *     default value will be used instead.  If `value` is a function,
31886            *     it will be injected and invoked, and the return value used.
31887            *
31888            *     *Note*: `undefined` is treated as "no default value" while `null`
31889            *     is treated as "the default value is `null`".
31890            *
31891            *     *Shorthand*: If you only need to configure the default value of the
31892            *     parameter, you may use a shorthand syntax.   In the **`params`**
31893            *     map, instead mapping the param name to a full parameter configuration
31894            *     object, simply set map it to the default parameter value, e.g.:
31895            *
31896            * <pre>// define a parameter's default value
31897            * params: {
31898            *     param1: { value: "defaultValue" }
31899            * }
31900            * // shorthand default values
31901            * params: {
31902            *     param1: "defaultValue",
31903            *     param2: "param2Default"
31904            * }</pre>
31905            *
31906            *   - ** array ** - {boolean=}: *(default: false)* If true, the param value will be
31907            *     treated as an array of values.  If you specified a Type, the value will be
31908            *     treated as an array of the specified Type.  Note: query parameter values
31909            *     default to a special `"auto"` mode.
31910            *
31911            *     For query parameters in `"auto"` mode, if multiple  values for a single parameter
31912            *     are present in the URL (e.g.: `/foo?bar=1&bar=2&bar=3`) then the values
31913            *     are mapped to an array (e.g.: `{ foo: [ '1', '2', '3' ] }`).  However, if
31914            *     only one value is present (e.g.: `/foo?bar=1`) then the value is treated as single
31915            *     value (e.g.: `{ foo: '1' }`).
31916            *
31917            * <pre>params: {
31918            *     param1: { array: true }
31919            * }</pre>
31920            *
31921            *   - ** squash ** - {bool|string=}: `squash` configures how a default parameter value is represented in the URL when
31922            *     the current parameter value is the same as the default value. If `squash` is not set, it uses the
31923            *     configured default squash policy.
31924            *     (See {@link ui.router.util.$urlMatcherFactory#methods_defaultSquashPolicy `defaultSquashPolicy()`})
31925            *
31926            *   There are three squash settings:
31927            *
31928            *     - false: The parameter's default value is not squashed.  It is encoded and included in the URL
31929            *     - true: The parameter's default value is omitted from the URL.  If the parameter is preceeded and followed
31930            *       by slashes in the state's `url` declaration, then one of those slashes are omitted.
31931            *       This can allow for cleaner looking URLs.
31932            *     - `"<arbitrary string>"`: The parameter's default value is replaced with an arbitrary placeholder of  your choice.
31933            *
31934            * <pre>params: {
31935            *     param1: {
31936            *       value: "defaultId",
31937            *       squash: true
31938            * } }
31939            * // squash "defaultValue" to "~"
31940            * params: {
31941            *     param1: {
31942            *       value: "defaultValue",
31943            *       squash: "~"
31944            * } }
31945            * </pre>
31946            *
31947            *
31948            * @example
31949            * <pre>
31950            * // Some state name examples
31951            *
31952            * // stateName can be a single top-level name (must be unique).
31953            * $stateProvider.state("home", {});
31954            *
31955            * // Or it can be a nested state name. This state is a child of the
31956            * // above "home" state.
31957            * $stateProvider.state("home.newest", {});
31958            *
31959            * // Nest states as deeply as needed.
31960            * $stateProvider.state("home.newest.abc.xyz.inception", {});
31961            *
31962            * // state() returns $stateProvider, so you can chain state declarations.
31963            * $stateProvider
31964            *   .state("home", {})
31965            *   .state("about", {})
31966            *   .state("contacts", {});
31967            * </pre>
31968            *
31969            */
31970           this.state = state;
31971           function state(name, definition) {
31972             /*jshint validthis: true */
31973             if (isObject(name)) definition = name;
31974             else definition.name = name;
31975             registerState(definition);
31976             return this;
31977           }
31978
31979           /**
31980            * @ngdoc object
31981            * @name ui.router.state.$state
31982            *
31983            * @requires $rootScope
31984            * @requires $q
31985            * @requires ui.router.state.$view
31986            * @requires $injector
31987            * @requires ui.router.util.$resolve
31988            * @requires ui.router.state.$stateParams
31989            * @requires ui.router.router.$urlRouter
31990            *
31991            * @property {object} params A param object, e.g. {sectionId: section.id)}, that 
31992            * you'd like to test against the current active state.
31993            * @property {object} current A reference to the state's config object. However 
31994            * you passed it in. Useful for accessing custom data.
31995            * @property {object} transition Currently pending transition. A promise that'll 
31996            * resolve or reject.
31997            *
31998            * @description
31999            * `$state` service is responsible for representing states as well as transitioning
32000            * between them. It also provides interfaces to ask for current state or even states
32001            * you're coming from.
32002            */
32003           this.$get = $get;
32004           $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$urlRouter', '$location', '$urlMatcherFactory'];
32005           function $get(   $rootScope,   $q,   $view,   $injector,   $resolve,   $stateParams,   $urlRouter,   $location,   $urlMatcherFactory) {
32006
32007             var TransitionSuperseded = $q.reject(new Error('transition superseded'));
32008             var TransitionPrevented = $q.reject(new Error('transition prevented'));
32009             var TransitionAborted = $q.reject(new Error('transition aborted'));
32010             var TransitionFailed = $q.reject(new Error('transition failed'));
32011
32012             // Handles the case where a state which is the target of a transition is not found, and the user
32013             // can optionally retry or defer the transition
32014             function handleRedirect(redirect, state, params, options) {
32015               /**
32016                * @ngdoc event
32017                * @name ui.router.state.$state#$stateNotFound
32018                * @eventOf ui.router.state.$state
32019                * @eventType broadcast on root scope
32020                * @description
32021                * Fired when a requested state **cannot be found** using the provided state name during transition.
32022                * The event is broadcast allowing any handlers a single chance to deal with the error (usually by
32023                * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler,
32024                * you can see its three properties in the example. You can use `event.preventDefault()` to abort the
32025                * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value.
32026                *
32027                * @param {Object} event Event object.
32028                * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties.
32029                * @param {State} fromState Current state object.
32030                * @param {Object} fromParams Current state params.
32031                *
32032                * @example
32033                *
32034                * <pre>
32035                * // somewhere, assume lazy.state has not been defined
32036                * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
32037                *
32038                * // somewhere else
32039                * $scope.$on('$stateNotFound',
32040                * function(event, unfoundState, fromState, fromParams){
32041                *     console.log(unfoundState.to); // "lazy.state"
32042                *     console.log(unfoundState.toParams); // {a:1, b:2}
32043                *     console.log(unfoundState.options); // {inherit:false} + default options
32044                * })
32045                * </pre>
32046                */
32047               var evt = $rootScope.$broadcast('$stateNotFound', redirect, state, params);
32048
32049               if (evt.defaultPrevented) {
32050                 $urlRouter.update();
32051                 return TransitionAborted;
32052               }
32053
32054               if (!evt.retry) {
32055                 return null;
32056               }
32057
32058               // Allow the handler to return a promise to defer state lookup retry
32059               if (options.$retry) {
32060                 $urlRouter.update();
32061                 return TransitionFailed;
32062               }
32063               var retryTransition = $state.transition = $q.when(evt.retry);
32064
32065               retryTransition.then(function() {
32066                 if (retryTransition !== $state.transition) return TransitionSuperseded;
32067                 redirect.options.$retry = true;
32068                 return $state.transitionTo(redirect.to, redirect.toParams, redirect.options);
32069               }, function() {
32070                 return TransitionAborted;
32071               });
32072               $urlRouter.update();
32073
32074               return retryTransition;
32075             }
32076
32077             root.locals = { resolve: null, globals: { $stateParams: {} } };
32078
32079             $state = {
32080               params: {},
32081               current: root.self,
32082               $current: root,
32083               transition: null
32084             };
32085
32086             /**
32087              * @ngdoc function
32088              * @name ui.router.state.$state#reload
32089              * @methodOf ui.router.state.$state
32090              *
32091              * @description
32092              * A method that force reloads the current state. All resolves are re-resolved,
32093              * controllers reinstantiated, and events re-fired.
32094              *
32095              * @example
32096              * <pre>
32097              * var app angular.module('app', ['ui.router']);
32098              *
32099              * app.controller('ctrl', function ($scope, $state) {
32100              *   $scope.reload = function(){
32101              *     $state.reload();
32102              *   }
32103              * });
32104              * </pre>
32105              *
32106              * `reload()` is just an alias for:
32107              * <pre>
32108              * $state.transitionTo($state.current, $stateParams, { 
32109              *   reload: true, inherit: false, notify: true
32110              * });
32111              * </pre>
32112              *
32113              * @param {string=|object=} state - A state name or a state object, which is the root of the resolves to be re-resolved.
32114              * @example
32115              * <pre>
32116              * //assuming app application consists of 3 states: 'contacts', 'contacts.detail', 'contacts.detail.item' 
32117              * //and current state is 'contacts.detail.item'
32118              * var app angular.module('app', ['ui.router']);
32119              *
32120              * app.controller('ctrl', function ($scope, $state) {
32121              *   $scope.reload = function(){
32122              *     //will reload 'contact.detail' and 'contact.detail.item' states
32123              *     $state.reload('contact.detail');
32124              *   }
32125              * });
32126              * </pre>
32127              *
32128              * `reload()` is just an alias for:
32129              * <pre>
32130              * $state.transitionTo($state.current, $stateParams, { 
32131              *   reload: true, inherit: false, notify: true
32132              * });
32133              * </pre>
32134
32135              * @returns {promise} A promise representing the state of the new transition. See
32136              * {@link ui.router.state.$state#methods_go $state.go}.
32137              */
32138             $state.reload = function reload(state) {
32139               return $state.transitionTo($state.current, $stateParams, { reload: state || true, inherit: false, notify: true});
32140             };
32141
32142             /**
32143              * @ngdoc function
32144              * @name ui.router.state.$state#go
32145              * @methodOf ui.router.state.$state
32146              *
32147              * @description
32148              * Convenience method for transitioning to a new state. `$state.go` calls 
32149              * `$state.transitionTo` internally but automatically sets options to 
32150              * `{ location: true, inherit: true, relative: $state.$current, notify: true }`. 
32151              * This allows you to easily use an absolute or relative to path and specify 
32152              * only the parameters you'd like to update (while letting unspecified parameters 
32153              * inherit from the currently active ancestor states).
32154              *
32155              * @example
32156              * <pre>
32157              * var app = angular.module('app', ['ui.router']);
32158              *
32159              * app.controller('ctrl', function ($scope, $state) {
32160              *   $scope.changeState = function () {
32161              *     $state.go('contact.detail');
32162              *   };
32163              * });
32164              * </pre>
32165              * <img src='../ngdoc_assets/StateGoExamples.png'/>
32166              *
32167              * @param {string} to Absolute state name or relative state path. Some examples:
32168              *
32169              * - `$state.go('contact.detail')` - will go to the `contact.detail` state
32170              * - `$state.go('^')` - will go to a parent state
32171              * - `$state.go('^.sibling')` - will go to a sibling state
32172              * - `$state.go('.child.grandchild')` - will go to grandchild state
32173              *
32174              * @param {object=} params A map of the parameters that will be sent to the state, 
32175              * will populate $stateParams. Any parameters that are not specified will be inherited from currently 
32176              * defined parameters. Only parameters specified in the state definition can be overridden, new 
32177              * parameters will be ignored. This allows, for example, going to a sibling state that shares parameters
32178              * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e.
32179              * transitioning to a sibling will get you the parameters for all parents, transitioning to a child
32180              * will get you all current parameters, etc.
32181              * @param {object=} options Options object. The options are:
32182              *
32183              * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
32184              *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
32185              * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
32186              * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
32187              *    defines which state to be relative from.
32188              * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
32189              * - **`reload`** (v0.2.5) - {boolean=false|string|object}, If `true` will force transition even if no state or params
32190              *    have changed.  It will reload the resolves and views of the current state and parent states.
32191              *    If `reload` is a string (or state object), the state object is fetched (by name, or object reference); and \
32192              *    the transition reloads the resolves and views for that matched state, and all its children states.
32193              *
32194              * @returns {promise} A promise representing the state of the new transition.
32195              *
32196              * Possible success values:
32197              *
32198              * - $state.current
32199              *
32200              * <br/>Possible rejection values:
32201              *
32202              * - 'transition superseded' - when a newer transition has been started after this one
32203              * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener
32204              * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or
32205              *   when a `$stateNotFound` `event.retry` promise errors.
32206              * - 'transition failed' - when a state has been unsuccessfully found after 2 tries.
32207              * - *resolve error* - when an error has occurred with a `resolve`
32208              *
32209              */
32210             $state.go = function go(to, params, options) {
32211               return $state.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options));
32212             };
32213
32214             /**
32215              * @ngdoc function
32216              * @name ui.router.state.$state#transitionTo
32217              * @methodOf ui.router.state.$state
32218              *
32219              * @description
32220              * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go}
32221              * uses `transitionTo` internally. `$state.go` is recommended in most situations.
32222              *
32223              * @example
32224              * <pre>
32225              * var app = angular.module('app', ['ui.router']);
32226              *
32227              * app.controller('ctrl', function ($scope, $state) {
32228              *   $scope.changeState = function () {
32229              *     $state.transitionTo('contact.detail');
32230              *   };
32231              * });
32232              * </pre>
32233              *
32234              * @param {string} to State name.
32235              * @param {object=} toParams A map of the parameters that will be sent to the state,
32236              * will populate $stateParams.
32237              * @param {object=} options Options object. The options are:
32238              *
32239              * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
32240              *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
32241              * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
32242              * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), 
32243              *    defines which state to be relative from.
32244              * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
32245              * - **`reload`** (v0.2.5) - {boolean=false|string=|object=}, If `true` will force transition even if the state or params 
32246              *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
32247              *    use this when you want to force a reload when *everything* is the same, including search params.
32248              *    if String, then will reload the state with the name given in reload, and any children.
32249              *    if Object, then a stateObj is expected, will reload the state found in stateObj, and any children.
32250              *
32251              * @returns {promise} A promise representing the state of the new transition. See
32252              * {@link ui.router.state.$state#methods_go $state.go}.
32253              */
32254             $state.transitionTo = function transitionTo(to, toParams, options) {
32255               toParams = toParams || {};
32256               options = extend({
32257                 location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false
32258               }, options || {});
32259
32260               var from = $state.$current, fromParams = $state.params, fromPath = from.path;
32261               var evt, toState = findState(to, options.relative);
32262
32263               // Store the hash param for later (since it will be stripped out by various methods)
32264               var hash = toParams['#'];
32265
32266               if (!isDefined(toState)) {
32267                 var redirect = { to: to, toParams: toParams, options: options };
32268                 var redirectResult = handleRedirect(redirect, from.self, fromParams, options);
32269
32270                 if (redirectResult) {
32271                   return redirectResult;
32272                 }
32273
32274                 // Always retry once if the $stateNotFound was not prevented
32275                 // (handles either redirect changed or state lazy-definition)
32276                 to = redirect.to;
32277                 toParams = redirect.toParams;
32278                 options = redirect.options;
32279                 toState = findState(to, options.relative);
32280
32281                 if (!isDefined(toState)) {
32282                   if (!options.relative) throw new Error("No such state '" + to + "'");
32283                   throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
32284                 }
32285               }
32286               if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
32287               if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
32288               if (!toState.params.$$validates(toParams)) return TransitionFailed;
32289
32290               toParams = toState.params.$$values(toParams);
32291               to = toState;
32292
32293               var toPath = to.path;
32294
32295               // Starting from the root of the path, keep all levels that haven't changed
32296               var keep = 0, state = toPath[keep], locals = root.locals, toLocals = [];
32297
32298               if (!options.reload) {
32299                 while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) {
32300                   locals = toLocals[keep] = state.locals;
32301                   keep++;
32302                   state = toPath[keep];
32303                 }
32304               } else if (isString(options.reload) || isObject(options.reload)) {
32305                 if (isObject(options.reload) && !options.reload.name) {
32306                   throw new Error('Invalid reload state object');
32307                 }
32308                 
32309                 var reloadState = options.reload === true ? fromPath[0] : findState(options.reload);
32310                 if (options.reload && !reloadState) {
32311                   throw new Error("No such reload state '" + (isString(options.reload) ? options.reload : options.reload.name) + "'");
32312                 }
32313
32314                 while (state && state === fromPath[keep] && state !== reloadState) {
32315                   locals = toLocals[keep] = state.locals;
32316                   keep++;
32317                   state = toPath[keep];
32318                 }
32319               }
32320
32321               // If we're going to the same state and all locals are kept, we've got nothing to do.
32322               // But clear 'transition', as we still want to cancel any other pending transitions.
32323               // TODO: We may not want to bump 'transition' if we're called from a location change
32324               // that we've initiated ourselves, because we might accidentally abort a legitimate
32325               // transition initiated from code?
32326               if (shouldSkipReload(to, toParams, from, fromParams, locals, options)) {
32327                 if (hash) toParams['#'] = hash;
32328                 $state.params = toParams;
32329                 copy($state.params, $stateParams);
32330                 copy(filterByKeys(to.params.$$keys(), $stateParams), to.locals.globals.$stateParams);
32331                 if (options.location && to.navigable && to.navigable.url) {
32332                   $urlRouter.push(to.navigable.url, toParams, {
32333                     $$avoidResync: true, replace: options.location === 'replace'
32334                   });
32335                   $urlRouter.update(true);
32336                 }
32337                 $state.transition = null;
32338                 return $q.when($state.current);
32339               }
32340
32341               // Filter parameters before we pass them to event handlers etc.
32342               toParams = filterByKeys(to.params.$$keys(), toParams || {});
32343               
32344               // Re-add the saved hash before we start returning things or broadcasting $stateChangeStart
32345               if (hash) toParams['#'] = hash;
32346               
32347               // Broadcast start event and cancel the transition if requested
32348               if (options.notify) {
32349                 /**
32350                  * @ngdoc event
32351                  * @name ui.router.state.$state#$stateChangeStart
32352                  * @eventOf ui.router.state.$state
32353                  * @eventType broadcast on root scope
32354                  * @description
32355                  * Fired when the state transition **begins**. You can use `event.preventDefault()`
32356                  * to prevent the transition from happening and then the transition promise will be
32357                  * rejected with a `'transition prevented'` value.
32358                  *
32359                  * @param {Object} event Event object.
32360                  * @param {State} toState The state being transitioned to.
32361                  * @param {Object} toParams The params supplied to the `toState`.
32362                  * @param {State} fromState The current state, pre-transition.
32363                  * @param {Object} fromParams The params supplied to the `fromState`.
32364                  *
32365                  * @example
32366                  *
32367                  * <pre>
32368                  * $rootScope.$on('$stateChangeStart',
32369                  * function(event, toState, toParams, fromState, fromParams){
32370                  *     event.preventDefault();
32371                  *     // transitionTo() promise will be rejected with
32372                  *     // a 'transition prevented' error
32373                  * })
32374                  * </pre>
32375                  */
32376                 if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams, options).defaultPrevented) {
32377                   $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
32378                   //Don't update and resync url if there's been a new transition started. see issue #2238, #600
32379                   if ($state.transition == null) $urlRouter.update();
32380                   return TransitionPrevented;
32381                 }
32382               }
32383
32384               // Resolve locals for the remaining states, but don't update any global state just
32385               // yet -- if anything fails to resolve the current state needs to remain untouched.
32386               // We also set up an inheritance chain for the locals here. This allows the view directive
32387               // to quickly look up the correct definition for each view in the current state. Even
32388               // though we create the locals object itself outside resolveState(), it is initially
32389               // empty and gets filled asynchronously. We need to keep track of the promise for the
32390               // (fully resolved) current locals, and pass this down the chain.
32391               var resolved = $q.when(locals);
32392
32393               for (var l = keep; l < toPath.length; l++, state = toPath[l]) {
32394                 locals = toLocals[l] = inherit(locals);
32395                 resolved = resolveState(state, toParams, state === to, resolved, locals, options);
32396               }
32397
32398               // Once everything is resolved, we are ready to perform the actual transition
32399               // and return a promise for the new state. We also keep track of what the
32400               // current promise is, so that we can detect overlapping transitions and
32401               // keep only the outcome of the last transition.
32402               var transition = $state.transition = resolved.then(function () {
32403                 var l, entering, exiting;
32404
32405                 if ($state.transition !== transition) return TransitionSuperseded;
32406
32407                 // Exit 'from' states not kept
32408                 for (l = fromPath.length - 1; l >= keep; l--) {
32409                   exiting = fromPath[l];
32410                   if (exiting.self.onExit) {
32411                     $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
32412                   }
32413                   exiting.locals = null;
32414                 }
32415
32416                 // Enter 'to' states not kept
32417                 for (l = keep; l < toPath.length; l++) {
32418                   entering = toPath[l];
32419                   entering.locals = toLocals[l];
32420                   if (entering.self.onEnter) {
32421                     $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
32422                   }
32423                 }
32424
32425                 // Run it again, to catch any transitions in callbacks
32426                 if ($state.transition !== transition) return TransitionSuperseded;
32427
32428                 // Update globals in $state
32429                 $state.$current = to;
32430                 $state.current = to.self;
32431                 $state.params = toParams;
32432                 copy($state.params, $stateParams);
32433                 $state.transition = null;
32434
32435                 if (options.location && to.navigable) {
32436                   $urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, {
32437                     $$avoidResync: true, replace: options.location === 'replace'
32438                   });
32439                 }
32440
32441                 if (options.notify) {
32442                 /**
32443                  * @ngdoc event
32444                  * @name ui.router.state.$state#$stateChangeSuccess
32445                  * @eventOf ui.router.state.$state
32446                  * @eventType broadcast on root scope
32447                  * @description
32448                  * Fired once the state transition is **complete**.
32449                  *
32450                  * @param {Object} event Event object.
32451                  * @param {State} toState The state being transitioned to.
32452                  * @param {Object} toParams The params supplied to the `toState`.
32453                  * @param {State} fromState The current state, pre-transition.
32454                  * @param {Object} fromParams The params supplied to the `fromState`.
32455                  */
32456                   $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams);
32457                 }
32458                 $urlRouter.update(true);
32459
32460                 return $state.current;
32461               }, function (error) {
32462                 if ($state.transition !== transition) return TransitionSuperseded;
32463
32464                 $state.transition = null;
32465                 /**
32466                  * @ngdoc event
32467                  * @name ui.router.state.$state#$stateChangeError
32468                  * @eventOf ui.router.state.$state
32469                  * @eventType broadcast on root scope
32470                  * @description
32471                  * Fired when an **error occurs** during transition. It's important to note that if you
32472                  * have any errors in your resolve functions (javascript errors, non-existent services, etc)
32473                  * they will not throw traditionally. You must listen for this $stateChangeError event to
32474                  * catch **ALL** errors.
32475                  *
32476                  * @param {Object} event Event object.
32477                  * @param {State} toState The state being transitioned to.
32478                  * @param {Object} toParams The params supplied to the `toState`.
32479                  * @param {State} fromState The current state, pre-transition.
32480                  * @param {Object} fromParams The params supplied to the `fromState`.
32481                  * @param {Error} error The resolve error object.
32482                  */
32483                 evt = $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error);
32484
32485                 if (!evt.defaultPrevented) {
32486                     $urlRouter.update();
32487                 }
32488
32489                 return $q.reject(error);
32490               });
32491
32492               return transition;
32493             };
32494
32495             /**
32496              * @ngdoc function
32497              * @name ui.router.state.$state#is
32498              * @methodOf ui.router.state.$state
32499              *
32500              * @description
32501              * Similar to {@link ui.router.state.$state#methods_includes $state.includes},
32502              * but only checks for the full state name. If params is supplied then it will be
32503              * tested for strict equality against the current active params object, so all params
32504              * must match with none missing and no extras.
32505              *
32506              * @example
32507              * <pre>
32508              * $state.$current.name = 'contacts.details.item';
32509              *
32510              * // absolute name
32511              * $state.is('contact.details.item'); // returns true
32512              * $state.is(contactDetailItemStateObject); // returns true
32513              *
32514              * // relative name (. and ^), typically from a template
32515              * // E.g. from the 'contacts.details' template
32516              * <div ng-class="{highlighted: $state.is('.item')}">Item</div>
32517              * </pre>
32518              *
32519              * @param {string|object} stateOrName The state name (absolute or relative) or state object you'd like to check.
32520              * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like
32521              * to test against the current active state.
32522              * @param {object=} options An options object.  The options are:
32523              *
32524              * - **`relative`** - {string|object} -  If `stateOrName` is a relative state name and `options.relative` is set, .is will
32525              * test relative to `options.relative` state (or name).
32526              *
32527              * @returns {boolean} Returns true if it is the state.
32528              */
32529             $state.is = function is(stateOrName, params, options) {
32530               options = extend({ relative: $state.$current }, options || {});
32531               var state = findState(stateOrName, options.relative);
32532
32533               if (!isDefined(state)) { return undefined; }
32534               if ($state.$current !== state) { return false; }
32535               return params ? equalForKeys(state.params.$$values(params), $stateParams) : true;
32536             };
32537
32538             /**
32539              * @ngdoc function
32540              * @name ui.router.state.$state#includes
32541              * @methodOf ui.router.state.$state
32542              *
32543              * @description
32544              * A method to determine if the current active state is equal to or is the child of the
32545              * state stateName. If any params are passed then they will be tested for a match as well.
32546              * Not all the parameters need to be passed, just the ones you'd like to test for equality.
32547              *
32548              * @example
32549              * Partial and relative names
32550              * <pre>
32551              * $state.$current.name = 'contacts.details.item';
32552              *
32553              * // Using partial names
32554              * $state.includes("contacts"); // returns true
32555              * $state.includes("contacts.details"); // returns true
32556              * $state.includes("contacts.details.item"); // returns true
32557              * $state.includes("contacts.list"); // returns false
32558              * $state.includes("about"); // returns false
32559              *
32560              * // Using relative names (. and ^), typically from a template
32561              * // E.g. from the 'contacts.details' template
32562              * <div ng-class="{highlighted: $state.includes('.item')}">Item</div>
32563              * </pre>
32564              *
32565              * Basic globbing patterns
32566              * <pre>
32567              * $state.$current.name = 'contacts.details.item.url';
32568              *
32569              * $state.includes("*.details.*.*"); // returns true
32570              * $state.includes("*.details.**"); // returns true
32571              * $state.includes("**.item.**"); // returns true
32572              * $state.includes("*.details.item.url"); // returns true
32573              * $state.includes("*.details.*.url"); // returns true
32574              * $state.includes("*.details.*"); // returns false
32575              * $state.includes("item.**"); // returns false
32576              * </pre>
32577              *
32578              * @param {string} stateOrName A partial name, relative name, or glob pattern
32579              * to be searched for within the current state name.
32580              * @param {object=} params A param object, e.g. `{sectionId: section.id}`,
32581              * that you'd like to test against the current active state.
32582              * @param {object=} options An options object.  The options are:
32583              *
32584              * - **`relative`** - {string|object=} -  If `stateOrName` is a relative state reference and `options.relative` is set,
32585              * .includes will test relative to `options.relative` state (or name).
32586              *
32587              * @returns {boolean} Returns true if it does include the state
32588              */
32589             $state.includes = function includes(stateOrName, params, options) {
32590               options = extend({ relative: $state.$current }, options || {});
32591               if (isString(stateOrName) && isGlob(stateOrName)) {
32592                 if (!doesStateMatchGlob(stateOrName)) {
32593                   return false;
32594                 }
32595                 stateOrName = $state.$current.name;
32596               }
32597
32598               var state = findState(stateOrName, options.relative);
32599               if (!isDefined(state)) { return undefined; }
32600               if (!isDefined($state.$current.includes[state.name])) { return false; }
32601               return params ? equalForKeys(state.params.$$values(params), $stateParams, objectKeys(params)) : true;
32602             };
32603
32604
32605             /**
32606              * @ngdoc function
32607              * @name ui.router.state.$state#href
32608              * @methodOf ui.router.state.$state
32609              *
32610              * @description
32611              * A url generation method that returns the compiled url for the given state populated with the given params.
32612              *
32613              * @example
32614              * <pre>
32615              * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
32616              * </pre>
32617              *
32618              * @param {string|object} stateOrName The state name or state object you'd like to generate a url from.
32619              * @param {object=} params An object of parameter values to fill the state's required parameters.
32620              * @param {object=} options Options object. The options are:
32621              *
32622              * - **`lossy`** - {boolean=true} -  If true, and if there is no url associated with the state provided in the
32623              *    first parameter, then the constructed href url will be built from the first navigable ancestor (aka
32624              *    ancestor with a valid url).
32625              * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
32626              * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
32627              *    defines which state to be relative from.
32628              * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
32629              * 
32630              * @returns {string} compiled state url
32631              */
32632             $state.href = function href(stateOrName, params, options) {
32633               options = extend({
32634                 lossy:    true,
32635                 inherit:  true,
32636                 absolute: false,
32637                 relative: $state.$current
32638               }, options || {});
32639
32640               var state = findState(stateOrName, options.relative);
32641
32642               if (!isDefined(state)) return null;
32643               if (options.inherit) params = inheritParams($stateParams, params || {}, $state.$current, state);
32644               
32645               var nav = (state && options.lossy) ? state.navigable : state;
32646
32647               if (!nav || nav.url === undefined || nav.url === null) {
32648                 return null;
32649               }
32650               return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys().concat('#'), params || {}), {
32651                 absolute: options.absolute
32652               });
32653             };
32654
32655             /**
32656              * @ngdoc function
32657              * @name ui.router.state.$state#get
32658              * @methodOf ui.router.state.$state
32659              *
32660              * @description
32661              * Returns the state configuration object for any specific state or all states.
32662              *
32663              * @param {string|object=} stateOrName (absolute or relative) If provided, will only get the config for
32664              * the requested state. If not provided, returns an array of ALL state configs.
32665              * @param {string|object=} context When stateOrName is a relative state reference, the state will be retrieved relative to context.
32666              * @returns {Object|Array} State configuration object or array of all objects.
32667              */
32668             $state.get = function (stateOrName, context) {
32669               if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; });
32670               var state = findState(stateOrName, context || $state.$current);
32671               return (state && state.self) ? state.self : null;
32672             };
32673
32674             function resolveState(state, params, paramsAreFiltered, inherited, dst, options) {
32675               // Make a restricted $stateParams with only the parameters that apply to this state if
32676               // necessary. In addition to being available to the controller and onEnter/onExit callbacks,
32677               // we also need $stateParams to be available for any $injector calls we make during the
32678               // dependency resolution process.
32679               var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params.$$keys(), params);
32680               var locals = { $stateParams: $stateParams };
32681
32682               // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
32683               // We're also including $stateParams in this; that way the parameters are restricted
32684               // to the set that should be visible to the state, and are independent of when we update
32685               // the global $state and $stateParams values.
32686               dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state);
32687               var promises = [dst.resolve.then(function (globals) {
32688                 dst.globals = globals;
32689               })];
32690               if (inherited) promises.push(inherited);
32691
32692               function resolveViews() {
32693                 var viewsPromises = [];
32694
32695                 // Resolve template and dependencies for all views.
32696                 forEach(state.views, function (view, name) {
32697                   var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {});
32698                   injectables.$template = [ function () {
32699                     return $view.load(name, { view: view, locals: dst.globals, params: $stateParams, notify: options.notify }) || '';
32700                   }];
32701
32702                   viewsPromises.push($resolve.resolve(injectables, dst.globals, dst.resolve, state).then(function (result) {
32703                     // References to the controller (only instantiated at link time)
32704                     if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) {
32705                       var injectLocals = angular.extend({}, injectables, dst.globals);
32706                       result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals);
32707                     } else {
32708                       result.$$controller = view.controller;
32709                     }
32710                     // Provide access to the state itself for internal use
32711                     result.$$state = state;
32712                     result.$$controllerAs = view.controllerAs;
32713                     dst[name] = result;
32714                   }));
32715                 });
32716
32717                 return $q.all(viewsPromises).then(function(){
32718                   return dst.globals;
32719                 });
32720               }
32721
32722               // Wait for all the promises and then return the activation object
32723               return $q.all(promises).then(resolveViews).then(function (values) {
32724                 return dst;
32725               });
32726             }
32727
32728             return $state;
32729           }
32730
32731           function shouldSkipReload(to, toParams, from, fromParams, locals, options) {
32732             // Return true if there are no differences in non-search (path/object) params, false if there are differences
32733             function nonSearchParamsEqual(fromAndToState, fromParams, toParams) {
32734               // Identify whether all the parameters that differ between `fromParams` and `toParams` were search params.
32735               function notSearchParam(key) {
32736                 return fromAndToState.params[key].location != "search";
32737               }
32738               var nonQueryParamKeys = fromAndToState.params.$$keys().filter(notSearchParam);
32739               var nonQueryParams = pick.apply({}, [fromAndToState.params].concat(nonQueryParamKeys));
32740               var nonQueryParamSet = new $$UMFP.ParamSet(nonQueryParams);
32741               return nonQueryParamSet.$$equals(fromParams, toParams);
32742             }
32743
32744             // If reload was not explicitly requested
32745             // and we're transitioning to the same state we're already in
32746             // and    the locals didn't change
32747             //     or they changed in a way that doesn't merit reloading
32748             //        (reloadOnParams:false, or reloadOnSearch.false and only search params changed)
32749             // Then return true.
32750             if (!options.reload && to === from &&
32751               (locals === from.locals || (to.self.reloadOnSearch === false && nonSearchParamsEqual(from, fromParams, toParams)))) {
32752               return true;
32753             }
32754           }
32755         }
32756
32757         angular.module('ui.router.state')
32758           .factory('$stateParams', function () { return {}; })
32759           .provider('$state', $StateProvider);
32760
32761
32762         $ViewProvider.$inject = [];
32763         function $ViewProvider() {
32764
32765           this.$get = $get;
32766           /**
32767            * @ngdoc object
32768            * @name ui.router.state.$view
32769            *
32770            * @requires ui.router.util.$templateFactory
32771            * @requires $rootScope
32772            *
32773            * @description
32774            *
32775            */
32776           $get.$inject = ['$rootScope', '$templateFactory'];
32777           function $get(   $rootScope,   $templateFactory) {
32778             return {
32779               // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... })
32780               /**
32781                * @ngdoc function
32782                * @name ui.router.state.$view#load
32783                * @methodOf ui.router.state.$view
32784                *
32785                * @description
32786                *
32787                * @param {string} name name
32788                * @param {object} options option object.
32789                */
32790               load: function load(name, options) {
32791                 var result, defaults = {
32792                   template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {}
32793                 };
32794                 options = extend(defaults, options);
32795
32796                 if (options.view) {
32797                   result = $templateFactory.fromConfig(options.view, options.params, options.locals);
32798                 }
32799                 return result;
32800               }
32801             };
32802           }
32803         }
32804
32805         angular.module('ui.router.state').provider('$view', $ViewProvider);
32806
32807         /**
32808          * @ngdoc object
32809          * @name ui.router.state.$uiViewScrollProvider
32810          *
32811          * @description
32812          * Provider that returns the {@link ui.router.state.$uiViewScroll} service function.
32813          */
32814         function $ViewScrollProvider() {
32815
32816           var useAnchorScroll = false;
32817
32818           /**
32819            * @ngdoc function
32820            * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll
32821            * @methodOf ui.router.state.$uiViewScrollProvider
32822            *
32823            * @description
32824            * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for
32825            * scrolling based on the url anchor.
32826            */
32827           this.useAnchorScroll = function () {
32828             useAnchorScroll = true;
32829           };
32830
32831           /**
32832            * @ngdoc object
32833            * @name ui.router.state.$uiViewScroll
32834            *
32835            * @requires $anchorScroll
32836            * @requires $timeout
32837            *
32838            * @description
32839            * When called with a jqLite element, it scrolls the element into view (after a
32840            * `$timeout` so the DOM has time to refresh).
32841            *
32842            * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor,
32843            * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}.
32844            */
32845           this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) {
32846             if (useAnchorScroll) {
32847               return $anchorScroll;
32848             }
32849
32850             return function ($element) {
32851               return $timeout(function () {
32852                 $element[0].scrollIntoView();
32853               }, 0, false);
32854             };
32855           }];
32856         }
32857
32858         angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider);
32859
32860         var ngMajorVer = angular.version.major;
32861         var ngMinorVer = angular.version.minor;
32862         /**
32863          * @ngdoc directive
32864          * @name ui.router.state.directive:ui-view
32865          *
32866          * @requires ui.router.state.$state
32867          * @requires $compile
32868          * @requires $controller
32869          * @requires $injector
32870          * @requires ui.router.state.$uiViewScroll
32871          * @requires $document
32872          *
32873          * @restrict ECA
32874          *
32875          * @description
32876          * The ui-view directive tells $state where to place your templates.
32877          *
32878          * @param {string=} name A view name. The name should be unique amongst the other views in the
32879          * same state. You can have views of the same name that live in different states.
32880          *
32881          * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window
32882          * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll
32883          * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you
32884          * scroll ui-view elements into view when they are populated during a state activation.
32885          *
32886          * @param {string=} noanimation If truthy, the non-animated renderer will be selected (no animations
32887          * will be applied to the ui-view)
32888          *
32889          * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll)
32890          * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.*
32891          *
32892          * @param {string=} onload Expression to evaluate whenever the view updates.
32893          * 
32894          * @example
32895          * A view can be unnamed or named. 
32896          * <pre>
32897          * <!-- Unnamed -->
32898          * <div ui-view></div> 
32899          * 
32900          * <!-- Named -->
32901          * <div ui-view="viewName"></div>
32902          * </pre>
32903          *
32904          * You can only have one unnamed view within any template (or root html). If you are only using a 
32905          * single view and it is unnamed then you can populate it like so:
32906          * <pre>
32907          * <div ui-view></div> 
32908          * $stateProvider.state("home", {
32909          *   template: "<h1>HELLO!</h1>"
32910          * })
32911          * </pre>
32912          * 
32913          * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#views `views`}
32914          * config property, by name, in this case an empty name:
32915          * <pre>
32916          * $stateProvider.state("home", {
32917          *   views: {
32918          *     "": {
32919          *       template: "<h1>HELLO!</h1>"
32920          *     }
32921          *   }    
32922          * })
32923          * </pre>
32924          * 
32925          * But typically you'll only use the views property if you name your view or have more than one view 
32926          * in the same template. There's not really a compelling reason to name a view if its the only one, 
32927          * but you could if you wanted, like so:
32928          * <pre>
32929          * <div ui-view="main"></div>
32930          * </pre> 
32931          * <pre>
32932          * $stateProvider.state("home", {
32933          *   views: {
32934          *     "main": {
32935          *       template: "<h1>HELLO!</h1>"
32936          *     }
32937          *   }    
32938          * })
32939          * </pre>
32940          * 
32941          * Really though, you'll use views to set up multiple views:
32942          * <pre>
32943          * <div ui-view></div>
32944          * <div ui-view="chart"></div> 
32945          * <div ui-view="data"></div> 
32946          * </pre>
32947          * 
32948          * <pre>
32949          * $stateProvider.state("home", {
32950          *   views: {
32951          *     "": {
32952          *       template: "<h1>HELLO!</h1>"
32953          *     },
32954          *     "chart": {
32955          *       template: "<chart_thing/>"
32956          *     },
32957          *     "data": {
32958          *       template: "<data_thing/>"
32959          *     }
32960          *   }    
32961          * })
32962          * </pre>
32963          *
32964          * Examples for `autoscroll`:
32965          *
32966          * <pre>
32967          * <!-- If autoscroll present with no expression,
32968          *      then scroll ui-view into view -->
32969          * <ui-view autoscroll/>
32970          *
32971          * <!-- If autoscroll present with valid expression,
32972          *      then scroll ui-view into view if expression evaluates to true -->
32973          * <ui-view autoscroll='true'/>
32974          * <ui-view autoscroll='false'/>
32975          * <ui-view autoscroll='scopeVariable'/>
32976          * </pre>
32977          */
32978         $ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll', '$interpolate'];
32979         function $ViewDirective(   $state,   $injector,   $uiViewScroll,   $interpolate) {
32980
32981           function getService() {
32982             return ($injector.has) ? function(service) {
32983               return $injector.has(service) ? $injector.get(service) : null;
32984             } : function(service) {
32985               try {
32986                 return $injector.get(service);
32987               } catch (e) {
32988                 return null;
32989               }
32990             };
32991           }
32992
32993           var service = getService(),
32994               $animator = service('$animator'),
32995               $animate = service('$animate');
32996
32997           // Returns a set of DOM manipulation functions based on which Angular version
32998           // it should use
32999           function getRenderer(attrs, scope) {
33000             var statics = {
33001               enter: function (element, target, cb) { target.after(element); cb(); },
33002               leave: function (element, cb) { element.remove(); cb(); }
33003             };
33004
33005             if (!!attrs.noanimation) return statics;
33006
33007             function animEnabled(element) {
33008               if (ngMajorVer === 1 && ngMinorVer >= 4) return !!$animate.enabled(element);
33009               if (ngMajorVer === 1 && ngMinorVer >= 2) return !!$animate.enabled();
33010               return (!!$animator);
33011             }
33012
33013             // ng 1.2+
33014             if ($animate) {
33015               return {
33016                 enter: function(element, target, cb) {
33017                   if (!animEnabled(element)) {
33018                     statics.enter(element, target, cb);
33019                   } else if (angular.version.minor > 2) {
33020                     $animate.enter(element, null, target).then(cb);
33021                   } else {
33022                     $animate.enter(element, null, target, cb);
33023                   }
33024                 },
33025                 leave: function(element, cb) {
33026                   if (!animEnabled(element)) {
33027                     statics.leave(element, cb);
33028                   } else if (angular.version.minor > 2) {
33029                     $animate.leave(element).then(cb);
33030                   } else {
33031                     $animate.leave(element, cb);
33032                   }
33033                 }
33034               };
33035             }
33036
33037             // ng 1.1.5
33038             if ($animator) {
33039               var animate = $animator && $animator(scope, attrs);
33040
33041               return {
33042                 enter: function(element, target, cb) {animate.enter(element, null, target); cb(); },
33043                 leave: function(element, cb) { animate.leave(element); cb(); }
33044               };
33045             }
33046
33047             return statics;
33048           }
33049
33050           var directive = {
33051             restrict: 'ECA',
33052             terminal: true,
33053             priority: 400,
33054             transclude: 'element',
33055             compile: function (tElement, tAttrs, $transclude) {
33056               return function (scope, $element, attrs) {
33057                 var previousEl, currentEl, currentScope, latestLocals,
33058                     onloadExp     = attrs.onload || '',
33059                     autoScrollExp = attrs.autoscroll,
33060                     renderer      = getRenderer(attrs, scope);
33061
33062                 scope.$on('$stateChangeSuccess', function() {
33063                   updateView(false);
33064                 });
33065
33066                 updateView(true);
33067
33068                 function cleanupLastView() {
33069                   var _previousEl = previousEl;
33070                   var _currentScope = currentScope;
33071
33072                   if (_currentScope) {
33073                     _currentScope._willBeDestroyed = true;
33074                   }
33075
33076                   function cleanOld() {
33077                     if (_previousEl) {
33078                       _previousEl.remove();
33079                     }
33080
33081                     if (_currentScope) {
33082                       _currentScope.$destroy();
33083                     }
33084                   }
33085
33086                   if (currentEl) {
33087                     renderer.leave(currentEl, function() {
33088                       cleanOld();
33089                       previousEl = null;
33090                     });
33091
33092                     previousEl = currentEl;
33093                   } else {
33094                     cleanOld();
33095                     previousEl = null;
33096                   }
33097
33098                   currentEl = null;
33099                   currentScope = null;
33100                 }
33101
33102                 function updateView(firstTime) {
33103                   var newScope,
33104                       name            = getUiViewName(scope, attrs, $element, $interpolate),
33105                       previousLocals  = name && $state.$current && $state.$current.locals[name];
33106
33107                   if (!firstTime && previousLocals === latestLocals || scope._willBeDestroyed) return; // nothing to do
33108                   newScope = scope.$new();
33109                   latestLocals = $state.$current.locals[name];
33110
33111                   /**
33112                    * @ngdoc event
33113                    * @name ui.router.state.directive:ui-view#$viewContentLoading
33114                    * @eventOf ui.router.state.directive:ui-view
33115                    * @eventType emits on ui-view directive scope
33116                    * @description
33117                    *
33118                    * Fired once the view **begins loading**, *before* the DOM is rendered.
33119                    *
33120                    * @param {Object} event Event object.
33121                    * @param {string} viewName Name of the view.
33122                    */
33123                   newScope.$emit('$viewContentLoading', name);
33124
33125                   var clone = $transclude(newScope, function(clone) {
33126                     renderer.enter(clone, $element, function onUiViewEnter() {
33127                       if(currentScope) {
33128                         currentScope.$emit('$viewContentAnimationEnded');
33129                       }
33130
33131                       if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) {
33132                         $uiViewScroll(clone);
33133                       }
33134                     });
33135                     cleanupLastView();
33136                   });
33137
33138                   currentEl = clone;
33139                   currentScope = newScope;
33140                   /**
33141                    * @ngdoc event
33142                    * @name ui.router.state.directive:ui-view#$viewContentLoaded
33143                    * @eventOf ui.router.state.directive:ui-view
33144                    * @eventType emits on ui-view directive scope
33145                    * @description
33146                    * Fired once the view is **loaded**, *after* the DOM is rendered.
33147                    *
33148                    * @param {Object} event Event object.
33149                    * @param {string} viewName Name of the view.
33150                    */
33151                   currentScope.$emit('$viewContentLoaded', name);
33152                   currentScope.$eval(onloadExp);
33153                 }
33154               };
33155             }
33156           };
33157
33158           return directive;
33159         }
33160
33161         $ViewDirectiveFill.$inject = ['$compile', '$controller', '$state', '$interpolate'];
33162         function $ViewDirectiveFill (  $compile,   $controller,   $state,   $interpolate) {
33163           return {
33164             restrict: 'ECA',
33165             priority: -400,
33166             compile: function (tElement) {
33167               var initial = tElement.html();
33168               return function (scope, $element, attrs) {
33169                 var current = $state.$current,
33170                     name = getUiViewName(scope, attrs, $element, $interpolate),
33171                     locals  = current && current.locals[name];
33172
33173                 if (! locals) {
33174                   return;
33175                 }
33176
33177                 $element.data('$uiView', { name: name, state: locals.$$state });
33178                 $element.html(locals.$template ? locals.$template : initial);
33179
33180                 var link = $compile($element.contents());
33181
33182                 if (locals.$$controller) {
33183                   locals.$scope = scope;
33184                   locals.$element = $element;
33185                   var controller = $controller(locals.$$controller, locals);
33186                   if (locals.$$controllerAs) {
33187                     scope[locals.$$controllerAs] = controller;
33188                   }
33189                   $element.data('$ngControllerController', controller);
33190                   $element.children().data('$ngControllerController', controller);
33191                 }
33192
33193                 link(scope);
33194               };
33195             }
33196           };
33197         }
33198
33199         /**
33200          * Shared ui-view code for both directives:
33201          * Given scope, element, and its attributes, return the view's name
33202          */
33203         function getUiViewName(scope, attrs, element, $interpolate) {
33204           var name = $interpolate(attrs.uiView || attrs.name || '')(scope);
33205           var inherited = element.inheritedData('$uiView');
33206           return name.indexOf('@') >= 0 ?  name :  (name + '@' + (inherited ? inherited.state.name : ''));
33207         }
33208
33209         angular.module('ui.router.state').directive('uiView', $ViewDirective);
33210         angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);
33211
33212         function parseStateRef(ref, current) {
33213           var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
33214           if (preparsed) ref = current + '(' + preparsed[1] + ')';
33215           parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
33216           if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
33217           return { state: parsed[1], paramExpr: parsed[3] || null };
33218         }
33219
33220         function stateContext(el) {
33221           var stateData = el.parent().inheritedData('$uiView');
33222
33223           if (stateData && stateData.state && stateData.state.name) {
33224             return stateData.state;
33225           }
33226         }
33227
33228         function getTypeInfo(el) {
33229           // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
33230           var isSvg = Object.prototype.toString.call(el.prop('href')) === '[object SVGAnimatedString]';
33231           var isForm = el[0].nodeName === "FORM";
33232
33233           return {
33234             attr: isForm ? "action" : (isSvg ? 'xlink:href' : 'href'),
33235             isAnchor: el.prop("tagName").toUpperCase() === "A",
33236             clickable: !isForm
33237           };
33238         }
33239
33240         function clickHook(el, $state, $timeout, type, current) {
33241           return function(e) {
33242             var button = e.which || e.button, target = current();
33243
33244             if (!(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || el.attr('target'))) {
33245               // HACK: This is to allow ng-clicks to be processed before the transition is initiated:
33246               var transition = $timeout(function() {
33247                 $state.go(target.state, target.params, target.options);
33248               });
33249               e.preventDefault();
33250
33251               // if the state has no URL, ignore one preventDefault from the <a> directive.
33252               var ignorePreventDefaultCount = type.isAnchor && !target.href ? 1: 0;
33253
33254               e.preventDefault = function() {
33255                 if (ignorePreventDefaultCount-- <= 0) $timeout.cancel(transition);
33256               };
33257             }
33258           };
33259         }
33260
33261         function defaultOpts(el, $state) {
33262           return { relative: stateContext(el) || $state.$current, inherit: true };
33263         }
33264
33265         /**
33266          * @ngdoc directive
33267          * @name ui.router.state.directive:ui-sref
33268          *
33269          * @requires ui.router.state.$state
33270          * @requires $timeout
33271          *
33272          * @restrict A
33273          *
33274          * @description
33275          * A directive that binds a link (`<a>` tag) to a state. If the state has an associated
33276          * URL, the directive will automatically generate & update the `href` attribute via
33277          * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking
33278          * the link will trigger a state transition with optional parameters.
33279          *
33280          * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be
33281          * handled natively by the browser.
33282          *
33283          * You can also use relative state paths within ui-sref, just like the relative
33284          * paths passed to `$state.go()`. You just need to be aware that the path is relative
33285          * to the state that the link lives in, in other words the state that loaded the
33286          * template containing the link.
33287          *
33288          * You can specify options to pass to {@link ui.router.state.$state#go $state.go()}
33289          * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`,
33290          * and `reload`.
33291          *
33292          * @example
33293          * Here's an example of how you'd use ui-sref and how it would compile. If you have the
33294          * following template:
33295          * <pre>
33296          * <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> | <a ui-sref="{page: 2}">Next page</a>
33297          *
33298          * <ul>
33299          *     <li ng-repeat="contact in contacts">
33300          *         <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a>
33301          *     </li>
33302          * </ul>
33303          * </pre>
33304          *
33305          * Then the compiled html would be (assuming Html5Mode is off and current state is contacts):
33306          * <pre>
33307          * <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>
33308          *
33309          * <ul>
33310          *     <li ng-repeat="contact in contacts">
33311          *         <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a>
33312          *     </li>
33313          *     <li ng-repeat="contact in contacts">
33314          *         <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a>
33315          *     </li>
33316          *     <li ng-repeat="contact in contacts">
33317          *         <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a>
33318          *     </li>
33319          * </ul>
33320          *
33321          * <a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
33322          * </pre>
33323          *
33324          * @param {string} ui-sref 'stateName' can be any valid absolute or relative state
33325          * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#go $state.go()}
33326          */
33327         $StateRefDirective.$inject = ['$state', '$timeout'];
33328         function $StateRefDirective($state, $timeout) {
33329           return {
33330             restrict: 'A',
33331             require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
33332             link: function(scope, element, attrs, uiSrefActive) {
33333               var ref    = parseStateRef(attrs.uiSref, $state.current.name);
33334               var def    = { state: ref.state, href: null, params: null };
33335               var type   = getTypeInfo(element);
33336               var active = uiSrefActive[1] || uiSrefActive[0];
33337
33338               def.options = extend(defaultOpts(element, $state), attrs.uiSrefOpts ? scope.$eval(attrs.uiSrefOpts) : {});
33339
33340               var update = function(val) {
33341                 if (val) def.params = angular.copy(val);
33342                 def.href = $state.href(ref.state, def.params, def.options);
33343
33344                 if (active) active.$$addStateInfo(ref.state, def.params);
33345                 if (def.href !== null) attrs.$set(type.attr, def.href);
33346               };
33347
33348               if (ref.paramExpr) {
33349                 scope.$watch(ref.paramExpr, function(val) { if (val !== def.params) update(val); }, true);
33350                 def.params = angular.copy(scope.$eval(ref.paramExpr));
33351               }
33352               update();
33353
33354               if (!type.clickable) return;
33355               element.bind("click", clickHook(element, $state, $timeout, type, function() { return def; }));
33356             }
33357           };
33358         }
33359
33360         /**
33361          * @ngdoc directive
33362          * @name ui.router.state.directive:ui-state
33363          *
33364          * @requires ui.router.state.uiSref
33365          *
33366          * @restrict A
33367          *
33368          * @description
33369          * Much like ui-sref, but will accept named $scope properties to evaluate for a state definition,
33370          * params and override options.
33371          *
33372          * @param {string} ui-state 'stateName' can be any valid absolute or relative state
33373          * @param {Object} ui-state-params params to pass to {@link ui.router.state.$state#href $state.href()}
33374          * @param {Object} ui-state-opts options to pass to {@link ui.router.state.$state#go $state.go()}
33375          */
33376         $StateRefDynamicDirective.$inject = ['$state', '$timeout'];
33377         function $StateRefDynamicDirective($state, $timeout) {
33378           return {
33379             restrict: 'A',
33380             require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
33381             link: function(scope, element, attrs, uiSrefActive) {
33382               var type   = getTypeInfo(element);
33383               var active = uiSrefActive[1] || uiSrefActive[0];
33384               var group  = [attrs.uiState, attrs.uiStateParams || null, attrs.uiStateOpts || null];
33385               var watch  = '[' + group.map(function(val) { return val || 'null'; }).join(', ') + ']';
33386               var def    = { state: null, params: null, options: null, href: null };
33387
33388               function runStateRefLink (group) {
33389                 def.state = group[0]; def.params = group[1]; def.options = group[2];
33390                 def.href = $state.href(def.state, def.params, def.options);
33391
33392                 if (active) active.$$addStateInfo(def.state, def.params);
33393                 if (def.href) attrs.$set(type.attr, def.href);
33394               }
33395
33396               scope.$watch(watch, runStateRefLink, true);
33397               runStateRefLink(scope.$eval(watch));
33398
33399               if (!type.clickable) return;
33400               element.bind("click", clickHook(element, $state, $timeout, type, function() { return def; }));
33401             }
33402           };
33403         }
33404
33405
33406         /**
33407          * @ngdoc directive
33408          * @name ui.router.state.directive:ui-sref-active
33409          *
33410          * @requires ui.router.state.$state
33411          * @requires ui.router.state.$stateParams
33412          * @requires $interpolate
33413          *
33414          * @restrict A
33415          *
33416          * @description
33417          * A directive working alongside ui-sref to add classes to an element when the
33418          * related ui-sref directive's state is active, and removing them when it is inactive.
33419          * The primary use-case is to simplify the special appearance of navigation menus
33420          * relying on `ui-sref`, by having the "active" state's menu button appear different,
33421          * distinguishing it from the inactive menu items.
33422          *
33423          * ui-sref-active can live on the same element as ui-sref or on a parent element. The first
33424          * ui-sref-active found at the same level or above the ui-sref will be used.
33425          *
33426          * Will activate when the ui-sref's target state or any child state is active. If you
33427          * need to activate only when the ui-sref target state is active and *not* any of
33428          * it's children, then you will use
33429          * {@link ui.router.state.directive:ui-sref-active-eq ui-sref-active-eq}
33430          *
33431          * @example
33432          * Given the following template:
33433          * <pre>
33434          * <ul>
33435          *   <li ui-sref-active="active" class="item">
33436          *     <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
33437          *   </li>
33438          * </ul>
33439          * </pre>
33440          *
33441          *
33442          * When the app state is "app.user" (or any children states), and contains the state parameter "user" with value "bilbobaggins",
33443          * the resulting HTML will appear as (note the 'active' class):
33444          * <pre>
33445          * <ul>
33446          *   <li ui-sref-active="active" class="item active">
33447          *     <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
33448          *   </li>
33449          * </ul>
33450          * </pre>
33451          *
33452          * The class name is interpolated **once** during the directives link time (any further changes to the
33453          * interpolated value are ignored).
33454          *
33455          * Multiple classes may be specified in a space-separated format:
33456          * <pre>
33457          * <ul>
33458          *   <li ui-sref-active='class1 class2 class3'>
33459          *     <a ui-sref="app.user">link</a>
33460          *   </li>
33461          * </ul>
33462          * </pre>
33463          *
33464          * It is also possible to pass ui-sref-active an expression that evaluates
33465          * to an object hash, whose keys represent active class names and whose
33466          * values represent the respective state names/globs.
33467          * ui-sref-active will match if the current active state **includes** any of
33468          * the specified state names/globs, even the abstract ones.
33469          *
33470          * @Example
33471          * Given the following template, with "admin" being an abstract state:
33472          * <pre>
33473          * <div ui-sref-active="{'active': 'admin.*'}">
33474          *   <a ui-sref-active="active" ui-sref="admin.roles">Roles</a>
33475          * </div>
33476          * </pre>
33477          *
33478          * When the current state is "admin.roles" the "active" class will be applied
33479          * to both the <div> and <a> elements. It is important to note that the state
33480          * names/globs passed to ui-sref-active shadow the state provided by ui-sref.
33481          */
33482
33483         /**
33484          * @ngdoc directive
33485          * @name ui.router.state.directive:ui-sref-active-eq
33486          *
33487          * @requires ui.router.state.$state
33488          * @requires ui.router.state.$stateParams
33489          * @requires $interpolate
33490          *
33491          * @restrict A
33492          *
33493          * @description
33494          * The same as {@link ui.router.state.directive:ui-sref-active ui-sref-active} but will only activate
33495          * when the exact target state used in the `ui-sref` is active; no child states.
33496          *
33497          */
33498         $StateRefActiveDirective.$inject = ['$state', '$stateParams', '$interpolate'];
33499         function $StateRefActiveDirective($state, $stateParams, $interpolate) {
33500           return  {
33501             restrict: "A",
33502             controller: ['$scope', '$element', '$attrs', '$timeout', function ($scope, $element, $attrs, $timeout) {
33503               var states = [], activeClasses = {}, activeEqClass, uiSrefActive;
33504
33505               // There probably isn't much point in $observing this
33506               // uiSrefActive and uiSrefActiveEq share the same directive object with some
33507               // slight difference in logic routing
33508               activeEqClass = $interpolate($attrs.uiSrefActiveEq || '', false)($scope);
33509
33510               try {
33511                 uiSrefActive = $scope.$eval($attrs.uiSrefActive);
33512               } catch (e) {
33513                 // Do nothing. uiSrefActive is not a valid expression.
33514                 // Fall back to using $interpolate below
33515               }
33516               uiSrefActive = uiSrefActive || $interpolate($attrs.uiSrefActive || '', false)($scope);
33517               if (isObject(uiSrefActive)) {
33518                 forEach(uiSrefActive, function(stateOrName, activeClass) {
33519                   if (isString(stateOrName)) {
33520                     var ref = parseStateRef(stateOrName, $state.current.name);
33521                     addState(ref.state, $scope.$eval(ref.paramExpr), activeClass);
33522                   }
33523                 });
33524               }
33525
33526               // Allow uiSref to communicate with uiSrefActive[Equals]
33527               this.$$addStateInfo = function (newState, newParams) {
33528                 // we already got an explicit state provided by ui-sref-active, so we
33529                 // shadow the one that comes from ui-sref
33530                 if (isObject(uiSrefActive) && states.length > 0) {
33531                   return;
33532                 }
33533                 addState(newState, newParams, uiSrefActive);
33534                 update();
33535               };
33536
33537               $scope.$on('$stateChangeSuccess', update);
33538
33539               function addState(stateName, stateParams, activeClass) {
33540                 var state = $state.get(stateName, stateContext($element));
33541                 var stateHash = createStateHash(stateName, stateParams);
33542
33543                 states.push({
33544                   state: state || { name: stateName },
33545                   params: stateParams,
33546                   hash: stateHash
33547                 });
33548
33549                 activeClasses[stateHash] = activeClass;
33550               }
33551
33552               /**
33553                * @param {string} state
33554                * @param {Object|string} [params]
33555                * @return {string}
33556                */
33557               function createStateHash(state, params) {
33558                 if (!isString(state)) {
33559                   throw new Error('state should be a string');
33560                 }
33561                 if (isObject(params)) {
33562                   return state + toJson(params);
33563                 }
33564                 params = $scope.$eval(params);
33565                 if (isObject(params)) {
33566                   return state + toJson(params);
33567                 }
33568                 return state;
33569               }
33570
33571               // Update route state
33572               function update() {
33573                 for (var i = 0; i < states.length; i++) {
33574                   if (anyMatch(states[i].state, states[i].params)) {
33575                     addClass($element, activeClasses[states[i].hash]);
33576                   } else {
33577                     removeClass($element, activeClasses[states[i].hash]);
33578                   }
33579
33580                   if (exactMatch(states[i].state, states[i].params)) {
33581                     addClass($element, activeEqClass);
33582                   } else {
33583                     removeClass($element, activeEqClass);
33584                   }
33585                 }
33586               }
33587
33588               function addClass(el, className) { $timeout(function () { el.addClass(className); }); }
33589               function removeClass(el, className) { el.removeClass(className); }
33590               function anyMatch(state, params) { return $state.includes(state.name, params); }
33591               function exactMatch(state, params) { return $state.is(state.name, params); }
33592
33593               update();
33594             }]
33595           };
33596         }
33597
33598         angular.module('ui.router.state')
33599           .directive('uiSref', $StateRefDirective)
33600           .directive('uiSrefActive', $StateRefActiveDirective)
33601           .directive('uiSrefActiveEq', $StateRefActiveDirective)
33602           .directive('uiState', $StateRefDynamicDirective);
33603
33604         /**
33605          * @ngdoc filter
33606          * @name ui.router.state.filter:isState
33607          *
33608          * @requires ui.router.state.$state
33609          *
33610          * @description
33611          * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}.
33612          */
33613         $IsStateFilter.$inject = ['$state'];
33614         function $IsStateFilter($state) {
33615           var isFilter = function (state, params) {
33616             return $state.is(state, params);
33617           };
33618           isFilter.$stateful = true;
33619           return isFilter;
33620         }
33621
33622         /**
33623          * @ngdoc filter
33624          * @name ui.router.state.filter:includedByState
33625          *
33626          * @requires ui.router.state.$state
33627          *
33628          * @description
33629          * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}.
33630          */
33631         $IncludedByStateFilter.$inject = ['$state'];
33632         function $IncludedByStateFilter($state) {
33633           var includesFilter = function (state, params, options) {
33634             return $state.includes(state, params, options);
33635           };
33636           includesFilter.$stateful = true;
33637           return  includesFilter;
33638         }
33639
33640         angular.module('ui.router.state')
33641           .filter('isState', $IsStateFilter)
33642           .filter('includedByState', $IncludedByStateFilter);
33643         })(window, window.angular);
33644
33645 /***/ },
33646 /* 4 */
33647 /***/ function(module, exports, __webpack_require__) {
33648
33649         __webpack_require__(5);
33650         module.exports = 'ngResource';
33651
33652
33653 /***/ },
33654 /* 5 */
33655 /***/ function(module, exports) {
33656
33657         /**
33658          * @license AngularJS v1.6.2
33659          * (c) 2010-2017 Google, Inc. http://angularjs.org
33660          * License: MIT
33661          */
33662         (function(window, angular) {'use strict';
33663
33664         var $resourceMinErr = angular.$$minErr('$resource');
33665
33666         // Helper functions and regex to lookup a dotted path on an object
33667         // stopping at undefined/null.  The path must be composed of ASCII
33668         // identifiers (just like $parse)
33669         var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
33670
33671         function isValidDottedPath(path) {
33672           return (path != null && path !== '' && path !== 'hasOwnProperty' &&
33673               MEMBER_NAME_REGEX.test('.' + path));
33674         }
33675
33676         function lookupDottedPath(obj, path) {
33677           if (!isValidDottedPath(path)) {
33678             throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
33679           }
33680           var keys = path.split('.');
33681           for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) {
33682             var key = keys[i];
33683             obj = (obj !== null) ? obj[key] : undefined;
33684           }
33685           return obj;
33686         }
33687
33688         /**
33689          * Create a shallow copy of an object and clear other fields from the destination
33690          */
33691         function shallowClearAndCopy(src, dst) {
33692           dst = dst || {};
33693
33694           angular.forEach(dst, function(value, key) {
33695             delete dst[key];
33696           });
33697
33698           for (var key in src) {
33699             if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
33700               dst[key] = src[key];
33701             }
33702           }
33703
33704           return dst;
33705         }
33706
33707         /**
33708          * @ngdoc module
33709          * @name ngResource
33710          * @description
33711          *
33712          * # ngResource
33713          *
33714          * The `ngResource` module provides interaction support with RESTful services
33715          * via the $resource service.
33716          *
33717          *
33718          * <div doc-module-components="ngResource"></div>
33719          *
33720          * See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage.
33721          */
33722
33723         /**
33724          * @ngdoc provider
33725          * @name $resourceProvider
33726          *
33727          * @description
33728          *
33729          * Use `$resourceProvider` to change the default behavior of the {@link ngResource.$resource}
33730          * service.
33731          *
33732          * ## Dependencies
33733          * Requires the {@link ngResource } module to be installed.
33734          *
33735          */
33736
33737         /**
33738          * @ngdoc service
33739          * @name $resource
33740          * @requires $http
33741          * @requires ng.$log
33742          * @requires $q
33743          * @requires ng.$timeout
33744          *
33745          * @description
33746          * A factory which creates a resource object that lets you interact with
33747          * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
33748          *
33749          * The returned resource object has action methods which provide high-level behaviors without
33750          * the need to interact with the low level {@link ng.$http $http} service.
33751          *
33752          * Requires the {@link ngResource `ngResource`} module to be installed.
33753          *
33754          * By default, trailing slashes will be stripped from the calculated URLs,
33755          * which can pose problems with server backends that do not expect that
33756          * behavior.  This can be disabled by configuring the `$resourceProvider` like
33757          * this:
33758          *
33759          * ```js
33760              app.config(['$resourceProvider', function($resourceProvider) {
33761                // Don't strip trailing slashes from calculated URLs
33762                $resourceProvider.defaults.stripTrailingSlashes = false;
33763              }]);
33764          * ```
33765          *
33766          * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
33767          *   `/user/:username`. If you are using a URL with a port number (e.g.
33768          *   `http://example.com:8080/api`), it will be respected.
33769          *
33770          *   If you are using a url with a suffix, just add the suffix, like this:
33771          *   `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
33772          *   or even `$resource('http://example.com/resource/:resource_id.:format')`
33773          *   If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
33774          *   collapsed down to a single `.`.  If you need this sequence to appear and not collapse then you
33775          *   can escape it with `/\.`.
33776          *
33777          * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
33778          *   `actions` methods. If a parameter value is a function, it will be called every time
33779          *   a param value needs to be obtained for a request (unless the param was overridden). The function
33780          *   will be passed the current data value as an argument.
33781          *
33782          *   Each key value in the parameter object is first bound to url template if present and then any
33783          *   excess keys are appended to the url search query after the `?`.
33784          *
33785          *   Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
33786          *   URL `/path/greet?salutation=Hello`.
33787          *
33788          *   If the parameter value is prefixed with `@`, then the value for that parameter will be
33789          *   extracted from the corresponding property on the `data` object (provided when calling a
33790          *   "non-GET" action method).
33791          *   For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
33792          *   `someParam` will be `data.someProp`.
33793          *   Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
33794          *   method that does not accept a request body)
33795          *
33796          * @param {Object.<Object>=} actions Hash with declaration of custom actions that will be available
33797          *   in addition to the default set of resource actions (see below). If a custom action has the same
33798          *   key as a default action (e.g. `save`), then the default action will be *overwritten*, and not
33799          *   extended.
33800          *
33801          *   The declaration should be created in the format of {@link ng.$http#usage $http.config}:
33802          *
33803          *       {action1: {method:?, params:?, isArray:?, headers:?, ...},
33804          *        action2: {method:?, params:?, isArray:?, headers:?, ...},
33805          *        ...}
33806          *
33807          *   Where:
33808          *
33809          *   - **`action`** – {string} – The name of action. This name becomes the name of the method on
33810          *     your resource object.
33811          *   - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
33812          *     `DELETE`, `JSONP`, etc).
33813          *   - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
33814          *     the parameter value is a function, it will be called every time when a param value needs to
33815          *     be obtained for a request (unless the param was overridden). The function will be passed the
33816          *     current data value as an argument.
33817          *   - **`url`** – {string} – action specific `url` override. The url templating is supported just
33818          *     like for the resource-level urls.
33819          *   - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
33820          *     see `returns` section.
33821          *   - **`transformRequest`** –
33822          *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
33823          *     transform function or an array of such functions. The transform function takes the http
33824          *     request body and headers and returns its transformed (typically serialized) version.
33825          *     By default, transformRequest will contain one function that checks if the request data is
33826          *     an object and serializes it using `angular.toJson`. To prevent this behavior, set
33827          *     `transformRequest` to an empty array: `transformRequest: []`
33828          *   - **`transformResponse`** –
33829          *     `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
33830          *     transform function or an array of such functions. The transform function takes the http
33831          *     response body, headers and status and returns its transformed (typically deserialized)
33832          *     version.
33833          *     By default, transformResponse will contain one function that checks if the response looks
33834          *     like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
33835          *     set `transformResponse` to an empty array: `transformResponse: []`
33836          *   - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
33837          *     GET request, otherwise if a cache instance built with
33838          *     {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
33839          *     caching.
33840          *   - **`timeout`** – `{number}` – timeout in milliseconds.<br />
33841          *     **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
33842          *     **not** supported in $resource, because the same value would be used for multiple requests.
33843          *     If you are looking for a way to cancel requests, you should use the `cancellable` option.
33844          *   - **`cancellable`** – `{boolean}` – if set to true, the request made by a "non-instance" call
33845          *     will be cancelled (if not already completed) by calling `$cancelRequest()` on the call's
33846          *     return value. Calling `$cancelRequest()` for a non-cancellable or an already
33847          *     completed/cancelled request will have no effect.<br />
33848          *   - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
33849          *     XHR object. See
33850          *     [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
33851          *     for more information.
33852          *   - **`responseType`** - `{string}` - see
33853          *     [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
33854          *   - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
33855          *     `response` and `responseError`. Both `response` and `responseError` interceptors get called
33856          *     with `http response` object. See {@link ng.$http $http interceptors}.
33857          *
33858          * @param {Object} options Hash with custom settings that should extend the
33859          *   default `$resourceProvider` behavior.  The supported options are:
33860          *
33861          *   - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
33862          *   slashes from any calculated URL will be stripped. (Defaults to true.)
33863          *   - **`cancellable`** – {boolean} – If true, the request made by a "non-instance" call will be
33864          *   cancelled (if not already completed) by calling `$cancelRequest()` on the call's return value.
33865          *   This can be overwritten per action. (Defaults to false.)
33866          *
33867          * @returns {Object} A resource "class" object with methods for the default set of resource actions
33868          *   optionally extended with custom `actions`. The default set contains these actions:
33869          *   ```js
33870          *   { 'get':    {method:'GET'},
33871          *     'save':   {method:'POST'},
33872          *     'query':  {method:'GET', isArray:true},
33873          *     'remove': {method:'DELETE'},
33874          *     'delete': {method:'DELETE'} };
33875          *   ```
33876          *
33877          *   Calling these methods invoke an {@link ng.$http} with the specified http method,
33878          *   destination and parameters. When the data is returned from the server then the object is an
33879          *   instance of the resource class. The actions `save`, `remove` and `delete` are available on it
33880          *   as  methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
33881          *   read, update, delete) on server-side data like this:
33882          *   ```js
33883          *   var User = $resource('/user/:userId', {userId:'@id'});
33884          *   var user = User.get({userId:123}, function() {
33885          *     user.abc = true;
33886          *     user.$save();
33887          *   });
33888          *   ```
33889          *
33890          *   It is important to realize that invoking a $resource object method immediately returns an
33891          *   empty reference (object or array depending on `isArray`). Once the data is returned from the
33892          *   server the existing reference is populated with the actual data. This is a useful trick since
33893          *   usually the resource is assigned to a model which is then rendered by the view. Having an empty
33894          *   object results in no rendering, once the data arrives from the server then the object is
33895          *   populated with the data and the view automatically re-renders itself showing the new data. This
33896          *   means that in most cases one never has to write a callback function for the action methods.
33897          *
33898          *   The action methods on the class object or instance object can be invoked with the following
33899          *   parameters:
33900          *
33901          *   - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
33902          *   - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
33903          *   - non-GET instance actions:  `instance.$action([parameters], [success], [error])`
33904          *
33905          *
33906          *   Success callback is called with (value (Object|Array), responseHeaders (Function),
33907          *   status (number), statusText (string)) arguments, where the value is the populated resource
33908          *   instance or collection object. The error callback is called with (httpResponse) argument.
33909          *
33910          *   Class actions return empty instance (with additional properties below).
33911          *   Instance actions return promise of the action.
33912          *
33913          *   The Resource instances and collections have these additional properties:
33914          *
33915          *   - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
33916          *     instance or collection.
33917          *
33918          *     On success, the promise is resolved with the same resource instance or collection object,
33919          *     updated with data from server. This makes it easy to use in
33920          *     {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
33921          *     rendering until the resource(s) are loaded.
33922          *
33923          *     On failure, the promise is rejected with the {@link ng.$http http response} object, without
33924          *     the `resource` property.
33925          *
33926          *     If an interceptor object was provided, the promise will instead be resolved with the value
33927          *     returned by the interceptor.
33928          *
33929          *   - `$resolved`: `true` after first server interaction is completed (either with success or
33930          *      rejection), `false` before that. Knowing if the Resource has been resolved is useful in
33931          *      data-binding.
33932          *
33933          *   The Resource instances and collections have these additional methods:
33934          *
33935          *   - `$cancelRequest`: If there is a cancellable, pending request related to the instance or
33936          *      collection, calling this method will abort the request.
33937          *
33938          *   The Resource instances have these additional methods:
33939          *
33940          *   - `toJSON`: It returns a simple object without any of the extra properties added as part of
33941          *     the Resource API. This object can be serialized through {@link angular.toJson} safely
33942          *     without attaching Angular-specific fields. Notice that `JSON.stringify` (and
33943          *     `angular.toJson`) automatically use this method when serializing a Resource instance
33944          *     (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior)).
33945          *
33946          * @example
33947          *
33948          * # Credit card resource
33949          *
33950          * ```js
33951              // Define CreditCard class
33952              var CreditCard = $resource('/user/:userId/card/:cardId',
33953               {userId:123, cardId:'@id'}, {
33954                charge: {method:'POST', params:{charge:true}}
33955               });
33956
33957              // We can retrieve a collection from the server
33958              var cards = CreditCard.query(function() {
33959                // GET: /user/123/card
33960                // server returns: [ {id:456, number:'1234', name:'Smith'} ];
33961
33962                var card = cards[0];
33963                // each item is an instance of CreditCard
33964                expect(card instanceof CreditCard).toEqual(true);
33965                card.name = "J. Smith";
33966                // non GET methods are mapped onto the instances
33967                card.$save();
33968                // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
33969                // server returns: {id:456, number:'1234', name: 'J. Smith'};
33970
33971                // our custom method is mapped as well.
33972                card.$charge({amount:9.99});
33973                // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
33974              });
33975
33976              // we can create an instance as well
33977              var newCard = new CreditCard({number:'0123'});
33978              newCard.name = "Mike Smith";
33979              newCard.$save();
33980              // POST: /user/123/card {number:'0123', name:'Mike Smith'}
33981              // server returns: {id:789, number:'0123', name: 'Mike Smith'};
33982              expect(newCard.id).toEqual(789);
33983          * ```
33984          *
33985          * The object returned from this function execution is a resource "class" which has "static" method
33986          * for each action in the definition.
33987          *
33988          * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
33989          * `headers`.
33990          *
33991          * @example
33992          *
33993          * # User resource
33994          *
33995          * When the data is returned from the server then the object is an instance of the resource type and
33996          * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
33997          * operations (create, read, update, delete) on server-side data.
33998
33999            ```js
34000              var User = $resource('/user/:userId', {userId:'@id'});
34001              User.get({userId:123}, function(user) {
34002                user.abc = true;
34003                user.$save();
34004              });
34005            ```
34006          *
34007          * It's worth noting that the success callback for `get`, `query` and other methods gets passed
34008          * in the response that came from the server as well as $http header getter function, so one
34009          * could rewrite the above example and get access to http headers as:
34010          *
34011            ```js
34012              var User = $resource('/user/:userId', {userId:'@id'});
34013              User.get({userId:123}, function(user, getResponseHeaders){
34014                user.abc = true;
34015                user.$save(function(user, putResponseHeaders) {
34016                  //user => saved user object
34017                  //putResponseHeaders => $http header getter
34018                });
34019              });
34020            ```
34021          *
34022          * You can also access the raw `$http` promise via the `$promise` property on the object returned
34023          *
34024            ```
34025              var User = $resource('/user/:userId', {userId:'@id'});
34026              User.get({userId:123})
34027                  .$promise.then(function(user) {
34028                    $scope.user = user;
34029                  });
34030            ```
34031          *
34032          * @example
34033          *
34034          * # Creating a custom 'PUT' request
34035          *
34036          * In this example we create a custom method on our resource to make a PUT request
34037          * ```js
34038          *    var app = angular.module('app', ['ngResource', 'ngRoute']);
34039          *
34040          *    // Some APIs expect a PUT request in the format URL/object/ID
34041          *    // Here we are creating an 'update' method
34042          *    app.factory('Notes', ['$resource', function($resource) {
34043          *    return $resource('/notes/:id', null,
34044          *        {
34045          *            'update': { method:'PUT' }
34046          *        });
34047          *    }]);
34048          *
34049          *    // In our controller we get the ID from the URL using ngRoute and $routeParams
34050          *    // We pass in $routeParams and our Notes factory along with $scope
34051          *    app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
34052                                               function($scope, $routeParams, Notes) {
34053          *    // First get a note object from the factory
34054          *    var note = Notes.get({ id:$routeParams.id });
34055          *    $id = note.id;
34056          *
34057          *    // Now call update passing in the ID first then the object you are updating
34058          *    Notes.update({ id:$id }, note);
34059          *
34060          *    // This will PUT /notes/ID with the note object in the request payload
34061          *    }]);
34062          * ```
34063          *
34064          * @example
34065          *
34066          * # Cancelling requests
34067          *
34068          * If an action's configuration specifies that it is cancellable, you can cancel the request related
34069          * to an instance or collection (as long as it is a result of a "non-instance" call):
34070          *
34071            ```js
34072              // ...defining the `Hotel` resource...
34073              var Hotel = $resource('/api/hotel/:id', {id: '@id'}, {
34074                // Let's make the `query()` method cancellable
34075                query: {method: 'get', isArray: true, cancellable: true}
34076              });
34077
34078              // ...somewhere in the PlanVacationController...
34079              ...
34080              this.onDestinationChanged = function onDestinationChanged(destination) {
34081                // We don't care about any pending request for hotels
34082                // in a different destination any more
34083                this.availableHotels.$cancelRequest();
34084
34085                // Let's query for hotels in '<destination>'
34086                // (calls: /api/hotel?location=<destination>)
34087                this.availableHotels = Hotel.query({location: destination});
34088              };
34089            ```
34090          *
34091          */
34092         angular.module('ngResource', ['ng']).
34093           provider('$resource', function ResourceProvider() {
34094             var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/;
34095
34096             var provider = this;
34097
34098             /**
34099              * @ngdoc property
34100              * @name $resourceProvider#defaults
34101              * @description
34102              * Object containing default options used when creating `$resource` instances.
34103              *
34104              * The default values satisfy a wide range of usecases, but you may choose to overwrite any of
34105              * them to further customize your instances. The available properties are:
34106              *
34107              * - **stripTrailingSlashes** – `{boolean}` – If true, then the trailing slashes from any
34108              *   calculated URL will be stripped.<br />
34109              *   (Defaults to true.)
34110              * - **cancellable** – `{boolean}` – If true, the request made by a "non-instance" call will be
34111              *   cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
34112              *   value. For more details, see {@link ngResource.$resource}. This can be overwritten per
34113              *   resource class or action.<br />
34114              *   (Defaults to false.)
34115              * - **actions** - `{Object.<Object>}` - A hash with default actions declarations. Actions are
34116              *   high-level methods corresponding to RESTful actions/methods on resources. An action may
34117              *   specify what HTTP method to use, what URL to hit, if the return value will be a single
34118              *   object or a collection (array) of objects etc. For more details, see
34119              *   {@link ngResource.$resource}. The actions can also be enhanced or overwritten per resource
34120              *   class.<br />
34121              *   The default actions are:
34122              *   ```js
34123              *   {
34124              *     get: {method: 'GET'},
34125              *     save: {method: 'POST'},
34126              *     query: {method: 'GET', isArray: true},
34127              *     remove: {method: 'DELETE'},
34128              *     delete: {method: 'DELETE'}
34129              *   }
34130              *   ```
34131              *
34132              * #### Example
34133              *
34134              * For example, you can specify a new `update` action that uses the `PUT` HTTP verb:
34135              *
34136              * ```js
34137              *   angular.
34138              *     module('myApp').
34139              *     config(['$resourceProvider', function ($resourceProvider) {
34140              *       $resourceProvider.defaults.actions.update = {
34141              *         method: 'PUT'
34142              *       };
34143              *     });
34144              * ```
34145              *
34146              * Or you can even overwrite the whole `actions` list and specify your own:
34147              *
34148              * ```js
34149              *   angular.
34150              *     module('myApp').
34151              *     config(['$resourceProvider', function ($resourceProvider) {
34152              *       $resourceProvider.defaults.actions = {
34153              *         create: {method: 'POST'},
34154              *         get:    {method: 'GET'},
34155              *         getAll: {method: 'GET', isArray:true},
34156              *         update: {method: 'PUT'},
34157              *         delete: {method: 'DELETE'}
34158              *       };
34159              *     });
34160              * ```
34161              *
34162              */
34163             this.defaults = {
34164               // Strip slashes by default
34165               stripTrailingSlashes: true,
34166
34167               // Make non-instance requests cancellable (via `$cancelRequest()`)
34168               cancellable: false,
34169
34170               // Default actions configuration
34171               actions: {
34172                 'get': {method: 'GET'},
34173                 'save': {method: 'POST'},
34174                 'query': {method: 'GET', isArray: true},
34175                 'remove': {method: 'DELETE'},
34176                 'delete': {method: 'DELETE'}
34177               }
34178             };
34179
34180             this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) {
34181
34182               var noop = angular.noop,
34183                   forEach = angular.forEach,
34184                   extend = angular.extend,
34185                   copy = angular.copy,
34186                   isArray = angular.isArray,
34187                   isDefined = angular.isDefined,
34188                   isFunction = angular.isFunction,
34189                   isNumber = angular.isNumber,
34190                   encodeUriQuery = angular.$$encodeUriQuery,
34191                   encodeUriSegment = angular.$$encodeUriSegment;
34192
34193               function Route(template, defaults) {
34194                 this.template = template;
34195                 this.defaults = extend({}, provider.defaults, defaults);
34196                 this.urlParams = {};
34197               }
34198
34199               Route.prototype = {
34200                 setUrlParams: function(config, params, actionUrl) {
34201                   var self = this,
34202                     url = actionUrl || self.template,
34203                     val,
34204                     encodedVal,
34205                     protocolAndIpv6 = '';
34206
34207                   var urlParams = self.urlParams = Object.create(null);
34208                   forEach(url.split(/\W/), function(param) {
34209                     if (param === 'hasOwnProperty') {
34210                       throw $resourceMinErr('badname', 'hasOwnProperty is not a valid parameter name.');
34211                     }
34212                     if (!(new RegExp('^\\d+$').test(param)) && param &&
34213                       (new RegExp('(^|[^\\\\]):' + param + '(\\W|$)').test(url))) {
34214                       urlParams[param] = {
34215                         isQueryParamValue: (new RegExp('\\?.*=:' + param + '(?:\\W|$)')).test(url)
34216                       };
34217                     }
34218                   });
34219                   url = url.replace(/\\:/g, ':');
34220                   url = url.replace(PROTOCOL_AND_IPV6_REGEX, function(match) {
34221                     protocolAndIpv6 = match;
34222                     return '';
34223                   });
34224
34225                   params = params || {};
34226                   forEach(self.urlParams, function(paramInfo, urlParam) {
34227                     val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
34228                     if (isDefined(val) && val !== null) {
34229                       if (paramInfo.isQueryParamValue) {
34230                         encodedVal = encodeUriQuery(val, true);
34231                       } else {
34232                         encodedVal = encodeUriSegment(val);
34233                       }
34234                       url = url.replace(new RegExp(':' + urlParam + '(\\W|$)', 'g'), function(match, p1) {
34235                         return encodedVal + p1;
34236                       });
34237                     } else {
34238                       url = url.replace(new RegExp('(/?):' + urlParam + '(\\W|$)', 'g'), function(match,
34239                           leadingSlashes, tail) {
34240                         if (tail.charAt(0) === '/') {
34241                           return tail;
34242                         } else {
34243                           return leadingSlashes + tail;
34244                         }
34245                       });
34246                     }
34247                   });
34248
34249                   // strip trailing slashes and set the url (unless this behavior is specifically disabled)
34250                   if (self.defaults.stripTrailingSlashes) {
34251                     url = url.replace(/\/+$/, '') || '/';
34252                   }
34253
34254                   // Collapse `/.` if found in the last URL path segment before the query.
34255                   // E.g. `http://url.com/id/.format?q=x` becomes `http://url.com/id.format?q=x`.
34256                   url = url.replace(/\/\.(?=\w+($|\?))/, '.');
34257                   // Replace escaped `/\.` with `/.`.
34258                   // (If `\.` comes from a param value, it will be encoded as `%5C.`.)
34259                   config.url = protocolAndIpv6 + url.replace(/\/(\\|%5C)\./, '/.');
34260
34261
34262                   // set params - delegate param encoding to $http
34263                   forEach(params, function(value, key) {
34264                     if (!self.urlParams[key]) {
34265                       config.params = config.params || {};
34266                       config.params[key] = value;
34267                     }
34268                   });
34269                 }
34270               };
34271
34272
34273               function resourceFactory(url, paramDefaults, actions, options) {
34274                 var route = new Route(url, options);
34275
34276                 actions = extend({}, provider.defaults.actions, actions);
34277
34278                 function extractParams(data, actionParams) {
34279                   var ids = {};
34280                   actionParams = extend({}, paramDefaults, actionParams);
34281                   forEach(actionParams, function(value, key) {
34282                     if (isFunction(value)) { value = value(data); }
34283                     ids[key] = value && value.charAt && value.charAt(0) === '@' ?
34284                       lookupDottedPath(data, value.substr(1)) : value;
34285                   });
34286                   return ids;
34287                 }
34288
34289                 function defaultResponseInterceptor(response) {
34290                   return response.resource;
34291                 }
34292
34293                 function Resource(value) {
34294                   shallowClearAndCopy(value || {}, this);
34295                 }
34296
34297                 Resource.prototype.toJSON = function() {
34298                   var data = extend({}, this);
34299                   delete data.$promise;
34300                   delete data.$resolved;
34301                   delete data.$cancelRequest;
34302                   return data;
34303                 };
34304
34305                 forEach(actions, function(action, name) {
34306                   var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
34307                   var numericTimeout = action.timeout;
34308                   var cancellable = isDefined(action.cancellable) ?
34309                       action.cancellable : route.defaults.cancellable;
34310
34311                   if (numericTimeout && !isNumber(numericTimeout)) {
34312                     $log.debug('ngResource:\n' +
34313                                '  Only numeric values are allowed as `timeout`.\n' +
34314                                '  Promises are not supported in $resource, because the same value would ' +
34315                                'be used for multiple requests. If you are looking for a way to cancel ' +
34316                                'requests, you should use the `cancellable` option.');
34317                     delete action.timeout;
34318                     numericTimeout = null;
34319                   }
34320
34321                   Resource[name] = function(a1, a2, a3, a4) {
34322                     var params = {}, data, success, error;
34323
34324                     switch (arguments.length) {
34325                       case 4:
34326                         error = a4;
34327                         success = a3;
34328                         // falls through
34329                       case 3:
34330                       case 2:
34331                         if (isFunction(a2)) {
34332                           if (isFunction(a1)) {
34333                             success = a1;
34334                             error = a2;
34335                             break;
34336                           }
34337
34338                           success = a2;
34339                           error = a3;
34340                           // falls through
34341                         } else {
34342                           params = a1;
34343                           data = a2;
34344                           success = a3;
34345                           break;
34346                         }
34347                         // falls through
34348                       case 1:
34349                         if (isFunction(a1)) success = a1;
34350                         else if (hasBody) data = a1;
34351                         else params = a1;
34352                         break;
34353                       case 0: break;
34354                       default:
34355                         throw $resourceMinErr('badargs',
34356                           'Expected up to 4 arguments [params, data, success, error], got {0} arguments',
34357                           arguments.length);
34358                     }
34359
34360                     var isInstanceCall = this instanceof Resource;
34361                     var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
34362                     var httpConfig = {};
34363                     var responseInterceptor = action.interceptor && action.interceptor.response ||
34364                       defaultResponseInterceptor;
34365                     var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
34366                       undefined;
34367                     var hasError = !!error;
34368                     var hasResponseErrorInterceptor = !!responseErrorInterceptor;
34369                     var timeoutDeferred;
34370                     var numericTimeoutPromise;
34371
34372                     forEach(action, function(value, key) {
34373                       switch (key) {
34374                         default:
34375                           httpConfig[key] = copy(value);
34376                           break;
34377                         case 'params':
34378                         case 'isArray':
34379                         case 'interceptor':
34380                         case 'cancellable':
34381                           break;
34382                       }
34383                     });
34384
34385                     if (!isInstanceCall && cancellable) {
34386                       timeoutDeferred = $q.defer();
34387                       httpConfig.timeout = timeoutDeferred.promise;
34388
34389                       if (numericTimeout) {
34390                         numericTimeoutPromise = $timeout(timeoutDeferred.resolve, numericTimeout);
34391                       }
34392                     }
34393
34394                     if (hasBody) httpConfig.data = data;
34395                     route.setUrlParams(httpConfig,
34396                       extend({}, extractParams(data, action.params || {}), params),
34397                       action.url);
34398
34399                     var promise = $http(httpConfig).then(function(response) {
34400                       var data = response.data;
34401
34402                       if (data) {
34403                         // Need to convert action.isArray to boolean in case it is undefined
34404                         if (isArray(data) !== (!!action.isArray)) {
34405                           throw $resourceMinErr('badcfg',
34406                               'Error in resource configuration for action `{0}`. Expected response to ' +
34407                               'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
34408                             isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
34409                         }
34410                         if (action.isArray) {
34411                           value.length = 0;
34412                           forEach(data, function(item) {
34413                             if (typeof item === 'object') {
34414                               value.push(new Resource(item));
34415                             } else {
34416                               // Valid JSON values may be string literals, and these should not be converted
34417                               // into objects. These items will not have access to the Resource prototype
34418                               // methods, but unfortunately there
34419                               value.push(item);
34420                             }
34421                           });
34422                         } else {
34423                           var promise = value.$promise;     // Save the promise
34424                           shallowClearAndCopy(data, value);
34425                           value.$promise = promise;         // Restore the promise
34426                         }
34427                       }
34428                       response.resource = value;
34429
34430                       return response;
34431                     });
34432
34433                     promise = promise['finally'](function() {
34434                       value.$resolved = true;
34435                       if (!isInstanceCall && cancellable) {
34436                         value.$cancelRequest = noop;
34437                         $timeout.cancel(numericTimeoutPromise);
34438                         timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null;
34439                       }
34440                     });
34441
34442                     promise = promise.then(
34443                       function(response) {
34444                         var value = responseInterceptor(response);
34445                         (success || noop)(value, response.headers, response.status, response.statusText);
34446                         return value;
34447                       },
34448                       (hasError || hasResponseErrorInterceptor) ?
34449                         function(response) {
34450                           if (hasError && !hasResponseErrorInterceptor) {
34451                             // Avoid `Possibly Unhandled Rejection` error,
34452                             // but still fulfill the returned promise with a rejection
34453                             promise.catch(noop);
34454                           }
34455                           if (hasError) error(response);
34456                           return hasResponseErrorInterceptor ?
34457                             responseErrorInterceptor(response) :
34458                             $q.reject(response);
34459                         } :
34460                         undefined);
34461
34462                     if (!isInstanceCall) {
34463                       // we are creating instance / collection
34464                       // - set the initial promise
34465                       // - return the instance / collection
34466                       value.$promise = promise;
34467                       value.$resolved = false;
34468                       if (cancellable) value.$cancelRequest = cancelRequest;
34469
34470                       return value;
34471                     }
34472
34473                     // instance call
34474                     return promise;
34475
34476                     function cancelRequest(value) {
34477                       promise.catch(noop);
34478                       timeoutDeferred.resolve(value);
34479                     }
34480                   };
34481
34482
34483                   Resource.prototype['$' + name] = function(params, success, error) {
34484                     if (isFunction(params)) {
34485                       error = success; success = params; params = {};
34486                     }
34487                     var result = Resource[name].call(this, params, this, success, error);
34488                     return result.$promise || result;
34489                   };
34490                 });
34491
34492                 Resource.bind = function(additionalParamDefaults) {
34493                   var extendedParamDefaults = extend({}, paramDefaults, additionalParamDefaults);
34494                   return resourceFactory(url, extendedParamDefaults, actions, options);
34495                 };
34496
34497                 return Resource;
34498               }
34499
34500               return resourceFactory;
34501             }];
34502           });
34503
34504
34505         })(window, window.angular);
34506
34507
34508 /***/ },
34509 /* 6 */
34510 /***/ function(module, exports, __webpack_require__) {
34511
34512         __webpack_require__(7);
34513
34514         module.exports = 'ui.bootstrap';
34515
34516
34517 /***/ },
34518 /* 7 */
34519 /***/ function(module, exports) {
34520
34521         /*
34522          * angular-ui-bootstrap
34523          * http://angular-ui.github.io/bootstrap/
34524
34525          * Version: 1.3.3 - 2016-05-22
34526          * License: MIT
34527          */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.datepicker","ui.bootstrap.position","ui.bootstrap.datepickerPopup","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"]);
34528         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/year.html","uib/template/datepickerPopup/popup.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"]);
34529         angular.module('ui.bootstrap.collapse', [])
34530
34531           .directive('uibCollapse', ['$animate', '$q', '$parse', '$injector', function($animate, $q, $parse, $injector) {
34532             var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;
34533             return {
34534               link: function(scope, element, attrs) {
34535                 var expandingExpr = $parse(attrs.expanding),
34536                     expandedExpr = $parse(attrs.expanded),
34537                     collapsingExpr = $parse(attrs.collapsing),
34538                     collapsedExpr = $parse(attrs.collapsed);
34539
34540                 if (!scope.$eval(attrs.uibCollapse)) {
34541                   element.addClass('in')
34542                     .addClass('collapse')
34543                     .attr('aria-expanded', true)
34544                     .attr('aria-hidden', false)
34545                     .css({height: 'auto'});
34546                 }
34547
34548                 function expand() {
34549                   if (element.hasClass('collapse') && element.hasClass('in')) {
34550                     return;
34551                   }
34552
34553                   $q.resolve(expandingExpr(scope))
34554                     .then(function() {
34555                       element.removeClass('collapse')
34556                         .addClass('collapsing')
34557                         .attr('aria-expanded', true)
34558                         .attr('aria-hidden', false);
34559
34560                       if ($animateCss) {
34561                         $animateCss(element, {
34562                           addClass: 'in',
34563                           easing: 'ease',
34564                           to: { height: element[0].scrollHeight + 'px' }
34565                         }).start()['finally'](expandDone);
34566                       } else {
34567                         $animate.addClass(element, 'in', {
34568                           to: { height: element[0].scrollHeight + 'px' }
34569                         }).then(expandDone);
34570                       }
34571                     });
34572                 }
34573
34574                 function expandDone() {
34575                   element.removeClass('collapsing')
34576                     .addClass('collapse')
34577                     .css({height: 'auto'});
34578                   expandedExpr(scope);
34579                 }
34580
34581                 function collapse() {
34582                   if (!element.hasClass('collapse') && !element.hasClass('in')) {
34583                     return collapseDone();
34584                   }
34585
34586                   $q.resolve(collapsingExpr(scope))
34587                     .then(function() {
34588                       element
34589                         // IMPORTANT: The height must be set before adding "collapsing" class.
34590                         // Otherwise, the browser attempts to animate from height 0 (in
34591                         // collapsing class) to the given height here.
34592                         .css({height: element[0].scrollHeight + 'px'})
34593                         // initially all panel collapse have the collapse class, this removal
34594                         // prevents the animation from jumping to collapsed state
34595                         .removeClass('collapse')
34596                         .addClass('collapsing')
34597                         .attr('aria-expanded', false)
34598                         .attr('aria-hidden', true);
34599
34600                       if ($animateCss) {
34601                         $animateCss(element, {
34602                           removeClass: 'in',
34603                           to: {height: '0'}
34604                         }).start()['finally'](collapseDone);
34605                       } else {
34606                         $animate.removeClass(element, 'in', {
34607                           to: {height: '0'}
34608                         }).then(collapseDone);
34609                       }
34610                     });
34611                 }
34612
34613                 function collapseDone() {
34614                   element.css({height: '0'}); // Required so that collapse works when animation is disabled
34615                   element.removeClass('collapsing')
34616                     .addClass('collapse');
34617                   collapsedExpr(scope);
34618                 }
34619
34620                 scope.$watch(attrs.uibCollapse, function(shouldCollapse) {
34621                   if (shouldCollapse) {
34622                     collapse();
34623                   } else {
34624                     expand();
34625                   }
34626                 });
34627               }
34628             };
34629           }]);
34630
34631         angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
34632
34633         .constant('uibAccordionConfig', {
34634           closeOthers: true
34635         })
34636
34637         .controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
34638           // This array keeps track of the accordion groups
34639           this.groups = [];
34640
34641           // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
34642           this.closeOthers = function(openGroup) {
34643             var closeOthers = angular.isDefined($attrs.closeOthers) ?
34644               $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
34645             if (closeOthers) {
34646               angular.forEach(this.groups, function(group) {
34647                 if (group !== openGroup) {
34648                   group.isOpen = false;
34649                 }
34650               });
34651             }
34652           };
34653
34654           // This is called from the accordion-group directive to add itself to the accordion
34655           this.addGroup = function(groupScope) {
34656             var that = this;
34657             this.groups.push(groupScope);
34658
34659             groupScope.$on('$destroy', function(event) {
34660               that.removeGroup(groupScope);
34661             });
34662           };
34663
34664           // This is called from the accordion-group directive when to remove itself
34665           this.removeGroup = function(group) {
34666             var index = this.groups.indexOf(group);
34667             if (index !== -1) {
34668               this.groups.splice(index, 1);
34669             }
34670           };
34671         }])
34672
34673         // The accordion directive simply sets up the directive controller
34674         // and adds an accordion CSS class to itself element.
34675         .directive('uibAccordion', function() {
34676           return {
34677             controller: 'UibAccordionController',
34678             controllerAs: 'accordion',
34679             transclude: true,
34680             templateUrl: function(element, attrs) {
34681               return attrs.templateUrl || 'uib/template/accordion/accordion.html';
34682             }
34683           };
34684         })
34685
34686         // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
34687         .directive('uibAccordionGroup', function() {
34688           return {
34689             require: '^uibAccordion',         // We need this directive to be inside an accordion
34690             transclude: true,              // It transcludes the contents of the directive into the template
34691             replace: true,                // The element containing the directive will be replaced with the template
34692             templateUrl: function(element, attrs) {
34693               return attrs.templateUrl || 'uib/template/accordion/accordion-group.html';
34694             },
34695             scope: {
34696               heading: '@',               // Interpolate the heading attribute onto this scope
34697               panelClass: '@?',           // Ditto with panelClass
34698               isOpen: '=?',
34699               isDisabled: '=?'
34700             },
34701             controller: function() {
34702               this.setHeading = function(element) {
34703                 this.heading = element;
34704               };
34705             },
34706             link: function(scope, element, attrs, accordionCtrl) {
34707               accordionCtrl.addGroup(scope);
34708
34709               scope.openClass = attrs.openClass || 'panel-open';
34710               scope.panelClass = attrs.panelClass || 'panel-default';
34711               scope.$watch('isOpen', function(value) {
34712                 element.toggleClass(scope.openClass, !!value);
34713                 if (value) {
34714                   accordionCtrl.closeOthers(scope);
34715                 }
34716               });
34717
34718               scope.toggleOpen = function($event) {
34719                 if (!scope.isDisabled) {
34720                   if (!$event || $event.which === 32) {
34721                     scope.isOpen = !scope.isOpen;
34722                   }
34723                 }
34724               };
34725
34726               var id = 'accordiongroup-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
34727               scope.headingId = id + '-tab';
34728               scope.panelId = id + '-panel';
34729             }
34730           };
34731         })
34732
34733         // Use accordion-heading below an accordion-group to provide a heading containing HTML
34734         .directive('uibAccordionHeading', function() {
34735           return {
34736             transclude: true,   // Grab the contents to be used as the heading
34737             template: '',       // In effect remove this element!
34738             replace: true,
34739             require: '^uibAccordionGroup',
34740             link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
34741               // Pass the heading to the accordion-group controller
34742               // so that it can be transcluded into the right place in the template
34743               // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
34744               accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
34745             }
34746           };
34747         })
34748
34749         // Use in the accordion-group template to indicate where you want the heading to be transcluded
34750         // You must provide the property on the accordion-group controller that will hold the transcluded element
34751         .directive('uibAccordionTransclude', function() {
34752           return {
34753             require: '^uibAccordionGroup',
34754             link: function(scope, element, attrs, controller) {
34755               scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {
34756                 if (heading) {
34757                   var elem = angular.element(element[0].querySelector(getHeaderSelectors()));
34758                   elem.html('');
34759                   elem.append(heading);
34760                 }
34761               });
34762             }
34763           };
34764
34765           function getHeaderSelectors() {
34766               return 'uib-accordion-header,' +
34767                   'data-uib-accordion-header,' +
34768                   'x-uib-accordion-header,' +
34769                   'uib\\:accordion-header,' +
34770                   '[uib-accordion-header],' +
34771                   '[data-uib-accordion-header],' +
34772                   '[x-uib-accordion-header]';
34773           }
34774         });
34775
34776         angular.module('ui.bootstrap.alert', [])
34777
34778         .controller('UibAlertController', ['$scope', '$attrs', '$interpolate', '$timeout', function($scope, $attrs, $interpolate, $timeout) {
34779           $scope.closeable = !!$attrs.close;
34780
34781           var dismissOnTimeout = angular.isDefined($attrs.dismissOnTimeout) ?
34782             $interpolate($attrs.dismissOnTimeout)($scope.$parent) : null;
34783
34784           if (dismissOnTimeout) {
34785             $timeout(function() {
34786               $scope.close();
34787             }, parseInt(dismissOnTimeout, 10));
34788           }
34789         }])
34790
34791         .directive('uibAlert', function() {
34792           return {
34793             controller: 'UibAlertController',
34794             controllerAs: 'alert',
34795             templateUrl: function(element, attrs) {
34796               return attrs.templateUrl || 'uib/template/alert/alert.html';
34797             },
34798             transclude: true,
34799             replace: true,
34800             scope: {
34801               type: '@',
34802               close: '&'
34803             }
34804           };
34805         });
34806
34807         angular.module('ui.bootstrap.buttons', [])
34808
34809         .constant('uibButtonConfig', {
34810           activeClass: 'active',
34811           toggleEvent: 'click'
34812         })
34813
34814         .controller('UibButtonsController', ['uibButtonConfig', function(buttonConfig) {
34815           this.activeClass = buttonConfig.activeClass || 'active';
34816           this.toggleEvent = buttonConfig.toggleEvent || 'click';
34817         }])
34818
34819         .directive('uibBtnRadio', ['$parse', function($parse) {
34820           return {
34821             require: ['uibBtnRadio', 'ngModel'],
34822             controller: 'UibButtonsController',
34823             controllerAs: 'buttons',
34824             link: function(scope, element, attrs, ctrls) {
34825               var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
34826               var uncheckableExpr = $parse(attrs.uibUncheckable);
34827
34828               element.find('input').css({display: 'none'});
34829
34830               //model -> UI
34831               ngModelCtrl.$render = function() {
34832                 element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.uibBtnRadio)));
34833               };
34834
34835               //ui->model
34836               element.on(buttonsCtrl.toggleEvent, function() {
34837                 if (attrs.disabled) {
34838                   return;
34839                 }
34840
34841                 var isActive = element.hasClass(buttonsCtrl.activeClass);
34842
34843                 if (!isActive || angular.isDefined(attrs.uncheckable)) {
34844                   scope.$apply(function() {
34845                     ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.uibBtnRadio));
34846                     ngModelCtrl.$render();
34847                   });
34848                 }
34849               });
34850
34851               if (attrs.uibUncheckable) {
34852                 scope.$watch(uncheckableExpr, function(uncheckable) {
34853                   attrs.$set('uncheckable', uncheckable ? '' : undefined);
34854                 });
34855               }
34856             }
34857           };
34858         }])
34859
34860         .directive('uibBtnCheckbox', function() {
34861           return {
34862             require: ['uibBtnCheckbox', 'ngModel'],
34863             controller: 'UibButtonsController',
34864             controllerAs: 'button',
34865             link: function(scope, element, attrs, ctrls) {
34866               var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
34867
34868               element.find('input').css({display: 'none'});
34869
34870               function getTrueValue() {
34871                 return getCheckboxValue(attrs.btnCheckboxTrue, true);
34872               }
34873
34874               function getFalseValue() {
34875                 return getCheckboxValue(attrs.btnCheckboxFalse, false);
34876               }
34877
34878               function getCheckboxValue(attribute, defaultValue) {
34879                 return angular.isDefined(attribute) ? scope.$eval(attribute) : defaultValue;
34880               }
34881
34882               //model -> UI
34883               ngModelCtrl.$render = function() {
34884                 element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
34885               };
34886
34887               //ui->model
34888               element.on(buttonsCtrl.toggleEvent, function() {
34889                 if (attrs.disabled) {
34890                   return;
34891                 }
34892
34893                 scope.$apply(function() {
34894                   ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
34895                   ngModelCtrl.$render();
34896                 });
34897               });
34898             }
34899           };
34900         });
34901
34902         angular.module('ui.bootstrap.carousel', [])
34903
34904         .controller('UibCarouselController', ['$scope', '$element', '$interval', '$timeout', '$animate', function($scope, $element, $interval, $timeout, $animate) {
34905           var self = this,
34906             slides = self.slides = $scope.slides = [],
34907             SLIDE_DIRECTION = 'uib-slideDirection',
34908             currentIndex = $scope.active,
34909             currentInterval, isPlaying, bufferedTransitions = [];
34910
34911           var destroyed = false;
34912
34913           self.addSlide = function(slide, element) {
34914             slides.push({
34915               slide: slide,
34916               element: element
34917             });
34918             slides.sort(function(a, b) {
34919               return +a.slide.index - +b.slide.index;
34920             });
34921             //if this is the first slide or the slide is set to active, select it
34922             if (slide.index === $scope.active || slides.length === 1 && !angular.isNumber($scope.active)) {
34923               if ($scope.$currentTransition) {
34924                 $scope.$currentTransition = null;
34925               }
34926
34927               currentIndex = slide.index;
34928               $scope.active = slide.index;
34929               setActive(currentIndex);
34930               self.select(slides[findSlideIndex(slide)]);
34931               if (slides.length === 1) {
34932                 $scope.play();
34933               }
34934             }
34935           };
34936
34937           self.getCurrentIndex = function() {
34938             for (var i = 0; i < slides.length; i++) {
34939               if (slides[i].slide.index === currentIndex) {
34940                 return i;
34941               }
34942             }
34943           };
34944
34945           self.next = $scope.next = function() {
34946             var newIndex = (self.getCurrentIndex() + 1) % slides.length;
34947
34948             if (newIndex === 0 && $scope.noWrap()) {
34949               $scope.pause();
34950               return;
34951             }
34952
34953             return self.select(slides[newIndex], 'next');
34954           };
34955
34956           self.prev = $scope.prev = function() {
34957             var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;
34958
34959             if ($scope.noWrap() && newIndex === slides.length - 1) {
34960               $scope.pause();
34961               return;
34962             }
34963
34964             return self.select(slides[newIndex], 'prev');
34965           };
34966
34967           self.removeSlide = function(slide) {
34968             var index = findSlideIndex(slide);
34969
34970             var bufferedIndex = bufferedTransitions.indexOf(slides[index]);
34971             if (bufferedIndex !== -1) {
34972               bufferedTransitions.splice(bufferedIndex, 1);
34973             }
34974
34975             //get the index of the slide inside the carousel
34976             slides.splice(index, 1);
34977             if (slides.length > 0 && currentIndex === index) {
34978               if (index >= slides.length) {
34979                 currentIndex = slides.length - 1;
34980                 $scope.active = currentIndex;
34981                 setActive(currentIndex);
34982                 self.select(slides[slides.length - 1]);
34983               } else {
34984                 currentIndex = index;
34985                 $scope.active = currentIndex;
34986                 setActive(currentIndex);
34987                 self.select(slides[index]);
34988               }
34989             } else if (currentIndex > index) {
34990               currentIndex--;
34991               $scope.active = currentIndex;
34992             }
34993
34994             //clean the active value when no more slide
34995             if (slides.length === 0) {
34996               currentIndex = null;
34997               $scope.active = null;
34998               clearBufferedTransitions();
34999             }
35000           };
35001
35002           /* direction: "prev" or "next" */
35003           self.select = $scope.select = function(nextSlide, direction) {
35004             var nextIndex = findSlideIndex(nextSlide.slide);
35005             //Decide direction if it's not given
35006             if (direction === undefined) {
35007               direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
35008             }
35009             //Prevent this user-triggered transition from occurring if there is already one in progress
35010             if (nextSlide.slide.index !== currentIndex &&
35011               !$scope.$currentTransition) {
35012               goNext(nextSlide.slide, nextIndex, direction);
35013             } else if (nextSlide && nextSlide.slide.index !== currentIndex && $scope.$currentTransition) {
35014               bufferedTransitions.push(slides[nextIndex]);
35015             }
35016           };
35017
35018           /* Allow outside people to call indexOf on slides array */
35019           $scope.indexOfSlide = function(slide) {
35020             return +slide.slide.index;
35021           };
35022
35023           $scope.isActive = function(slide) {
35024             return $scope.active === slide.slide.index;
35025           };
35026
35027           $scope.isPrevDisabled = function() {
35028             return $scope.active === 0 && $scope.noWrap();
35029           };
35030
35031           $scope.isNextDisabled = function() {
35032             return $scope.active === slides.length - 1 && $scope.noWrap();
35033           };
35034
35035           $scope.pause = function() {
35036             if (!$scope.noPause) {
35037               isPlaying = false;
35038               resetTimer();
35039             }
35040           };
35041
35042           $scope.play = function() {
35043             if (!isPlaying) {
35044               isPlaying = true;
35045               restartTimer();
35046             }
35047           };
35048
35049           $scope.$on('$destroy', function() {
35050             destroyed = true;
35051             resetTimer();
35052           });
35053
35054           $scope.$watch('noTransition', function(noTransition) {
35055             $animate.enabled($element, !noTransition);
35056           });
35057
35058           $scope.$watch('interval', restartTimer);
35059
35060           $scope.$watchCollection('slides', resetTransition);
35061
35062           $scope.$watch('active', function(index) {
35063             if (angular.isNumber(index) && currentIndex !== index) {
35064               for (var i = 0; i < slides.length; i++) {
35065                 if (slides[i].slide.index === index) {
35066                   index = i;
35067                   break;
35068                 }
35069               }
35070
35071               var slide = slides[index];
35072               if (slide) {
35073                 setActive(index);
35074                 self.select(slides[index]);
35075                 currentIndex = index;
35076               }
35077             }
35078           });
35079
35080           function clearBufferedTransitions() {
35081             while (bufferedTransitions.length) {
35082               bufferedTransitions.shift();
35083             }
35084           }
35085
35086           function getSlideByIndex(index) {
35087             for (var i = 0, l = slides.length; i < l; ++i) {
35088               if (slides[i].index === index) {
35089                 return slides[i];
35090               }
35091             }
35092           }
35093
35094           function setActive(index) {
35095             for (var i = 0; i < slides.length; i++) {
35096               slides[i].slide.active = i === index;
35097             }
35098           }
35099
35100           function goNext(slide, index, direction) {
35101             if (destroyed) {
35102               return;
35103             }
35104
35105             angular.extend(slide, {direction: direction});
35106             angular.extend(slides[currentIndex].slide || {}, {direction: direction});
35107             if ($animate.enabled($element) && !$scope.$currentTransition &&
35108               slides[index].element && self.slides.length > 1) {
35109               slides[index].element.data(SLIDE_DIRECTION, slide.direction);
35110               var currentIdx = self.getCurrentIndex();
35111
35112               if (angular.isNumber(currentIdx) && slides[currentIdx].element) {
35113                 slides[currentIdx].element.data(SLIDE_DIRECTION, slide.direction);
35114               }
35115
35116               $scope.$currentTransition = true;
35117               $animate.on('addClass', slides[index].element, function(element, phase) {
35118                 if (phase === 'close') {
35119                   $scope.$currentTransition = null;
35120                   $animate.off('addClass', element);
35121                   if (bufferedTransitions.length) {
35122                     var nextSlide = bufferedTransitions.pop().slide;
35123                     var nextIndex = nextSlide.index;
35124                     var nextDirection = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
35125                     clearBufferedTransitions();
35126
35127                     goNext(nextSlide, nextIndex, nextDirection);
35128                   }
35129                 }
35130               });
35131             }
35132
35133             $scope.active = slide.index;
35134             currentIndex = slide.index;
35135             setActive(index);
35136
35137             //every time you change slides, reset the timer
35138             restartTimer();
35139           }
35140
35141           function findSlideIndex(slide) {
35142             for (var i = 0; i < slides.length; i++) {
35143               if (slides[i].slide === slide) {
35144                 return i;
35145               }
35146             }
35147           }
35148
35149           function resetTimer() {
35150             if (currentInterval) {
35151               $interval.cancel(currentInterval);
35152               currentInterval = null;
35153             }
35154           }
35155
35156           function resetTransition(slides) {
35157             if (!slides.length) {
35158               $scope.$currentTransition = null;
35159               clearBufferedTransitions();
35160             }
35161           }
35162
35163           function restartTimer() {
35164             resetTimer();
35165             var interval = +$scope.interval;
35166             if (!isNaN(interval) && interval > 0) {
35167               currentInterval = $interval(timerFn, interval);
35168             }
35169           }
35170
35171           function timerFn() {
35172             var interval = +$scope.interval;
35173             if (isPlaying && !isNaN(interval) && interval > 0 && slides.length) {
35174               $scope.next();
35175             } else {
35176               $scope.pause();
35177             }
35178           }
35179         }])
35180
35181         .directive('uibCarousel', function() {
35182           return {
35183             transclude: true,
35184             replace: true,
35185             controller: 'UibCarouselController',
35186             controllerAs: 'carousel',
35187             templateUrl: function(element, attrs) {
35188               return attrs.templateUrl || 'uib/template/carousel/carousel.html';
35189             },
35190             scope: {
35191               active: '=',
35192               interval: '=',
35193               noTransition: '=',
35194               noPause: '=',
35195               noWrap: '&'
35196             }
35197           };
35198         })
35199
35200         .directive('uibSlide', function() {
35201           return {
35202             require: '^uibCarousel',
35203             transclude: true,
35204             replace: true,
35205             templateUrl: function(element, attrs) {
35206               return attrs.templateUrl || 'uib/template/carousel/slide.html';
35207             },
35208             scope: {
35209               actual: '=?',
35210               index: '=?'
35211             },
35212             link: function (scope, element, attrs, carouselCtrl) {
35213               carouselCtrl.addSlide(scope, element);
35214               //when the scope is destroyed then remove the slide from the current slides array
35215               scope.$on('$destroy', function() {
35216                 carouselCtrl.removeSlide(scope);
35217               });
35218             }
35219           };
35220         })
35221
35222         .animation('.item', ['$animateCss',
35223         function($animateCss) {
35224           var SLIDE_DIRECTION = 'uib-slideDirection';
35225
35226           function removeClass(element, className, callback) {
35227             element.removeClass(className);
35228             if (callback) {
35229               callback();
35230             }
35231           }
35232
35233           return {
35234             beforeAddClass: function(element, className, done) {
35235               if (className === 'active') {
35236                 var stopped = false;
35237                 var direction = element.data(SLIDE_DIRECTION);
35238                 var directionClass = direction === 'next' ? 'left' : 'right';
35239                 var removeClassFn = removeClass.bind(this, element,
35240                   directionClass + ' ' + direction, done);
35241                 element.addClass(direction);
35242
35243                 $animateCss(element, {addClass: directionClass})
35244                   .start()
35245                   .done(removeClassFn);
35246
35247                 return function() {
35248                   stopped = true;
35249                 };
35250               }
35251               done();
35252             },
35253             beforeRemoveClass: function (element, className, done) {
35254               if (className === 'active') {
35255                 var stopped = false;
35256                 var direction = element.data(SLIDE_DIRECTION);
35257                 var directionClass = direction === 'next' ? 'left' : 'right';
35258                 var removeClassFn = removeClass.bind(this, element, directionClass, done);
35259
35260                 $animateCss(element, {addClass: directionClass})
35261                   .start()
35262                   .done(removeClassFn);
35263
35264                 return function() {
35265                   stopped = true;
35266                 };
35267               }
35268               done();
35269             }
35270           };
35271         }]);
35272
35273         angular.module('ui.bootstrap.dateparser', [])
35274
35275         .service('uibDateParser', ['$log', '$locale', 'dateFilter', 'orderByFilter', function($log, $locale, dateFilter, orderByFilter) {
35276           // Pulled from https://github.com/mbostock/d3/blob/master/src/format/requote.js
35277           var SPECIAL_CHARACTERS_REGEXP = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
35278
35279           var localeId;
35280           var formatCodeToRegex;
35281
35282           this.init = function() {
35283             localeId = $locale.id;
35284
35285             this.parsers = {};
35286             this.formatters = {};
35287
35288             formatCodeToRegex = [
35289               {
35290                 key: 'yyyy',
35291                 regex: '\\d{4}',
35292                 apply: function(value) { this.year = +value; },
35293                 formatter: function(date) {
35294                   var _date = new Date();
35295                   _date.setFullYear(Math.abs(date.getFullYear()));
35296                   return dateFilter(_date, 'yyyy');
35297                 }
35298               },
35299               {
35300                 key: 'yy',
35301                 regex: '\\d{2}',
35302                 apply: function(value) { value = +value; this.year = value < 69 ? value + 2000 : value + 1900; },
35303                 formatter: function(date) {
35304                   var _date = new Date();
35305                   _date.setFullYear(Math.abs(date.getFullYear()));
35306                   return dateFilter(_date, 'yy');
35307                 }
35308               },
35309               {
35310                 key: 'y',
35311                 regex: '\\d{1,4}',
35312                 apply: function(value) { this.year = +value; },
35313                 formatter: function(date) {
35314                   var _date = new Date();
35315                   _date.setFullYear(Math.abs(date.getFullYear()));
35316                   return dateFilter(_date, 'y');
35317                 }
35318               },
35319               {
35320                 key: 'M!',
35321                 regex: '0?[1-9]|1[0-2]',
35322                 apply: function(value) { this.month = value - 1; },
35323                 formatter: function(date) {
35324                   var value = date.getMonth();
35325                   if (/^[0-9]$/.test(value)) {
35326                     return dateFilter(date, 'MM');
35327                   }
35328
35329                   return dateFilter(date, 'M');
35330                 }
35331               },
35332               {
35333                 key: 'MMMM',
35334                 regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
35335                 apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); },
35336                 formatter: function(date) { return dateFilter(date, 'MMMM'); }
35337               },
35338               {
35339                 key: 'MMM',
35340                 regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
35341                 apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); },
35342                 formatter: function(date) { return dateFilter(date, 'MMM'); }
35343               },
35344               {
35345                 key: 'MM',
35346                 regex: '0[1-9]|1[0-2]',
35347                 apply: function(value) { this.month = value - 1; },
35348                 formatter: function(date) { return dateFilter(date, 'MM'); }
35349               },
35350               {
35351                 key: 'M',
35352                 regex: '[1-9]|1[0-2]',
35353                 apply: function(value) { this.month = value - 1; },
35354                 formatter: function(date) { return dateFilter(date, 'M'); }
35355               },
35356               {
35357                 key: 'd!',
35358                 regex: '[0-2]?[0-9]{1}|3[0-1]{1}',
35359                 apply: function(value) { this.date = +value; },
35360                 formatter: function(date) {
35361                   var value = date.getDate();
35362                   if (/^[1-9]$/.test(value)) {
35363                     return dateFilter(date, 'dd');
35364                   }
35365
35366                   return dateFilter(date, 'd');
35367                 }
35368               },
35369               {
35370                 key: 'dd',
35371                 regex: '[0-2][0-9]{1}|3[0-1]{1}',
35372                 apply: function(value) { this.date = +value; },
35373                 formatter: function(date) { return dateFilter(date, 'dd'); }
35374               },
35375               {
35376                 key: 'd',
35377                 regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
35378                 apply: function(value) { this.date = +value; },
35379                 formatter: function(date) { return dateFilter(date, 'd'); }
35380               },
35381               {
35382                 key: 'EEEE',
35383                 regex: $locale.DATETIME_FORMATS.DAY.join('|'),
35384                 formatter: function(date) { return dateFilter(date, 'EEEE'); }
35385               },
35386               {
35387                 key: 'EEE',
35388                 regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|'),
35389                 formatter: function(date) { return dateFilter(date, 'EEE'); }
35390               },
35391               {
35392                 key: 'HH',
35393                 regex: '(?:0|1)[0-9]|2[0-3]',
35394                 apply: function(value) { this.hours = +value; },
35395                 formatter: function(date) { return dateFilter(date, 'HH'); }
35396               },
35397               {
35398                 key: 'hh',
35399                 regex: '0[0-9]|1[0-2]',
35400                 apply: function(value) { this.hours = +value; },
35401                 formatter: function(date) { return dateFilter(date, 'hh'); }
35402               },
35403               {
35404                 key: 'H',
35405                 regex: '1?[0-9]|2[0-3]',
35406                 apply: function(value) { this.hours = +value; },
35407                 formatter: function(date) { return dateFilter(date, 'H'); }
35408               },
35409               {
35410                 key: 'h',
35411                 regex: '[0-9]|1[0-2]',
35412                 apply: function(value) { this.hours = +value; },
35413                 formatter: function(date) { return dateFilter(date, 'h'); }
35414               },
35415               {
35416                 key: 'mm',
35417                 regex: '[0-5][0-9]',
35418                 apply: function(value) { this.minutes = +value; },
35419                 formatter: function(date) { return dateFilter(date, 'mm'); }
35420               },
35421               {
35422                 key: 'm',
35423                 regex: '[0-9]|[1-5][0-9]',
35424                 apply: function(value) { this.minutes = +value; },
35425                 formatter: function(date) { return dateFilter(date, 'm'); }
35426               },
35427               {
35428                 key: 'sss',
35429                 regex: '[0-9][0-9][0-9]',
35430                 apply: function(value) { this.milliseconds = +value; },
35431                 formatter: function(date) { return dateFilter(date, 'sss'); }
35432               },
35433               {
35434                 key: 'ss',
35435                 regex: '[0-5][0-9]',
35436                 apply: function(value) { this.seconds = +value; },
35437                 formatter: function(date) { return dateFilter(date, 'ss'); }
35438               },
35439               {
35440                 key: 's',
35441                 regex: '[0-9]|[1-5][0-9]',
35442                 apply: function(value) { this.seconds = +value; },
35443                 formatter: function(date) { return dateFilter(date, 's'); }
35444               },
35445               {
35446                 key: 'a',
35447                 regex: $locale.DATETIME_FORMATS.AMPMS.join('|'),
35448                 apply: function(value) {
35449                   if (this.hours === 12) {
35450                     this.hours = 0;
35451                   }
35452
35453                   if (value === 'PM') {
35454                     this.hours += 12;
35455                   }
35456                 },
35457                 formatter: function(date) { return dateFilter(date, 'a'); }
35458               },
35459               {
35460                 key: 'Z',
35461                 regex: '[+-]\\d{4}',
35462                 apply: function(value) {
35463                   var matches = value.match(/([+-])(\d{2})(\d{2})/),
35464                     sign = matches[1],
35465                     hours = matches[2],
35466                     minutes = matches[3];
35467                   this.hours += toInt(sign + hours);
35468                   this.minutes += toInt(sign + minutes);
35469                 },
35470                 formatter: function(date) {
35471                   return dateFilter(date, 'Z');
35472                 }
35473               },
35474               {
35475                 key: 'ww',
35476                 regex: '[0-4][0-9]|5[0-3]',
35477                 formatter: function(date) { return dateFilter(date, 'ww'); }
35478               },
35479               {
35480                 key: 'w',
35481                 regex: '[0-9]|[1-4][0-9]|5[0-3]',
35482                 formatter: function(date) { return dateFilter(date, 'w'); }
35483               },
35484               {
35485                 key: 'GGGG',
35486                 regex: $locale.DATETIME_FORMATS.ERANAMES.join('|').replace(/\s/g, '\\s'),
35487                 formatter: function(date) { return dateFilter(date, 'GGGG'); }
35488               },
35489               {
35490                 key: 'GGG',
35491                 regex: $locale.DATETIME_FORMATS.ERAS.join('|'),
35492                 formatter: function(date) { return dateFilter(date, 'GGG'); }
35493               },
35494               {
35495                 key: 'GG',
35496                 regex: $locale.DATETIME_FORMATS.ERAS.join('|'),
35497                 formatter: function(date) { return dateFilter(date, 'GG'); }
35498               },
35499               {
35500                 key: 'G',
35501                 regex: $locale.DATETIME_FORMATS.ERAS.join('|'),
35502                 formatter: function(date) { return dateFilter(date, 'G'); }
35503               }
35504             ];
35505           };
35506
35507           this.init();
35508
35509           function createParser(format, func) {
35510             var map = [], regex = format.split('');
35511
35512             // check for literal values
35513             var quoteIndex = format.indexOf('\'');
35514             if (quoteIndex > -1) {
35515               var inLiteral = false;
35516               format = format.split('');
35517               for (var i = quoteIndex; i < format.length; i++) {
35518                 if (inLiteral) {
35519                   if (format[i] === '\'') {
35520                     if (i + 1 < format.length && format[i+1] === '\'') { // escaped single quote
35521                       format[i+1] = '$';
35522                       regex[i+1] = '';
35523                     } else { // end of literal
35524                       regex[i] = '';
35525                       inLiteral = false;
35526                     }
35527                   }
35528                   format[i] = '$';
35529                 } else {
35530                   if (format[i] === '\'') { // start of literal
35531                     format[i] = '$';
35532                     regex[i] = '';
35533                     inLiteral = true;
35534                   }
35535                 }
35536               }
35537
35538               format = format.join('');
35539             }
35540
35541             angular.forEach(formatCodeToRegex, function(data) {
35542               var index = format.indexOf(data.key);
35543
35544               if (index > -1) {
35545                 format = format.split('');
35546
35547                 regex[index] = '(' + data.regex + ')';
35548                 format[index] = '$'; // Custom symbol to define consumed part of format
35549                 for (var i = index + 1, n = index + data.key.length; i < n; i++) {
35550                   regex[i] = '';
35551                   format[i] = '$';
35552                 }
35553                 format = format.join('');
35554
35555                 map.push({
35556                   index: index,
35557                   key: data.key,
35558                   apply: data[func],
35559                   matcher: data.regex
35560                 });
35561               }
35562             });
35563
35564             return {
35565               regex: new RegExp('^' + regex.join('') + '$'),
35566               map: orderByFilter(map, 'index')
35567             };
35568           }
35569
35570           this.filter = function(date, format) {
35571             if (!angular.isDate(date) || isNaN(date) || !format) {
35572               return '';
35573             }
35574
35575             format = $locale.DATETIME_FORMATS[format] || format;
35576
35577             if ($locale.id !== localeId) {
35578               this.init();
35579             }
35580
35581             if (!this.formatters[format]) {
35582               this.formatters[format] = createParser(format, 'formatter');
35583             }
35584
35585             var parser = this.formatters[format],
35586               map = parser.map;
35587
35588             var _format = format;
35589
35590             return map.reduce(function(str, mapper, i) {
35591               var match = _format.match(new RegExp('(.*)' + mapper.key));
35592               if (match && angular.isString(match[1])) {
35593                 str += match[1];
35594                 _format = _format.replace(match[1] + mapper.key, '');
35595               }
35596
35597               var endStr = i === map.length - 1 ? _format : '';
35598
35599               if (mapper.apply) {
35600                 return str + mapper.apply.call(null, date) + endStr;
35601               }
35602
35603               return str + endStr;
35604             }, '');
35605           };
35606
35607           this.parse = function(input, format, baseDate) {
35608             if (!angular.isString(input) || !format) {
35609               return input;
35610             }
35611
35612             format = $locale.DATETIME_FORMATS[format] || format;
35613             format = format.replace(SPECIAL_CHARACTERS_REGEXP, '\\$&');
35614
35615             if ($locale.id !== localeId) {
35616               this.init();
35617             }
35618
35619             if (!this.parsers[format]) {
35620               this.parsers[format] = createParser(format, 'apply');
35621             }
35622
35623             var parser = this.parsers[format],
35624                 regex = parser.regex,
35625                 map = parser.map,
35626                 results = input.match(regex),
35627                 tzOffset = false;
35628             if (results && results.length) {
35629               var fields, dt;
35630               if (angular.isDate(baseDate) && !isNaN(baseDate.getTime())) {
35631                 fields = {
35632                   year: baseDate.getFullYear(),
35633                   month: baseDate.getMonth(),
35634                   date: baseDate.getDate(),
35635                   hours: baseDate.getHours(),
35636                   minutes: baseDate.getMinutes(),
35637                   seconds: baseDate.getSeconds(),
35638                   milliseconds: baseDate.getMilliseconds()
35639                 };
35640               } else {
35641                 if (baseDate) {
35642                   $log.warn('dateparser:', 'baseDate is not a valid date');
35643                 }
35644                 fields = { year: 1900, month: 0, date: 1, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 };
35645               }
35646
35647               for (var i = 1, n = results.length; i < n; i++) {
35648                 var mapper = map[i - 1];
35649                 if (mapper.matcher === 'Z') {
35650                   tzOffset = true;
35651                 }
35652
35653                 if (mapper.apply) {
35654                   mapper.apply.call(fields, results[i]);
35655                 }
35656               }
35657
35658               var datesetter = tzOffset ? Date.prototype.setUTCFullYear :
35659                 Date.prototype.setFullYear;
35660               var timesetter = tzOffset ? Date.prototype.setUTCHours :
35661                 Date.prototype.setHours;
35662
35663               if (isValid(fields.year, fields.month, fields.date)) {
35664                 if (angular.isDate(baseDate) && !isNaN(baseDate.getTime()) && !tzOffset) {
35665                   dt = new Date(baseDate);
35666                   datesetter.call(dt, fields.year, fields.month, fields.date);
35667                   timesetter.call(dt, fields.hours, fields.minutes,
35668                     fields.seconds, fields.milliseconds);
35669                 } else {
35670                   dt = new Date(0);
35671                   datesetter.call(dt, fields.year, fields.month, fields.date);
35672                   timesetter.call(dt, fields.hours || 0, fields.minutes || 0,
35673                     fields.seconds || 0, fields.milliseconds || 0);
35674                 }
35675               }
35676
35677               return dt;
35678             }
35679           };
35680
35681           // Check if date is valid for specific month (and year for February).
35682           // Month: 0 = Jan, 1 = Feb, etc
35683           function isValid(year, month, date) {
35684             if (date < 1) {
35685               return false;
35686             }
35687
35688             if (month === 1 && date > 28) {
35689               return date === 29 && (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0);
35690             }
35691
35692             if (month === 3 || month === 5 || month === 8 || month === 10) {
35693               return date < 31;
35694             }
35695
35696             return true;
35697           }
35698
35699           function toInt(str) {
35700             return parseInt(str, 10);
35701           }
35702
35703           this.toTimezone = toTimezone;
35704           this.fromTimezone = fromTimezone;
35705           this.timezoneToOffset = timezoneToOffset;
35706           this.addDateMinutes = addDateMinutes;
35707           this.convertTimezoneToLocal = convertTimezoneToLocal;
35708
35709           function toTimezone(date, timezone) {
35710             return date && timezone ? convertTimezoneToLocal(date, timezone) : date;
35711           }
35712
35713           function fromTimezone(date, timezone) {
35714             return date && timezone ? convertTimezoneToLocal(date, timezone, true) : date;
35715           }
35716
35717           //https://github.com/angular/angular.js/blob/622c42169699ec07fc6daaa19fe6d224e5d2f70e/src/Angular.js#L1207
35718           function timezoneToOffset(timezone, fallback) {
35719             timezone = timezone.replace(/:/g, '');
35720             var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
35721             return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
35722           }
35723
35724           function addDateMinutes(date, minutes) {
35725             date = new Date(date.getTime());
35726             date.setMinutes(date.getMinutes() + minutes);
35727             return date;
35728           }
35729
35730           function convertTimezoneToLocal(date, timezone, reverse) {
35731             reverse = reverse ? -1 : 1;
35732             var dateTimezoneOffset = date.getTimezoneOffset();
35733             var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
35734             return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
35735           }
35736         }]);
35737
35738         // Avoiding use of ng-class as it creates a lot of watchers when a class is to be applied to
35739         // at most one element.
35740         angular.module('ui.bootstrap.isClass', [])
35741         .directive('uibIsClass', [
35742                  '$animate',
35743         function ($animate) {
35744           //                    11111111          22222222
35745           var ON_REGEXP = /^\s*([\s\S]+?)\s+on\s+([\s\S]+?)\s*$/;
35746           //                    11111111           22222222
35747           var IS_REGEXP = /^\s*([\s\S]+?)\s+for\s+([\s\S]+?)\s*$/;
35748
35749           var dataPerTracked = {};
35750
35751           return {
35752             restrict: 'A',
35753             compile: function(tElement, tAttrs) {
35754               var linkedScopes = [];
35755               var instances = [];
35756               var expToData = {};
35757               var lastActivated = null;
35758               var onExpMatches = tAttrs.uibIsClass.match(ON_REGEXP);
35759               var onExp = onExpMatches[2];
35760               var expsStr = onExpMatches[1];
35761               var exps = expsStr.split(',');
35762
35763               return linkFn;
35764
35765               function linkFn(scope, element, attrs) {
35766                 linkedScopes.push(scope);
35767                 instances.push({
35768                   scope: scope,
35769                   element: element
35770                 });
35771
35772                 exps.forEach(function(exp, k) {
35773                   addForExp(exp, scope);
35774                 });
35775
35776                 scope.$on('$destroy', removeScope);
35777               }
35778
35779               function addForExp(exp, scope) {
35780                 var matches = exp.match(IS_REGEXP);
35781                 var clazz = scope.$eval(matches[1]);
35782                 var compareWithExp = matches[2];
35783                 var data = expToData[exp];
35784                 if (!data) {
35785                   var watchFn = function(compareWithVal) {
35786                     var newActivated = null;
35787                     instances.some(function(instance) {
35788                       var thisVal = instance.scope.$eval(onExp);
35789                       if (thisVal === compareWithVal) {
35790                         newActivated = instance;
35791                         return true;
35792                       }
35793                     });
35794                     if (data.lastActivated !== newActivated) {
35795                       if (data.lastActivated) {
35796                         $animate.removeClass(data.lastActivated.element, clazz);
35797                       }
35798                       if (newActivated) {
35799                         $animate.addClass(newActivated.element, clazz);
35800                       }
35801                       data.lastActivated = newActivated;
35802                     }
35803                   };
35804                   expToData[exp] = data = {
35805                     lastActivated: null,
35806                     scope: scope,
35807                     watchFn: watchFn,
35808                     compareWithExp: compareWithExp,
35809                     watcher: scope.$watch(compareWithExp, watchFn)
35810                   };
35811                 }
35812                 data.watchFn(scope.$eval(compareWithExp));
35813               }
35814
35815               function removeScope(e) {
35816                 var removedScope = e.targetScope;
35817                 var index = linkedScopes.indexOf(removedScope);
35818                 linkedScopes.splice(index, 1);
35819                 instances.splice(index, 1);
35820                 if (linkedScopes.length) {
35821                   var newWatchScope = linkedScopes[0];
35822                   angular.forEach(expToData, function(data) {
35823                     if (data.scope === removedScope) {
35824                       data.watcher = newWatchScope.$watch(data.compareWithExp, data.watchFn);
35825                       data.scope = newWatchScope;
35826                     }
35827                   });
35828                 } else {
35829                   expToData = {};
35830                 }
35831               }
35832             }
35833           };
35834         }]);
35835         angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.isClass'])
35836
35837         .value('$datepickerSuppressError', false)
35838
35839         .value('$datepickerLiteralWarning', true)
35840
35841         .constant('uibDatepickerConfig', {
35842           datepickerMode: 'day',
35843           formatDay: 'dd',
35844           formatMonth: 'MMMM',
35845           formatYear: 'yyyy',
35846           formatDayHeader: 'EEE',
35847           formatDayTitle: 'MMMM yyyy',
35848           formatMonthTitle: 'yyyy',
35849           maxDate: null,
35850           maxMode: 'year',
35851           minDate: null,
35852           minMode: 'day',
35853           ngModelOptions: {},
35854           shortcutPropagation: false,
35855           showWeeks: true,
35856           yearColumns: 5,
35857           yearRows: 4
35858         })
35859
35860         .controller('UibDatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$locale', '$log', 'dateFilter', 'uibDatepickerConfig', '$datepickerLiteralWarning', '$datepickerSuppressError', 'uibDateParser',
35861           function($scope, $attrs, $parse, $interpolate, $locale, $log, dateFilter, datepickerConfig, $datepickerLiteralWarning, $datepickerSuppressError, dateParser) {
35862           var self = this,
35863               ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl;
35864               ngModelOptions = {},
35865               watchListeners = [],
35866               optionsUsed = !!$attrs.datepickerOptions;
35867
35868           if (!$scope.datepickerOptions) {
35869             $scope.datepickerOptions = {};
35870           }
35871
35872           // Modes chain
35873           this.modes = ['day', 'month', 'year'];
35874
35875           [
35876             'customClass',
35877             'dateDisabled',
35878             'datepickerMode',
35879             'formatDay',
35880             'formatDayHeader',
35881             'formatDayTitle',
35882             'formatMonth',
35883             'formatMonthTitle',
35884             'formatYear',
35885             'maxDate',
35886             'maxMode',
35887             'minDate',
35888             'minMode',
35889             'showWeeks',
35890             'shortcutPropagation',
35891             'startingDay',
35892             'yearColumns',
35893             'yearRows'
35894           ].forEach(function(key) {
35895             switch (key) {
35896               case 'customClass':
35897               case 'dateDisabled':
35898                 $scope[key] = $scope.datepickerOptions[key] || angular.noop;
35899                 break;
35900               case 'datepickerMode':
35901                 $scope.datepickerMode = angular.isDefined($scope.datepickerOptions.datepickerMode) ?
35902                   $scope.datepickerOptions.datepickerMode : datepickerConfig.datepickerMode;
35903                 break;
35904               case 'formatDay':
35905               case 'formatDayHeader':
35906               case 'formatDayTitle':
35907               case 'formatMonth':
35908               case 'formatMonthTitle':
35909               case 'formatYear':
35910                 self[key] = angular.isDefined($scope.datepickerOptions[key]) ?
35911                   $interpolate($scope.datepickerOptions[key])($scope.$parent) :
35912                   datepickerConfig[key];
35913                 break;
35914               case 'showWeeks':
35915               case 'shortcutPropagation':
35916               case 'yearColumns':
35917               case 'yearRows':
35918                 self[key] = angular.isDefined($scope.datepickerOptions[key]) ?
35919                   $scope.datepickerOptions[key] : datepickerConfig[key];
35920                 break;
35921               case 'startingDay':
35922                 if (angular.isDefined($scope.datepickerOptions.startingDay)) {
35923                   self.startingDay = $scope.datepickerOptions.startingDay;
35924                 } else if (angular.isNumber(datepickerConfig.startingDay)) {
35925                   self.startingDay = datepickerConfig.startingDay;
35926                 } else {
35927                   self.startingDay = ($locale.DATETIME_FORMATS.FIRSTDAYOFWEEK + 8) % 7;
35928                 }
35929
35930                 break;
35931               case 'maxDate':
35932               case 'minDate':
35933                 $scope.$watch('datepickerOptions.' + key, function(value) {
35934                   if (value) {
35935                     if (angular.isDate(value)) {
35936                       self[key] = dateParser.fromTimezone(new Date(value), ngModelOptions.timezone);
35937                     } else {
35938                       if ($datepickerLiteralWarning) {
35939                         $log.warn('Literal date support has been deprecated, please switch to date object usage');
35940                       }
35941
35942                       self[key] = new Date(dateFilter(value, 'medium'));
35943                     }
35944                   } else {
35945                     self[key] = datepickerConfig[key] ?
35946                       dateParser.fromTimezone(new Date(datepickerConfig[key]), ngModelOptions.timezone) :
35947                       null;
35948                   }
35949
35950                   self.refreshView();
35951                 });
35952
35953                 break;
35954               case 'maxMode':
35955               case 'minMode':
35956                 if ($scope.datepickerOptions[key]) {
35957                   $scope.$watch(function() { return $scope.datepickerOptions[key]; }, function(value) {
35958                     self[key] = $scope[key] = angular.isDefined(value) ? value : datepickerOptions[key];
35959                     if (key === 'minMode' && self.modes.indexOf($scope.datepickerOptions.datepickerMode) < self.modes.indexOf(self[key]) ||
35960                       key === 'maxMode' && self.modes.indexOf($scope.datepickerOptions.datepickerMode) > self.modes.indexOf(self[key])) {
35961                       $scope.datepickerMode = self[key];
35962                       $scope.datepickerOptions.datepickerMode = self[key];
35963                     }
35964                   });
35965                 } else {
35966                   self[key] = $scope[key] = datepickerConfig[key] || null;
35967                 }
35968
35969                 break;
35970             }
35971           });
35972
35973           $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
35974
35975           $scope.disabled = angular.isDefined($attrs.disabled) || false;
35976           if (angular.isDefined($attrs.ngDisabled)) {
35977             watchListeners.push($scope.$parent.$watch($attrs.ngDisabled, function(disabled) {
35978               $scope.disabled = disabled;
35979               self.refreshView();
35980             }));
35981           }
35982
35983           $scope.isActive = function(dateObject) {
35984             if (self.compare(dateObject.date, self.activeDate) === 0) {
35985               $scope.activeDateId = dateObject.uid;
35986               return true;
35987             }
35988             return false;
35989           };
35990
35991           this.init = function(ngModelCtrl_) {
35992             ngModelCtrl = ngModelCtrl_;
35993             ngModelOptions = ngModelCtrl_.$options || datepickerConfig.ngModelOptions;
35994             if ($scope.datepickerOptions.initDate) {
35995               self.activeDate = dateParser.fromTimezone($scope.datepickerOptions.initDate, ngModelOptions.timezone) || new Date();
35996               $scope.$watch('datepickerOptions.initDate', function(initDate) {
35997                 if (initDate && (ngModelCtrl.$isEmpty(ngModelCtrl.$modelValue) || ngModelCtrl.$invalid)) {
35998                   self.activeDate = dateParser.fromTimezone(initDate, ngModelOptions.timezone);
35999                   self.refreshView();
36000                 }
36001               });
36002             } else {
36003               self.activeDate = new Date();
36004             }
36005
36006             var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : new Date();
36007             this.activeDate = !isNaN(date) ?
36008               dateParser.fromTimezone(date, ngModelOptions.timezone) :
36009               dateParser.fromTimezone(new Date(), ngModelOptions.timezone);
36010
36011             ngModelCtrl.$render = function() {
36012               self.render();
36013             };
36014           };
36015
36016           this.render = function() {
36017             if (ngModelCtrl.$viewValue) {
36018               var date = new Date(ngModelCtrl.$viewValue),
36019                   isValid = !isNaN(date);
36020
36021               if (isValid) {
36022                 this.activeDate = dateParser.fromTimezone(date, ngModelOptions.timezone);
36023               } else if (!$datepickerSuppressError) {
36024                 $log.error('Datepicker directive: "ng-model" value must be a Date object');
36025               }
36026             }
36027             this.refreshView();
36028           };
36029
36030           this.refreshView = function() {
36031             if (this.element) {
36032               $scope.selectedDt = null;
36033               this._refreshView();
36034               if ($scope.activeDt) {
36035                 $scope.activeDateId = $scope.activeDt.uid;
36036               }
36037
36038               var date = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
36039               date = dateParser.fromTimezone(date, ngModelOptions.timezone);
36040               ngModelCtrl.$setValidity('dateDisabled', !date ||
36041                 this.element && !this.isDisabled(date));
36042             }
36043           };
36044
36045           this.createDateObject = function(date, format) {
36046             var model = ngModelCtrl.$viewValue ? new Date(ngModelCtrl.$viewValue) : null;
36047             model = dateParser.fromTimezone(model, ngModelOptions.timezone);
36048             var today = new Date();
36049             today = dateParser.fromTimezone(today, ngModelOptions.timezone);
36050             var time = this.compare(date, today);
36051             var dt = {
36052               date: date,
36053               label: dateParser.filter(date, format),
36054               selected: model && this.compare(date, model) === 0,
36055               disabled: this.isDisabled(date),
36056               past: time < 0,
36057               current: time === 0,
36058               future: time > 0,
36059               customClass: this.customClass(date) || null
36060             };
36061
36062             if (model && this.compare(date, model) === 0) {
36063               $scope.selectedDt = dt;
36064             }
36065
36066             if (self.activeDate && this.compare(dt.date, self.activeDate) === 0) {
36067               $scope.activeDt = dt;
36068             }
36069
36070             return dt;
36071           };
36072
36073           this.isDisabled = function(date) {
36074             return $scope.disabled ||
36075               this.minDate && this.compare(date, this.minDate) < 0 ||
36076               this.maxDate && this.compare(date, this.maxDate) > 0 ||
36077               $scope.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode});
36078           };
36079
36080           this.customClass = function(date) {
36081             return $scope.customClass({date: date, mode: $scope.datepickerMode});
36082           };
36083
36084           // Split array into smaller arrays
36085           this.split = function(arr, size) {
36086             var arrays = [];
36087             while (arr.length > 0) {
36088               arrays.push(arr.splice(0, size));
36089             }
36090             return arrays;
36091           };
36092
36093           $scope.select = function(date) {
36094             if ($scope.datepickerMode === self.minMode) {
36095               var dt = ngModelCtrl.$viewValue ? dateParser.fromTimezone(new Date(ngModelCtrl.$viewValue), ngModelOptions.timezone) : new Date(0, 0, 0, 0, 0, 0, 0);
36096               dt.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
36097               dt = dateParser.toTimezone(dt, ngModelOptions.timezone);
36098               ngModelCtrl.$setViewValue(dt);
36099               ngModelCtrl.$render();
36100             } else {
36101               self.activeDate = date;
36102               setMode(self.modes[self.modes.indexOf($scope.datepickerMode) - 1]);
36103
36104               $scope.$emit('uib:datepicker.mode');
36105             }
36106
36107             $scope.$broadcast('uib:datepicker.focus');
36108           };
36109
36110           $scope.move = function(direction) {
36111             var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
36112                 month = self.activeDate.getMonth() + direction * (self.step.months || 0);
36113             self.activeDate.setFullYear(year, month, 1);
36114             self.refreshView();
36115           };
36116
36117           $scope.toggleMode = function(direction) {
36118             direction = direction || 1;
36119
36120             if ($scope.datepickerMode === self.maxMode && direction === 1 ||
36121               $scope.datepickerMode === self.minMode && direction === -1) {
36122               return;
36123             }
36124
36125             setMode(self.modes[self.modes.indexOf($scope.datepickerMode) + direction]);
36126
36127             $scope.$emit('uib:datepicker.mode');
36128           };
36129
36130           // Key event mapper
36131           $scope.keys = { 13: 'enter', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 37: 'left', 38: 'up', 39: 'right', 40: 'down' };
36132
36133           var focusElement = function() {
36134             self.element[0].focus();
36135           };
36136
36137           // Listen for focus requests from popup directive
36138           $scope.$on('uib:datepicker.focus', focusElement);
36139
36140           $scope.keydown = function(evt) {
36141             var key = $scope.keys[evt.which];
36142
36143             if (!key || evt.shiftKey || evt.altKey || $scope.disabled) {
36144               return;
36145             }
36146
36147             evt.preventDefault();
36148             if (!self.shortcutPropagation) {
36149               evt.stopPropagation();
36150             }
36151
36152             if (key === 'enter' || key === 'space') {
36153               if (self.isDisabled(self.activeDate)) {
36154                 return; // do nothing
36155               }
36156               $scope.select(self.activeDate);
36157             } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
36158               $scope.toggleMode(key === 'up' ? 1 : -1);
36159             } else {
36160               self.handleKeyDown(key, evt);
36161               self.refreshView();
36162             }
36163           };
36164
36165           $scope.$on('$destroy', function() {
36166             //Clear all watch listeners on destroy
36167             while (watchListeners.length) {
36168               watchListeners.shift()();
36169             }
36170           });
36171
36172           function setMode(mode) {
36173             $scope.datepickerMode = mode;
36174             $scope.datepickerOptions.datepickerMode = mode;
36175           }
36176         }])
36177
36178         .controller('UibDaypickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36179           var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
36180
36181           this.step = { months: 1 };
36182           this.element = $element;
36183           function getDaysInMonth(year, month) {
36184             return month === 1 && year % 4 === 0 &&
36185               (year % 100 !== 0 || year % 400 === 0) ? 29 : DAYS_IN_MONTH[month];
36186           }
36187
36188           this.init = function(ctrl) {
36189             angular.extend(ctrl, this);
36190             scope.showWeeks = ctrl.showWeeks;
36191             ctrl.refreshView();
36192           };
36193
36194           this.getDates = function(startDate, n) {
36195             var dates = new Array(n), current = new Date(startDate), i = 0, date;
36196             while (i < n) {
36197               date = new Date(current);
36198               dates[i++] = date;
36199               current.setDate(current.getDate() + 1);
36200             }
36201             return dates;
36202           };
36203
36204           this._refreshView = function() {
36205             var year = this.activeDate.getFullYear(),
36206               month = this.activeDate.getMonth(),
36207               firstDayOfMonth = new Date(this.activeDate);
36208
36209             firstDayOfMonth.setFullYear(year, month, 1);
36210
36211             var difference = this.startingDay - firstDayOfMonth.getDay(),
36212               numDisplayedFromPreviousMonth = difference > 0 ?
36213                 7 - difference : - difference,
36214               firstDate = new Date(firstDayOfMonth);
36215
36216             if (numDisplayedFromPreviousMonth > 0) {
36217               firstDate.setDate(-numDisplayedFromPreviousMonth + 1);
36218             }
36219
36220             // 42 is the number of days on a six-week calendar
36221             var days = this.getDates(firstDate, 42);
36222             for (var i = 0; i < 42; i ++) {
36223               days[i] = angular.extend(this.createDateObject(days[i], this.formatDay), {
36224                 secondary: days[i].getMonth() !== month,
36225                 uid: scope.uniqueId + '-' + i
36226               });
36227             }
36228
36229             scope.labels = new Array(7);
36230             for (var j = 0; j < 7; j++) {
36231               scope.labels[j] = {
36232                 abbr: dateFilter(days[j].date, this.formatDayHeader),
36233                 full: dateFilter(days[j].date, 'EEEE')
36234               };
36235             }
36236
36237             scope.title = dateFilter(this.activeDate, this.formatDayTitle);
36238             scope.rows = this.split(days, 7);
36239
36240             if (scope.showWeeks) {
36241               scope.weekNumbers = [];
36242               var thursdayIndex = (4 + 7 - this.startingDay) % 7,
36243                   numWeeks = scope.rows.length;
36244               for (var curWeek = 0; curWeek < numWeeks; curWeek++) {
36245                 scope.weekNumbers.push(
36246                   getISO8601WeekNumber(scope.rows[curWeek][thursdayIndex].date));
36247               }
36248             }
36249           };
36250
36251           this.compare = function(date1, date2) {
36252             var _date1 = new Date(date1.getFullYear(), date1.getMonth(), date1.getDate());
36253             var _date2 = new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
36254             _date1.setFullYear(date1.getFullYear());
36255             _date2.setFullYear(date2.getFullYear());
36256             return _date1 - _date2;
36257           };
36258
36259           function getISO8601WeekNumber(date) {
36260             var checkDate = new Date(date);
36261             checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
36262             var time = checkDate.getTime();
36263             checkDate.setMonth(0); // Compare with Jan 1
36264             checkDate.setDate(1);
36265             return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
36266           }
36267
36268           this.handleKeyDown = function(key, evt) {
36269             var date = this.activeDate.getDate();
36270
36271             if (key === 'left') {
36272               date = date - 1;
36273             } else if (key === 'up') {
36274               date = date - 7;
36275             } else if (key === 'right') {
36276               date = date + 1;
36277             } else if (key === 'down') {
36278               date = date + 7;
36279             } else if (key === 'pageup' || key === 'pagedown') {
36280               var month = this.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
36281               this.activeDate.setMonth(month, 1);
36282               date = Math.min(getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth()), date);
36283             } else if (key === 'home') {
36284               date = 1;
36285             } else if (key === 'end') {
36286               date = getDaysInMonth(this.activeDate.getFullYear(), this.activeDate.getMonth());
36287             }
36288             this.activeDate.setDate(date);
36289           };
36290         }])
36291
36292         .controller('UibMonthpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36293           this.step = { years: 1 };
36294           this.element = $element;
36295
36296           this.init = function(ctrl) {
36297             angular.extend(ctrl, this);
36298             ctrl.refreshView();
36299           };
36300
36301           this._refreshView = function() {
36302             var months = new Array(12),
36303                 year = this.activeDate.getFullYear(),
36304                 date;
36305
36306             for (var i = 0; i < 12; i++) {
36307               date = new Date(this.activeDate);
36308               date.setFullYear(year, i, 1);
36309               months[i] = angular.extend(this.createDateObject(date, this.formatMonth), {
36310                 uid: scope.uniqueId + '-' + i
36311               });
36312             }
36313
36314             scope.title = dateFilter(this.activeDate, this.formatMonthTitle);
36315             scope.rows = this.split(months, 3);
36316           };
36317
36318           this.compare = function(date1, date2) {
36319             var _date1 = new Date(date1.getFullYear(), date1.getMonth());
36320             var _date2 = new Date(date2.getFullYear(), date2.getMonth());
36321             _date1.setFullYear(date1.getFullYear());
36322             _date2.setFullYear(date2.getFullYear());
36323             return _date1 - _date2;
36324           };
36325
36326           this.handleKeyDown = function(key, evt) {
36327             var date = this.activeDate.getMonth();
36328
36329             if (key === 'left') {
36330               date = date - 1;
36331             } else if (key === 'up') {
36332               date = date - 3;
36333             } else if (key === 'right') {
36334               date = date + 1;
36335             } else if (key === 'down') {
36336               date = date + 3;
36337             } else if (key === 'pageup' || key === 'pagedown') {
36338               var year = this.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
36339               this.activeDate.setFullYear(year);
36340             } else if (key === 'home') {
36341               date = 0;
36342             } else if (key === 'end') {
36343               date = 11;
36344             }
36345             this.activeDate.setMonth(date);
36346           };
36347         }])
36348
36349         .controller('UibYearpickerController', ['$scope', '$element', 'dateFilter', function(scope, $element, dateFilter) {
36350           var columns, range;
36351           this.element = $element;
36352
36353           function getStartingYear(year) {
36354             return parseInt((year - 1) / range, 10) * range + 1;
36355           }
36356
36357           this.yearpickerInit = function() {
36358             columns = this.yearColumns;
36359             range = this.yearRows * columns;
36360             this.step = { years: range };
36361           };
36362
36363           this._refreshView = function() {
36364             var years = new Array(range), date;
36365
36366             for (var i = 0, start = getStartingYear(this.activeDate.getFullYear()); i < range; i++) {
36367               date = new Date(this.activeDate);
36368               date.setFullYear(start + i, 0, 1);
36369               years[i] = angular.extend(this.createDateObject(date, this.formatYear), {
36370                 uid: scope.uniqueId + '-' + i
36371               });
36372             }
36373
36374             scope.title = [years[0].label, years[range - 1].label].join(' - ');
36375             scope.rows = this.split(years, columns);
36376             scope.columns = columns;
36377           };
36378
36379           this.compare = function(date1, date2) {
36380             return date1.getFullYear() - date2.getFullYear();
36381           };
36382
36383           this.handleKeyDown = function(key, evt) {
36384             var date = this.activeDate.getFullYear();
36385
36386             if (key === 'left') {
36387               date = date - 1;
36388             } else if (key === 'up') {
36389               date = date - columns;
36390             } else if (key === 'right') {
36391               date = date + 1;
36392             } else if (key === 'down') {
36393               date = date + columns;
36394             } else if (key === 'pageup' || key === 'pagedown') {
36395               date += (key === 'pageup' ? - 1 : 1) * range;
36396             } else if (key === 'home') {
36397               date = getStartingYear(this.activeDate.getFullYear());
36398             } else if (key === 'end') {
36399               date = getStartingYear(this.activeDate.getFullYear()) + range - 1;
36400             }
36401             this.activeDate.setFullYear(date);
36402           };
36403         }])
36404
36405         .directive('uibDatepicker', function() {
36406           return {
36407             replace: true,
36408             templateUrl: function(element, attrs) {
36409               return attrs.templateUrl || 'uib/template/datepicker/datepicker.html';
36410             },
36411             scope: {
36412               datepickerOptions: '=?'
36413             },
36414             require: ['uibDatepicker', '^ngModel'],
36415             controller: 'UibDatepickerController',
36416             controllerAs: 'datepicker',
36417             link: function(scope, element, attrs, ctrls) {
36418               var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
36419
36420               datepickerCtrl.init(ngModelCtrl);
36421             }
36422           };
36423         })
36424
36425         .directive('uibDaypicker', function() {
36426           return {
36427             replace: true,
36428             templateUrl: function(element, attrs) {
36429               return attrs.templateUrl || 'uib/template/datepicker/day.html';
36430             },
36431             require: ['^uibDatepicker', 'uibDaypicker'],
36432             controller: 'UibDaypickerController',
36433             link: function(scope, element, attrs, ctrls) {
36434               var datepickerCtrl = ctrls[0],
36435                 daypickerCtrl = ctrls[1];
36436
36437               daypickerCtrl.init(datepickerCtrl);
36438             }
36439           };
36440         })
36441
36442         .directive('uibMonthpicker', function() {
36443           return {
36444             replace: true,
36445             templateUrl: function(element, attrs) {
36446               return attrs.templateUrl || 'uib/template/datepicker/month.html';
36447             },
36448             require: ['^uibDatepicker', 'uibMonthpicker'],
36449             controller: 'UibMonthpickerController',
36450             link: function(scope, element, attrs, ctrls) {
36451               var datepickerCtrl = ctrls[0],
36452                 monthpickerCtrl = ctrls[1];
36453
36454               monthpickerCtrl.init(datepickerCtrl);
36455             }
36456           };
36457         })
36458
36459         .directive('uibYearpicker', function() {
36460           return {
36461             replace: true,
36462             templateUrl: function(element, attrs) {
36463               return attrs.templateUrl || 'uib/template/datepicker/year.html';
36464             },
36465             require: ['^uibDatepicker', 'uibYearpicker'],
36466             controller: 'UibYearpickerController',
36467             link: function(scope, element, attrs, ctrls) {
36468               var ctrl = ctrls[0];
36469               angular.extend(ctrl, ctrls[1]);
36470               ctrl.yearpickerInit();
36471
36472               ctrl.refreshView();
36473             }
36474           };
36475         });
36476
36477         angular.module('ui.bootstrap.position', [])
36478
36479         /**
36480          * A set of utility methods for working with the DOM.
36481          * It is meant to be used where we need to absolute-position elements in
36482          * relation to another element (this is the case for tooltips, popovers,
36483          * typeahead suggestions etc.).
36484          */
36485           .factory('$uibPosition', ['$document', '$window', function($document, $window) {
36486             /**
36487              * Used by scrollbarWidth() function to cache scrollbar's width.
36488              * Do not access this variable directly, use scrollbarWidth() instead.
36489              */
36490             var SCROLLBAR_WIDTH;
36491             /**
36492              * scrollbar on body and html element in IE and Edge overlay
36493              * content and should be considered 0 width.
36494              */
36495             var BODY_SCROLLBAR_WIDTH;
36496             var OVERFLOW_REGEX = {
36497               normal: /(auto|scroll)/,
36498               hidden: /(auto|scroll|hidden)/
36499             };
36500             var PLACEMENT_REGEX = {
36501               auto: /\s?auto?\s?/i,
36502               primary: /^(top|bottom|left|right)$/,
36503               secondary: /^(top|bottom|left|right|center)$/,
36504               vertical: /^(top|bottom)$/
36505             };
36506             var BODY_REGEX = /(HTML|BODY)/;
36507
36508             return {
36509
36510               /**
36511                * Provides a raw DOM element from a jQuery/jQLite element.
36512                *
36513                * @param {element} elem - The element to convert.
36514                *
36515                * @returns {element} A HTML element.
36516                */
36517               getRawNode: function(elem) {
36518                 return elem.nodeName ? elem : elem[0] || elem;
36519               },
36520
36521               /**
36522                * Provides a parsed number for a style property.  Strips
36523                * units and casts invalid numbers to 0.
36524                *
36525                * @param {string} value - The style value to parse.
36526                *
36527                * @returns {number} A valid number.
36528                */
36529               parseStyle: function(value) {
36530                 value = parseFloat(value);
36531                 return isFinite(value) ? value : 0;
36532               },
36533
36534               /**
36535                * Provides the closest positioned ancestor.
36536                *
36537                * @param {element} element - The element to get the offest parent for.
36538                *
36539                * @returns {element} The closest positioned ancestor.
36540                */
36541               offsetParent: function(elem) {
36542                 elem = this.getRawNode(elem);
36543
36544                 var offsetParent = elem.offsetParent || $document[0].documentElement;
36545
36546                 function isStaticPositioned(el) {
36547                   return ($window.getComputedStyle(el).position || 'static') === 'static';
36548                 }
36549
36550                 while (offsetParent && offsetParent !== $document[0].documentElement && isStaticPositioned(offsetParent)) {
36551                   offsetParent = offsetParent.offsetParent;
36552                 }
36553
36554                 return offsetParent || $document[0].documentElement;
36555               },
36556
36557               /**
36558                * Provides the scrollbar width, concept from TWBS measureScrollbar()
36559                * function in https://github.com/twbs/bootstrap/blob/master/js/modal.js
36560                * In IE and Edge, scollbar on body and html element overlay and should
36561                * return a width of 0.
36562                *
36563                * @returns {number} The width of the browser scollbar.
36564                */
36565               scrollbarWidth: function(isBody) {
36566                 if (isBody) {
36567                   if (angular.isUndefined(BODY_SCROLLBAR_WIDTH)) {
36568                     var bodyElem = $document.find('body');
36569                     bodyElem.addClass('uib-position-body-scrollbar-measure');
36570                     BODY_SCROLLBAR_WIDTH = $window.innerWidth - bodyElem[0].clientWidth;
36571                     BODY_SCROLLBAR_WIDTH = isFinite(BODY_SCROLLBAR_WIDTH) ? BODY_SCROLLBAR_WIDTH : 0;
36572                     bodyElem.removeClass('uib-position-body-scrollbar-measure');
36573                   }
36574                   return BODY_SCROLLBAR_WIDTH;
36575                 }
36576
36577                 if (angular.isUndefined(SCROLLBAR_WIDTH)) {
36578                   var scrollElem = angular.element('<div class="uib-position-scrollbar-measure"></div>');
36579                   $document.find('body').append(scrollElem);
36580                   SCROLLBAR_WIDTH = scrollElem[0].offsetWidth - scrollElem[0].clientWidth;
36581                   SCROLLBAR_WIDTH = isFinite(SCROLLBAR_WIDTH) ? SCROLLBAR_WIDTH : 0;
36582                   scrollElem.remove();
36583                 }
36584
36585                 return SCROLLBAR_WIDTH;
36586               },
36587
36588               /**
36589                * Provides the padding required on an element to replace the scrollbar.
36590                *
36591                * @returns {object} An object with the following properties:
36592                *   <ul>
36593                *     <li>**scrollbarWidth**: the width of the scrollbar</li>
36594                *     <li>**widthOverflow**: whether the the width is overflowing</li>
36595                *     <li>**right**: the amount of right padding on the element needed to replace the scrollbar</li>
36596                *     <li>**rightOriginal**: the amount of right padding currently on the element</li>
36597                *     <li>**heightOverflow**: whether the the height is overflowing</li>
36598                *     <li>**bottom**: the amount of bottom padding on the element needed to replace the scrollbar</li>
36599                *     <li>**bottomOriginal**: the amount of bottom padding currently on the element</li>
36600                *   </ul>
36601                */
36602               scrollbarPadding: function(elem) {
36603                 elem = this.getRawNode(elem);
36604
36605                 var elemStyle = $window.getComputedStyle(elem);
36606                 var paddingRight = this.parseStyle(elemStyle.paddingRight);
36607                 var paddingBottom = this.parseStyle(elemStyle.paddingBottom);
36608                 var scrollParent = this.scrollParent(elem, false, true);
36609                 var scrollbarWidth = this.scrollbarWidth(scrollParent, BODY_REGEX.test(scrollParent.tagName));
36610
36611                 return {
36612                   scrollbarWidth: scrollbarWidth,
36613                   widthOverflow: scrollParent.scrollWidth > scrollParent.clientWidth,
36614                   right: paddingRight + scrollbarWidth,
36615                   originalRight: paddingRight,
36616                   heightOverflow: scrollParent.scrollHeight > scrollParent.clientHeight,
36617                   bottom: paddingBottom + scrollbarWidth,
36618                   originalBottom: paddingBottom
36619                  };
36620               },
36621
36622               /**
36623                * Checks to see if the element is scrollable.
36624                *
36625                * @param {element} elem - The element to check.
36626                * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered,
36627                *   default is false.
36628                *
36629                * @returns {boolean} Whether the element is scrollable.
36630                */
36631               isScrollable: function(elem, includeHidden) {
36632                 elem = this.getRawNode(elem);
36633
36634                 var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal;
36635                 var elemStyle = $window.getComputedStyle(elem);
36636                 return overflowRegex.test(elemStyle.overflow + elemStyle.overflowY + elemStyle.overflowX);
36637               },
36638
36639               /**
36640                * Provides the closest scrollable ancestor.
36641                * A port of the jQuery UI scrollParent method:
36642                * https://github.com/jquery/jquery-ui/blob/master/ui/scroll-parent.js
36643                *
36644                * @param {element} elem - The element to find the scroll parent of.
36645                * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered,
36646                *   default is false.
36647                * @param {boolean=} [includeSelf=false] - Should the element being passed be
36648                * included in the scrollable llokup.
36649                *
36650                * @returns {element} A HTML element.
36651                */
36652               scrollParent: function(elem, includeHidden, includeSelf) {
36653                 elem = this.getRawNode(elem);
36654
36655                 var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal;
36656                 var documentEl = $document[0].documentElement;
36657                 var elemStyle = $window.getComputedStyle(elem);
36658                 if (includeSelf && overflowRegex.test(elemStyle.overflow + elemStyle.overflowY + elemStyle.overflowX)) {
36659                   return elem;
36660                 }
36661                 var excludeStatic = elemStyle.position === 'absolute';
36662                 var scrollParent = elem.parentElement || documentEl;
36663
36664                 if (scrollParent === documentEl || elemStyle.position === 'fixed') {
36665                   return documentEl;
36666                 }
36667
36668                 while (scrollParent.parentElement && scrollParent !== documentEl) {
36669                   var spStyle = $window.getComputedStyle(scrollParent);
36670                   if (excludeStatic && spStyle.position !== 'static') {
36671                     excludeStatic = false;
36672                   }
36673
36674                   if (!excludeStatic && overflowRegex.test(spStyle.overflow + spStyle.overflowY + spStyle.overflowX)) {
36675                     break;
36676                   }
36677                   scrollParent = scrollParent.parentElement;
36678                 }
36679
36680                 return scrollParent;
36681               },
36682
36683               /**
36684                * Provides read-only equivalent of jQuery's position function:
36685                * http://api.jquery.com/position/ - distance to closest positioned
36686                * ancestor.  Does not account for margins by default like jQuery position.
36687                *
36688                * @param {element} elem - The element to caclulate the position on.
36689                * @param {boolean=} [includeMargins=false] - Should margins be accounted
36690                * for, default is false.
36691                *
36692                * @returns {object} An object with the following properties:
36693                *   <ul>
36694                *     <li>**width**: the width of the element</li>
36695                *     <li>**height**: the height of the element</li>
36696                *     <li>**top**: distance to top edge of offset parent</li>
36697                *     <li>**left**: distance to left edge of offset parent</li>
36698                *   </ul>
36699                */
36700               position: function(elem, includeMagins) {
36701                 elem = this.getRawNode(elem);
36702
36703                 var elemOffset = this.offset(elem);
36704                 if (includeMagins) {
36705                   var elemStyle = $window.getComputedStyle(elem);
36706                   elemOffset.top -= this.parseStyle(elemStyle.marginTop);
36707                   elemOffset.left -= this.parseStyle(elemStyle.marginLeft);
36708                 }
36709                 var parent = this.offsetParent(elem);
36710                 var parentOffset = {top: 0, left: 0};
36711
36712                 if (parent !== $document[0].documentElement) {
36713                   parentOffset = this.offset(parent);
36714                   parentOffset.top += parent.clientTop - parent.scrollTop;
36715                   parentOffset.left += parent.clientLeft - parent.scrollLeft;
36716                 }
36717
36718                 return {
36719                   width: Math.round(angular.isNumber(elemOffset.width) ? elemOffset.width : elem.offsetWidth),
36720                   height: Math.round(angular.isNumber(elemOffset.height) ? elemOffset.height : elem.offsetHeight),
36721                   top: Math.round(elemOffset.top - parentOffset.top),
36722                   left: Math.round(elemOffset.left - parentOffset.left)
36723                 };
36724               },
36725
36726               /**
36727                * Provides read-only equivalent of jQuery's offset function:
36728                * http://api.jquery.com/offset/ - distance to viewport.  Does
36729                * not account for borders, margins, or padding on the body
36730                * element.
36731                *
36732                * @param {element} elem - The element to calculate the offset on.
36733                *
36734                * @returns {object} An object with the following properties:
36735                *   <ul>
36736                *     <li>**width**: the width of the element</li>
36737                *     <li>**height**: the height of the element</li>
36738                *     <li>**top**: distance to top edge of viewport</li>
36739                *     <li>**right**: distance to bottom edge of viewport</li>
36740                *   </ul>
36741                */
36742               offset: function(elem) {
36743                 elem = this.getRawNode(elem);
36744
36745                 var elemBCR = elem.getBoundingClientRect();
36746                 return {
36747                   width: Math.round(angular.isNumber(elemBCR.width) ? elemBCR.width : elem.offsetWidth),
36748                   height: Math.round(angular.isNumber(elemBCR.height) ? elemBCR.height : elem.offsetHeight),
36749                   top: Math.round(elemBCR.top + ($window.pageYOffset || $document[0].documentElement.scrollTop)),
36750                   left: Math.round(elemBCR.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft))
36751                 };
36752               },
36753
36754               /**
36755                * Provides offset distance to the closest scrollable ancestor
36756                * or viewport.  Accounts for border and scrollbar width.
36757                *
36758                * Right and bottom dimensions represent the distance to the
36759                * respective edge of the viewport element.  If the element
36760                * edge extends beyond the viewport, a negative value will be
36761                * reported.
36762                *
36763                * @param {element} elem - The element to get the viewport offset for.
36764                * @param {boolean=} [useDocument=false] - Should the viewport be the document element instead
36765                * of the first scrollable element, default is false.
36766                * @param {boolean=} [includePadding=true] - Should the padding on the offset parent element
36767                * be accounted for, default is true.
36768                *
36769                * @returns {object} An object with the following properties:
36770                *   <ul>
36771                *     <li>**top**: distance to the top content edge of viewport element</li>
36772                *     <li>**bottom**: distance to the bottom content edge of viewport element</li>
36773                *     <li>**left**: distance to the left content edge of viewport element</li>
36774                *     <li>**right**: distance to the right content edge of viewport element</li>
36775                *   </ul>
36776                */
36777               viewportOffset: function(elem, useDocument, includePadding) {
36778                 elem = this.getRawNode(elem);
36779                 includePadding = includePadding !== false ? true : false;
36780
36781                 var elemBCR = elem.getBoundingClientRect();
36782                 var offsetBCR = {top: 0, left: 0, bottom: 0, right: 0};
36783
36784                 var offsetParent = useDocument ? $document[0].documentElement : this.scrollParent(elem);
36785                 var offsetParentBCR = offsetParent.getBoundingClientRect();
36786
36787                 offsetBCR.top = offsetParentBCR.top + offsetParent.clientTop;
36788                 offsetBCR.left = offsetParentBCR.left + offsetParent.clientLeft;
36789                 if (offsetParent === $document[0].documentElement) {
36790                   offsetBCR.top += $window.pageYOffset;
36791                   offsetBCR.left += $window.pageXOffset;
36792                 }
36793                 offsetBCR.bottom = offsetBCR.top + offsetParent.clientHeight;
36794                 offsetBCR.right = offsetBCR.left + offsetParent.clientWidth;
36795
36796                 if (includePadding) {
36797                   var offsetParentStyle = $window.getComputedStyle(offsetParent);
36798                   offsetBCR.top += this.parseStyle(offsetParentStyle.paddingTop);
36799                   offsetBCR.bottom -= this.parseStyle(offsetParentStyle.paddingBottom);
36800                   offsetBCR.left += this.parseStyle(offsetParentStyle.paddingLeft);
36801                   offsetBCR.right -= this.parseStyle(offsetParentStyle.paddingRight);
36802                 }
36803
36804                 return {
36805                   top: Math.round(elemBCR.top - offsetBCR.top),
36806                   bottom: Math.round(offsetBCR.bottom - elemBCR.bottom),
36807                   left: Math.round(elemBCR.left - offsetBCR.left),
36808                   right: Math.round(offsetBCR.right - elemBCR.right)
36809                 };
36810               },
36811
36812               /**
36813                * Provides an array of placement values parsed from a placement string.
36814                * Along with the 'auto' indicator, supported placement strings are:
36815                *   <ul>
36816                *     <li>top: element on top, horizontally centered on host element.</li>
36817                *     <li>top-left: element on top, left edge aligned with host element left edge.</li>
36818                *     <li>top-right: element on top, lerightft edge aligned with host element right edge.</li>
36819                *     <li>bottom: element on bottom, horizontally centered on host element.</li>
36820                *     <li>bottom-left: element on bottom, left edge aligned with host element left edge.</li>
36821                *     <li>bottom-right: element on bottom, right edge aligned with host element right edge.</li>
36822                *     <li>left: element on left, vertically centered on host element.</li>
36823                *     <li>left-top: element on left, top edge aligned with host element top edge.</li>
36824                *     <li>left-bottom: element on left, bottom edge aligned with host element bottom edge.</li>
36825                *     <li>right: element on right, vertically centered on host element.</li>
36826                *     <li>right-top: element on right, top edge aligned with host element top edge.</li>
36827                *     <li>right-bottom: element on right, bottom edge aligned with host element bottom edge.</li>
36828                *   </ul>
36829                * A placement string with an 'auto' indicator is expected to be
36830                * space separated from the placement, i.e: 'auto bottom-left'  If
36831                * the primary and secondary placement values do not match 'top,
36832                * bottom, left, right' then 'top' will be the primary placement and
36833                * 'center' will be the secondary placement.  If 'auto' is passed, true
36834                * will be returned as the 3rd value of the array.
36835                *
36836                * @param {string} placement - The placement string to parse.
36837                *
36838                * @returns {array} An array with the following values
36839                * <ul>
36840                *   <li>**[0]**: The primary placement.</li>
36841                *   <li>**[1]**: The secondary placement.</li>
36842                *   <li>**[2]**: If auto is passed: true, else undefined.</li>
36843                * </ul>
36844                */
36845               parsePlacement: function(placement) {
36846                 var autoPlace = PLACEMENT_REGEX.auto.test(placement);
36847                 if (autoPlace) {
36848                   placement = placement.replace(PLACEMENT_REGEX.auto, '');
36849                 }
36850
36851                 placement = placement.split('-');
36852
36853                 placement[0] = placement[0] || 'top';
36854                 if (!PLACEMENT_REGEX.primary.test(placement[0])) {
36855                   placement[0] = 'top';
36856                 }
36857
36858                 placement[1] = placement[1] || 'center';
36859                 if (!PLACEMENT_REGEX.secondary.test(placement[1])) {
36860                   placement[1] = 'center';
36861                 }
36862
36863                 if (autoPlace) {
36864                   placement[2] = true;
36865                 } else {
36866                   placement[2] = false;
36867                 }
36868
36869                 return placement;
36870               },
36871
36872               /**
36873                * Provides coordinates for an element to be positioned relative to
36874                * another element.  Passing 'auto' as part of the placement parameter
36875                * will enable smart placement - where the element fits. i.e:
36876                * 'auto left-top' will check to see if there is enough space to the left
36877                * of the hostElem to fit the targetElem, if not place right (same for secondary
36878                * top placement).  Available space is calculated using the viewportOffset
36879                * function.
36880                *
36881                * @param {element} hostElem - The element to position against.
36882                * @param {element} targetElem - The element to position.
36883                * @param {string=} [placement=top] - The placement for the targetElem,
36884                *   default is 'top'. 'center' is assumed as secondary placement for
36885                *   'top', 'left', 'right', and 'bottom' placements.  Available placements are:
36886                *   <ul>
36887                *     <li>top</li>
36888                *     <li>top-right</li>
36889                *     <li>top-left</li>
36890                *     <li>bottom</li>
36891                *     <li>bottom-left</li>
36892                *     <li>bottom-right</li>
36893                *     <li>left</li>
36894                *     <li>left-top</li>
36895                *     <li>left-bottom</li>
36896                *     <li>right</li>
36897                *     <li>right-top</li>
36898                *     <li>right-bottom</li>
36899                *   </ul>
36900                * @param {boolean=} [appendToBody=false] - Should the top and left values returned
36901                *   be calculated from the body element, default is false.
36902                *
36903                * @returns {object} An object with the following properties:
36904                *   <ul>
36905                *     <li>**top**: Value for targetElem top.</li>
36906                *     <li>**left**: Value for targetElem left.</li>
36907                *     <li>**placement**: The resolved placement.</li>
36908                *   </ul>
36909                */
36910               positionElements: function(hostElem, targetElem, placement, appendToBody) {
36911                 hostElem = this.getRawNode(hostElem);
36912                 targetElem = this.getRawNode(targetElem);
36913
36914                 // need to read from prop to support tests.
36915                 var targetWidth = angular.isDefined(targetElem.offsetWidth) ? targetElem.offsetWidth : targetElem.prop('offsetWidth');
36916                 var targetHeight = angular.isDefined(targetElem.offsetHeight) ? targetElem.offsetHeight : targetElem.prop('offsetHeight');
36917
36918                 placement = this.parsePlacement(placement);
36919
36920                 var hostElemPos = appendToBody ? this.offset(hostElem) : this.position(hostElem);
36921                 var targetElemPos = {top: 0, left: 0, placement: ''};
36922
36923                 if (placement[2]) {
36924                   var viewportOffset = this.viewportOffset(hostElem, appendToBody);
36925
36926                   var targetElemStyle = $window.getComputedStyle(targetElem);
36927                   var adjustedSize = {
36928                     width: targetWidth + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginLeft) + this.parseStyle(targetElemStyle.marginRight))),
36929                     height: targetHeight + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginTop) + this.parseStyle(targetElemStyle.marginBottom)))
36930                   };
36931
36932                   placement[0] = placement[0] === 'top' && adjustedSize.height > viewportOffset.top && adjustedSize.height <= viewportOffset.bottom ? 'bottom' :
36933                                  placement[0] === 'bottom' && adjustedSize.height > viewportOffset.bottom && adjustedSize.height <= viewportOffset.top ? 'top' :
36934                                  placement[0] === 'left' && adjustedSize.width > viewportOffset.left && adjustedSize.width <= viewportOffset.right ? 'right' :
36935                                  placement[0] === 'right' && adjustedSize.width > viewportOffset.right && adjustedSize.width <= viewportOffset.left ? 'left' :
36936                                  placement[0];
36937
36938                   placement[1] = placement[1] === 'top' && adjustedSize.height - hostElemPos.height > viewportOffset.bottom && adjustedSize.height - hostElemPos.height <= viewportOffset.top ? 'bottom' :
36939                                  placement[1] === 'bottom' && adjustedSize.height - hostElemPos.height > viewportOffset.top && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom ? 'top' :
36940                                  placement[1] === 'left' && adjustedSize.width - hostElemPos.width > viewportOffset.right && adjustedSize.width - hostElemPos.width <= viewportOffset.left ? 'right' :
36941                                  placement[1] === 'right' && adjustedSize.width - hostElemPos.width > viewportOffset.left && adjustedSize.width - hostElemPos.width <= viewportOffset.right ? 'left' :
36942                                  placement[1];
36943
36944                   if (placement[1] === 'center') {
36945                     if (PLACEMENT_REGEX.vertical.test(placement[0])) {
36946                       var xOverflow = hostElemPos.width / 2 - targetWidth / 2;
36947                       if (viewportOffset.left + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.right) {
36948                         placement[1] = 'left';
36949                       } else if (viewportOffset.right + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.left) {
36950                         placement[1] = 'right';
36951                       }
36952                     } else {
36953                       var yOverflow = hostElemPos.height / 2 - adjustedSize.height / 2;
36954                       if (viewportOffset.top + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom) {
36955                         placement[1] = 'top';
36956                       } else if (viewportOffset.bottom + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.top) {
36957                         placement[1] = 'bottom';
36958                       }
36959                     }
36960                   }
36961                 }
36962
36963                 switch (placement[0]) {
36964                   case 'top':
36965                     targetElemPos.top = hostElemPos.top - targetHeight;
36966                     break;
36967                   case 'bottom':
36968                     targetElemPos.top = hostElemPos.top + hostElemPos.height;
36969                     break;
36970                   case 'left':
36971                     targetElemPos.left = hostElemPos.left - targetWidth;
36972                     break;
36973                   case 'right':
36974                     targetElemPos.left = hostElemPos.left + hostElemPos.width;
36975                     break;
36976                 }
36977
36978                 switch (placement[1]) {
36979                   case 'top':
36980                     targetElemPos.top = hostElemPos.top;
36981                     break;
36982                   case 'bottom':
36983                     targetElemPos.top = hostElemPos.top + hostElemPos.height - targetHeight;
36984                     break;
36985                   case 'left':
36986                     targetElemPos.left = hostElemPos.left;
36987                     break;
36988                   case 'right':
36989                     targetElemPos.left = hostElemPos.left + hostElemPos.width - targetWidth;
36990                     break;
36991                   case 'center':
36992                     if (PLACEMENT_REGEX.vertical.test(placement[0])) {
36993                       targetElemPos.left = hostElemPos.left + hostElemPos.width / 2 - targetWidth / 2;
36994                     } else {
36995                       targetElemPos.top = hostElemPos.top + hostElemPos.height / 2 - targetHeight / 2;
36996                     }
36997                     break;
36998                 }
36999
37000                 targetElemPos.top = Math.round(targetElemPos.top);
37001                 targetElemPos.left = Math.round(targetElemPos.left);
37002                 targetElemPos.placement = placement[1] === 'center' ? placement[0] : placement[0] + '-' + placement[1];
37003
37004                 return targetElemPos;
37005               },
37006
37007               /**
37008               * Provides a way for positioning tooltip & dropdown
37009               * arrows when using placement options beyond the standard
37010               * left, right, top, or bottom.
37011               *
37012               * @param {element} elem - The tooltip/dropdown element.
37013               * @param {string} placement - The placement for the elem.
37014               */
37015               positionArrow: function(elem, placement) {
37016                 elem = this.getRawNode(elem);
37017
37018                 var innerElem = elem.querySelector('.tooltip-inner, .popover-inner');
37019                 if (!innerElem) {
37020                   return;
37021                 }
37022
37023                 var isTooltip = angular.element(innerElem).hasClass('tooltip-inner');
37024
37025                 var arrowElem = isTooltip ? elem.querySelector('.tooltip-arrow') : elem.querySelector('.arrow');
37026                 if (!arrowElem) {
37027                   return;
37028                 }
37029
37030                 var arrowCss = {
37031                   top: '',
37032                   bottom: '',
37033                   left: '',
37034                   right: ''
37035                 };
37036
37037                 placement = this.parsePlacement(placement);
37038                 if (placement[1] === 'center') {
37039                   // no adjustment necessary - just reset styles
37040                   angular.element(arrowElem).css(arrowCss);
37041                   return;
37042                 }
37043
37044                 var borderProp = 'border-' + placement[0] + '-width';
37045                 var borderWidth = $window.getComputedStyle(arrowElem)[borderProp];
37046
37047                 var borderRadiusProp = 'border-';
37048                 if (PLACEMENT_REGEX.vertical.test(placement[0])) {
37049                   borderRadiusProp += placement[0] + '-' + placement[1];
37050                 } else {
37051                   borderRadiusProp += placement[1] + '-' + placement[0];
37052                 }
37053                 borderRadiusProp += '-radius';
37054                 var borderRadius = $window.getComputedStyle(isTooltip ? innerElem : elem)[borderRadiusProp];
37055
37056                 switch (placement[0]) {
37057                   case 'top':
37058                     arrowCss.bottom = isTooltip ? '0' : '-' + borderWidth;
37059                     break;
37060                   case 'bottom':
37061                     arrowCss.top = isTooltip ? '0' : '-' + borderWidth;
37062                     break;
37063                   case 'left':
37064                     arrowCss.right = isTooltip ? '0' : '-' + borderWidth;
37065                     break;
37066                   case 'right':
37067                     arrowCss.left = isTooltip ? '0' : '-' + borderWidth;
37068                     break;
37069                 }
37070
37071                 arrowCss[placement[1]] = borderRadius;
37072
37073                 angular.element(arrowElem).css(arrowCss);
37074               }
37075             };
37076           }]);
37077
37078         angular.module('ui.bootstrap.datepickerPopup', ['ui.bootstrap.datepicker', 'ui.bootstrap.position'])
37079
37080         .value('$datepickerPopupLiteralWarning', true)
37081
37082         .constant('uibDatepickerPopupConfig', {
37083           altInputFormats: [],
37084           appendToBody: false,
37085           clearText: 'Clear',
37086           closeOnDateSelection: true,
37087           closeText: 'Done',
37088           currentText: 'Today',
37089           datepickerPopup: 'yyyy-MM-dd',
37090           datepickerPopupTemplateUrl: 'uib/template/datepickerPopup/popup.html',
37091           datepickerTemplateUrl: 'uib/template/datepicker/datepicker.html',
37092           html5Types: {
37093             date: 'yyyy-MM-dd',
37094             'datetime-local': 'yyyy-MM-ddTHH:mm:ss.sss',
37095             'month': 'yyyy-MM'
37096           },
37097           onOpenFocus: true,
37098           showButtonBar: true,
37099           placement: 'auto bottom-left'
37100         })
37101
37102         .controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$window', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', '$datepickerPopupLiteralWarning',
37103         function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, $datepickerPopupLiteralWarning) {
37104           var cache = {},
37105             isHtml5DateInput = false;
37106           var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
37107             datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl, scrollParentEl,
37108             ngModel, ngModelOptions, $popup, altInputFormats, watchListeners = [],
37109             timezone;
37110
37111           this.init = function(_ngModel_) {
37112             ngModel = _ngModel_;
37113             ngModelOptions = _ngModel_.$options;
37114             closeOnDateSelection = angular.isDefined($attrs.closeOnDateSelection) ?
37115               $scope.$parent.$eval($attrs.closeOnDateSelection) :
37116               datepickerPopupConfig.closeOnDateSelection;
37117             appendToBody = angular.isDefined($attrs.datepickerAppendToBody) ?
37118               $scope.$parent.$eval($attrs.datepickerAppendToBody) :
37119               datepickerPopupConfig.appendToBody;
37120             onOpenFocus = angular.isDefined($attrs.onOpenFocus) ?
37121               $scope.$parent.$eval($attrs.onOpenFocus) : datepickerPopupConfig.onOpenFocus;
37122             datepickerPopupTemplateUrl = angular.isDefined($attrs.datepickerPopupTemplateUrl) ?
37123               $attrs.datepickerPopupTemplateUrl :
37124               datepickerPopupConfig.datepickerPopupTemplateUrl;
37125             datepickerTemplateUrl = angular.isDefined($attrs.datepickerTemplateUrl) ?
37126               $attrs.datepickerTemplateUrl : datepickerPopupConfig.datepickerTemplateUrl;
37127             altInputFormats = angular.isDefined($attrs.altInputFormats) ?
37128               $scope.$parent.$eval($attrs.altInputFormats) :
37129               datepickerPopupConfig.altInputFormats;
37130
37131             $scope.showButtonBar = angular.isDefined($attrs.showButtonBar) ?
37132               $scope.$parent.$eval($attrs.showButtonBar) :
37133               datepickerPopupConfig.showButtonBar;
37134
37135             if (datepickerPopupConfig.html5Types[$attrs.type]) {
37136               dateFormat = datepickerPopupConfig.html5Types[$attrs.type];
37137               isHtml5DateInput = true;
37138             } else {
37139               dateFormat = $attrs.uibDatepickerPopup || datepickerPopupConfig.datepickerPopup;
37140               $attrs.$observe('uibDatepickerPopup', function(value, oldValue) {
37141                 var newDateFormat = value || datepickerPopupConfig.datepickerPopup;
37142                 // Invalidate the $modelValue to ensure that formatters re-run
37143                 // FIXME: Refactor when PR is merged: https://github.com/angular/angular.js/pull/10764
37144                 if (newDateFormat !== dateFormat) {
37145                   dateFormat = newDateFormat;
37146                   ngModel.$modelValue = null;
37147
37148                   if (!dateFormat) {
37149                     throw new Error('uibDatepickerPopup must have a date format specified.');
37150                   }
37151                 }
37152               });
37153             }
37154
37155             if (!dateFormat) {
37156               throw new Error('uibDatepickerPopup must have a date format specified.');
37157             }
37158
37159             if (isHtml5DateInput && $attrs.uibDatepickerPopup) {
37160               throw new Error('HTML5 date input types do not support custom formats.');
37161             }
37162
37163             // popup element used to display calendar
37164             popupEl = angular.element('<div uib-datepicker-popup-wrap><div uib-datepicker></div></div>');
37165             if (ngModelOptions) {
37166               timezone = ngModelOptions.timezone;
37167               $scope.ngModelOptions = angular.copy(ngModelOptions);
37168               $scope.ngModelOptions.timezone = null;
37169               if ($scope.ngModelOptions.updateOnDefault === true) {
37170                 $scope.ngModelOptions.updateOn = $scope.ngModelOptions.updateOn ?
37171                   $scope.ngModelOptions.updateOn + ' default' : 'default';
37172               }
37173
37174               popupEl.attr('ng-model-options', 'ngModelOptions');
37175             } else {
37176               timezone = null;
37177             }
37178
37179             popupEl.attr({
37180               'ng-model': 'date',
37181               'ng-change': 'dateSelection(date)',
37182               'template-url': datepickerPopupTemplateUrl
37183             });
37184
37185             // datepicker element
37186             datepickerEl = angular.element(popupEl.children()[0]);
37187             datepickerEl.attr('template-url', datepickerTemplateUrl);
37188
37189             if (!$scope.datepickerOptions) {
37190               $scope.datepickerOptions = {};
37191             }
37192
37193             if (isHtml5DateInput) {
37194               if ($attrs.type === 'month') {
37195                 $scope.datepickerOptions.datepickerMode = 'month';
37196                 $scope.datepickerOptions.minMode = 'month';
37197               }
37198             }
37199
37200             datepickerEl.attr('datepicker-options', 'datepickerOptions');
37201
37202             if (!isHtml5DateInput) {
37203               // Internal API to maintain the correct ng-invalid-[key] class
37204               ngModel.$$parserName = 'date';
37205               ngModel.$validators.date = validator;
37206               ngModel.$parsers.unshift(parseDate);
37207               ngModel.$formatters.push(function(value) {
37208                 if (ngModel.$isEmpty(value)) {
37209                   $scope.date = value;
37210                   return value;
37211                 }
37212
37213                 if (angular.isNumber(value)) {
37214                   value = new Date(value);
37215                 }
37216
37217                 $scope.date = dateParser.fromTimezone(value, timezone);
37218
37219                 return dateParser.filter($scope.date, dateFormat);
37220               });
37221             } else {
37222               ngModel.$formatters.push(function(value) {
37223                 $scope.date = dateParser.fromTimezone(value, timezone);
37224                 return value;
37225               });
37226             }
37227
37228             // Detect changes in the view from the text box
37229             ngModel.$viewChangeListeners.push(function() {
37230               $scope.date = parseDateString(ngModel.$viewValue);
37231             });
37232
37233             $element.on('keydown', inputKeydownBind);
37234
37235             $popup = $compile(popupEl)($scope);
37236             // Prevent jQuery cache memory leak (template is now redundant after linking)
37237             popupEl.remove();
37238
37239             if (appendToBody) {
37240               $document.find('body').append($popup);
37241             } else {
37242               $element.after($popup);
37243             }
37244
37245             $scope.$on('$destroy', function() {
37246               if ($scope.isOpen === true) {
37247                 if (!$rootScope.$$phase) {
37248                   $scope.$apply(function() {
37249                     $scope.isOpen = false;
37250                   });
37251                 }
37252               }
37253
37254               $popup.remove();
37255               $element.off('keydown', inputKeydownBind);
37256               $document.off('click', documentClickBind);
37257               if (scrollParentEl) {
37258                 scrollParentEl.off('scroll', positionPopup);
37259               }
37260               angular.element($window).off('resize', positionPopup);
37261
37262               //Clear all watch listeners on destroy
37263               while (watchListeners.length) {
37264                 watchListeners.shift()();
37265               }
37266             });
37267           };
37268
37269           $scope.getText = function(key) {
37270             return $scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
37271           };
37272
37273           $scope.isDisabled = function(date) {
37274             if (date === 'today') {
37275               date = dateParser.fromTimezone(new Date(), timezone);
37276             }
37277
37278             var dates = {};
37279             angular.forEach(['minDate', 'maxDate'], function(key) {
37280               if (!$scope.datepickerOptions[key]) {
37281                 dates[key] = null;
37282               } else if (angular.isDate($scope.datepickerOptions[key])) {
37283                 dates[key] = dateParser.fromTimezone(new Date($scope.datepickerOptions[key]), timezone);
37284               } else {
37285                 if ($datepickerPopupLiteralWarning) {
37286                   $log.warn('Literal date support has been deprecated, please switch to date object usage');
37287                 }
37288
37289                 dates[key] = new Date(dateFilter($scope.datepickerOptions[key], 'medium'));
37290               }
37291             });
37292
37293             return $scope.datepickerOptions &&
37294               dates.minDate && $scope.compare(date, dates.minDate) < 0 ||
37295               dates.maxDate && $scope.compare(date, dates.maxDate) > 0;
37296           };
37297
37298           $scope.compare = function(date1, date2) {
37299             return new Date(date1.getFullYear(), date1.getMonth(), date1.getDate()) - new Date(date2.getFullYear(), date2.getMonth(), date2.getDate());
37300           };
37301
37302           // Inner change
37303           $scope.dateSelection = function(dt) {
37304             if (angular.isDefined(dt)) {
37305               $scope.date = dt;
37306             }
37307             var date = $scope.date ? dateParser.filter($scope.date, dateFormat) : null; // Setting to NULL is necessary for form validators to function
37308             $element.val(date);
37309             ngModel.$setViewValue(date);
37310
37311             if (closeOnDateSelection) {
37312               $scope.isOpen = false;
37313               $element[0].focus();
37314             }
37315           };
37316
37317           $scope.keydown = function(evt) {
37318             if (evt.which === 27) {
37319               evt.stopPropagation();
37320               $scope.isOpen = false;
37321               $element[0].focus();
37322             }
37323           };
37324
37325           $scope.select = function(date, evt) {
37326             evt.stopPropagation();
37327
37328             if (date === 'today') {
37329               var today = new Date();
37330               if (angular.isDate($scope.date)) {
37331                 date = new Date($scope.date);
37332                 date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
37333               } else {
37334                 date = new Date(today.setHours(0, 0, 0, 0));
37335               }
37336             }
37337             $scope.dateSelection(date);
37338           };
37339
37340           $scope.close = function(evt) {
37341             evt.stopPropagation();
37342
37343             $scope.isOpen = false;
37344             $element[0].focus();
37345           };
37346
37347           $scope.disabled = angular.isDefined($attrs.disabled) || false;
37348           if ($attrs.ngDisabled) {
37349             watchListeners.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(disabled) {
37350               $scope.disabled = disabled;
37351             }));
37352           }
37353
37354           $scope.$watch('isOpen', function(value) {
37355             if (value) {
37356               if (!$scope.disabled) {
37357                 $timeout(function() {
37358                   positionPopup();
37359
37360                   if (onOpenFocus) {
37361                     $scope.$broadcast('uib:datepicker.focus');
37362                   }
37363
37364                   $document.on('click', documentClickBind);
37365
37366                   var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
37367                   if (appendToBody || $position.parsePlacement(placement)[2]) {
37368                     scrollParentEl = scrollParentEl || angular.element($position.scrollParent($element));
37369                     if (scrollParentEl) {
37370                       scrollParentEl.on('scroll', positionPopup);
37371                     }
37372                   } else {
37373                     scrollParentEl = null;
37374                   }
37375
37376                   angular.element($window).on('resize', positionPopup);
37377                 }, 0, false);
37378               } else {
37379                 $scope.isOpen = false;
37380               }
37381             } else {
37382               $document.off('click', documentClickBind);
37383               if (scrollParentEl) {
37384                 scrollParentEl.off('scroll', positionPopup);
37385               }
37386               angular.element($window).off('resize', positionPopup);
37387             }
37388           });
37389
37390           function cameltoDash(string) {
37391             return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
37392           }
37393
37394           function parseDateString(viewValue) {
37395             var date = dateParser.parse(viewValue, dateFormat, $scope.date);
37396             if (isNaN(date)) {
37397               for (var i = 0; i < altInputFormats.length; i++) {
37398                 date = dateParser.parse(viewValue, altInputFormats[i], $scope.date);
37399                 if (!isNaN(date)) {
37400                   return date;
37401                 }
37402               }
37403             }
37404             return date;
37405           }
37406
37407           function parseDate(viewValue) {
37408             if (angular.isNumber(viewValue)) {
37409               // presumably timestamp to date object
37410               viewValue = new Date(viewValue);
37411             }
37412
37413             if (!viewValue) {
37414               return null;
37415             }
37416
37417             if (angular.isDate(viewValue) && !isNaN(viewValue)) {
37418               return viewValue;
37419             }
37420
37421             if (angular.isString(viewValue)) {
37422               var date = parseDateString(viewValue);
37423               if (!isNaN(date)) {
37424                 return dateParser.toTimezone(date, timezone);
37425               }
37426             }
37427
37428             return ngModel.$options && ngModel.$options.allowInvalid ? viewValue : undefined;
37429           }
37430
37431           function validator(modelValue, viewValue) {
37432             var value = modelValue || viewValue;
37433
37434             if (!$attrs.ngRequired && !value) {
37435               return true;
37436             }
37437
37438             if (angular.isNumber(value)) {
37439               value = new Date(value);
37440             }
37441
37442             if (!value) {
37443               return true;
37444             }
37445
37446             if (angular.isDate(value) && !isNaN(value)) {
37447               return true;
37448             }
37449
37450             if (angular.isString(value)) {
37451               return !isNaN(parseDateString(viewValue));
37452             }
37453
37454             return false;
37455           }
37456
37457           function documentClickBind(event) {
37458             if (!$scope.isOpen && $scope.disabled) {
37459               return;
37460             }
37461
37462             var popup = $popup[0];
37463             var dpContainsTarget = $element[0].contains(event.target);
37464             // The popup node may not be an element node
37465             // In some browsers (IE) only element nodes have the 'contains' function
37466             var popupContainsTarget = popup.contains !== undefined && popup.contains(event.target);
37467             if ($scope.isOpen && !(dpContainsTarget || popupContainsTarget)) {
37468               $scope.$apply(function() {
37469                 $scope.isOpen = false;
37470               });
37471             }
37472           }
37473
37474           function inputKeydownBind(evt) {
37475             if (evt.which === 27 && $scope.isOpen) {
37476               evt.preventDefault();
37477               evt.stopPropagation();
37478               $scope.$apply(function() {
37479                 $scope.isOpen = false;
37480               });
37481               $element[0].focus();
37482             } else if (evt.which === 40 && !$scope.isOpen) {
37483               evt.preventDefault();
37484               evt.stopPropagation();
37485               $scope.$apply(function() {
37486                 $scope.isOpen = true;
37487               });
37488             }
37489           }
37490
37491           function positionPopup() {
37492             if ($scope.isOpen) {
37493               var dpElement = angular.element($popup[0].querySelector('.uib-datepicker-popup'));
37494               var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
37495               var position = $position.positionElements($element, dpElement, placement, appendToBody);
37496               dpElement.css({top: position.top + 'px', left: position.left + 'px'});
37497               if (dpElement.hasClass('uib-position-measure')) {
37498                 dpElement.removeClass('uib-position-measure');
37499               }
37500             }
37501           }
37502
37503           $scope.$on('uib:datepicker.mode', function() {
37504             $timeout(positionPopup, 0, false);
37505           });
37506         }])
37507
37508         .directive('uibDatepickerPopup', function() {
37509           return {
37510             require: ['ngModel', 'uibDatepickerPopup'],
37511             controller: 'UibDatepickerPopupController',
37512             scope: {
37513               datepickerOptions: '=?',
37514               isOpen: '=?',
37515               currentText: '@',
37516               clearText: '@',
37517               closeText: '@'
37518             },
37519             link: function(scope, element, attrs, ctrls) {
37520               var ngModel = ctrls[0],
37521                 ctrl = ctrls[1];
37522
37523               ctrl.init(ngModel);
37524             }
37525           };
37526         })
37527
37528         .directive('uibDatepickerPopupWrap', function() {
37529           return {
37530             replace: true,
37531             transclude: true,
37532             templateUrl: function(element, attrs) {
37533               return attrs.templateUrl || 'uib/template/datepickerPopup/popup.html';
37534             }
37535           };
37536         });
37537
37538         angular.module('ui.bootstrap.debounce', [])
37539         /**
37540          * A helper, internal service that debounces a function
37541          */
37542           .factory('$$debounce', ['$timeout', function($timeout) {
37543             return function(callback, debounceTime) {
37544               var timeoutPromise;
37545
37546               return function() {
37547                 var self = this;
37548                 var args = Array.prototype.slice.call(arguments);
37549                 if (timeoutPromise) {
37550                   $timeout.cancel(timeoutPromise);
37551                 }
37552
37553                 timeoutPromise = $timeout(function() {
37554                   callback.apply(self, args);
37555                 }, debounceTime);
37556               };
37557             };
37558           }]);
37559
37560         angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
37561
37562         .constant('uibDropdownConfig', {
37563           appendToOpenClass: 'uib-dropdown-open',
37564           openClass: 'open'
37565         })
37566
37567         .service('uibDropdownService', ['$document', '$rootScope', function($document, $rootScope) {
37568           var openScope = null;
37569
37570           this.open = function(dropdownScope, element) {
37571             if (!openScope) {
37572               $document.on('click', closeDropdown);
37573               element.on('keydown', keybindFilter);
37574             }
37575
37576             if (openScope && openScope !== dropdownScope) {
37577               openScope.isOpen = false;
37578             }
37579
37580             openScope = dropdownScope;
37581           };
37582
37583           this.close = function(dropdownScope, element) {
37584             if (openScope === dropdownScope) {
37585               openScope = null;
37586               $document.off('click', closeDropdown);
37587               element.off('keydown', keybindFilter);
37588             }
37589           };
37590
37591           var closeDropdown = function(evt) {
37592             // This method may still be called during the same mouse event that
37593             // unbound this event handler. So check openScope before proceeding.
37594             if (!openScope) { return; }
37595
37596             if (evt && openScope.getAutoClose() === 'disabled') { return; }
37597
37598             if (evt && evt.which === 3) { return; }
37599
37600             var toggleElement = openScope.getToggleElement();
37601             if (evt && toggleElement && toggleElement[0].contains(evt.target)) {
37602               return;
37603             }
37604
37605             var dropdownElement = openScope.getDropdownElement();
37606             if (evt && openScope.getAutoClose() === 'outsideClick' &&
37607               dropdownElement && dropdownElement[0].contains(evt.target)) {
37608               return;
37609             }
37610
37611             openScope.isOpen = false;
37612
37613             if (!$rootScope.$$phase) {
37614               openScope.$apply();
37615             }
37616           };
37617
37618           var keybindFilter = function(evt) {
37619             if (evt.which === 27) {
37620               evt.stopPropagation();
37621               openScope.focusToggleElement();
37622               closeDropdown();
37623             } else if (openScope.isKeynavEnabled() && [38, 40].indexOf(evt.which) !== -1 && openScope.isOpen) {
37624               evt.preventDefault();
37625               evt.stopPropagation();
37626               openScope.focusDropdownEntry(evt.which);
37627             }
37628           };
37629         }])
37630
37631         .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) {
37632           var self = this,
37633             scope = $scope.$new(), // create a child scope so we are not polluting original one
37634             templateScope,
37635             appendToOpenClass = dropdownConfig.appendToOpenClass,
37636             openClass = dropdownConfig.openClass,
37637             getIsOpen,
37638             setIsOpen = angular.noop,
37639             toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop,
37640             appendToBody = false,
37641             appendTo = null,
37642             keynavEnabled = false,
37643             selectedOption = null,
37644             body = $document.find('body');
37645
37646           $element.addClass('dropdown');
37647
37648           this.init = function() {
37649             if ($attrs.isOpen) {
37650               getIsOpen = $parse($attrs.isOpen);
37651               setIsOpen = getIsOpen.assign;
37652
37653               $scope.$watch(getIsOpen, function(value) {
37654                 scope.isOpen = !!value;
37655               });
37656             }
37657
37658             if (angular.isDefined($attrs.dropdownAppendTo)) {
37659               var appendToEl = $parse($attrs.dropdownAppendTo)(scope);
37660               if (appendToEl) {
37661                 appendTo = angular.element(appendToEl);
37662               }
37663             }
37664
37665             appendToBody = angular.isDefined($attrs.dropdownAppendToBody);
37666             keynavEnabled = angular.isDefined($attrs.keyboardNav);
37667
37668             if (appendToBody && !appendTo) {
37669               appendTo = body;
37670             }
37671
37672             if (appendTo && self.dropdownMenu) {
37673               appendTo.append(self.dropdownMenu);
37674               $element.on('$destroy', function handleDestroyEvent() {
37675                 self.dropdownMenu.remove();
37676               });
37677             }
37678           };
37679
37680           this.toggle = function(open) {
37681             scope.isOpen = arguments.length ? !!open : !scope.isOpen;
37682             if (angular.isFunction(setIsOpen)) {
37683               setIsOpen(scope, scope.isOpen);
37684             }
37685
37686             return scope.isOpen;
37687           };
37688
37689           // Allow other directives to watch status
37690           this.isOpen = function() {
37691             return scope.isOpen;
37692           };
37693
37694           scope.getToggleElement = function() {
37695             return self.toggleElement;
37696           };
37697
37698           scope.getAutoClose = function() {
37699             return $attrs.autoClose || 'always'; //or 'outsideClick' or 'disabled'
37700           };
37701
37702           scope.getElement = function() {
37703             return $element;
37704           };
37705
37706           scope.isKeynavEnabled = function() {
37707             return keynavEnabled;
37708           };
37709
37710           scope.focusDropdownEntry = function(keyCode) {
37711             var elems = self.dropdownMenu ? //If append to body is used.
37712               angular.element(self.dropdownMenu).find('a') :
37713               $element.find('ul').eq(0).find('a');
37714
37715             switch (keyCode) {
37716               case 40: {
37717                 if (!angular.isNumber(self.selectedOption)) {
37718                   self.selectedOption = 0;
37719                 } else {
37720                   self.selectedOption = self.selectedOption === elems.length - 1 ?
37721                     self.selectedOption :
37722                     self.selectedOption + 1;
37723                 }
37724                 break;
37725               }
37726               case 38: {
37727                 if (!angular.isNumber(self.selectedOption)) {
37728                   self.selectedOption = elems.length - 1;
37729                 } else {
37730                   self.selectedOption = self.selectedOption === 0 ?
37731                     0 : self.selectedOption - 1;
37732                 }
37733                 break;
37734               }
37735             }
37736             elems[self.selectedOption].focus();
37737           };
37738
37739           scope.getDropdownElement = function() {
37740             return self.dropdownMenu;
37741           };
37742
37743           scope.focusToggleElement = function() {
37744             if (self.toggleElement) {
37745               self.toggleElement[0].focus();
37746             }
37747           };
37748
37749           scope.$watch('isOpen', function(isOpen, wasOpen) {
37750             if (appendTo && self.dropdownMenu) {
37751               var pos = $position.positionElements($element, self.dropdownMenu, 'bottom-left', true),
37752                 css,
37753                 rightalign,
37754                 scrollbarWidth;
37755
37756               css = {
37757                 top: pos.top + 'px',
37758                 display: isOpen ? 'block' : 'none'
37759               };
37760
37761               rightalign = self.dropdownMenu.hasClass('dropdown-menu-right');
37762               if (!rightalign) {
37763                 css.left = pos.left + 'px';
37764                 css.right = 'auto';
37765               } else {
37766                 css.left = 'auto';
37767                 scrollbarWidth = $position.scrollbarWidth(true);
37768                 css.right = window.innerWidth - scrollbarWidth -
37769                   (pos.left + $element.prop('offsetWidth')) + 'px';
37770               }
37771
37772               // Need to adjust our positioning to be relative to the appendTo container
37773               // if it's not the body element
37774               if (!appendToBody) {
37775                 var appendOffset = $position.offset(appendTo);
37776
37777                 css.top = pos.top - appendOffset.top + 'px';
37778
37779                 if (!rightalign) {
37780                   css.left = pos.left - appendOffset.left + 'px';
37781                 } else {
37782                   css.right = window.innerWidth -
37783                     (pos.left - appendOffset.left + $element.prop('offsetWidth')) + 'px';
37784                 }
37785               }
37786
37787               self.dropdownMenu.css(css);
37788             }
37789
37790             var openContainer = appendTo ? appendTo : $element;
37791             var hasOpenClass = openContainer.hasClass(appendTo ? appendToOpenClass : openClass);
37792
37793             if (hasOpenClass === !isOpen) {
37794               $animate[isOpen ? 'addClass' : 'removeClass'](openContainer, appendTo ? appendToOpenClass : openClass).then(function() {
37795                 if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
37796                   toggleInvoker($scope, { open: !!isOpen });
37797                 }
37798               });
37799             }
37800
37801             if (isOpen) {
37802               if (self.dropdownMenuTemplateUrl) {
37803                 $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) {
37804                   templateScope = scope.$new();
37805                   $compile(tplContent.trim())(templateScope, function(dropdownElement) {
37806                     var newEl = dropdownElement;
37807                     self.dropdownMenu.replaceWith(newEl);
37808                     self.dropdownMenu = newEl;
37809                   });
37810                 });
37811               }
37812
37813               scope.focusToggleElement();
37814               uibDropdownService.open(scope, $element);
37815             } else {
37816               if (self.dropdownMenuTemplateUrl) {
37817                 if (templateScope) {
37818                   templateScope.$destroy();
37819                 }
37820                 var newEl = angular.element('<ul class="dropdown-menu"></ul>');
37821                 self.dropdownMenu.replaceWith(newEl);
37822                 self.dropdownMenu = newEl;
37823               }
37824
37825               uibDropdownService.close(scope, $element);
37826               self.selectedOption = null;
37827             }
37828
37829             if (angular.isFunction(setIsOpen)) {
37830               setIsOpen($scope, isOpen);
37831             }
37832           });
37833         }])
37834
37835         .directive('uibDropdown', function() {
37836           return {
37837             controller: 'UibDropdownController',
37838             link: function(scope, element, attrs, dropdownCtrl) {
37839               dropdownCtrl.init();
37840             }
37841           };
37842         })
37843
37844         .directive('uibDropdownMenu', function() {
37845           return {
37846             restrict: 'A',
37847             require: '?^uibDropdown',
37848             link: function(scope, element, attrs, dropdownCtrl) {
37849               if (!dropdownCtrl || angular.isDefined(attrs.dropdownNested)) {
37850                 return;
37851               }
37852
37853               element.addClass('dropdown-menu');
37854
37855               var tplUrl = attrs.templateUrl;
37856               if (tplUrl) {
37857                 dropdownCtrl.dropdownMenuTemplateUrl = tplUrl;
37858               }
37859
37860               if (!dropdownCtrl.dropdownMenu) {
37861                 dropdownCtrl.dropdownMenu = element;
37862               }
37863             }
37864           };
37865         })
37866
37867         .directive('uibDropdownToggle', function() {
37868           return {
37869             require: '?^uibDropdown',
37870             link: function(scope, element, attrs, dropdownCtrl) {
37871               if (!dropdownCtrl) {
37872                 return;
37873               }
37874
37875               element.addClass('dropdown-toggle');
37876
37877               dropdownCtrl.toggleElement = element;
37878
37879               var toggleDropdown = function(event) {
37880                 event.preventDefault();
37881
37882                 if (!element.hasClass('disabled') && !attrs.disabled) {
37883                   scope.$apply(function() {
37884                     dropdownCtrl.toggle();
37885                   });
37886                 }
37887               };
37888
37889               element.bind('click', toggleDropdown);
37890
37891               // WAI-ARIA
37892               element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
37893               scope.$watch(dropdownCtrl.isOpen, function(isOpen) {
37894                 element.attr('aria-expanded', !!isOpen);
37895               });
37896
37897               scope.$on('$destroy', function() {
37898                 element.unbind('click', toggleDropdown);
37899               });
37900             }
37901           };
37902         });
37903
37904         angular.module('ui.bootstrap.stackedMap', [])
37905         /**
37906          * A helper, internal data structure that acts as a map but also allows getting / removing
37907          * elements in the LIFO order
37908          */
37909           .factory('$$stackedMap', function() {
37910             return {
37911               createNew: function() {
37912                 var stack = [];
37913
37914                 return {
37915                   add: function(key, value) {
37916                     stack.push({
37917                       key: key,
37918                       value: value
37919                     });
37920                   },
37921                   get: function(key) {
37922                     for (var i = 0; i < stack.length; i++) {
37923                       if (key === stack[i].key) {
37924                         return stack[i];
37925                       }
37926                     }
37927                   },
37928                   keys: function() {
37929                     var keys = [];
37930                     for (var i = 0; i < stack.length; i++) {
37931                       keys.push(stack[i].key);
37932                     }
37933                     return keys;
37934                   },
37935                   top: function() {
37936                     return stack[stack.length - 1];
37937                   },
37938                   remove: function(key) {
37939                     var idx = -1;
37940                     for (var i = 0; i < stack.length; i++) {
37941                       if (key === stack[i].key) {
37942                         idx = i;
37943                         break;
37944                       }
37945                     }
37946                     return stack.splice(idx, 1)[0];
37947                   },
37948                   removeTop: function() {
37949                     return stack.splice(stack.length - 1, 1)[0];
37950                   },
37951                   length: function() {
37952                     return stack.length;
37953                   }
37954                 };
37955               }
37956             };
37957           });
37958         angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.position'])
37959         /**
37960          * A helper, internal data structure that stores all references attached to key
37961          */
37962           .factory('$$multiMap', function() {
37963             return {
37964               createNew: function() {
37965                 var map = {};
37966
37967                 return {
37968                   entries: function() {
37969                     return Object.keys(map).map(function(key) {
37970                       return {
37971                         key: key,
37972                         value: map[key]
37973                       };
37974                     });
37975                   },
37976                   get: function(key) {
37977                     return map[key];
37978                   },
37979                   hasKey: function(key) {
37980                     return !!map[key];
37981                   },
37982                   keys: function() {
37983                     return Object.keys(map);
37984                   },
37985                   put: function(key, value) {
37986                     if (!map[key]) {
37987                       map[key] = [];
37988                     }
37989
37990                     map[key].push(value);
37991                   },
37992                   remove: function(key, value) {
37993                     var values = map[key];
37994
37995                     if (!values) {
37996                       return;
37997                     }
37998
37999                     var idx = values.indexOf(value);
38000
38001                     if (idx !== -1) {
38002                       values.splice(idx, 1);
38003                     }
38004
38005                     if (!values.length) {
38006                       delete map[key];
38007                     }
38008                   }
38009                 };
38010               }
38011             };
38012           })
38013
38014         /**
38015          * Pluggable resolve mechanism for the modal resolve resolution
38016          * Supports UI Router's $resolve service
38017          */
38018           .provider('$uibResolve', function() {
38019             var resolve = this;
38020             this.resolver = null;
38021
38022             this.setResolver = function(resolver) {
38023               this.resolver = resolver;
38024             };
38025
38026             this.$get = ['$injector', '$q', function($injector, $q) {
38027               var resolver = resolve.resolver ? $injector.get(resolve.resolver) : null;
38028               return {
38029                 resolve: function(invocables, locals, parent, self) {
38030                   if (resolver) {
38031                     return resolver.resolve(invocables, locals, parent, self);
38032                   }
38033
38034                   var promises = [];
38035
38036                   angular.forEach(invocables, function(value) {
38037                     if (angular.isFunction(value) || angular.isArray(value)) {
38038                       promises.push($q.resolve($injector.invoke(value)));
38039                     } else if (angular.isString(value)) {
38040                       promises.push($q.resolve($injector.get(value)));
38041                     } else {
38042                       promises.push($q.resolve(value));
38043                     }
38044                   });
38045
38046                   return $q.all(promises).then(function(resolves) {
38047                     var resolveObj = {};
38048                     var resolveIter = 0;
38049                     angular.forEach(invocables, function(value, key) {
38050                       resolveObj[key] = resolves[resolveIter++];
38051                     });
38052
38053                     return resolveObj;
38054                   });
38055                 }
38056               };
38057             }];
38058           })
38059
38060         /**
38061          * A helper directive for the $modal service. It creates a backdrop element.
38062          */
38063           .directive('uibModalBackdrop', ['$animate', '$injector', '$uibModalStack',
38064           function($animate, $injector, $modalStack) {
38065             return {
38066               replace: true,
38067               templateUrl: 'uib/template/modal/backdrop.html',
38068               compile: function(tElement, tAttrs) {
38069                 tElement.addClass(tAttrs.backdropClass);
38070                 return linkFn;
38071               }
38072             };
38073
38074             function linkFn(scope, element, attrs) {
38075               if (attrs.modalInClass) {
38076                 $animate.addClass(element, attrs.modalInClass);
38077
38078                 scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
38079                   var done = setIsAsync();
38080                   if (scope.modalOptions.animation) {
38081                     $animate.removeClass(element, attrs.modalInClass).then(done);
38082                   } else {
38083                     done();
38084                   }
38085                 });
38086               }
38087             }
38088           }])
38089
38090           .directive('uibModalWindow', ['$uibModalStack', '$q', '$animateCss', '$document',
38091           function($modalStack, $q, $animateCss, $document) {
38092             return {
38093               scope: {
38094                 index: '@'
38095               },
38096               replace: true,
38097               transclude: true,
38098               templateUrl: function(tElement, tAttrs) {
38099                 return tAttrs.templateUrl || 'uib/template/modal/window.html';
38100               },
38101               link: function(scope, element, attrs) {
38102                 element.addClass(attrs.windowClass || '');
38103                 element.addClass(attrs.windowTopClass || '');
38104                 scope.size = attrs.size;
38105
38106                 scope.close = function(evt) {
38107                   var modal = $modalStack.getTop();
38108                   if (modal && modal.value.backdrop &&
38109                     modal.value.backdrop !== 'static' &&
38110                     evt.target === evt.currentTarget) {
38111                     evt.preventDefault();
38112                     evt.stopPropagation();
38113                     $modalStack.dismiss(modal.key, 'backdrop click');
38114                   }
38115                 };
38116
38117                 // moved from template to fix issue #2280
38118                 element.on('click', scope.close);
38119
38120                 // This property is only added to the scope for the purpose of detecting when this directive is rendered.
38121                 // We can detect that by using this property in the template associated with this directive and then use
38122                 // {@link Attribute#$observe} on it. For more details please see {@link TableColumnResize}.
38123                 scope.$isRendered = true;
38124
38125                 // Deferred object that will be resolved when this modal is render.
38126                 var modalRenderDeferObj = $q.defer();
38127                 // Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
38128                 // In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
38129                 attrs.$observe('modalRender', function(value) {
38130                   if (value === 'true') {
38131                     modalRenderDeferObj.resolve();
38132                   }
38133                 });
38134
38135                 modalRenderDeferObj.promise.then(function() {
38136                   var animationPromise = null;
38137
38138                   if (attrs.modalInClass) {
38139                     animationPromise = $animateCss(element, {
38140                       addClass: attrs.modalInClass
38141                     }).start();
38142
38143                     scope.$on($modalStack.NOW_CLOSING_EVENT, function(e, setIsAsync) {
38144                       var done = setIsAsync();
38145                       $animateCss(element, {
38146                         removeClass: attrs.modalInClass
38147                       }).start().then(done);
38148                     });
38149                   }
38150
38151
38152                   $q.when(animationPromise).then(function() {
38153                     // Notify {@link $modalStack} that modal is rendered.
38154                     var modal = $modalStack.getTop();
38155                     if (modal) {
38156                       $modalStack.modalRendered(modal.key);
38157                     }
38158
38159                     /**
38160                      * If something within the freshly-opened modal already has focus (perhaps via a
38161                      * directive that causes focus). then no need to try and focus anything.
38162                      */
38163                     if (!($document[0].activeElement && element[0].contains($document[0].activeElement))) {
38164                       var inputWithAutofocus = element[0].querySelector('[autofocus]');
38165                       /**
38166                        * Auto-focusing of a freshly-opened modal element causes any child elements
38167                        * with the autofocus attribute to lose focus. This is an issue on touch
38168                        * based devices which will show and then hide the onscreen keyboard.
38169                        * Attempts to refocus the autofocus element via JavaScript will not reopen
38170                        * the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
38171                        * the modal element if the modal does not contain an autofocus element.
38172                        */
38173                       if (inputWithAutofocus) {
38174                         inputWithAutofocus.focus();
38175                       } else {
38176                         element[0].focus();
38177                       }
38178                     }
38179                   });
38180                 });
38181               }
38182             };
38183           }])
38184
38185           .directive('uibModalAnimationClass', function() {
38186             return {
38187               compile: function(tElement, tAttrs) {
38188                 if (tAttrs.modalAnimation) {
38189                   tElement.addClass(tAttrs.uibModalAnimationClass);
38190                 }
38191               }
38192             };
38193           })
38194
38195           .directive('uibModalTransclude', function() {
38196             return {
38197               link: function(scope, element, attrs, controller, transclude) {
38198                 transclude(scope.$parent, function(clone) {
38199                   element.empty();
38200                   element.append(clone);
38201                 });
38202               }
38203             };
38204           })
38205
38206           .factory('$uibModalStack', ['$animate', '$animateCss', '$document',
38207             '$compile', '$rootScope', '$q', '$$multiMap', '$$stackedMap', '$uibPosition',
38208             function($animate, $animateCss, $document, $compile, $rootScope, $q, $$multiMap, $$stackedMap, $uibPosition) {
38209               var OPENED_MODAL_CLASS = 'modal-open';
38210
38211               var backdropDomEl, backdropScope;
38212               var openedWindows = $$stackedMap.createNew();
38213               var openedClasses = $$multiMap.createNew();
38214               var $modalStack = {
38215                 NOW_CLOSING_EVENT: 'modal.stack.now-closing'
38216               };
38217               var topModalIndex = 0;
38218               var previousTopOpenedModal = null;
38219
38220               //Modal focus behavior
38221               var tabableSelector = 'a[href], area[href], input:not([disabled]), ' +
38222                 'button:not([disabled]),select:not([disabled]), textarea:not([disabled]), ' +
38223                 'iframe, object, embed, *[tabindex], *[contenteditable=true]';
38224               var scrollbarPadding;
38225
38226               function isVisible(element) {
38227                 return !!(element.offsetWidth ||
38228                   element.offsetHeight ||
38229                   element.getClientRects().length);
38230               }
38231
38232               function backdropIndex() {
38233                 var topBackdropIndex = -1;
38234                 var opened = openedWindows.keys();
38235                 for (var i = 0; i < opened.length; i++) {
38236                   if (openedWindows.get(opened[i]).value.backdrop) {
38237                     topBackdropIndex = i;
38238                   }
38239                 }
38240
38241                 // If any backdrop exist, ensure that it's index is always
38242                 // right below the top modal
38243                 if (topBackdropIndex > -1 && topBackdropIndex < topModalIndex) {
38244                   topBackdropIndex = topModalIndex;
38245                 }
38246                 return topBackdropIndex;
38247               }
38248
38249               $rootScope.$watch(backdropIndex, function(newBackdropIndex) {
38250                 if (backdropScope) {
38251                   backdropScope.index = newBackdropIndex;
38252                 }
38253               });
38254
38255               function removeModalWindow(modalInstance, elementToReceiveFocus) {
38256                 var modalWindow = openedWindows.get(modalInstance).value;
38257                 var appendToElement = modalWindow.appendTo;
38258
38259                 //clean up the stack
38260                 openedWindows.remove(modalInstance);
38261                 previousTopOpenedModal = openedWindows.top();
38262                 if (previousTopOpenedModal) {
38263                   topModalIndex = parseInt(previousTopOpenedModal.value.modalDomEl.attr('index'), 10);
38264                 }
38265
38266                 removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
38267                   var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
38268                   openedClasses.remove(modalBodyClass, modalInstance);
38269                   var areAnyOpen = openedClasses.hasKey(modalBodyClass);
38270                   appendToElement.toggleClass(modalBodyClass, areAnyOpen);
38271                   if (!areAnyOpen && scrollbarPadding && scrollbarPadding.heightOverflow && scrollbarPadding.scrollbarWidth) {
38272                     if (scrollbarPadding.originalRight) {
38273                       appendToElement.css({paddingRight: scrollbarPadding.originalRight + 'px'});
38274                     } else {
38275                       appendToElement.css({paddingRight: ''});
38276                     }
38277                     scrollbarPadding = null;
38278                   }
38279                   toggleTopWindowClass(true);
38280                 }, modalWindow.closedDeferred);
38281                 checkRemoveBackdrop();
38282
38283                 //move focus to specified element if available, or else to body
38284                 if (elementToReceiveFocus && elementToReceiveFocus.focus) {
38285                   elementToReceiveFocus.focus();
38286                 } else if (appendToElement.focus) {
38287                   appendToElement.focus();
38288                 }
38289               }
38290
38291               // Add or remove "windowTopClass" from the top window in the stack
38292               function toggleTopWindowClass(toggleSwitch) {
38293                 var modalWindow;
38294
38295                 if (openedWindows.length() > 0) {
38296                   modalWindow = openedWindows.top().value;
38297                   modalWindow.modalDomEl.toggleClass(modalWindow.windowTopClass || '', toggleSwitch);
38298                 }
38299               }
38300
38301               function checkRemoveBackdrop() {
38302                 //remove backdrop if no longer needed
38303                 if (backdropDomEl && backdropIndex() === -1) {
38304                   var backdropScopeRef = backdropScope;
38305                   removeAfterAnimate(backdropDomEl, backdropScope, function() {
38306                     backdropScopeRef = null;
38307                   });
38308                   backdropDomEl = undefined;
38309                   backdropScope = undefined;
38310                 }
38311               }
38312
38313               function removeAfterAnimate(domEl, scope, done, closedDeferred) {
38314                 var asyncDeferred;
38315                 var asyncPromise = null;
38316                 var setIsAsync = function() {
38317                   if (!asyncDeferred) {
38318                     asyncDeferred = $q.defer();
38319                     asyncPromise = asyncDeferred.promise;
38320                   }
38321
38322                   return function asyncDone() {
38323                     asyncDeferred.resolve();
38324                   };
38325                 };
38326                 scope.$broadcast($modalStack.NOW_CLOSING_EVENT, setIsAsync);
38327
38328                 // Note that it's intentional that asyncPromise might be null.
38329                 // That's when setIsAsync has not been called during the
38330                 // NOW_CLOSING_EVENT broadcast.
38331                 return $q.when(asyncPromise).then(afterAnimating);
38332
38333                 function afterAnimating() {
38334                   if (afterAnimating.done) {
38335                     return;
38336                   }
38337                   afterAnimating.done = true;
38338
38339                   $animate.leave(domEl).then(function() {
38340                     domEl.remove();
38341                     if (closedDeferred) {
38342                       closedDeferred.resolve();
38343                     }
38344                   });
38345
38346                   scope.$destroy();
38347                   if (done) {
38348                     done();
38349                   }
38350                 }
38351               }
38352
38353               $document.on('keydown', keydownListener);
38354
38355               $rootScope.$on('$destroy', function() {
38356                 $document.off('keydown', keydownListener);
38357               });
38358
38359               function keydownListener(evt) {
38360                 if (evt.isDefaultPrevented()) {
38361                   return evt;
38362                 }
38363
38364                 var modal = openedWindows.top();
38365                 if (modal) {
38366                   switch (evt.which) {
38367                     case 27: {
38368                       if (modal.value.keyboard) {
38369                         evt.preventDefault();
38370                         $rootScope.$apply(function() {
38371                           $modalStack.dismiss(modal.key, 'escape key press');
38372                         });
38373                       }
38374                       break;
38375                     }
38376                     case 9: {
38377                       var list = $modalStack.loadFocusElementList(modal);
38378                       var focusChanged = false;
38379                       if (evt.shiftKey) {
38380                         if ($modalStack.isFocusInFirstItem(evt, list) || $modalStack.isModalFocused(evt, modal)) {
38381                           focusChanged = $modalStack.focusLastFocusableElement(list);
38382                         }
38383                       } else {
38384                         if ($modalStack.isFocusInLastItem(evt, list)) {
38385                           focusChanged = $modalStack.focusFirstFocusableElement(list);
38386                         }
38387                       }
38388
38389                       if (focusChanged) {
38390                         evt.preventDefault();
38391                         evt.stopPropagation();
38392                       }
38393
38394                       break;
38395                     }
38396                   }
38397                 }
38398               }
38399
38400               $modalStack.open = function(modalInstance, modal) {
38401                 var modalOpener = $document[0].activeElement,
38402                   modalBodyClass = modal.openedClass || OPENED_MODAL_CLASS;
38403
38404                 toggleTopWindowClass(false);
38405
38406                 // Store the current top first, to determine what index we ought to use
38407                 // for the current top modal
38408                 previousTopOpenedModal = openedWindows.top();
38409
38410                 openedWindows.add(modalInstance, {
38411                   deferred: modal.deferred,
38412                   renderDeferred: modal.renderDeferred,
38413                   closedDeferred: modal.closedDeferred,
38414                   modalScope: modal.scope,
38415                   backdrop: modal.backdrop,
38416                   keyboard: modal.keyboard,
38417                   openedClass: modal.openedClass,
38418                   windowTopClass: modal.windowTopClass,
38419                   animation: modal.animation,
38420                   appendTo: modal.appendTo
38421                 });
38422
38423                 openedClasses.put(modalBodyClass, modalInstance);
38424
38425                 var appendToElement = modal.appendTo,
38426                     currBackdropIndex = backdropIndex();
38427
38428                 if (!appendToElement.length) {
38429                   throw new Error('appendTo element not found. Make sure that the element passed is in DOM.');
38430                 }
38431
38432                 if (currBackdropIndex >= 0 && !backdropDomEl) {
38433                   backdropScope = $rootScope.$new(true);
38434                   backdropScope.modalOptions = modal;
38435                   backdropScope.index = currBackdropIndex;
38436                   backdropDomEl = angular.element('<div uib-modal-backdrop="modal-backdrop"></div>');
38437                   backdropDomEl.attr('backdrop-class', modal.backdropClass);
38438                   if (modal.animation) {
38439                     backdropDomEl.attr('modal-animation', 'true');
38440                   }
38441                   $compile(backdropDomEl)(backdropScope);
38442                   $animate.enter(backdropDomEl, appendToElement);
38443                   scrollbarPadding = $uibPosition.scrollbarPadding(appendToElement);
38444                   if (scrollbarPadding.heightOverflow && scrollbarPadding.scrollbarWidth) {
38445                     appendToElement.css({paddingRight: scrollbarPadding.right + 'px'});
38446                   }
38447                 }
38448
38449                 // Set the top modal index based on the index of the previous top modal
38450                 topModalIndex = previousTopOpenedModal ? parseInt(previousTopOpenedModal.value.modalDomEl.attr('index'), 10) + 1 : 0;
38451                 var angularDomEl = angular.element('<div uib-modal-window="modal-window"></div>');
38452                 angularDomEl.attr({
38453                   'template-url': modal.windowTemplateUrl,
38454                   'window-class': modal.windowClass,
38455                   'window-top-class': modal.windowTopClass,
38456                   'size': modal.size,
38457                   'index': topModalIndex,
38458                   'animate': 'animate'
38459                 }).html(modal.content);
38460                 if (modal.animation) {
38461                   angularDomEl.attr('modal-animation', 'true');
38462                 }
38463
38464                 appendToElement.addClass(modalBodyClass);
38465                 $animate.enter($compile(angularDomEl)(modal.scope), appendToElement);
38466
38467                 openedWindows.top().value.modalDomEl = angularDomEl;
38468                 openedWindows.top().value.modalOpener = modalOpener;
38469               };
38470
38471               function broadcastClosing(modalWindow, resultOrReason, closing) {
38472                 return !modalWindow.value.modalScope.$broadcast('modal.closing', resultOrReason, closing).defaultPrevented;
38473               }
38474
38475               $modalStack.close = function(modalInstance, result) {
38476                 var modalWindow = openedWindows.get(modalInstance);
38477                 if (modalWindow && broadcastClosing(modalWindow, result, true)) {
38478                   modalWindow.value.modalScope.$$uibDestructionScheduled = true;
38479                   modalWindow.value.deferred.resolve(result);
38480                   removeModalWindow(modalInstance, modalWindow.value.modalOpener);
38481                   return true;
38482                 }
38483                 return !modalWindow;
38484               };
38485
38486               $modalStack.dismiss = function(modalInstance, reason) {
38487                 var modalWindow = openedWindows.get(modalInstance);
38488                 if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
38489                   modalWindow.value.modalScope.$$uibDestructionScheduled = true;
38490                   modalWindow.value.deferred.reject(reason);
38491                   removeModalWindow(modalInstance, modalWindow.value.modalOpener);
38492                   return true;
38493                 }
38494                 return !modalWindow;
38495               };
38496
38497               $modalStack.dismissAll = function(reason) {
38498                 var topModal = this.getTop();
38499                 while (topModal && this.dismiss(topModal.key, reason)) {
38500                   topModal = this.getTop();
38501                 }
38502               };
38503
38504               $modalStack.getTop = function() {
38505                 return openedWindows.top();
38506               };
38507
38508               $modalStack.modalRendered = function(modalInstance) {
38509                 var modalWindow = openedWindows.get(modalInstance);
38510                 if (modalWindow) {
38511                   modalWindow.value.renderDeferred.resolve();
38512                 }
38513               };
38514
38515               $modalStack.focusFirstFocusableElement = function(list) {
38516                 if (list.length > 0) {
38517                   list[0].focus();
38518                   return true;
38519                 }
38520                 return false;
38521               };
38522
38523               $modalStack.focusLastFocusableElement = function(list) {
38524                 if (list.length > 0) {
38525                   list[list.length - 1].focus();
38526                   return true;
38527                 }
38528                 return false;
38529               };
38530
38531               $modalStack.isModalFocused = function(evt, modalWindow) {
38532                 if (evt && modalWindow) {
38533                   var modalDomEl = modalWindow.value.modalDomEl;
38534                   if (modalDomEl && modalDomEl.length) {
38535                     return (evt.target || evt.srcElement) === modalDomEl[0];
38536                   }
38537                 }
38538                 return false;
38539               };
38540
38541               $modalStack.isFocusInFirstItem = function(evt, list) {
38542                 if (list.length > 0) {
38543                   return (evt.target || evt.srcElement) === list[0];
38544                 }
38545                 return false;
38546               };
38547
38548               $modalStack.isFocusInLastItem = function(evt, list) {
38549                 if (list.length > 0) {
38550                   return (evt.target || evt.srcElement) === list[list.length - 1];
38551                 }
38552                 return false;
38553               };
38554
38555               $modalStack.loadFocusElementList = function(modalWindow) {
38556                 if (modalWindow) {
38557                   var modalDomE1 = modalWindow.value.modalDomEl;
38558                   if (modalDomE1 && modalDomE1.length) {
38559                     var elements = modalDomE1[0].querySelectorAll(tabableSelector);
38560                     return elements ?
38561                       Array.prototype.filter.call(elements, function(element) {
38562                         return isVisible(element);
38563                       }) : elements;
38564                   }
38565                 }
38566               };
38567
38568               return $modalStack;
38569             }])
38570
38571           .provider('$uibModal', function() {
38572             var $modalProvider = {
38573               options: {
38574                 animation: true,
38575                 backdrop: true, //can also be false or 'static'
38576                 keyboard: true
38577               },
38578               $get: ['$rootScope', '$q', '$document', '$templateRequest', '$controller', '$uibResolve', '$uibModalStack',
38579                 function ($rootScope, $q, $document, $templateRequest, $controller, $uibResolve, $modalStack) {
38580                   var $modal = {};
38581
38582                   function getTemplatePromise(options) {
38583                     return options.template ? $q.when(options.template) :
38584                       $templateRequest(angular.isFunction(options.templateUrl) ?
38585                         options.templateUrl() : options.templateUrl);
38586                   }
38587
38588                   var promiseChain = null;
38589                   $modal.getPromiseChain = function() {
38590                     return promiseChain;
38591                   };
38592
38593                   $modal.open = function(modalOptions) {
38594                     var modalResultDeferred = $q.defer();
38595                     var modalOpenedDeferred = $q.defer();
38596                     var modalClosedDeferred = $q.defer();
38597                     var modalRenderDeferred = $q.defer();
38598
38599                     //prepare an instance of a modal to be injected into controllers and returned to a caller
38600                     var modalInstance = {
38601                       result: modalResultDeferred.promise,
38602                       opened: modalOpenedDeferred.promise,
38603                       closed: modalClosedDeferred.promise,
38604                       rendered: modalRenderDeferred.promise,
38605                       close: function (result) {
38606                         return $modalStack.close(modalInstance, result);
38607                       },
38608                       dismiss: function (reason) {
38609                         return $modalStack.dismiss(modalInstance, reason);
38610                       }
38611                     };
38612
38613                     //merge and clean up options
38614                     modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
38615                     modalOptions.resolve = modalOptions.resolve || {};
38616                     modalOptions.appendTo = modalOptions.appendTo || $document.find('body').eq(0);
38617
38618                     //verify options
38619                     if (!modalOptions.template && !modalOptions.templateUrl) {
38620                       throw new Error('One of template or templateUrl options is required.');
38621                     }
38622
38623                     var templateAndResolvePromise =
38624                       $q.all([getTemplatePromise(modalOptions), $uibResolve.resolve(modalOptions.resolve, {}, null, null)]);
38625
38626                     function resolveWithTemplate() {
38627                       return templateAndResolvePromise;
38628                     }
38629
38630                     // Wait for the resolution of the existing promise chain.
38631                     // Then switch to our own combined promise dependency (regardless of how the previous modal fared).
38632                     // Then add to $modalStack and resolve opened.
38633                     // Finally clean up the chain variable if no subsequent modal has overwritten it.
38634                     var samePromise;
38635                     samePromise = promiseChain = $q.all([promiseChain])
38636                       .then(resolveWithTemplate, resolveWithTemplate)
38637                       .then(function resolveSuccess(tplAndVars) {
38638                         var providedScope = modalOptions.scope || $rootScope;
38639
38640                         var modalScope = providedScope.$new();
38641                         modalScope.$close = modalInstance.close;
38642                         modalScope.$dismiss = modalInstance.dismiss;
38643
38644                         modalScope.$on('$destroy', function() {
38645                           if (!modalScope.$$uibDestructionScheduled) {
38646                             modalScope.$dismiss('$uibUnscheduledDestruction');
38647                           }
38648                         });
38649
38650                         var ctrlInstance, ctrlInstantiate, ctrlLocals = {};
38651
38652                         //controllers
38653                         if (modalOptions.controller) {
38654                           ctrlLocals.$scope = modalScope;
38655                           ctrlLocals.$scope.$resolve = {};
38656                           ctrlLocals.$uibModalInstance = modalInstance;
38657                           angular.forEach(tplAndVars[1], function(value, key) {
38658                             ctrlLocals[key] = value;
38659                             ctrlLocals.$scope.$resolve[key] = value;
38660                           });
38661
38662                           // the third param will make the controller instantiate later,private api
38663                           // @see https://github.com/angular/angular.js/blob/master/src/ng/controller.js#L126
38664                           ctrlInstantiate = $controller(modalOptions.controller, ctrlLocals, true, modalOptions.controllerAs);
38665                           if (modalOptions.controllerAs && modalOptions.bindToController) {
38666                             ctrlInstance = ctrlInstantiate.instance;
38667                             ctrlInstance.$close = modalScope.$close;
38668                             ctrlInstance.$dismiss = modalScope.$dismiss;
38669                             angular.extend(ctrlInstance, {
38670                               $resolve: ctrlLocals.$scope.$resolve
38671                             }, providedScope);
38672                           }
38673
38674                           ctrlInstance = ctrlInstantiate();
38675
38676                           if (angular.isFunction(ctrlInstance.$onInit)) {
38677                             ctrlInstance.$onInit();
38678                           }
38679                         }
38680
38681                         $modalStack.open(modalInstance, {
38682                           scope: modalScope,
38683                           deferred: modalResultDeferred,
38684                           renderDeferred: modalRenderDeferred,
38685                           closedDeferred: modalClosedDeferred,
38686                           content: tplAndVars[0],
38687                           animation: modalOptions.animation,
38688                           backdrop: modalOptions.backdrop,
38689                           keyboard: modalOptions.keyboard,
38690                           backdropClass: modalOptions.backdropClass,
38691                           windowTopClass: modalOptions.windowTopClass,
38692                           windowClass: modalOptions.windowClass,
38693                           windowTemplateUrl: modalOptions.windowTemplateUrl,
38694                           size: modalOptions.size,
38695                           openedClass: modalOptions.openedClass,
38696                           appendTo: modalOptions.appendTo
38697                         });
38698                         modalOpenedDeferred.resolve(true);
38699
38700                     }, function resolveError(reason) {
38701                       modalOpenedDeferred.reject(reason);
38702                       modalResultDeferred.reject(reason);
38703                     })['finally'](function() {
38704                       if (promiseChain === samePromise) {
38705                         promiseChain = null;
38706                       }
38707                     });
38708
38709                     return modalInstance;
38710                   };
38711
38712                   return $modal;
38713                 }
38714               ]
38715             };
38716
38717             return $modalProvider;
38718           });
38719
38720         angular.module('ui.bootstrap.paging', [])
38721         /**
38722          * Helper internal service for generating common controller code between the
38723          * pager and pagination components
38724          */
38725         .factory('uibPaging', ['$parse', function($parse) {
38726           return {
38727             create: function(ctrl, $scope, $attrs) {
38728               ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
38729               ctrl.ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl
38730               ctrl._watchers = [];
38731
38732               ctrl.init = function(ngModelCtrl, config) {
38733                 ctrl.ngModelCtrl = ngModelCtrl;
38734                 ctrl.config = config;
38735
38736                 ngModelCtrl.$render = function() {
38737                   ctrl.render();
38738                 };
38739
38740                 if ($attrs.itemsPerPage) {
38741                   ctrl._watchers.push($scope.$parent.$watch($attrs.itemsPerPage, function(value) {
38742                     ctrl.itemsPerPage = parseInt(value, 10);
38743                     $scope.totalPages = ctrl.calculateTotalPages();
38744                     ctrl.updatePage();
38745                   }));
38746                 } else {
38747                   ctrl.itemsPerPage = config.itemsPerPage;
38748                 }
38749
38750                 $scope.$watch('totalItems', function(newTotal, oldTotal) {
38751                   if (angular.isDefined(newTotal) || newTotal !== oldTotal) {
38752                     $scope.totalPages = ctrl.calculateTotalPages();
38753                     ctrl.updatePage();
38754                   }
38755                 });
38756               };
38757
38758               ctrl.calculateTotalPages = function() {
38759                 var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage);
38760                 return Math.max(totalPages || 0, 1);
38761               };
38762
38763               ctrl.render = function() {
38764                 $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1;
38765               };
38766
38767               $scope.selectPage = function(page, evt) {
38768                 if (evt) {
38769                   evt.preventDefault();
38770                 }
38771
38772                 var clickAllowed = !$scope.ngDisabled || !evt;
38773                 if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) {
38774                   if (evt && evt.target) {
38775                     evt.target.blur();
38776                   }
38777                   ctrl.ngModelCtrl.$setViewValue(page);
38778                   ctrl.ngModelCtrl.$render();
38779                 }
38780               };
38781
38782               $scope.getText = function(key) {
38783                 return $scope[key + 'Text'] || ctrl.config[key + 'Text'];
38784               };
38785
38786               $scope.noPrevious = function() {
38787                 return $scope.page === 1;
38788               };
38789
38790               $scope.noNext = function() {
38791                 return $scope.page === $scope.totalPages;
38792               };
38793
38794               ctrl.updatePage = function() {
38795                 ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable
38796
38797                 if ($scope.page > $scope.totalPages) {
38798                   $scope.selectPage($scope.totalPages);
38799                 } else {
38800                   ctrl.ngModelCtrl.$render();
38801                 }
38802               };
38803
38804               $scope.$on('$destroy', function() {
38805                 while (ctrl._watchers.length) {
38806                   ctrl._watchers.shift()();
38807                 }
38808               });
38809             }
38810           };
38811         }]);
38812
38813         angular.module('ui.bootstrap.pager', ['ui.bootstrap.paging'])
38814
38815         .controller('UibPagerController', ['$scope', '$attrs', 'uibPaging', 'uibPagerConfig', function($scope, $attrs, uibPaging, uibPagerConfig) {
38816           $scope.align = angular.isDefined($attrs.align) ? $scope.$parent.$eval($attrs.align) : uibPagerConfig.align;
38817
38818           uibPaging.create(this, $scope, $attrs);
38819         }])
38820
38821         .constant('uibPagerConfig', {
38822           itemsPerPage: 10,
38823           previousText: '« Previous',
38824           nextText: 'Next »',
38825           align: true
38826         })
38827
38828         .directive('uibPager', ['uibPagerConfig', function(uibPagerConfig) {
38829           return {
38830             scope: {
38831               totalItems: '=',
38832               previousText: '@',
38833               nextText: '@',
38834               ngDisabled: '='
38835             },
38836             require: ['uibPager', '?ngModel'],
38837             controller: 'UibPagerController',
38838             controllerAs: 'pager',
38839             templateUrl: function(element, attrs) {
38840               return attrs.templateUrl || 'uib/template/pager/pager.html';
38841             },
38842             replace: true,
38843             link: function(scope, element, attrs, ctrls) {
38844               var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
38845
38846               if (!ngModelCtrl) {
38847                 return; // do nothing if no ng-model
38848               }
38849
38850               paginationCtrl.init(ngModelCtrl, uibPagerConfig);
38851             }
38852           };
38853         }]);
38854
38855         angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging'])
38856         .controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function($scope, $attrs, $parse, uibPaging, uibPaginationConfig) {
38857           var ctrl = this;
38858           // Setup configuration parameters
38859           var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize,
38860             rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate,
38861             forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses,
38862             boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers,
38863             pageLabel = angular.isDefined($attrs.pageLabel) ? function(idx) { return $scope.$parent.$eval($attrs.pageLabel, {$page: idx}); } : angular.identity;
38864           $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks;
38865           $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks;
38866
38867           uibPaging.create(this, $scope, $attrs);
38868
38869           if ($attrs.maxSize) {
38870             ctrl._watchers.push($scope.$parent.$watch($parse($attrs.maxSize), function(value) {
38871               maxSize = parseInt(value, 10);
38872               ctrl.render();
38873             }));
38874           }
38875
38876           // Create page object used in template
38877           function makePage(number, text, isActive) {
38878             return {
38879               number: number,
38880               text: text,
38881               active: isActive
38882             };
38883           }
38884
38885           function getPages(currentPage, totalPages) {
38886             var pages = [];
38887
38888             // Default page limits
38889             var startPage = 1, endPage = totalPages;
38890             var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;
38891
38892             // recompute if maxSize
38893             if (isMaxSized) {
38894               if (rotate) {
38895                 // Current page is displayed in the middle of the visible ones
38896                 startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
38897                 endPage = startPage + maxSize - 1;
38898
38899                 // Adjust if limit is exceeded
38900                 if (endPage > totalPages) {
38901                   endPage = totalPages;
38902                   startPage = endPage - maxSize + 1;
38903                 }
38904               } else {
38905                 // Visible pages are paginated with maxSize
38906                 startPage = (Math.ceil(currentPage / maxSize) - 1) * maxSize + 1;
38907
38908                 // Adjust last page if limit is exceeded
38909                 endPage = Math.min(startPage + maxSize - 1, totalPages);
38910               }
38911             }
38912
38913             // Add page number links
38914             for (var number = startPage; number <= endPage; number++) {
38915               var page = makePage(number, pageLabel(number), number === currentPage);
38916               pages.push(page);
38917             }
38918
38919             // Add links to move between page sets
38920             if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) {
38921               if (startPage > 1) {
38922                 if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning
38923                 var previousPageSet = makePage(startPage - 1, '...', false);
38924                 pages.unshift(previousPageSet);
38925               }
38926                 if (boundaryLinkNumbers) {
38927                   if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential
38928                     var secondPageLink = makePage(2, '2', false);
38929                     pages.unshift(secondPageLink);
38930                   }
38931                   //add the first page
38932                   var firstPageLink = makePage(1, '1', false);
38933                   pages.unshift(firstPageLink);
38934                 }
38935               }
38936
38937               if (endPage < totalPages) {
38938                 if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end
38939                 var nextPageSet = makePage(endPage + 1, '...', false);
38940                 pages.push(nextPageSet);
38941               }
38942                 if (boundaryLinkNumbers) {
38943                   if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential
38944                     var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false);
38945                     pages.push(secondToLastPageLink);
38946                   }
38947                   //add the last page
38948                   var lastPageLink = makePage(totalPages, totalPages, false);
38949                   pages.push(lastPageLink);
38950                 }
38951               }
38952             }
38953             return pages;
38954           }
38955
38956           var originalRender = this.render;
38957           this.render = function() {
38958             originalRender();
38959             if ($scope.page > 0 && $scope.page <= $scope.totalPages) {
38960               $scope.pages = getPages($scope.page, $scope.totalPages);
38961             }
38962           };
38963         }])
38964
38965         .constant('uibPaginationConfig', {
38966           itemsPerPage: 10,
38967           boundaryLinks: false,
38968           boundaryLinkNumbers: false,
38969           directionLinks: true,
38970           firstText: 'First',
38971           previousText: 'Previous',
38972           nextText: 'Next',
38973           lastText: 'Last',
38974           rotate: true,
38975           forceEllipses: false
38976         })
38977
38978         .directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, uibPaginationConfig) {
38979           return {
38980             scope: {
38981               totalItems: '=',
38982               firstText: '@',
38983               previousText: '@',
38984               nextText: '@',
38985               lastText: '@',
38986               ngDisabled:'='
38987             },
38988             require: ['uibPagination', '?ngModel'],
38989             controller: 'UibPaginationController',
38990             controllerAs: 'pagination',
38991             templateUrl: function(element, attrs) {
38992               return attrs.templateUrl || 'uib/template/pagination/pagination.html';
38993             },
38994             replace: true,
38995             link: function(scope, element, attrs, ctrls) {
38996               var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
38997
38998               if (!ngModelCtrl) {
38999                  return; // do nothing if no ng-model
39000               }
39001
39002               paginationCtrl.init(ngModelCtrl, uibPaginationConfig);
39003             }
39004           };
39005         }]);
39006
39007         /**
39008          * The following features are still outstanding: animation as a
39009          * function, placement as a function, inside, support for more triggers than
39010          * just mouse enter/leave, html tooltips, and selector delegation.
39011          */
39012         angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.stackedMap'])
39013
39014         /**
39015          * The $tooltip service creates tooltip- and popover-like directives as well as
39016          * houses global options for them.
39017          */
39018         .provider('$uibTooltip', function() {
39019           // The default options tooltip and popover.
39020           var defaultOptions = {
39021             placement: 'top',
39022             placementClassPrefix: '',
39023             animation: true,
39024             popupDelay: 0,
39025             popupCloseDelay: 0,
39026             useContentExp: false
39027           };
39028
39029           // Default hide triggers for each show trigger
39030           var triggerMap = {
39031             'mouseenter': 'mouseleave',
39032             'click': 'click',
39033             'outsideClick': 'outsideClick',
39034             'focus': 'blur',
39035             'none': ''
39036           };
39037
39038           // The options specified to the provider globally.
39039           var globalOptions = {};
39040
39041           /**
39042            * `options({})` allows global configuration of all tooltips in the
39043            * application.
39044            *
39045            *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
39046            *     // place tooltips left instead of top by default
39047            *     $tooltipProvider.options( { placement: 'left' } );
39048            *   });
39049            */
39050                 this.options = function(value) {
39051                         angular.extend(globalOptions, value);
39052                 };
39053
39054           /**
39055            * This allows you to extend the set of trigger mappings available. E.g.:
39056            *
39057            *   $tooltipProvider.setTriggers( { 'openTrigger': 'closeTrigger' } );
39058            */
39059           this.setTriggers = function setTriggers(triggers) {
39060             angular.extend(triggerMap, triggers);
39061           };
39062
39063           /**
39064            * This is a helper function for translating camel-case to snake_case.
39065            */
39066           function snake_case(name) {
39067             var regexp = /[A-Z]/g;
39068             var separator = '-';
39069             return name.replace(regexp, function(letter, pos) {
39070               return (pos ? separator : '') + letter.toLowerCase();
39071             });
39072           }
39073
39074           /**
39075            * Returns the actual instance of the $tooltip service.
39076            * TODO support multiple triggers
39077            */
39078           this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) {
39079             var openedTooltips = $$stackedMap.createNew();
39080             $document.on('keypress', keypressListener);
39081
39082             $rootScope.$on('$destroy', function() {
39083               $document.off('keypress', keypressListener);
39084             });
39085
39086             function keypressListener(e) {
39087               if (e.which === 27) {
39088                 var last = openedTooltips.top();
39089                 if (last) {
39090                   last.value.close();
39091                   openedTooltips.removeTop();
39092                   last = null;
39093                 }
39094               }
39095             }
39096
39097             return function $tooltip(ttType, prefix, defaultTriggerShow, options) {
39098               options = angular.extend({}, defaultOptions, globalOptions, options);
39099
39100               /**
39101                * Returns an object of show and hide triggers.
39102                *
39103                * If a trigger is supplied,
39104                * it is used to show the tooltip; otherwise, it will use the `trigger`
39105                * option passed to the `$tooltipProvider.options` method; else it will
39106                * default to the trigger supplied to this directive factory.
39107                *
39108                * The hide trigger is based on the show trigger. If the `trigger` option
39109                * was passed to the `$tooltipProvider.options` method, it will use the
39110                * mapped trigger from `triggerMap` or the passed trigger if the map is
39111                * undefined; otherwise, it uses the `triggerMap` value of the show
39112                * trigger; else it will just use the show trigger.
39113                */
39114               function getTriggers(trigger) {
39115                 var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
39116                 var hide = show.map(function(trigger) {
39117                   return triggerMap[trigger] || trigger;
39118                 });
39119                 return {
39120                   show: show,
39121                   hide: hide
39122                 };
39123               }
39124
39125               var directiveName = snake_case(ttType);
39126
39127               var startSym = $interpolate.startSymbol();
39128               var endSym = $interpolate.endSymbol();
39129               var template =
39130                 '<div '+ directiveName + '-popup ' +
39131                   'uib-title="' + startSym + 'title' + endSym + '" ' +
39132                   (options.useContentExp ?
39133                     'content-exp="contentExp()" ' :
39134                     'content="' + startSym + 'content' + endSym + '" ') +
39135                   'placement="' + startSym + 'placement' + endSym + '" ' +
39136                   'popup-class="' + startSym + 'popupClass' + endSym + '" ' +
39137                   'animation="animation" ' +
39138                   'is-open="isOpen" ' +
39139                   'origin-scope="origScope" ' +
39140                   'class="uib-position-measure"' +
39141                   '>' +
39142                 '</div>';
39143
39144               return {
39145                 compile: function(tElem, tAttrs) {
39146                   var tooltipLinker = $compile(template);
39147
39148                   return function link(scope, element, attrs, tooltipCtrl) {
39149                     var tooltip;
39150                     var tooltipLinkedScope;
39151                     var transitionTimeout;
39152                     var showTimeout;
39153                     var hideTimeout;
39154                     var positionTimeout;
39155                     var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
39156                     var triggers = getTriggers(undefined);
39157                     var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
39158                     var ttScope = scope.$new(true);
39159                     var repositionScheduled = false;
39160                     var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
39161                     var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false;
39162                     var observers = [];
39163                     var lastPlacement;
39164
39165                     var positionTooltip = function() {
39166                       // check if tooltip exists and is not empty
39167                       if (!tooltip || !tooltip.html()) { return; }
39168
39169                       if (!positionTimeout) {
39170                         positionTimeout = $timeout(function() {
39171                           var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
39172                           tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px' });
39173
39174                           if (!tooltip.hasClass(ttPosition.placement.split('-')[0])) {
39175                             tooltip.removeClass(lastPlacement.split('-')[0]);
39176                             tooltip.addClass(ttPosition.placement.split('-')[0]);
39177                           }
39178
39179                           if (!tooltip.hasClass(options.placementClassPrefix + ttPosition.placement)) {
39180                             tooltip.removeClass(options.placementClassPrefix + lastPlacement);
39181                             tooltip.addClass(options.placementClassPrefix + ttPosition.placement);
39182                           }
39183
39184                           // first time through tt element will have the
39185                           // uib-position-measure class or if the placement
39186                           // has changed we need to position the arrow.
39187                           if (tooltip.hasClass('uib-position-measure')) {
39188                             $position.positionArrow(tooltip, ttPosition.placement);
39189                             tooltip.removeClass('uib-position-measure');
39190                           } else if (lastPlacement !== ttPosition.placement) {
39191                             $position.positionArrow(tooltip, ttPosition.placement);
39192                           }
39193                           lastPlacement = ttPosition.placement;
39194
39195                           positionTimeout = null;
39196                         }, 0, false);
39197                       }
39198                     };
39199
39200                     // Set up the correct scope to allow transclusion later
39201                     ttScope.origScope = scope;
39202
39203                     // By default, the tooltip is not open.
39204                     // TODO add ability to start tooltip opened
39205                     ttScope.isOpen = false;
39206                     openedTooltips.add(ttScope, {
39207                       close: hide
39208                     });
39209
39210                     function toggleTooltipBind() {
39211                       if (!ttScope.isOpen) {
39212                         showTooltipBind();
39213                       } else {
39214                         hideTooltipBind();
39215                       }
39216                     }
39217
39218                     // Show the tooltip with delay if specified, otherwise show it immediately
39219                     function showTooltipBind() {
39220                       if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
39221                         return;
39222                       }
39223
39224                       cancelHide();
39225                       prepareTooltip();
39226
39227                       if (ttScope.popupDelay) {
39228                         // Do nothing if the tooltip was already scheduled to pop-up.
39229                         // This happens if show is triggered multiple times before any hide is triggered.
39230                         if (!showTimeout) {
39231                           showTimeout = $timeout(show, ttScope.popupDelay, false);
39232                         }
39233                       } else {
39234                         show();
39235                       }
39236                     }
39237
39238                     function hideTooltipBind() {
39239                       cancelShow();
39240
39241                       if (ttScope.popupCloseDelay) {
39242                         if (!hideTimeout) {
39243                           hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
39244                         }
39245                       } else {
39246                         hide();
39247                       }
39248                     }
39249
39250                     // Show the tooltip popup element.
39251                     function show() {
39252                       cancelShow();
39253                       cancelHide();
39254
39255                       // Don't show empty tooltips.
39256                       if (!ttScope.content) {
39257                         return angular.noop;
39258                       }
39259
39260                       createTooltip();
39261
39262                       // And show the tooltip.
39263                       ttScope.$evalAsync(function() {
39264                         ttScope.isOpen = true;
39265                         assignIsOpen(true);
39266                         positionTooltip();
39267                       });
39268                     }
39269
39270                     function cancelShow() {
39271                       if (showTimeout) {
39272                         $timeout.cancel(showTimeout);
39273                         showTimeout = null;
39274                       }
39275
39276                       if (positionTimeout) {
39277                         $timeout.cancel(positionTimeout);
39278                         positionTimeout = null;
39279                       }
39280                     }
39281
39282                     // Hide the tooltip popup element.
39283                     function hide() {
39284                       if (!ttScope) {
39285                         return;
39286                       }
39287
39288                       // First things first: we don't show it anymore.
39289                       ttScope.$evalAsync(function() {
39290                         if (ttScope) {
39291                           ttScope.isOpen = false;
39292                           assignIsOpen(false);
39293                           // And now we remove it from the DOM. However, if we have animation, we
39294                           // need to wait for it to expire beforehand.
39295                           // FIXME: this is a placeholder for a port of the transitions library.
39296                           // The fade transition in TWBS is 150ms.
39297                           if (ttScope.animation) {
39298                             if (!transitionTimeout) {
39299                               transitionTimeout = $timeout(removeTooltip, 150, false);
39300                             }
39301                           } else {
39302                             removeTooltip();
39303                           }
39304                         }
39305                       });
39306                     }
39307
39308                     function cancelHide() {
39309                       if (hideTimeout) {
39310                         $timeout.cancel(hideTimeout);
39311                         hideTimeout = null;
39312                       }
39313
39314                       if (transitionTimeout) {
39315                         $timeout.cancel(transitionTimeout);
39316                         transitionTimeout = null;
39317                       }
39318                     }
39319
39320                     function createTooltip() {
39321                       // There can only be one tooltip element per directive shown at once.
39322                       if (tooltip) {
39323                         return;
39324                       }
39325
39326                       tooltipLinkedScope = ttScope.$new();
39327                       tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
39328                         if (appendToBody) {
39329                           $document.find('body').append(tooltip);
39330                         } else {
39331                           element.after(tooltip);
39332                         }
39333                       });
39334
39335                       prepObservers();
39336                     }
39337
39338                     function removeTooltip() {
39339                       cancelShow();
39340                       cancelHide();
39341                       unregisterObservers();
39342
39343                       if (tooltip) {
39344                         tooltip.remove();
39345                         tooltip = null;
39346                       }
39347                       if (tooltipLinkedScope) {
39348                         tooltipLinkedScope.$destroy();
39349                         tooltipLinkedScope = null;
39350                       }
39351                     }
39352
39353                     /**
39354                      * Set the initial scope values. Once
39355                      * the tooltip is created, the observers
39356                      * will be added to keep things in sync.
39357                      */
39358                     function prepareTooltip() {
39359                       ttScope.title = attrs[prefix + 'Title'];
39360                       if (contentParse) {
39361                         ttScope.content = contentParse(scope);
39362                       } else {
39363                         ttScope.content = attrs[ttType];
39364                       }
39365
39366                       ttScope.popupClass = attrs[prefix + 'Class'];
39367                       ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement;
39368                       var placement = $position.parsePlacement(ttScope.placement);
39369                       lastPlacement = placement[1] ? placement[0] + '-' + placement[1] : placement[0];
39370
39371                       var delay = parseInt(attrs[prefix + 'PopupDelay'], 10);
39372                       var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10);
39373                       ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
39374                       ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
39375                     }
39376
39377                     function assignIsOpen(isOpen) {
39378                       if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
39379                         isOpenParse.assign(scope, isOpen);
39380                       }
39381                     }
39382
39383                     ttScope.contentExp = function() {
39384                       return ttScope.content;
39385                     };
39386
39387                     /**
39388                      * Observe the relevant attributes.
39389                      */
39390                     attrs.$observe('disabled', function(val) {
39391                       if (val) {
39392                         cancelShow();
39393                       }
39394
39395                       if (val && ttScope.isOpen) {
39396                         hide();
39397                       }
39398                     });
39399
39400                     if (isOpenParse) {
39401                       scope.$watch(isOpenParse, function(val) {
39402                         if (ttScope && !val === ttScope.isOpen) {
39403                           toggleTooltipBind();
39404                         }
39405                       });
39406                     }
39407
39408                     function prepObservers() {
39409                       observers.length = 0;
39410
39411                       if (contentParse) {
39412                         observers.push(
39413                           scope.$watch(contentParse, function(val) {
39414                             ttScope.content = val;
39415                             if (!val && ttScope.isOpen) {
39416                               hide();
39417                             }
39418                           })
39419                         );
39420
39421                         observers.push(
39422                           tooltipLinkedScope.$watch(function() {
39423                             if (!repositionScheduled) {
39424                               repositionScheduled = true;
39425                               tooltipLinkedScope.$$postDigest(function() {
39426                                 repositionScheduled = false;
39427                                 if (ttScope && ttScope.isOpen) {
39428                                   positionTooltip();
39429                                 }
39430                               });
39431                             }
39432                           })
39433                         );
39434                       } else {
39435                         observers.push(
39436                           attrs.$observe(ttType, function(val) {
39437                             ttScope.content = val;
39438                             if (!val && ttScope.isOpen) {
39439                               hide();
39440                             } else {
39441                               positionTooltip();
39442                             }
39443                           })
39444                         );
39445                       }
39446
39447                       observers.push(
39448                         attrs.$observe(prefix + 'Title', function(val) {
39449                           ttScope.title = val;
39450                           if (ttScope.isOpen) {
39451                             positionTooltip();
39452                           }
39453                         })
39454                       );
39455
39456                       observers.push(
39457                         attrs.$observe(prefix + 'Placement', function(val) {
39458                           ttScope.placement = val ? val : options.placement;
39459                           if (ttScope.isOpen) {
39460                             positionTooltip();
39461                           }
39462                         })
39463                       );
39464                     }
39465
39466                     function unregisterObservers() {
39467                       if (observers.length) {
39468                         angular.forEach(observers, function(observer) {
39469                           observer();
39470                         });
39471                         observers.length = 0;
39472                       }
39473                     }
39474
39475                     // hide tooltips/popovers for outsideClick trigger
39476                     function bodyHideTooltipBind(e) {
39477                       if (!ttScope || !ttScope.isOpen || !tooltip) {
39478                         return;
39479                       }
39480                       // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked
39481                       if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) {
39482                         hideTooltipBind();
39483                       }
39484                     }
39485
39486                     var unregisterTriggers = function() {
39487                       triggers.show.forEach(function(trigger) {
39488                         if (trigger === 'outsideClick') {
39489                           element.off('click', toggleTooltipBind);
39490                         } else {
39491                           element.off(trigger, showTooltipBind);
39492                           element.off(trigger, toggleTooltipBind);
39493                         }
39494                       });
39495                       triggers.hide.forEach(function(trigger) {
39496                         if (trigger === 'outsideClick') {
39497                           $document.off('click', bodyHideTooltipBind);
39498                         } else {
39499                           element.off(trigger, hideTooltipBind);
39500                         }
39501                       });
39502                     };
39503
39504                     function prepTriggers() {
39505                       var val = attrs[prefix + 'Trigger'];
39506                       unregisterTriggers();
39507
39508                       triggers = getTriggers(val);
39509
39510                       if (triggers.show !== 'none') {
39511                         triggers.show.forEach(function(trigger, idx) {
39512                           if (trigger === 'outsideClick') {
39513                             element.on('click', toggleTooltipBind);
39514                             $document.on('click', bodyHideTooltipBind);
39515                           } else if (trigger === triggers.hide[idx]) {
39516                             element.on(trigger, toggleTooltipBind);
39517                           } else if (trigger) {
39518                             element.on(trigger, showTooltipBind);
39519                             element.on(triggers.hide[idx], hideTooltipBind);
39520                           }
39521
39522                           element.on('keypress', function(e) {
39523                             if (e.which === 27) {
39524                               hideTooltipBind();
39525                             }
39526                           });
39527                         });
39528                       }
39529                     }
39530
39531                     prepTriggers();
39532
39533                     var animation = scope.$eval(attrs[prefix + 'Animation']);
39534                     ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation;
39535
39536                     var appendToBodyVal;
39537                     var appendKey = prefix + 'AppendToBody';
39538                     if (appendKey in attrs && attrs[appendKey] === undefined) {
39539                       appendToBodyVal = true;
39540                     } else {
39541                       appendToBodyVal = scope.$eval(attrs[appendKey]);
39542                     }
39543
39544                     appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody;
39545
39546                     // Make sure tooltip is destroyed and removed.
39547                     scope.$on('$destroy', function onDestroyTooltip() {
39548                       unregisterTriggers();
39549                       removeTooltip();
39550                       openedTooltips.remove(ttScope);
39551                       ttScope = null;
39552                     });
39553                   };
39554                 }
39555               };
39556             };
39557           }];
39558         })
39559
39560         // This is mostly ngInclude code but with a custom scope
39561         .directive('uibTooltipTemplateTransclude', [
39562                  '$animate', '$sce', '$compile', '$templateRequest',
39563         function ($animate, $sce, $compile, $templateRequest) {
39564           return {
39565             link: function(scope, elem, attrs) {
39566               var origScope = scope.$eval(attrs.tooltipTemplateTranscludeScope);
39567
39568               var changeCounter = 0,
39569                 currentScope,
39570                 previousElement,
39571                 currentElement;
39572
39573               var cleanupLastIncludeContent = function() {
39574                 if (previousElement) {
39575                   previousElement.remove();
39576                   previousElement = null;
39577                 }
39578
39579                 if (currentScope) {
39580                   currentScope.$destroy();
39581                   currentScope = null;
39582                 }
39583
39584                 if (currentElement) {
39585                   $animate.leave(currentElement).then(function() {
39586                     previousElement = null;
39587                   });
39588                   previousElement = currentElement;
39589                   currentElement = null;
39590                 }
39591               };
39592
39593               scope.$watch($sce.parseAsResourceUrl(attrs.uibTooltipTemplateTransclude), function(src) {
39594                 var thisChangeId = ++changeCounter;
39595
39596                 if (src) {
39597                   //set the 2nd param to true to ignore the template request error so that the inner
39598                   //contents and scope can be cleaned up.
39599                   $templateRequest(src, true).then(function(response) {
39600                     if (thisChangeId !== changeCounter) { return; }
39601                     var newScope = origScope.$new();
39602                     var template = response;
39603
39604                     var clone = $compile(template)(newScope, function(clone) {
39605                       cleanupLastIncludeContent();
39606                       $animate.enter(clone, elem);
39607                     });
39608
39609                     currentScope = newScope;
39610                     currentElement = clone;
39611
39612                     currentScope.$emit('$includeContentLoaded', src);
39613                   }, function() {
39614                     if (thisChangeId === changeCounter) {
39615                       cleanupLastIncludeContent();
39616                       scope.$emit('$includeContentError', src);
39617                     }
39618                   });
39619                   scope.$emit('$includeContentRequested', src);
39620                 } else {
39621                   cleanupLastIncludeContent();
39622                 }
39623               });
39624
39625               scope.$on('$destroy', cleanupLastIncludeContent);
39626             }
39627           };
39628         }])
39629
39630         /**
39631          * Note that it's intentional that these classes are *not* applied through $animate.
39632          * They must not be animated as they're expected to be present on the tooltip on
39633          * initialization.
39634          */
39635         .directive('uibTooltipClasses', ['$uibPosition', function($uibPosition) {
39636           return {
39637             restrict: 'A',
39638             link: function(scope, element, attrs) {
39639               // need to set the primary position so the
39640               // arrow has space during position measure.
39641               // tooltip.positionTooltip()
39642               if (scope.placement) {
39643                 // // There are no top-left etc... classes
39644                 // // in TWBS, so we need the primary position.
39645                 var position = $uibPosition.parsePlacement(scope.placement);
39646                 element.addClass(position[0]);
39647               }
39648
39649               if (scope.popupClass) {
39650                 element.addClass(scope.popupClass);
39651               }
39652
39653               if (scope.animation()) {
39654                 element.addClass(attrs.tooltipAnimationClass);
39655               }
39656             }
39657           };
39658         }])
39659
39660         .directive('uibTooltipPopup', function() {
39661           return {
39662             replace: true,
39663             scope: { content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
39664             templateUrl: 'uib/template/tooltip/tooltip-popup.html'
39665           };
39666         })
39667
39668         .directive('uibTooltip', [ '$uibTooltip', function($uibTooltip) {
39669           return $uibTooltip('uibTooltip', 'tooltip', 'mouseenter');
39670         }])
39671
39672         .directive('uibTooltipTemplatePopup', function() {
39673           return {
39674             replace: true,
39675             scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
39676               originScope: '&' },
39677             templateUrl: 'uib/template/tooltip/tooltip-template-popup.html'
39678           };
39679         })
39680
39681         .directive('uibTooltipTemplate', ['$uibTooltip', function($uibTooltip) {
39682           return $uibTooltip('uibTooltipTemplate', 'tooltip', 'mouseenter', {
39683             useContentExp: true
39684           });
39685         }])
39686
39687         .directive('uibTooltipHtmlPopup', function() {
39688           return {
39689             replace: true,
39690             scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
39691             templateUrl: 'uib/template/tooltip/tooltip-html-popup.html'
39692           };
39693         })
39694
39695         .directive('uibTooltipHtml', ['$uibTooltip', function($uibTooltip) {
39696           return $uibTooltip('uibTooltipHtml', 'tooltip', 'mouseenter', {
39697             useContentExp: true
39698           });
39699         }]);
39700
39701         /**
39702          * The following features are still outstanding: popup delay, animation as a
39703          * function, placement as a function, inside, support for more triggers than
39704          * just mouse enter/leave, and selector delegatation.
39705          */
39706         angular.module('ui.bootstrap.popover', ['ui.bootstrap.tooltip'])
39707
39708         .directive('uibPopoverTemplatePopup', function() {
39709           return {
39710             replace: true,
39711             scope: { uibTitle: '@', contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&',
39712               originScope: '&' },
39713             templateUrl: 'uib/template/popover/popover-template.html'
39714           };
39715         })
39716
39717         .directive('uibPopoverTemplate', ['$uibTooltip', function($uibTooltip) {
39718           return $uibTooltip('uibPopoverTemplate', 'popover', 'click', {
39719             useContentExp: true
39720           });
39721         }])
39722
39723         .directive('uibPopoverHtmlPopup', function() {
39724           return {
39725             replace: true,
39726             scope: { contentExp: '&', uibTitle: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
39727             templateUrl: 'uib/template/popover/popover-html.html'
39728           };
39729         })
39730
39731         .directive('uibPopoverHtml', ['$uibTooltip', function($uibTooltip) {
39732           return $uibTooltip('uibPopoverHtml', 'popover', 'click', {
39733             useContentExp: true
39734           });
39735         }])
39736
39737         .directive('uibPopoverPopup', function() {
39738           return {
39739             replace: true,
39740             scope: { uibTitle: '@', content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' },
39741             templateUrl: 'uib/template/popover/popover.html'
39742           };
39743         })
39744
39745         .directive('uibPopover', ['$uibTooltip', function($uibTooltip) {
39746           return $uibTooltip('uibPopover', 'popover', 'click');
39747         }]);
39748
39749         angular.module('ui.bootstrap.progressbar', [])
39750
39751         .constant('uibProgressConfig', {
39752           animate: true,
39753           max: 100
39754         })
39755
39756         .controller('UibProgressController', ['$scope', '$attrs', 'uibProgressConfig', function($scope, $attrs, progressConfig) {
39757           var self = this,
39758               animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
39759
39760           this.bars = [];
39761           $scope.max = getMaxOrDefault();
39762
39763           this.addBar = function(bar, element, attrs) {
39764             if (!animate) {
39765               element.css({'transition': 'none'});
39766             }
39767
39768             this.bars.push(bar);
39769
39770             bar.max = getMaxOrDefault();
39771             bar.title = attrs && angular.isDefined(attrs.title) ? attrs.title : 'progressbar';
39772
39773             bar.$watch('value', function(value) {
39774               bar.recalculatePercentage();
39775             });
39776
39777             bar.recalculatePercentage = function() {
39778               var totalPercentage = self.bars.reduce(function(total, bar) {
39779                 bar.percent = +(100 * bar.value / bar.max).toFixed(2);
39780                 return total + bar.percent;
39781               }, 0);
39782
39783               if (totalPercentage > 100) {
39784                 bar.percent -= totalPercentage - 100;
39785               }
39786             };
39787
39788             bar.$on('$destroy', function() {
39789               element = null;
39790               self.removeBar(bar);
39791             });
39792           };
39793
39794           this.removeBar = function(bar) {
39795             this.bars.splice(this.bars.indexOf(bar), 1);
39796             this.bars.forEach(function (bar) {
39797               bar.recalculatePercentage();
39798             });
39799           };
39800
39801           //$attrs.$observe('maxParam', function(maxParam) {
39802           $scope.$watch('maxParam', function(maxParam) {
39803             self.bars.forEach(function(bar) {
39804               bar.max = getMaxOrDefault();
39805               bar.recalculatePercentage();
39806             });
39807           });
39808
39809           function getMaxOrDefault () {
39810             return angular.isDefined($scope.maxParam) ? $scope.maxParam : progressConfig.max;
39811           }
39812         }])
39813
39814         .directive('uibProgress', function() {
39815           return {
39816             replace: true,
39817             transclude: true,
39818             controller: 'UibProgressController',
39819             require: 'uibProgress',
39820             scope: {
39821               maxParam: '=?max'
39822             },
39823             templateUrl: 'uib/template/progressbar/progress.html'
39824           };
39825         })
39826
39827         .directive('uibBar', function() {
39828           return {
39829             replace: true,
39830             transclude: true,
39831             require: '^uibProgress',
39832             scope: {
39833               value: '=',
39834               type: '@'
39835             },
39836             templateUrl: 'uib/template/progressbar/bar.html',
39837             link: function(scope, element, attrs, progressCtrl) {
39838               progressCtrl.addBar(scope, element, attrs);
39839             }
39840           };
39841         })
39842
39843         .directive('uibProgressbar', function() {
39844           return {
39845             replace: true,
39846             transclude: true,
39847             controller: 'UibProgressController',
39848             scope: {
39849               value: '=',
39850               maxParam: '=?max',
39851               type: '@'
39852             },
39853             templateUrl: 'uib/template/progressbar/progressbar.html',
39854             link: function(scope, element, attrs, progressCtrl) {
39855               progressCtrl.addBar(scope, angular.element(element.children()[0]), {title: attrs.title});
39856             }
39857           };
39858         });
39859
39860         angular.module('ui.bootstrap.rating', [])
39861
39862         .constant('uibRatingConfig', {
39863           max: 5,
39864           stateOn: null,
39865           stateOff: null,
39866           enableReset: true,
39867           titles : ['one', 'two', 'three', 'four', 'five']
39868         })
39869
39870         .controller('UibRatingController', ['$scope', '$attrs', 'uibRatingConfig', function($scope, $attrs, ratingConfig) {
39871           var ngModelCtrl = { $setViewValue: angular.noop },
39872             self = this;
39873
39874           this.init = function(ngModelCtrl_) {
39875             ngModelCtrl = ngModelCtrl_;
39876             ngModelCtrl.$render = this.render;
39877
39878             ngModelCtrl.$formatters.push(function(value) {
39879               if (angular.isNumber(value) && value << 0 !== value) {
39880                 value = Math.round(value);
39881               }
39882
39883               return value;
39884             });
39885
39886             this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
39887             this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
39888             this.enableReset = angular.isDefined($attrs.enableReset) ?
39889               $scope.$parent.$eval($attrs.enableReset) : ratingConfig.enableReset;
39890             var tmpTitles = angular.isDefined($attrs.titles) ? $scope.$parent.$eval($attrs.titles) : ratingConfig.titles;
39891             this.titles = angular.isArray(tmpTitles) && tmpTitles.length > 0 ?
39892               tmpTitles : ratingConfig.titles;
39893
39894             var ratingStates = angular.isDefined($attrs.ratingStates) ?
39895               $scope.$parent.$eval($attrs.ratingStates) :
39896               new Array(angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max);
39897             $scope.range = this.buildTemplateObjects(ratingStates);
39898           };
39899
39900           this.buildTemplateObjects = function(states) {
39901             for (var i = 0, n = states.length; i < n; i++) {
39902               states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff, title: this.getTitle(i) }, states[i]);
39903             }
39904             return states;
39905           };
39906
39907           this.getTitle = function(index) {
39908             if (index >= this.titles.length) {
39909               return index + 1;
39910             }
39911
39912             return this.titles[index];
39913           };
39914
39915           $scope.rate = function(value) {
39916             if (!$scope.readonly && value >= 0 && value <= $scope.range.length) {
39917               var newViewValue = self.enableReset && ngModelCtrl.$viewValue === value ? 0 : value;
39918               ngModelCtrl.$setViewValue(newViewValue);
39919               ngModelCtrl.$render();
39920             }
39921           };
39922
39923           $scope.enter = function(value) {
39924             if (!$scope.readonly) {
39925               $scope.value = value;
39926             }
39927             $scope.onHover({value: value});
39928           };
39929
39930           $scope.reset = function() {
39931             $scope.value = ngModelCtrl.$viewValue;
39932             $scope.onLeave();
39933           };
39934
39935           $scope.onKeydown = function(evt) {
39936             if (/(37|38|39|40)/.test(evt.which)) {
39937               evt.preventDefault();
39938               evt.stopPropagation();
39939               $scope.rate($scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1));
39940             }
39941           };
39942
39943           this.render = function() {
39944             $scope.value = ngModelCtrl.$viewValue;
39945             $scope.title = self.getTitle($scope.value - 1);
39946           };
39947         }])
39948
39949         .directive('uibRating', function() {
39950           return {
39951             require: ['uibRating', 'ngModel'],
39952             scope: {
39953               readonly: '=?readOnly',
39954               onHover: '&',
39955               onLeave: '&'
39956             },
39957             controller: 'UibRatingController',
39958             templateUrl: 'uib/template/rating/rating.html',
39959             replace: true,
39960             link: function(scope, element, attrs, ctrls) {
39961               var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
39962               ratingCtrl.init(ngModelCtrl);
39963             }
39964           };
39965         });
39966
39967         angular.module('ui.bootstrap.tabs', [])
39968
39969         .controller('UibTabsetController', ['$scope', function ($scope) {
39970           var ctrl = this,
39971             oldIndex;
39972           ctrl.tabs = [];
39973
39974           ctrl.select = function(index, evt) {
39975             if (!destroyed) {
39976               var previousIndex = findTabIndex(oldIndex);
39977               var previousSelected = ctrl.tabs[previousIndex];
39978               if (previousSelected) {
39979                 previousSelected.tab.onDeselect({
39980                   $event: evt,
39981                   $selectedIndex: index
39982                 });
39983                 if (evt && evt.isDefaultPrevented()) {
39984                   return;
39985                 }
39986                 previousSelected.tab.active = false;
39987               }
39988
39989               var selected = ctrl.tabs[index];
39990               if (selected) {
39991                 selected.tab.onSelect({
39992                   $event: evt
39993                 });
39994                 selected.tab.active = true;
39995                 ctrl.active = selected.index;
39996                 oldIndex = selected.index;
39997               } else if (!selected && angular.isDefined(oldIndex)) {
39998                 ctrl.active = null;
39999                 oldIndex = null;
40000               }
40001             }
40002           };
40003
40004           ctrl.addTab = function addTab(tab) {
40005             ctrl.tabs.push({
40006               tab: tab,
40007               index: tab.index
40008             });
40009             ctrl.tabs.sort(function(t1, t2) {
40010               if (t1.index > t2.index) {
40011                 return 1;
40012               }
40013
40014               if (t1.index < t2.index) {
40015                 return -1;
40016               }
40017
40018               return 0;
40019             });
40020
40021             if (tab.index === ctrl.active || !angular.isDefined(ctrl.active) && ctrl.tabs.length === 1) {
40022               var newActiveIndex = findTabIndex(tab.index);
40023               ctrl.select(newActiveIndex);
40024             }
40025           };
40026
40027           ctrl.removeTab = function removeTab(tab) {
40028             var index;
40029             for (var i = 0; i < ctrl.tabs.length; i++) {
40030               if (ctrl.tabs[i].tab === tab) {
40031                 index = i;
40032                 break;
40033               }
40034             }
40035
40036             if (ctrl.tabs[index].index === ctrl.active) {
40037               var newActiveTabIndex = index === ctrl.tabs.length - 1 ?
40038                 index - 1 : index + 1 % ctrl.tabs.length;
40039               ctrl.select(newActiveTabIndex);
40040             }
40041
40042             ctrl.tabs.splice(index, 1);
40043           };
40044
40045           $scope.$watch('tabset.active', function(val) {
40046             if (angular.isDefined(val) && val !== oldIndex) {
40047               ctrl.select(findTabIndex(val));
40048             }
40049           });
40050
40051           var destroyed;
40052           $scope.$on('$destroy', function() {
40053             destroyed = true;
40054           });
40055
40056           function findTabIndex(index) {
40057             for (var i = 0; i < ctrl.tabs.length; i++) {
40058               if (ctrl.tabs[i].index === index) {
40059                 return i;
40060               }
40061             }
40062           }
40063         }])
40064
40065         .directive('uibTabset', function() {
40066           return {
40067             transclude: true,
40068             replace: true,
40069             scope: {},
40070             bindToController: {
40071               active: '=?',
40072               type: '@'
40073             },
40074             controller: 'UibTabsetController',
40075             controllerAs: 'tabset',
40076             templateUrl: function(element, attrs) {
40077               return attrs.templateUrl || 'uib/template/tabs/tabset.html';
40078             },
40079             link: function(scope, element, attrs) {
40080               scope.vertical = angular.isDefined(attrs.vertical) ?
40081                 scope.$parent.$eval(attrs.vertical) : false;
40082               scope.justified = angular.isDefined(attrs.justified) ?
40083                 scope.$parent.$eval(attrs.justified) : false;
40084             }
40085           };
40086         })
40087
40088         .directive('uibTab', ['$parse', function($parse) {
40089           return {
40090             require: '^uibTabset',
40091             replace: true,
40092             templateUrl: function(element, attrs) {
40093               return attrs.templateUrl || 'uib/template/tabs/tab.html';
40094             },
40095             transclude: true,
40096             scope: {
40097               heading: '@',
40098               index: '=?',
40099               classes: '@?',
40100               onSelect: '&select', //This callback is called in contentHeadingTransclude
40101                                   //once it inserts the tab's content into the dom
40102               onDeselect: '&deselect'
40103             },
40104             controller: function() {
40105               //Empty controller so other directives can require being 'under' a tab
40106             },
40107             controllerAs: 'tab',
40108             link: function(scope, elm, attrs, tabsetCtrl, transclude) {
40109               scope.disabled = false;
40110               if (attrs.disable) {
40111                 scope.$parent.$watch($parse(attrs.disable), function(value) {
40112                   scope.disabled = !! value;
40113                 });
40114               }
40115
40116               if (angular.isUndefined(attrs.index)) {
40117                 if (tabsetCtrl.tabs && tabsetCtrl.tabs.length) {
40118                   scope.index = Math.max.apply(null, tabsetCtrl.tabs.map(function(t) { return t.index; })) + 1;
40119                 } else {
40120                   scope.index = 0;
40121                 }
40122               }
40123
40124               if (angular.isUndefined(attrs.classes)) {
40125                 scope.classes = '';
40126               }
40127
40128               scope.select = function(evt) {
40129                 if (!scope.disabled) {
40130                   var index;
40131                   for (var i = 0; i < tabsetCtrl.tabs.length; i++) {
40132                     if (tabsetCtrl.tabs[i].tab === scope) {
40133                       index = i;
40134                       break;
40135                     }
40136                   }
40137
40138                   tabsetCtrl.select(index, evt);
40139                 }
40140               };
40141
40142               tabsetCtrl.addTab(scope);
40143               scope.$on('$destroy', function() {
40144                 tabsetCtrl.removeTab(scope);
40145               });
40146
40147               //We need to transclude later, once the content container is ready.
40148               //when this link happens, we're inside a tab heading.
40149               scope.$transcludeFn = transclude;
40150             }
40151           };
40152         }])
40153
40154         .directive('uibTabHeadingTransclude', function() {
40155           return {
40156             restrict: 'A',
40157             require: '^uibTab',
40158             link: function(scope, elm) {
40159               scope.$watch('headingElement', function updateHeadingElement(heading) {
40160                 if (heading) {
40161                   elm.html('');
40162                   elm.append(heading);
40163                 }
40164               });
40165             }
40166           };
40167         })
40168
40169         .directive('uibTabContentTransclude', function() {
40170           return {
40171             restrict: 'A',
40172             require: '^uibTabset',
40173             link: function(scope, elm, attrs) {
40174               var tab = scope.$eval(attrs.uibTabContentTransclude).tab;
40175
40176               //Now our tab is ready to be transcluded: both the tab heading area
40177               //and the tab content area are loaded.  Transclude 'em both.
40178               tab.$transcludeFn(tab.$parent, function(contents) {
40179                 angular.forEach(contents, function(node) {
40180                   if (isTabHeading(node)) {
40181                     //Let tabHeadingTransclude know.
40182                     tab.headingElement = node;
40183                   } else {
40184                     elm.append(node);
40185                   }
40186                 });
40187               });
40188             }
40189           };
40190
40191           function isTabHeading(node) {
40192             return node.tagName && (
40193               node.hasAttribute('uib-tab-heading') ||
40194               node.hasAttribute('data-uib-tab-heading') ||
40195               node.hasAttribute('x-uib-tab-heading') ||
40196               node.tagName.toLowerCase() === 'uib-tab-heading' ||
40197               node.tagName.toLowerCase() === 'data-uib-tab-heading' ||
40198               node.tagName.toLowerCase() === 'x-uib-tab-heading' ||
40199               node.tagName.toLowerCase() === 'uib:tab-heading'
40200             );
40201           }
40202         });
40203
40204         angular.module('ui.bootstrap.timepicker', [])
40205
40206         .constant('uibTimepickerConfig', {
40207           hourStep: 1,
40208           minuteStep: 1,
40209           secondStep: 1,
40210           showMeridian: true,
40211           showSeconds: false,
40212           meridians: null,
40213           readonlyInput: false,
40214           mousewheel: true,
40215           arrowkeys: true,
40216           showSpinners: true,
40217           templateUrl: 'uib/template/timepicker/timepicker.html'
40218         })
40219
40220         .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) {
40221           var selected = new Date(),
40222             watchers = [],
40223             ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
40224             meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS,
40225             padHours = angular.isDefined($attrs.padHours) ? $scope.$parent.$eval($attrs.padHours) : true;
40226
40227           $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0;
40228           $element.removeAttr('tabindex');
40229
40230           this.init = function(ngModelCtrl_, inputs) {
40231             ngModelCtrl = ngModelCtrl_;
40232             ngModelCtrl.$render = this.render;
40233
40234             ngModelCtrl.$formatters.unshift(function(modelValue) {
40235               return modelValue ? new Date(modelValue) : null;
40236             });
40237
40238             var hoursInputEl = inputs.eq(0),
40239                 minutesInputEl = inputs.eq(1),
40240                 secondsInputEl = inputs.eq(2);
40241
40242             var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
40243
40244             if (mousewheel) {
40245               this.setupMousewheelEvents(hoursInputEl, minutesInputEl, secondsInputEl);
40246             }
40247
40248             var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys;
40249             if (arrowkeys) {
40250               this.setupArrowkeyEvents(hoursInputEl, minutesInputEl, secondsInputEl);
40251             }
40252
40253             $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
40254             this.setupInputEvents(hoursInputEl, minutesInputEl, secondsInputEl);
40255           };
40256
40257           var hourStep = timepickerConfig.hourStep;
40258           if ($attrs.hourStep) {
40259             watchers.push($scope.$parent.$watch($parse($attrs.hourStep), function(value) {
40260               hourStep = +value;
40261             }));
40262           }
40263
40264           var minuteStep = timepickerConfig.minuteStep;
40265           if ($attrs.minuteStep) {
40266             watchers.push($scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
40267               minuteStep = +value;
40268             }));
40269           }
40270
40271           var min;
40272           watchers.push($scope.$parent.$watch($parse($attrs.min), function(value) {
40273             var dt = new Date(value);
40274             min = isNaN(dt) ? undefined : dt;
40275           }));
40276
40277           var max;
40278           watchers.push($scope.$parent.$watch($parse($attrs.max), function(value) {
40279             var dt = new Date(value);
40280             max = isNaN(dt) ? undefined : dt;
40281           }));
40282
40283           var disabled = false;
40284           if ($attrs.ngDisabled) {
40285             watchers.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(value) {
40286               disabled = value;
40287             }));
40288           }
40289
40290           $scope.noIncrementHours = function() {
40291             var incrementedSelected = addMinutes(selected, hourStep * 60);
40292             return disabled || incrementedSelected > max ||
40293               incrementedSelected < selected && incrementedSelected < min;
40294           };
40295
40296           $scope.noDecrementHours = function() {
40297             var decrementedSelected = addMinutes(selected, -hourStep * 60);
40298             return disabled || decrementedSelected < min ||
40299               decrementedSelected > selected && decrementedSelected > max;
40300           };
40301
40302           $scope.noIncrementMinutes = function() {
40303             var incrementedSelected = addMinutes(selected, minuteStep);
40304             return disabled || incrementedSelected > max ||
40305               incrementedSelected < selected && incrementedSelected < min;
40306           };
40307
40308           $scope.noDecrementMinutes = function() {
40309             var decrementedSelected = addMinutes(selected, -minuteStep);
40310             return disabled || decrementedSelected < min ||
40311               decrementedSelected > selected && decrementedSelected > max;
40312           };
40313
40314           $scope.noIncrementSeconds = function() {
40315             var incrementedSelected = addSeconds(selected, secondStep);
40316             return disabled || incrementedSelected > max ||
40317               incrementedSelected < selected && incrementedSelected < min;
40318           };
40319
40320           $scope.noDecrementSeconds = function() {
40321             var decrementedSelected = addSeconds(selected, -secondStep);
40322             return disabled || decrementedSelected < min ||
40323               decrementedSelected > selected && decrementedSelected > max;
40324           };
40325
40326           $scope.noToggleMeridian = function() {
40327             if (selected.getHours() < 12) {
40328               return disabled || addMinutes(selected, 12 * 60) > max;
40329             }
40330
40331             return disabled || addMinutes(selected, -12 * 60) < min;
40332           };
40333
40334           var secondStep = timepickerConfig.secondStep;
40335           if ($attrs.secondStep) {
40336             watchers.push($scope.$parent.$watch($parse($attrs.secondStep), function(value) {
40337               secondStep = +value;
40338             }));
40339           }
40340
40341           $scope.showSeconds = timepickerConfig.showSeconds;
40342           if ($attrs.showSeconds) {
40343             watchers.push($scope.$parent.$watch($parse($attrs.showSeconds), function(value) {
40344               $scope.showSeconds = !!value;
40345             }));
40346           }
40347
40348           // 12H / 24H mode
40349           $scope.showMeridian = timepickerConfig.showMeridian;
40350           if ($attrs.showMeridian) {
40351             watchers.push($scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
40352               $scope.showMeridian = !!value;
40353
40354               if (ngModelCtrl.$error.time) {
40355                 // Evaluate from template
40356                 var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
40357                 if (angular.isDefined(hours) && angular.isDefined(minutes)) {
40358                   selected.setHours(hours);
40359                   refresh();
40360                 }
40361               } else {
40362                 updateTemplate();
40363               }
40364             }));
40365           }
40366
40367           // Get $scope.hours in 24H mode if valid
40368           function getHoursFromTemplate() {
40369             var hours = +$scope.hours;
40370             var valid = $scope.showMeridian ? hours > 0 && hours < 13 :
40371               hours >= 0 && hours < 24;
40372             if (!valid || $scope.hours === '') {
40373               return undefined;
40374             }
40375
40376             if ($scope.showMeridian) {
40377               if (hours === 12) {
40378                 hours = 0;
40379               }
40380               if ($scope.meridian === meridians[1]) {
40381                 hours = hours + 12;
40382               }
40383             }
40384             return hours;
40385           }
40386
40387           function getMinutesFromTemplate() {
40388             var minutes = +$scope.minutes;
40389             var valid = minutes >= 0 && minutes < 60;
40390             if (!valid || $scope.minutes === '') {
40391               return undefined;
40392             }
40393             return minutes;
40394           }
40395
40396           function getSecondsFromTemplate() {
40397             var seconds = +$scope.seconds;
40398             return seconds >= 0 && seconds < 60 ? seconds : undefined;
40399           }
40400
40401           function pad(value, noPad) {
40402             if (value === null) {
40403               return '';
40404             }
40405
40406             return angular.isDefined(value) && value.toString().length < 2 && !noPad ?
40407               '0' + value : value.toString();
40408           }
40409
40410           // Respond on mousewheel spin
40411           this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
40412             var isScrollingUp = function(e) {
40413               if (e.originalEvent) {
40414                 e = e.originalEvent;
40415               }
40416               //pick correct delta variable depending on event
40417               var delta = e.wheelDelta ? e.wheelDelta : -e.deltaY;
40418               return e.detail || delta > 0;
40419             };
40420
40421             hoursInputEl.bind('mousewheel wheel', function(e) {
40422               if (!disabled) {
40423                 $scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours());
40424               }
40425               e.preventDefault();
40426             });
40427
40428             minutesInputEl.bind('mousewheel wheel', function(e) {
40429               if (!disabled) {
40430                 $scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes());
40431               }
40432               e.preventDefault();
40433             });
40434
40435              secondsInputEl.bind('mousewheel wheel', function(e) {
40436               if (!disabled) {
40437                 $scope.$apply(isScrollingUp(e) ? $scope.incrementSeconds() : $scope.decrementSeconds());
40438               }
40439               e.preventDefault();
40440             });
40441           };
40442
40443           // Respond on up/down arrowkeys
40444           this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
40445             hoursInputEl.bind('keydown', function(e) {
40446               if (!disabled) {
40447                 if (e.which === 38) { // up
40448                   e.preventDefault();
40449                   $scope.incrementHours();
40450                   $scope.$apply();
40451                 } else if (e.which === 40) { // down
40452                   e.preventDefault();
40453                   $scope.decrementHours();
40454                   $scope.$apply();
40455                 }
40456               }
40457             });
40458
40459             minutesInputEl.bind('keydown', function(e) {
40460               if (!disabled) {
40461                 if (e.which === 38) { // up
40462                   e.preventDefault();
40463                   $scope.incrementMinutes();
40464                   $scope.$apply();
40465                 } else if (e.which === 40) { // down
40466                   e.preventDefault();
40467                   $scope.decrementMinutes();
40468                   $scope.$apply();
40469                 }
40470               }
40471             });
40472
40473             secondsInputEl.bind('keydown', function(e) {
40474               if (!disabled) {
40475                 if (e.which === 38) { // up
40476                   e.preventDefault();
40477                   $scope.incrementSeconds();
40478                   $scope.$apply();
40479                 } else if (e.which === 40) { // down
40480                   e.preventDefault();
40481                   $scope.decrementSeconds();
40482                   $scope.$apply();
40483                 }
40484               }
40485             });
40486           };
40487
40488           this.setupInputEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) {
40489             if ($scope.readonlyInput) {
40490               $scope.updateHours = angular.noop;
40491               $scope.updateMinutes = angular.noop;
40492               $scope.updateSeconds = angular.noop;
40493               return;
40494             }
40495
40496             var invalidate = function(invalidHours, invalidMinutes, invalidSeconds) {
40497               ngModelCtrl.$setViewValue(null);
40498               ngModelCtrl.$setValidity('time', false);
40499               if (angular.isDefined(invalidHours)) {
40500                 $scope.invalidHours = invalidHours;
40501               }
40502
40503               if (angular.isDefined(invalidMinutes)) {
40504                 $scope.invalidMinutes = invalidMinutes;
40505               }
40506
40507               if (angular.isDefined(invalidSeconds)) {
40508                 $scope.invalidSeconds = invalidSeconds;
40509               }
40510             };
40511
40512             $scope.updateHours = function() {
40513               var hours = getHoursFromTemplate(),
40514                 minutes = getMinutesFromTemplate();
40515
40516               ngModelCtrl.$setDirty();
40517
40518               if (angular.isDefined(hours) && angular.isDefined(minutes)) {
40519                 selected.setHours(hours);
40520                 selected.setMinutes(minutes);
40521                 if (selected < min || selected > max) {
40522                   invalidate(true);
40523                 } else {
40524                   refresh('h');
40525                 }
40526               } else {
40527                 invalidate(true);
40528               }
40529             };
40530
40531             hoursInputEl.bind('blur', function(e) {
40532               ngModelCtrl.$setTouched();
40533               if (modelIsEmpty()) {
40534                 makeValid();
40535               } else if ($scope.hours === null || $scope.hours === '') {
40536                 invalidate(true);
40537               } else if (!$scope.invalidHours && $scope.hours < 10) {
40538                 $scope.$apply(function() {
40539                   $scope.hours = pad($scope.hours, !padHours);
40540                 });
40541               }
40542             });
40543
40544             $scope.updateMinutes = function() {
40545               var minutes = getMinutesFromTemplate(),
40546                 hours = getHoursFromTemplate();
40547
40548               ngModelCtrl.$setDirty();
40549
40550               if (angular.isDefined(minutes) && angular.isDefined(hours)) {
40551                 selected.setHours(hours);
40552                 selected.setMinutes(minutes);
40553                 if (selected < min || selected > max) {
40554                   invalidate(undefined, true);
40555                 } else {
40556                   refresh('m');
40557                 }
40558               } else {
40559                 invalidate(undefined, true);
40560               }
40561             };
40562
40563             minutesInputEl.bind('blur', function(e) {
40564               ngModelCtrl.$setTouched();
40565               if (modelIsEmpty()) {
40566                 makeValid();
40567               } else if ($scope.minutes === null) {
40568                 invalidate(undefined, true);
40569               } else if (!$scope.invalidMinutes && $scope.minutes < 10) {
40570                 $scope.$apply(function() {
40571                   $scope.minutes = pad($scope.minutes);
40572                 });
40573               }
40574             });
40575
40576             $scope.updateSeconds = function() {
40577               var seconds = getSecondsFromTemplate();
40578
40579               ngModelCtrl.$setDirty();
40580
40581               if (angular.isDefined(seconds)) {
40582                 selected.setSeconds(seconds);
40583                 refresh('s');
40584               } else {
40585                 invalidate(undefined, undefined, true);
40586               }
40587             };
40588
40589             secondsInputEl.bind('blur', function(e) {
40590               if (modelIsEmpty()) {
40591                 makeValid();
40592               } else if (!$scope.invalidSeconds && $scope.seconds < 10) {
40593                 $scope.$apply( function() {
40594                   $scope.seconds = pad($scope.seconds);
40595                 });
40596               }
40597             });
40598
40599           };
40600
40601           this.render = function() {
40602             var date = ngModelCtrl.$viewValue;
40603
40604             if (isNaN(date)) {
40605               ngModelCtrl.$setValidity('time', false);
40606               $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.');
40607             } else {
40608               if (date) {
40609                 selected = date;
40610               }
40611
40612               if (selected < min || selected > max) {
40613                 ngModelCtrl.$setValidity('time', false);
40614                 $scope.invalidHours = true;
40615                 $scope.invalidMinutes = true;
40616               } else {
40617                 makeValid();
40618               }
40619               updateTemplate();
40620             }
40621           };
40622
40623           // Call internally when we know that model is valid.
40624           function refresh(keyboardChange) {
40625             makeValid();
40626             ngModelCtrl.$setViewValue(new Date(selected));
40627             updateTemplate(keyboardChange);
40628           }
40629
40630           function makeValid() {
40631             ngModelCtrl.$setValidity('time', true);
40632             $scope.invalidHours = false;
40633             $scope.invalidMinutes = false;
40634             $scope.invalidSeconds = false;
40635           }
40636
40637           function updateTemplate(keyboardChange) {
40638             if (!ngModelCtrl.$modelValue) {
40639               $scope.hours = null;
40640               $scope.minutes = null;
40641               $scope.seconds = null;
40642               $scope.meridian = meridians[0];
40643             } else {
40644               var hours = selected.getHours(),
40645                 minutes = selected.getMinutes(),
40646                 seconds = selected.getSeconds();
40647
40648               if ($scope.showMeridian) {
40649                 hours = hours === 0 || hours === 12 ? 12 : hours % 12; // Convert 24 to 12 hour system
40650               }
40651
40652               $scope.hours = keyboardChange === 'h' ? hours : pad(hours, !padHours);
40653               if (keyboardChange !== 'm') {
40654                 $scope.minutes = pad(minutes);
40655               }
40656               $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
40657
40658               if (keyboardChange !== 's') {
40659                 $scope.seconds = pad(seconds);
40660               }
40661               $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
40662             }
40663           }
40664
40665           function addSecondsToSelected(seconds) {
40666             selected = addSeconds(selected, seconds);
40667             refresh();
40668           }
40669
40670           function addMinutes(selected, minutes) {
40671             return addSeconds(selected, minutes*60);
40672           }
40673
40674           function addSeconds(date, seconds) {
40675             var dt = new Date(date.getTime() + seconds * 1000);
40676             var newDate = new Date(date);
40677             newDate.setHours(dt.getHours(), dt.getMinutes(), dt.getSeconds());
40678             return newDate;
40679           }
40680
40681           function modelIsEmpty() {
40682             return ($scope.hours === null || $scope.hours === '') &&
40683               ($scope.minutes === null || $scope.minutes === '') &&
40684               (!$scope.showSeconds || $scope.showSeconds && ($scope.seconds === null || $scope.seconds === ''));
40685           }
40686
40687           $scope.showSpinners = angular.isDefined($attrs.showSpinners) ?
40688             $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners;
40689
40690           $scope.incrementHours = function() {
40691             if (!$scope.noIncrementHours()) {
40692               addSecondsToSelected(hourStep * 60 * 60);
40693             }
40694           };
40695
40696           $scope.decrementHours = function() {
40697             if (!$scope.noDecrementHours()) {
40698               addSecondsToSelected(-hourStep * 60 * 60);
40699             }
40700           };
40701
40702           $scope.incrementMinutes = function() {
40703             if (!$scope.noIncrementMinutes()) {
40704               addSecondsToSelected(minuteStep * 60);
40705             }
40706           };
40707
40708           $scope.decrementMinutes = function() {
40709             if (!$scope.noDecrementMinutes()) {
40710               addSecondsToSelected(-minuteStep * 60);
40711             }
40712           };
40713
40714           $scope.incrementSeconds = function() {
40715             if (!$scope.noIncrementSeconds()) {
40716               addSecondsToSelected(secondStep);
40717             }
40718           };
40719
40720           $scope.decrementSeconds = function() {
40721             if (!$scope.noDecrementSeconds()) {
40722               addSecondsToSelected(-secondStep);
40723             }
40724           };
40725
40726           $scope.toggleMeridian = function() {
40727             var minutes = getMinutesFromTemplate(),
40728                 hours = getHoursFromTemplate();
40729
40730             if (!$scope.noToggleMeridian()) {
40731               if (angular.isDefined(minutes) && angular.isDefined(hours)) {
40732                 addSecondsToSelected(12 * 60 * (selected.getHours() < 12 ? 60 : -60));
40733               } else {
40734                 $scope.meridian = $scope.meridian === meridians[0] ? meridians[1] : meridians[0];
40735               }
40736             }
40737           };
40738
40739           $scope.blur = function() {
40740             ngModelCtrl.$setTouched();
40741           };
40742
40743           $scope.$on('$destroy', function() {
40744             while (watchers.length) {
40745               watchers.shift()();
40746             }
40747           });
40748         }])
40749
40750         .directive('uibTimepicker', ['uibTimepickerConfig', function(uibTimepickerConfig) {
40751           return {
40752             require: ['uibTimepicker', '?^ngModel'],
40753             controller: 'UibTimepickerController',
40754             controllerAs: 'timepicker',
40755             replace: true,
40756             scope: {},
40757             templateUrl: function(element, attrs) {
40758               return attrs.templateUrl || uibTimepickerConfig.templateUrl;
40759             },
40760             link: function(scope, element, attrs, ctrls) {
40761               var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
40762
40763               if (ngModelCtrl) {
40764                 timepickerCtrl.init(ngModelCtrl, element.find('input'));
40765               }
40766             }
40767           };
40768         }]);
40769
40770         angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap.position'])
40771
40772         /**
40773          * A helper service that can parse typeahead's syntax (string provided by users)
40774          * Extracted to a separate service for ease of unit testing
40775          */
40776           .factory('uibTypeaheadParser', ['$parse', function($parse) {
40777             //                      00000111000000000000022200000000000000003333333333333330000000000044000
40778             var TYPEAHEAD_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;
40779             return {
40780               parse: function(input) {
40781                 var match = input.match(TYPEAHEAD_REGEXP);
40782                 if (!match) {
40783                   throw new Error(
40784                     'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
40785                       ' but got "' + input + '".');
40786                 }
40787
40788                 return {
40789                   itemName: match[3],
40790                   source: $parse(match[4]),
40791                   viewMapper: $parse(match[2] || match[1]),
40792                   modelMapper: $parse(match[1])
40793                 };
40794               }
40795             };
40796           }])
40797
40798           .controller('UibTypeaheadController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$$debounce', '$uibPosition', 'uibTypeaheadParser',
40799             function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) {
40800             var HOT_KEYS = [9, 13, 27, 38, 40];
40801             var eventDebounceTime = 200;
40802             var modelCtrl, ngModelOptions;
40803             //SUPPORTED ATTRIBUTES (OPTIONS)
40804
40805             //minimal no of characters that needs to be entered before typeahead kicks-in
40806             var minLength = originalScope.$eval(attrs.typeaheadMinLength);
40807             if (!minLength && minLength !== 0) {
40808               minLength = 1;
40809             }
40810
40811             originalScope.$watch(attrs.typeaheadMinLength, function (newVal) {
40812                 minLength = !newVal && newVal !== 0 ? 1 : newVal;
40813             });
40814
40815             //minimal wait time after last character typed before typeahead kicks-in
40816             var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
40817
40818             //should it restrict model values to the ones selected from the popup only?
40819             var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
40820             originalScope.$watch(attrs.typeaheadEditable, function (newVal) {
40821               isEditable = newVal !== false;
40822             });
40823
40824             //binding to a variable that indicates if matches are being retrieved asynchronously
40825             var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
40826
40827             //a function to determine if an event should cause selection
40828             var isSelectEvent = attrs.typeaheadShouldSelect ? $parse(attrs.typeaheadShouldSelect) : function(scope, vals) {
40829               var evt = vals.$event;
40830               return evt.which === 13 || evt.which === 9;
40831             };
40832
40833             //a callback executed when a match is selected
40834             var onSelectCallback = $parse(attrs.typeaheadOnSelect);
40835
40836             //should it select highlighted popup value when losing focus?
40837             var isSelectOnBlur = angular.isDefined(attrs.typeaheadSelectOnBlur) ? originalScope.$eval(attrs.typeaheadSelectOnBlur) : false;
40838
40839             //binding to a variable that indicates if there were no results after the query is completed
40840             var isNoResultsSetter = $parse(attrs.typeaheadNoResults).assign || angular.noop;
40841
40842             var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
40843
40844             var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
40845
40846             var appendTo = attrs.typeaheadAppendTo ?
40847               originalScope.$eval(attrs.typeaheadAppendTo) : null;
40848
40849             var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;
40850
40851             //If input matches an item of the list exactly, select it automatically
40852             var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
40853
40854             //binding to a variable that indicates if dropdown is open
40855             var isOpenSetter = $parse(attrs.typeaheadIsOpen).assign || angular.noop;
40856
40857             var showHint = originalScope.$eval(attrs.typeaheadShowHint) || false;
40858
40859             //INTERNAL VARIABLES
40860
40861             //model setter executed upon match selection
40862             var parsedModel = $parse(attrs.ngModel);
40863             var invokeModelSetter = $parse(attrs.ngModel + '($$$p)');
40864             var $setModelValue = function(scope, newValue) {
40865               if (angular.isFunction(parsedModel(originalScope)) &&
40866                 ngModelOptions && ngModelOptions.$options && ngModelOptions.$options.getterSetter) {
40867                 return invokeModelSetter(scope, {$$$p: newValue});
40868               }
40869
40870               return parsedModel.assign(scope, newValue);
40871             };
40872
40873             //expressions used by typeahead
40874             var parserResult = typeaheadParser.parse(attrs.uibTypeahead);
40875
40876             var hasFocus;
40877
40878             //Used to avoid bug in iOS webview where iOS keyboard does not fire
40879             //mousedown & mouseup events
40880             //Issue #3699
40881             var selected;
40882
40883             //create a child scope for the typeahead directive so we are not polluting original scope
40884             //with typeahead-specific data (matches, query etc.)
40885             var scope = originalScope.$new();
40886             var offDestroy = originalScope.$on('$destroy', function() {
40887               scope.$destroy();
40888             });
40889             scope.$on('$destroy', offDestroy);
40890
40891             // WAI-ARIA
40892             var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
40893             element.attr({
40894               'aria-autocomplete': 'list',
40895               'aria-expanded': false,
40896               'aria-owns': popupId
40897             });
40898
40899             var inputsContainer, hintInputElem;
40900             //add read-only input to show hint
40901             if (showHint) {
40902               inputsContainer = angular.element('<div></div>');
40903               inputsContainer.css('position', 'relative');
40904               element.after(inputsContainer);
40905               hintInputElem = element.clone();
40906               hintInputElem.attr('placeholder', '');
40907               hintInputElem.attr('tabindex', '-1');
40908               hintInputElem.val('');
40909               hintInputElem.css({
40910                 'position': 'absolute',
40911                 'top': '0px',
40912                 'left': '0px',
40913                 'border-color': 'transparent',
40914                 'box-shadow': 'none',
40915                 'opacity': 1,
40916                 'background': 'none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255)',
40917                 'color': '#999'
40918               });
40919               element.css({
40920                 'position': 'relative',
40921                 'vertical-align': 'top',
40922                 'background-color': 'transparent'
40923               });
40924               inputsContainer.append(hintInputElem);
40925               hintInputElem.after(element);
40926             }
40927
40928             //pop-up element used to display matches
40929             var popUpEl = angular.element('<div uib-typeahead-popup></div>');
40930             popUpEl.attr({
40931               id: popupId,
40932               matches: 'matches',
40933               active: 'activeIdx',
40934               select: 'select(activeIdx, evt)',
40935               'move-in-progress': 'moveInProgress',
40936               query: 'query',
40937               position: 'position',
40938               'assign-is-open': 'assignIsOpen(isOpen)',
40939               debounce: 'debounceUpdate'
40940             });
40941             //custom item template
40942             if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
40943               popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
40944             }
40945
40946             if (angular.isDefined(attrs.typeaheadPopupTemplateUrl)) {
40947               popUpEl.attr('popup-template-url', attrs.typeaheadPopupTemplateUrl);
40948             }
40949
40950             var resetHint = function() {
40951               if (showHint) {
40952                 hintInputElem.val('');
40953               }
40954             };
40955
40956             var resetMatches = function() {
40957               scope.matches = [];
40958               scope.activeIdx = -1;
40959               element.attr('aria-expanded', false);
40960               resetHint();
40961             };
40962
40963             var getMatchId = function(index) {
40964               return popupId + '-option-' + index;
40965             };
40966
40967             // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
40968             // This attribute is added or removed automatically when the `activeIdx` changes.
40969             scope.$watch('activeIdx', function(index) {
40970               if (index < 0) {
40971                 element.removeAttr('aria-activedescendant');
40972               } else {
40973                 element.attr('aria-activedescendant', getMatchId(index));
40974               }
40975             });
40976
40977             var inputIsExactMatch = function(inputValue, index) {
40978               if (scope.matches.length > index && inputValue) {
40979                 return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
40980               }
40981
40982               return false;
40983             };
40984
40985             var getMatchesAsync = function(inputValue, evt) {
40986               var locals = {$viewValue: inputValue};
40987               isLoadingSetter(originalScope, true);
40988               isNoResultsSetter(originalScope, false);
40989               $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
40990                 //it might happen that several async queries were in progress if a user were typing fast
40991                 //but we are interested only in responses that correspond to the current view value
40992                 var onCurrentRequest = inputValue === modelCtrl.$viewValue;
40993                 if (onCurrentRequest && hasFocus) {
40994                   if (matches && matches.length > 0) {
40995                     scope.activeIdx = focusFirst ? 0 : -1;
40996                     isNoResultsSetter(originalScope, false);
40997                     scope.matches.length = 0;
40998
40999                     //transform labels
41000                     for (var i = 0; i < matches.length; i++) {
41001                       locals[parserResult.itemName] = matches[i];
41002                       scope.matches.push({
41003                         id: getMatchId(i),
41004                         label: parserResult.viewMapper(scope, locals),
41005                         model: matches[i]
41006                       });
41007                     }
41008
41009                     scope.query = inputValue;
41010                     //position pop-up with matches - we need to re-calculate its position each time we are opening a window
41011                     //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
41012                     //due to other elements being rendered
41013                     recalculatePosition();
41014
41015                     element.attr('aria-expanded', true);
41016
41017                     //Select the single remaining option if user input matches
41018                     if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)) {
41019                       if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
41020                         $$debounce(function() {
41021                           scope.select(0, evt);
41022                         }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
41023                       } else {
41024                         scope.select(0, evt);
41025                       }
41026                     }
41027
41028                     if (showHint) {
41029                       var firstLabel = scope.matches[0].label;
41030                       if (angular.isString(inputValue) &&
41031                         inputValue.length > 0 &&
41032                         firstLabel.slice(0, inputValue.length).toUpperCase() === inputValue.toUpperCase()) {
41033                         hintInputElem.val(inputValue + firstLabel.slice(inputValue.length));
41034                       } else {
41035                         hintInputElem.val('');
41036                       }
41037                     }
41038                   } else {
41039                     resetMatches();
41040                     isNoResultsSetter(originalScope, true);
41041                   }
41042                 }
41043                 if (onCurrentRequest) {
41044                   isLoadingSetter(originalScope, false);
41045                 }
41046               }, function() {
41047                 resetMatches();
41048                 isLoadingSetter(originalScope, false);
41049                 isNoResultsSetter(originalScope, true);
41050               });
41051             };
41052
41053             // bind events only if appendToBody params exist - performance feature
41054             if (appendToBody) {
41055               angular.element($window).on('resize', fireRecalculating);
41056               $document.find('body').on('scroll', fireRecalculating);
41057             }
41058
41059             // Declare the debounced function outside recalculating for
41060             // proper debouncing
41061             var debouncedRecalculate = $$debounce(function() {
41062               // if popup is visible
41063               if (scope.matches.length) {
41064                 recalculatePosition();
41065               }
41066
41067               scope.moveInProgress = false;
41068             }, eventDebounceTime);
41069
41070             // Default progress type
41071             scope.moveInProgress = false;
41072
41073             function fireRecalculating() {
41074               if (!scope.moveInProgress) {
41075                 scope.moveInProgress = true;
41076                 scope.$digest();
41077               }
41078
41079               debouncedRecalculate();
41080             }
41081
41082             // recalculate actual position and set new values to scope
41083             // after digest loop is popup in right position
41084             function recalculatePosition() {
41085               scope.position = appendToBody ? $position.offset(element) : $position.position(element);
41086               scope.position.top += element.prop('offsetHeight');
41087             }
41088
41089             //we need to propagate user's query so we can higlight matches
41090             scope.query = undefined;
41091
41092             //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
41093             var timeoutPromise;
41094
41095             var scheduleSearchWithTimeout = function(inputValue) {
41096               timeoutPromise = $timeout(function() {
41097                 getMatchesAsync(inputValue);
41098               }, waitTime);
41099             };
41100
41101             var cancelPreviousTimeout = function() {
41102               if (timeoutPromise) {
41103                 $timeout.cancel(timeoutPromise);
41104               }
41105             };
41106
41107             resetMatches();
41108
41109             scope.assignIsOpen = function (isOpen) {
41110               isOpenSetter(originalScope, isOpen);
41111             };
41112
41113             scope.select = function(activeIdx, evt) {
41114               //called from within the $digest() cycle
41115               var locals = {};
41116               var model, item;
41117
41118               selected = true;
41119               locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
41120               model = parserResult.modelMapper(originalScope, locals);
41121               $setModelValue(originalScope, model);
41122               modelCtrl.$setValidity('editable', true);
41123               modelCtrl.$setValidity('parse', true);
41124
41125               onSelectCallback(originalScope, {
41126                 $item: item,
41127                 $model: model,
41128                 $label: parserResult.viewMapper(originalScope, locals),
41129                 $event: evt
41130               });
41131
41132               resetMatches();
41133
41134               //return focus to the input element if a match was selected via a mouse click event
41135               // use timeout to avoid $rootScope:inprog error
41136               if (scope.$eval(attrs.typeaheadFocusOnSelect) !== false) {
41137                 $timeout(function() { element[0].focus(); }, 0, false);
41138               }
41139             };
41140
41141             //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
41142             element.on('keydown', function(evt) {
41143               //typeahead is open and an "interesting" key was pressed
41144               if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
41145                 return;
41146               }
41147
41148               var shouldSelect = isSelectEvent(originalScope, {$event: evt});
41149
41150               /**
41151                * if there's nothing selected (i.e. focusFirst) and enter or tab is hit
41152                * or
41153                * shift + tab is pressed to bring focus to the previous element
41154                * then clear the results
41155                */
41156               if (scope.activeIdx === -1 && shouldSelect || evt.which === 9 && !!evt.shiftKey) {
41157                 resetMatches();
41158                 scope.$digest();
41159                 return;
41160               }
41161
41162               evt.preventDefault();
41163               var target;
41164               switch (evt.which) {
41165                 case 27: // escape
41166                   evt.stopPropagation();
41167
41168                   resetMatches();
41169                   originalScope.$digest();
41170                   break;
41171                 case 38: // up arrow
41172                   scope.activeIdx = (scope.activeIdx > 0 ? scope.activeIdx : scope.matches.length) - 1;
41173                   scope.$digest();
41174                   target = popUpEl.find('li')[scope.activeIdx];
41175                   target.parentNode.scrollTop = target.offsetTop;
41176                   break;
41177                 case 40: // down arrow
41178                   scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
41179                   scope.$digest();
41180                   target = popUpEl.find('li')[scope.activeIdx];
41181                   target.parentNode.scrollTop = target.offsetTop;
41182                   break;
41183                 default:
41184                   if (shouldSelect) {
41185                     scope.$apply(function() {
41186                       if (angular.isNumber(scope.debounceUpdate) || angular.isObject(scope.debounceUpdate)) {
41187                         $$debounce(function() {
41188                           scope.select(scope.activeIdx, evt);
41189                         }, angular.isNumber(scope.debounceUpdate) ? scope.debounceUpdate : scope.debounceUpdate['default']);
41190                       } else {
41191                         scope.select(scope.activeIdx, evt);
41192                       }
41193                     });
41194                   }
41195               }
41196             });
41197
41198             element.bind('focus', function (evt) {
41199               hasFocus = true;
41200               if (minLength === 0 && !modelCtrl.$viewValue) {
41201                 $timeout(function() {
41202                   getMatchesAsync(modelCtrl.$viewValue, evt);
41203                 }, 0);
41204               }
41205             });
41206
41207             element.bind('blur', function(evt) {
41208               if (isSelectOnBlur && scope.matches.length && scope.activeIdx !== -1 && !selected) {
41209                 selected = true;
41210                 scope.$apply(function() {
41211                   if (angular.isObject(scope.debounceUpdate) && angular.isNumber(scope.debounceUpdate.blur)) {
41212                     $$debounce(function() {
41213                       scope.select(scope.activeIdx, evt);
41214                     }, scope.debounceUpdate.blur);
41215                   } else {
41216                     scope.select(scope.activeIdx, evt);
41217                   }
41218                 });
41219               }
41220               if (!isEditable && modelCtrl.$error.editable) {
41221                 modelCtrl.$setViewValue();
41222                 // Reset validity as we are clearing
41223                 modelCtrl.$setValidity('editable', true);
41224                 modelCtrl.$setValidity('parse', true);
41225                 element.val('');
41226               }
41227               hasFocus = false;
41228               selected = false;
41229             });
41230
41231             // Keep reference to click handler to unbind it.
41232             var dismissClickHandler = function(evt) {
41233               // Issue #3973
41234               // Firefox treats right click as a click on document
41235               if (element[0] !== evt.target && evt.which !== 3 && scope.matches.length !== 0) {
41236                 resetMatches();
41237                 if (!$rootScope.$$phase) {
41238                   originalScope.$digest();
41239                 }
41240               }
41241             };
41242
41243             $document.on('click', dismissClickHandler);
41244
41245             originalScope.$on('$destroy', function() {
41246               $document.off('click', dismissClickHandler);
41247               if (appendToBody || appendTo) {
41248                 $popup.remove();
41249               }
41250
41251               if (appendToBody) {
41252                 angular.element($window).off('resize', fireRecalculating);
41253                 $document.find('body').off('scroll', fireRecalculating);
41254               }
41255               // Prevent jQuery cache memory leak
41256               popUpEl.remove();
41257
41258               if (showHint) {
41259                   inputsContainer.remove();
41260               }
41261             });
41262
41263             var $popup = $compile(popUpEl)(scope);
41264
41265             if (appendToBody) {
41266               $document.find('body').append($popup);
41267             } else if (appendTo) {
41268               angular.element(appendTo).eq(0).append($popup);
41269             } else {
41270               element.after($popup);
41271             }
41272
41273             this.init = function(_modelCtrl, _ngModelOptions) {
41274               modelCtrl = _modelCtrl;
41275               ngModelOptions = _ngModelOptions;
41276
41277               scope.debounceUpdate = modelCtrl.$options && $parse(modelCtrl.$options.debounce)(originalScope);
41278
41279               //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
41280               //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
41281               modelCtrl.$parsers.unshift(function(inputValue) {
41282                 hasFocus = true;
41283
41284                 if (minLength === 0 || inputValue && inputValue.length >= minLength) {
41285                   if (waitTime > 0) {
41286                     cancelPreviousTimeout();
41287                     scheduleSearchWithTimeout(inputValue);
41288                   } else {
41289                     getMatchesAsync(inputValue);
41290                   }
41291                 } else {
41292                   isLoadingSetter(originalScope, false);
41293                   cancelPreviousTimeout();
41294                   resetMatches();
41295                 }
41296
41297                 if (isEditable) {
41298                   return inputValue;
41299                 }
41300
41301                 if (!inputValue) {
41302                   // Reset in case user had typed something previously.
41303                   modelCtrl.$setValidity('editable', true);
41304                   return null;
41305                 }
41306
41307                 modelCtrl.$setValidity('editable', false);
41308                 return undefined;
41309               });
41310
41311               modelCtrl.$formatters.push(function(modelValue) {
41312                 var candidateViewValue, emptyViewValue;
41313                 var locals = {};
41314
41315                 // The validity may be set to false via $parsers (see above) if
41316                 // the model is restricted to selected values. If the model
41317                 // is set manually it is considered to be valid.
41318                 if (!isEditable) {
41319                   modelCtrl.$setValidity('editable', true);
41320                 }
41321
41322                 if (inputFormatter) {
41323                   locals.$model = modelValue;
41324                   return inputFormatter(originalScope, locals);
41325                 }
41326
41327                 //it might happen that we don't have enough info to properly render input value
41328                 //we need to check for this situation and simply return model value if we can't apply custom formatting
41329                 locals[parserResult.itemName] = modelValue;
41330                 candidateViewValue = parserResult.viewMapper(originalScope, locals);
41331                 locals[parserResult.itemName] = undefined;
41332                 emptyViewValue = parserResult.viewMapper(originalScope, locals);
41333
41334                 return candidateViewValue !== emptyViewValue ? candidateViewValue : modelValue;
41335               });
41336             };
41337           }])
41338
41339           .directive('uibTypeahead', function() {
41340             return {
41341               controller: 'UibTypeaheadController',
41342               require: ['ngModel', '^?ngModelOptions', 'uibTypeahead'],
41343               link: function(originalScope, element, attrs, ctrls) {
41344                 ctrls[2].init(ctrls[0], ctrls[1]);
41345               }
41346             };
41347           })
41348
41349           .directive('uibTypeaheadPopup', ['$$debounce', function($$debounce) {
41350             return {
41351               scope: {
41352                 matches: '=',
41353                 query: '=',
41354                 active: '=',
41355                 position: '&',
41356                 moveInProgress: '=',
41357                 select: '&',
41358                 assignIsOpen: '&',
41359                 debounce: '&'
41360               },
41361               replace: true,
41362               templateUrl: function(element, attrs) {
41363                 return attrs.popupTemplateUrl || 'uib/template/typeahead/typeahead-popup.html';
41364               },
41365               link: function(scope, element, attrs) {
41366                 scope.templateUrl = attrs.templateUrl;
41367
41368                 scope.isOpen = function() {
41369                   var isDropdownOpen = scope.matches.length > 0;
41370                   scope.assignIsOpen({ isOpen: isDropdownOpen });
41371                   return isDropdownOpen;
41372                 };
41373
41374                 scope.isActive = function(matchIdx) {
41375                   return scope.active === matchIdx;
41376                 };
41377
41378                 scope.selectActive = function(matchIdx) {
41379                   scope.active = matchIdx;
41380                 };
41381
41382                 scope.selectMatch = function(activeIdx, evt) {
41383                   var debounce = scope.debounce();
41384                   if (angular.isNumber(debounce) || angular.isObject(debounce)) {
41385                     $$debounce(function() {
41386                       scope.select({activeIdx: activeIdx, evt: evt});
41387                     }, angular.isNumber(debounce) ? debounce : debounce['default']);
41388                   } else {
41389                     scope.select({activeIdx: activeIdx, evt: evt});
41390                   }
41391                 };
41392               }
41393             };
41394           }])
41395
41396           .directive('uibTypeaheadMatch', ['$templateRequest', '$compile', '$parse', function($templateRequest, $compile, $parse) {
41397             return {
41398               scope: {
41399                 index: '=',
41400                 match: '=',
41401                 query: '='
41402               },
41403               link: function(scope, element, attrs) {
41404                 var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'uib/template/typeahead/typeahead-match.html';
41405                 $templateRequest(tplUrl).then(function(tplContent) {
41406                   var tplEl = angular.element(tplContent.trim());
41407                   element.replaceWith(tplEl);
41408                   $compile(tplEl)(scope);
41409                 });
41410               }
41411             };
41412           }])
41413
41414           .filter('uibTypeaheadHighlight', ['$sce', '$injector', '$log', function($sce, $injector, $log) {
41415             var isSanitizePresent;
41416             isSanitizePresent = $injector.has('$sanitize');
41417
41418             function escapeRegexp(queryToEscape) {
41419               // Regex: capture the whole query string and replace it with the string that will be used to match
41420               // the results, for example if the capture is "a" the result will be \a
41421               return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
41422             }
41423
41424             function containsHtml(matchItem) {
41425               return /<.*>/g.test(matchItem);
41426             }
41427
41428             return function(matchItem, query) {
41429               if (!isSanitizePresent && containsHtml(matchItem)) {
41430                 $log.warn('Unsafe use of typeahead please use ngSanitize'); // Warn the user about the danger
41431               }
41432               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
41433               if (!isSanitizePresent) {
41434                 matchItem = $sce.trustAsHtml(matchItem); // If $sanitize is not present we pack the string in a $sce object for the ng-bind-html directive
41435               }
41436               return matchItem;
41437             };
41438           }]);
41439
41440         angular.module("uib/template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
41441           $templateCache.put("uib/template/accordion/accordion-group.html",
41442             "<div class=\"panel\" ng-class=\"panelClass || 'panel-default'\">\n" +
41443             "  <div role=\"tab\" id=\"{{::headingId}}\" aria-selected=\"{{isOpen}}\" class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\">\n" +
41444             "    <h4 class=\"panel-title\">\n" +
41445             "      <a role=\"button\" data-toggle=\"collapse\" href aria-expanded=\"{{isOpen}}\" aria-controls=\"{{::panelId}}\" tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" uib-accordion-transclude=\"heading\"><span uib-accordion-header ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></a>\n" +
41446             "    </h4>\n" +
41447             "  </div>\n" +
41448             "  <div id=\"{{::panelId}}\" aria-labelledby=\"{{::headingId}}\" aria-hidden=\"{{!isOpen}}\" role=\"tabpanel\" class=\"panel-collapse collapse\" uib-collapse=\"!isOpen\">\n" +
41449             "    <div class=\"panel-body\" ng-transclude></div>\n" +
41450             "  </div>\n" +
41451             "</div>\n" +
41452             "");
41453         }]);
41454
41455         angular.module("uib/template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
41456           $templateCache.put("uib/template/accordion/accordion.html",
41457             "<div role=\"tablist\" class=\"panel-group\" ng-transclude></div>");
41458         }]);
41459
41460         angular.module("uib/template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
41461           $templateCache.put("uib/template/alert/alert.html",
41462             "<div class=\"alert\" ng-class=\"['alert-' + (type || 'warning'), closeable ? 'alert-dismissible' : null]\" role=\"alert\">\n" +
41463             "    <button ng-show=\"closeable\" type=\"button\" class=\"close\" ng-click=\"close({$event: $event})\">\n" +
41464             "        <span aria-hidden=\"true\">&times;</span>\n" +
41465             "        <span class=\"sr-only\">Close</span>\n" +
41466             "    </button>\n" +
41467             "    <div ng-transclude></div>\n" +
41468             "</div>\n" +
41469             "");
41470         }]);
41471
41472         angular.module("uib/template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
41473           $templateCache.put("uib/template/carousel/carousel.html",
41474             "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\">\n" +
41475             "  <div class=\"carousel-inner\" ng-transclude></div>\n" +
41476             "  <a role=\"button\" href class=\"left carousel-control\" ng-click=\"prev()\" ng-class=\"{ disabled: isPrevDisabled() }\" ng-show=\"slides.length > 1\">\n" +
41477             "    <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-left\"></span>\n" +
41478             "    <span class=\"sr-only\">previous</span>\n" +
41479             "  </a>\n" +
41480             "  <a role=\"button\" href class=\"right carousel-control\" ng-click=\"next()\" ng-class=\"{ disabled: isNextDisabled() }\" ng-show=\"slides.length > 1\">\n" +
41481             "    <span aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-right\"></span>\n" +
41482             "    <span class=\"sr-only\">next</span>\n" +
41483             "  </a>\n" +
41484             "  <ol class=\"carousel-indicators\" ng-show=\"slides.length > 1\">\n" +
41485             "    <li ng-repeat=\"slide in slides | orderBy:indexOfSlide track by $index\" ng-class=\"{ active: isActive(slide) }\" ng-click=\"select(slide)\">\n" +
41486             "      <span class=\"sr-only\">slide {{ $index + 1 }} of {{ slides.length }}<span ng-if=\"isActive(slide)\">, currently active</span></span>\n" +
41487             "    </li>\n" +
41488             "  </ol>\n" +
41489             "</div>\n" +
41490             "");
41491         }]);
41492
41493         angular.module("uib/template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
41494           $templateCache.put("uib/template/carousel/slide.html",
41495             "<div ng-class=\"{\n" +
41496             "    'active': active\n" +
41497             "  }\" class=\"item text-center\" ng-transclude></div>\n" +
41498             "");
41499         }]);
41500
41501         angular.module("uib/template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
41502           $templateCache.put("uib/template/datepicker/datepicker.html",
41503             "<div class=\"uib-datepicker\" ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
41504             "  <uib-daypicker ng-switch-when=\"day\" tabindex=\"0\"></uib-daypicker>\n" +
41505             "  <uib-monthpicker ng-switch-when=\"month\" tabindex=\"0\"></uib-monthpicker>\n" +
41506             "  <uib-yearpicker ng-switch-when=\"year\" tabindex=\"0\"></uib-yearpicker>\n" +
41507             "</div>\n" +
41508             "");
41509         }]);
41510
41511         angular.module("uib/template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
41512           $templateCache.put("uib/template/datepicker/day.html",
41513             "<table class=\"uib-daypicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
41514             "  <thead>\n" +
41515             "    <tr>\n" +
41516             "      <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" +
41517             "      <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\"><strong>{{title}}</strong></button></th>\n" +
41518             "      <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" +
41519             "    </tr>\n" +
41520             "    <tr>\n" +
41521             "      <th ng-if=\"showWeeks\" class=\"text-center\"></th>\n" +
41522             "      <th ng-repeat=\"label in ::labels track by $index\" class=\"text-center\"><small aria-label=\"{{::label.full}}\">{{::label.abbr}}</small></th>\n" +
41523             "    </tr>\n" +
41524             "  </thead>\n" +
41525             "  <tbody>\n" +
41526             "    <tr class=\"uib-weeks\" ng-repeat=\"row in rows track by $index\">\n" +
41527             "      <td ng-if=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
41528             "      <td ng-repeat=\"dt in row\" class=\"uib-day text-center\" role=\"gridcell\"\n" +
41529             "        id=\"{{::dt.uid}}\"\n" +
41530             "        ng-class=\"::dt.customClass\">\n" +
41531             "        <button type=\"button\" class=\"btn btn-default btn-sm\"\n" +
41532             "          uib-is-class=\"\n" +
41533             "            'btn-info' for selectedDt,\n" +
41534             "            'active' for activeDt\n" +
41535             "            on dt\"\n" +
41536             "          ng-click=\"select(dt.date)\"\n" +
41537             "          ng-disabled=\"::dt.disabled\"\n" +
41538             "          tabindex=\"-1\"><span ng-class=\"::{'text-muted': dt.secondary, 'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
41539             "      </td>\n" +
41540             "    </tr>\n" +
41541             "  </tbody>\n" +
41542             "</table>\n" +
41543             "");
41544         }]);
41545
41546         angular.module("uib/template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
41547           $templateCache.put("uib/template/datepicker/month.html",
41548             "<table class=\"uib-monthpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
41549             "  <thead>\n" +
41550             "    <tr>\n" +
41551             "      <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" +
41552             "      <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\"><strong>{{title}}</strong></button></th>\n" +
41553             "      <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" +
41554             "    </tr>\n" +
41555             "  </thead>\n" +
41556             "  <tbody>\n" +
41557             "    <tr class=\"uib-months\" ng-repeat=\"row in rows track by $index\">\n" +
41558             "      <td ng-repeat=\"dt in row\" class=\"uib-month text-center\" role=\"gridcell\"\n" +
41559             "        id=\"{{::dt.uid}}\"\n" +
41560             "        ng-class=\"::dt.customClass\">\n" +
41561             "        <button type=\"button\" class=\"btn btn-default\"\n" +
41562             "          uib-is-class=\"\n" +
41563             "            'btn-info' for selectedDt,\n" +
41564             "            'active' for activeDt\n" +
41565             "            on dt\"\n" +
41566             "          ng-click=\"select(dt.date)\"\n" +
41567             "          ng-disabled=\"::dt.disabled\"\n" +
41568             "          tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
41569             "      </td>\n" +
41570             "    </tr>\n" +
41571             "  </tbody>\n" +
41572             "</table>\n" +
41573             "");
41574         }]);
41575
41576         angular.module("uib/template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
41577           $templateCache.put("uib/template/datepicker/year.html",
41578             "<table class=\"uib-yearpicker\" role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
41579             "  <thead>\n" +
41580             "    <tr>\n" +
41581             "      <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" +
41582             "      <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\"><strong>{{title}}</strong></button></th>\n" +
41583             "      <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" +
41584             "    </tr>\n" +
41585             "  </thead>\n" +
41586             "  <tbody>\n" +
41587             "    <tr class=\"uib-years\" ng-repeat=\"row in rows track by $index\">\n" +
41588             "      <td ng-repeat=\"dt in row\" class=\"uib-year text-center\" role=\"gridcell\"\n" +
41589             "        id=\"{{::dt.uid}}\"\n" +
41590             "        ng-class=\"::dt.customClass\">\n" +
41591             "        <button type=\"button\" class=\"btn btn-default\"\n" +
41592             "          uib-is-class=\"\n" +
41593             "            'btn-info' for selectedDt,\n" +
41594             "            'active' for activeDt\n" +
41595             "            on dt\"\n" +
41596             "          ng-click=\"select(dt.date)\"\n" +
41597             "          ng-disabled=\"::dt.disabled\"\n" +
41598             "          tabindex=\"-1\"><span ng-class=\"::{'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
41599             "      </td>\n" +
41600             "    </tr>\n" +
41601             "  </tbody>\n" +
41602             "</table>\n" +
41603             "");
41604         }]);
41605
41606         angular.module("uib/template/datepickerPopup/popup.html", []).run(["$templateCache", function($templateCache) {
41607           $templateCache.put("uib/template/datepickerPopup/popup.html",
41608             "<div>\n" +
41609             "  <ul class=\"uib-datepicker-popup dropdown-menu uib-position-measure\" dropdown-nested ng-if=\"isOpen\" ng-keydown=\"keydown($event)\" ng-click=\"$event.stopPropagation()\">\n" +
41610             "    <li ng-transclude></li>\n" +
41611             "    <li ng-if=\"showButtonBar\" class=\"uib-button-bar\">\n" +
41612             "      <span class=\"btn-group pull-left\">\n" +
41613             "        <button type=\"button\" class=\"btn btn-sm btn-info uib-datepicker-current\" ng-click=\"select('today', $event)\" ng-disabled=\"isDisabled('today')\">{{ getText('current') }}</button>\n" +
41614             "        <button type=\"button\" class=\"btn btn-sm btn-danger uib-clear\" ng-click=\"select(null, $event)\">{{ getText('clear') }}</button>\n" +
41615             "      </span>\n" +
41616             "      <button type=\"button\" class=\"btn btn-sm btn-success pull-right uib-close\" ng-click=\"close($event)\">{{ getText('close') }}</button>\n" +
41617             "    </li>\n" +
41618             "  </ul>\n" +
41619             "</div>\n" +
41620             "");
41621         }]);
41622
41623         angular.module("uib/template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
41624           $templateCache.put("uib/template/modal/backdrop.html",
41625             "<div class=\"modal-backdrop\"\n" +
41626             "     uib-modal-animation-class=\"fade\"\n" +
41627             "     modal-in-class=\"in\"\n" +
41628             "     ng-style=\"{'z-index': 1040 + (index && 1 || 0) + index*10}\"\n" +
41629             "></div>\n" +
41630             "");
41631         }]);
41632
41633         angular.module("uib/template/modal/window.html", []).run(["$templateCache", function($templateCache) {
41634           $templateCache.put("uib/template/modal/window.html",
41635             "<div modal-render=\"{{$isRendered}}\" tabindex=\"-1\" role=\"dialog\" class=\"modal\"\n" +
41636             "    uib-modal-animation-class=\"fade\"\n" +
41637             "    modal-in-class=\"in\"\n" +
41638             "    ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\">\n" +
41639             "    <div class=\"modal-dialog {{size ? 'modal-' + size : ''}}\"><div class=\"modal-content\" uib-modal-transclude></div></div>\n" +
41640             "</div>\n" +
41641             "");
41642         }]);
41643
41644         angular.module("uib/template/pager/pager.html", []).run(["$templateCache", function($templateCache) {
41645           $templateCache.put("uib/template/pager/pager.html",
41646             "<ul class=\"pager\">\n" +
41647             "  <li ng-class=\"{disabled: noPrevious()||ngDisabled, previous: align}\"><a href ng-click=\"selectPage(page - 1, $event)\">{{::getText('previous')}}</a></li>\n" +
41648             "  <li ng-class=\"{disabled: noNext()||ngDisabled, next: align}\"><a href ng-click=\"selectPage(page + 1, $event)\">{{::getText('next')}}</a></li>\n" +
41649             "</ul>\n" +
41650             "");
41651         }]);
41652
41653         angular.module("uib/template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
41654           $templateCache.put("uib/template/pagination/pagination.html",
41655             "<ul class=\"pagination\">\n" +
41656             "  <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noPrevious()||ngDisabled}\" class=\"pagination-first\"><a href ng-click=\"selectPage(1, $event)\">{{::getText('first')}}</a></li>\n" +
41657             "  <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" +
41658             "  <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" +
41659             "  <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" +
41660             "  <li ng-if=\"::boundaryLinks\" ng-class=\"{disabled: noNext()||ngDisabled}\" class=\"pagination-last\"><a href ng-click=\"selectPage(totalPages, $event)\">{{::getText('last')}}</a></li>\n" +
41661             "</ul>\n" +
41662             "");
41663         }]);
41664
41665         angular.module("uib/template/tooltip/tooltip-html-popup.html", []).run(["$templateCache", function($templateCache) {
41666           $templateCache.put("uib/template/tooltip/tooltip-html-popup.html",
41667             "<div class=\"tooltip\"\n" +
41668             "  tooltip-animation-class=\"fade\"\n" +
41669             "  uib-tooltip-classes\n" +
41670             "  ng-class=\"{ in: isOpen() }\">\n" +
41671             "  <div class=\"tooltip-arrow\"></div>\n" +
41672             "  <div class=\"tooltip-inner\" ng-bind-html=\"contentExp()\"></div>\n" +
41673             "</div>\n" +
41674             "");
41675         }]);
41676
41677         angular.module("uib/template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
41678           $templateCache.put("uib/template/tooltip/tooltip-popup.html",
41679             "<div class=\"tooltip\"\n" +
41680             "  tooltip-animation-class=\"fade\"\n" +
41681             "  uib-tooltip-classes\n" +
41682             "  ng-class=\"{ in: isOpen() }\">\n" +
41683             "  <div class=\"tooltip-arrow\"></div>\n" +
41684             "  <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
41685             "</div>\n" +
41686             "");
41687         }]);
41688
41689         angular.module("uib/template/tooltip/tooltip-template-popup.html", []).run(["$templateCache", function($templateCache) {
41690           $templateCache.put("uib/template/tooltip/tooltip-template-popup.html",
41691             "<div class=\"tooltip\"\n" +
41692             "  tooltip-animation-class=\"fade\"\n" +
41693             "  uib-tooltip-classes\n" +
41694             "  ng-class=\"{ in: isOpen() }\">\n" +
41695             "  <div class=\"tooltip-arrow\"></div>\n" +
41696             "  <div class=\"tooltip-inner\"\n" +
41697             "    uib-tooltip-template-transclude=\"contentExp()\"\n" +
41698             "    tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
41699             "</div>\n" +
41700             "");
41701         }]);
41702
41703         angular.module("uib/template/popover/popover-html.html", []).run(["$templateCache", function($templateCache) {
41704           $templateCache.put("uib/template/popover/popover-html.html",
41705             "<div class=\"popover\"\n" +
41706             "  tooltip-animation-class=\"fade\"\n" +
41707             "  uib-tooltip-classes\n" +
41708             "  ng-class=\"{ in: isOpen() }\">\n" +
41709             "  <div class=\"arrow\"></div>\n" +
41710             "\n" +
41711             "  <div class=\"popover-inner\">\n" +
41712             "      <h3 class=\"popover-title\" ng-bind=\"uibTitle\" ng-if=\"uibTitle\"></h3>\n" +
41713             "      <div class=\"popover-content\" ng-bind-html=\"contentExp()\"></div>\n" +
41714             "  </div>\n" +
41715             "</div>\n" +
41716             "");
41717         }]);
41718
41719         angular.module("uib/template/popover/popover-template.html", []).run(["$templateCache", function($templateCache) {
41720           $templateCache.put("uib/template/popover/popover-template.html",
41721             "<div class=\"popover\"\n" +
41722             "  tooltip-animation-class=\"fade\"\n" +
41723             "  uib-tooltip-classes\n" +
41724             "  ng-class=\"{ in: isOpen() }\">\n" +
41725             "  <div class=\"arrow\"></div>\n" +
41726             "\n" +
41727             "  <div class=\"popover-inner\">\n" +
41728             "      <h3 class=\"popover-title\" ng-bind=\"uibTitle\" ng-if=\"uibTitle\"></h3>\n" +
41729             "      <div class=\"popover-content\"\n" +
41730             "        uib-tooltip-template-transclude=\"contentExp()\"\n" +
41731             "        tooltip-template-transclude-scope=\"originScope()\"></div>\n" +
41732             "  </div>\n" +
41733             "</div>\n" +
41734             "");
41735         }]);
41736
41737         angular.module("uib/template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
41738           $templateCache.put("uib/template/popover/popover.html",
41739             "<div class=\"popover\"\n" +
41740             "  tooltip-animation-class=\"fade\"\n" +
41741             "  uib-tooltip-classes\n" +
41742             "  ng-class=\"{ in: isOpen() }\">\n" +
41743             "  <div class=\"arrow\"></div>\n" +
41744             "\n" +
41745             "  <div class=\"popover-inner\">\n" +
41746             "      <h3 class=\"popover-title\" ng-bind=\"uibTitle\" ng-if=\"uibTitle\"></h3>\n" +
41747             "      <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
41748             "  </div>\n" +
41749             "</div>\n" +
41750             "");
41751         }]);
41752
41753         angular.module("uib/template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
41754           $templateCache.put("uib/template/progressbar/bar.html",
41755             "<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" +
41756             "");
41757         }]);
41758
41759         angular.module("uib/template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
41760           $templateCache.put("uib/template/progressbar/progress.html",
41761             "<div class=\"progress\" ng-transclude aria-labelledby=\"{{::title}}\"></div>");
41762         }]);
41763
41764         angular.module("uib/template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) {
41765           $templateCache.put("uib/template/progressbar/progressbar.html",
41766             "<div class=\"progress\">\n" +
41767             "  <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" +
41768             "</div>\n" +
41769             "");
41770         }]);
41771
41772         angular.module("uib/template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
41773           $templateCache.put("uib/template/rating/rating.html",
41774             "<span ng-mouseleave=\"reset()\" ng-keydown=\"onKeydown($event)\" tabindex=\"0\" role=\"slider\" aria-valuemin=\"0\" aria-valuemax=\"{{range.length}}\" aria-valuenow=\"{{value}}\" aria-valuetext=\"{{title}}\">\n" +
41775             "    <span ng-repeat-start=\"r in range track by $index\" class=\"sr-only\">({{ $index < value ? '*' : ' ' }})</span>\n" +
41776             "    <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}}\"></i>\n" +
41777             "</span>\n" +
41778             "");
41779         }]);
41780
41781         angular.module("uib/template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
41782           $templateCache.put("uib/template/tabs/tab.html",
41783             "<li ng-class=\"[{active: active, disabled: disabled}, classes]\" class=\"uib-tab nav-item\">\n" +
41784             "  <a href ng-click=\"select($event)\" class=\"nav-link\" uib-tab-heading-transclude>{{heading}}</a>\n" +
41785             "</li>\n" +
41786             "");
41787         }]);
41788
41789         angular.module("uib/template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
41790           $templateCache.put("uib/template/tabs/tabset.html",
41791             "<div>\n" +
41792             "  <ul class=\"nav nav-{{tabset.type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
41793             "  <div class=\"tab-content\">\n" +
41794             "    <div class=\"tab-pane\"\n" +
41795             "         ng-repeat=\"tab in tabset.tabs\"\n" +
41796             "         ng-class=\"{active: tabset.active === tab.index}\"\n" +
41797             "         uib-tab-content-transclude=\"tab\">\n" +
41798             "    </div>\n" +
41799             "  </div>\n" +
41800             "</div>\n" +
41801             "");
41802         }]);
41803
41804         angular.module("uib/template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
41805           $templateCache.put("uib/template/timepicker/timepicker.html",
41806             "<table class=\"uib-timepicker\">\n" +
41807             "  <tbody>\n" +
41808             "    <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
41809             "      <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" +
41810             "      <td>&nbsp;</td>\n" +
41811             "      <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" +
41812             "      <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
41813             "      <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" +
41814             "      <td ng-show=\"showMeridian\"></td>\n" +
41815             "    </tr>\n" +
41816             "    <tr>\n" +
41817             "      <td class=\"form-group uib-time hours\" ng-class=\"{'has-error': invalidHours}\">\n" +
41818             "        <input type=\"text\" placeholder=\"HH\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"form-control text-center\" ng-readonly=\"::readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"noIncrementHours()\" ng-blur=\"blur()\">\n" +
41819             "      </td>\n" +
41820             "      <td class=\"uib-separator\">:</td>\n" +
41821             "      <td class=\"form-group uib-time minutes\" ng-class=\"{'has-error': invalidMinutes}\">\n" +
41822             "        <input type=\"text\" placeholder=\"MM\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"form-control text-center\" ng-readonly=\"::readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"noIncrementMinutes()\" ng-blur=\"blur()\">\n" +
41823             "      </td>\n" +
41824             "      <td ng-show=\"showSeconds\" class=\"uib-separator\">:</td>\n" +
41825             "      <td class=\"form-group uib-time seconds\" ng-class=\"{'has-error': invalidSeconds}\" ng-show=\"showSeconds\">\n" +
41826             "        <input type=\"text\" placeholder=\"SS\" ng-model=\"seconds\" ng-change=\"updateSeconds()\" class=\"form-control text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\" tabindex=\"{{::tabindex}}\" ng-disabled=\"noIncrementSeconds()\" ng-blur=\"blur()\">\n" +
41827             "      </td>\n" +
41828             "      <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" +
41829             "    </tr>\n" +
41830             "    <tr class=\"text-center\" ng-show=\"::showSpinners\">\n" +
41831             "      <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" +
41832             "      <td>&nbsp;</td>\n" +
41833             "      <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" +
41834             "      <td ng-show=\"showSeconds\">&nbsp;</td>\n" +
41835             "      <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" +
41836             "      <td ng-show=\"showMeridian\"></td>\n" +
41837             "    </tr>\n" +
41838             "  </tbody>\n" +
41839             "</table>\n" +
41840             "");
41841         }]);
41842
41843         angular.module("uib/template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
41844           $templateCache.put("uib/template/typeahead/typeahead-match.html",
41845             "<a href\n" +
41846             "   tabindex=\"-1\"\n" +
41847             "   ng-bind-html=\"match.label | uibTypeaheadHighlight:query\"\n" +
41848             "   ng-attr-title=\"{{match.label}}\"></a>\n" +
41849             "");
41850         }]);
41851
41852         angular.module("uib/template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
41853           $templateCache.put("uib/template/typeahead/typeahead-popup.html",
41854             "<ul class=\"dropdown-menu\" ng-show=\"isOpen() && !moveInProgress\" ng-style=\"{top: position().top+'px', left: position().left+'px'}\" role=\"listbox\" aria-hidden=\"{{!isOpen()}}\">\n" +
41855             "    <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" +
41856             "        <div uib-typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
41857             "    </li>\n" +
41858             "</ul>\n" +
41859             "");
41860         }]);
41861         angular.module('ui.bootstrap.carousel').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibCarouselCss && 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>'); angular.$$uibCarouselCss = true; });
41862         angular.module('ui.bootstrap.datepicker').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibDatepickerCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-datepicker .uib-title{width:100%;}.uib-day button,.uib-month button,.uib-year button{min-width:100%;}.uib-left,.uib-right{width:100%}</style>'); angular.$$uibDatepickerCss = true; });
41863         angular.module('ui.bootstrap.position').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibPositionCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-position-measure{display:block !important;visibility:hidden !important;position:absolute !important;top:-9999px !important;left:-9999px !important;}.uib-position-scrollbar-measure{position:absolute !important;top:-9999px !important;width:50px !important;height:50px !important;overflow:scroll !important;}.uib-position-body-scrollbar-measure{overflow:scroll !important;}</style>'); angular.$$uibPositionCss = true; });
41864         angular.module('ui.bootstrap.datepickerPopup').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibDatepickerpopupCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-datepicker-popup.dropdown-menu{display:block;float:none;margin:0;}.uib-button-bar{padding:10px 9px 2px;}</style>'); angular.$$uibDatepickerpopupCss = true; });
41865         angular.module('ui.bootstrap.tooltip').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTooltipCss && angular.element(document).find('head').prepend('<style type="text/css">[uib-tooltip-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-popup].tooltip.right-bottom > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.right-bottom > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.right-bottom > .tooltip-arrow,[uib-popover-popup].popover.top-left > .arrow,[uib-popover-popup].popover.top-right > .arrow,[uib-popover-popup].popover.bottom-left > .arrow,[uib-popover-popup].popover.bottom-right > .arrow,[uib-popover-popup].popover.left-top > .arrow,[uib-popover-popup].popover.left-bottom > .arrow,[uib-popover-popup].popover.right-top > .arrow,[uib-popover-popup].popover.right-bottom > .arrow,[uib-popover-html-popup].popover.top-left > .arrow,[uib-popover-html-popup].popover.top-right > .arrow,[uib-popover-html-popup].popover.bottom-left > .arrow,[uib-popover-html-popup].popover.bottom-right > .arrow,[uib-popover-html-popup].popover.left-top > .arrow,[uib-popover-html-popup].popover.left-bottom > .arrow,[uib-popover-html-popup].popover.right-top > .arrow,[uib-popover-html-popup].popover.right-bottom > .arrow,[uib-popover-template-popup].popover.top-left > .arrow,[uib-popover-template-popup].popover.top-right > .arrow,[uib-popover-template-popup].popover.bottom-left > .arrow,[uib-popover-template-popup].popover.bottom-right > .arrow,[uib-popover-template-popup].popover.left-top > .arrow,[uib-popover-template-popup].popover.left-bottom > .arrow,[uib-popover-template-popup].popover.right-top > .arrow,[uib-popover-template-popup].popover.right-bottom > .arrow{top:auto;bottom:auto;left:auto;right:auto;margin:0;}[uib-popover-popup].popover,[uib-popover-html-popup].popover,[uib-popover-template-popup].popover{display:block !important;}</style>'); angular.$$uibTooltipCss = true; });
41866         angular.module('ui.bootstrap.timepicker').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTimepickerCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-time input{width:50px;}</style>'); angular.$$uibTimepickerCss = true; });
41867         angular.module('ui.bootstrap.typeahead').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTypeaheadCss && angular.element(document).find('head').prepend('<style type="text/css">[uib-typeahead-popup].dropdown-menu{display:block;}</style>'); angular.$$uibTypeaheadCss = true; });
41868
41869 /***/ },
41870 /* 8 */
41871 /***/ function(module, exports) {
41872
41873         var app;
41874         (function (app) {
41875             var declares;
41876             (function (declares) {
41877                 var CommandInfo = (function () {
41878                     function CommandInfo(name) {
41879                         this.name = name;
41880                     }
41881                     return CommandInfo;
41882                 })();
41883                 declares.CommandInfo = CommandInfo;
41884             })(declares = app.declares || (app.declares = {}));
41885         })(app || (app = {}));
41886         var app;
41887         (function (app) {
41888             var services;
41889             (function (services) {
41890                 var APIEndPoint = (function () {
41891                     function APIEndPoint($resource, $http) {
41892                         this.$resource = $resource;
41893                         this.$http = $http;
41894                     }
41895                     APIEndPoint.prototype.resource = function (endPoint, data) {
41896                         var customAction = {
41897                             method: 'GET',
41898                             isArray: false
41899                         };
41900                         var execute = {
41901                             method: 'POST',
41902                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
41903                         };
41904                         return this.$resource(endPoint, {}, { execute: execute });
41905                     };
41906                     APIEndPoint.prototype.getOptionControlFile = function (command) {
41907                         var endPoint = '/api/v1/optionControlFile/' + command;
41908                         return this.resource(endPoint, {}).get();
41909                     };
41910                     APIEndPoint.prototype.getFiles = function (fileId) {
41911                         var endPoint = '/api/v1/workspace';
41912                         if (fileId) {
41913                             endPoint += '/' + fileId;
41914                         }
41915                         return this.resource(endPoint, {}).get();
41916                     };
41917                     APIEndPoint.prototype.getDirectories = function () {
41918                         var endPoint = '/api/v1/all/workspace/directory';
41919                         return this.resource(endPoint, {}).get();
41920                     };
41921                     APIEndPoint.prototype.getTags = function () {
41922                         var endPoint = '/api/v1/tagList';
41923                         return this.resource(endPoint, {}).get();
41924                     };
41925                     APIEndPoint.prototype.getCommands = function () {
41926                         var endPoint = '/api/v1/commandList';
41927                         return this.resource(endPoint, {}).get();
41928                     };
41929                     APIEndPoint.prototype.execute = function (data) {
41930                         var endPoint = '/api/v1/execution';
41931                         var fd = new FormData();
41932                         fd.append('data', data);
41933                         return this.$http.post(endPoint, fd, {
41934                             headers: { 'Content-Type': undefined },
41935                             transformRequest: angular.identity
41936                         });
41937                     };
41938                     APIEndPoint.prototype.debug = function () {
41939                         var endPoint = '/api/v1/debug';
41940                         return this.$http.get(endPoint);
41941                     };
41942                     APIEndPoint.prototype.upload = function () {
41943                         var endPoint = '/api/v1/upload';
41944                         return this.$http.get(endPoint);
41945                     };
41946                     APIEndPoint.prototype.help = function (command) {
41947                         var endPoint = '/api/v1/help/' + command;
41948                         return this.$http.get(endPoint);
41949                     };
41950                     return APIEndPoint;
41951                 })();
41952                 services.APIEndPoint = APIEndPoint;
41953             })(services = app.services || (app.services = {}));
41954         })(app || (app = {}));
41955         var app;
41956         (function (app) {
41957             var services;
41958             (function (services) {
41959                 var MyModal = (function () {
41960                     function MyModal($uibModal) {
41961                         this.$uibModal = $uibModal;
41962                         this.modalOption = {
41963                             backdrop: true,
41964                             controller: null,
41965                             templateUrl: null,
41966                             size: null
41967                         };
41968                     }
41969                     MyModal.prototype.open = function (modalName) {
41970                         if (modalName === 'SelectCommand') {
41971                             this.modalOption.templateUrl = 'templates/select-command.html';
41972                             this.modalOption.size = 'lg';
41973                         }
41974                         return this.$uibModal.open(this.modalOption);
41975                     };
41976                     MyModal.prototype.selectCommand = function () {
41977                         this.modalOption.templateUrl = 'templates/select-command.html';
41978                         this.modalOption.controller = 'selectCommandController';
41979                         this.modalOption.controllerAs = 'c';
41980                         this.modalOption.size = 'lg';
41981                         return this.$uibModal.open(this.modalOption);
41982                     };
41983                     MyModal.prototype.preview = function () {
41984                         this.modalOption.templateUrl = 'templates/preview.html';
41985                         this.modalOption.controller = 'previewController';
41986                         this.modalOption.controllerAs = 'c';
41987                         this.modalOption.size = 'lg';
41988                         return this.$uibModal.open(this.modalOption);
41989                     };
41990                     MyModal.prototype.upload = function () {
41991                         this.modalOption.templateUrl = 'templates/upload.html';
41992                         this.modalOption.controller = 'uploadController';
41993                         this.modalOption.controllerAs = 'c';
41994                         this.modalOption.size = 'lg';
41995                         return this.$uibModal.open(this.modalOption);
41996                     };
41997                     MyModal.$inject = ['$uibModal'];
41998                     return MyModal;
41999                 })();
42000                 services.MyModal = MyModal;
42001             })(services = app.services || (app.services = {}));
42002         })(app || (app = {}));
42003         var app;
42004         (function (app) {
42005             var services;
42006             (function (services) {
42007                 var WebSocket = (function () {
42008                     function WebSocket($rootScope) {
42009                         this.$rootScope = $rootScope;
42010                         this.socket = io.connect();
42011                     }
42012                     WebSocket.prototype.on = function (eventName, callback) {
42013                         var socket = this.socket;
42014                         var rootScope = this.$rootScope;
42015                         socket.on(eventName, function () {
42016                             var args = arguments;
42017                             rootScope.$apply(function () {
42018                                 callback.apply(socket, args);
42019                             });
42020                         });
42021                     };
42022                     WebSocket.prototype.emit = function (eventName, data, callback) {
42023                         var socket = this.socket;
42024                         var rootScope = this.$rootScope;
42025                         this.socket.emit(eventName, data, function () {
42026                             var args = arguments;
42027                             rootScope.$apply(function () {
42028                                 if (callback)
42029                                     callback.apply(socket, args);
42030                             });
42031                         });
42032                     };
42033                     return WebSocket;
42034                 })();
42035                 services.WebSocket = WebSocket;
42036             })(services = app.services || (app.services = {}));
42037         })(app || (app = {}));
42038         var app;
42039         (function (app) {
42040             var services;
42041             (function (services) {
42042                 var Console = (function () {
42043                     function Console(WebSocket, $rootScope) {
42044                         this.WebSocket = WebSocket;
42045                         this.$rootScope = $rootScope;
42046                         this.WebSocket = WebSocket;
42047                         this.$rootScope = $rootScope;
42048                         this.directiveIDs = [];
42049                         var directiveIDs = this.directiveIDs;
42050                         this.WebSocket.on('console', function (d) {
42051                             var id = d.id;
42052                             var message = d.message;
42053                             if (directiveIDs.indexOf(id) > -1) {
42054                                 $rootScope.$emit(id, message);
42055                             }
42056                         });
42057                     }
42058                     Console.prototype.addDirective = function (id) {
42059                         if (!(this.directiveIDs.indexOf(id) > -1)) {
42060                             this.directiveIDs.push(id);
42061                         }
42062                     };
42063                     Console.prototype.removeDirective = function (id) {
42064                         var i = this.directiveIDs.indexOf(id);
42065                         if (i > -1) {
42066                             this.directiveIDs.splice(i, 1);
42067                         }
42068                     };
42069                     Console.prototype.showIDs = function () {
42070                         console.log(this.directiveIDs);
42071                     };
42072                     return Console;
42073                 })();
42074                 services.Console = Console;
42075             })(services = app.services || (app.services = {}));
42076         })(app || (app = {}));
42077         var app;
42078         (function (app) {
42079             var directives;
42080             (function (directives) {
42081                 var Command = (function () {
42082                     function Command() {
42083                         this.restrict = 'E';
42084                         this.replace = true;
42085                         this.scope = true;
42086                         this.controller = 'commandController';
42087                         this.controllerAs = 'ctrl';
42088                         this.bindToController = {
42089                             index: '=',
42090                             name: '=',
42091                             remove: '&',
42092                             list: '='
42093                         };
42094                         this.templateUrl = 'templates/command.html';
42095                     }
42096                     Command.Factory = function () {
42097                         var directive = function () {
42098                             return new Command();
42099                         };
42100                         directive.$inject = [];
42101                         return directive;
42102                     };
42103                     return Command;
42104                 })();
42105                 directives.Command = Command;
42106                 var CommandController = (function () {
42107                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
42108                         this.APIEndPoint = APIEndPoint;
42109                         this.$scope = $scope;
42110                         this.MyModal = MyModal;
42111                         this.WebSocket = WebSocket;
42112                         this.$window = $window;
42113                         this.$rootScope = $rootScope;
42114                         this.Console = Console;
42115                         var controller = this;
42116                         this.APIEndPoint
42117                             .getOptionControlFile(this.name)
42118                             .$promise
42119                             .then(function (result) {
42120                             controller.options = result.info;
42121                         });
42122                         this.APIEndPoint
42123                             .getDirectories()
42124                             .$promise
42125                             .then(function (result) {
42126                             controller.dirs = result.info;
42127                         });
42128                         this.heading = "[" + this.index + "]: dcdFilePrint";
42129                         this.isOpen = true;
42130                         this.$scope.$on('close', function () {
42131                             controller.isOpen = false;
42132                         });
42133                         function guid() {
42134                             function s4() {
42135                                 return Math.floor((1 + Math.random()) * 0x10000)
42136                                     .toString(16)
42137                                     .substring(1);
42138                             }
42139                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
42140                                 s4() + '-' + s4() + s4() + s4();
42141                         }
42142                         this.uuid = guid();
42143                         this.Console.addDirective(this.uuid);
42144                         this.Console.showIDs();
42145                     }
42146                     CommandController.prototype.submit = function () {
42147                         var opt = [];
42148                         angular.forEach(this.options, function (option) {
42149                             var obj = {
42150                                 name: option.option,
42151                                 arguments: []
42152                             };
42153                             angular.forEach(option.arg, function (arg) {
42154                                 if (arg.input) {
42155                                     if (typeof arg.input === 'object') {
42156                                         obj.arguments.push(arg.input.name);
42157                                     }
42158                                     else {
42159                                         obj.arguments.push(arg.input);
42160                                     }
42161                                 }
42162                             });
42163                             if (obj.arguments.length > 0) {
42164                                 opt.push(obj);
42165                             }
42166                         });
42167                         var execObj = {
42168                             command: this.name,
42169                             workspace: this.workspace.fileId,
42170                             options: opt
42171                         };
42172                         this.APIEndPoint
42173                             .execute(JSON.stringify(execObj))
42174                             .then(function (result) {
42175                             console.log(result);
42176                         });
42177                     };
42178                     CommandController.prototype.removeMySelf = function (index) {
42179                         this.$scope.$destroy();
42180                         this.Console.removeDirective(this.uuid);
42181                         this.remove()(index, this.list);
42182                         this.Console.showIDs();
42183                     };
42184                     CommandController.prototype.reloadFiles = function () {
42185                         var _this = this;
42186                         var fileId = this.workspace.fileId;
42187                         this.APIEndPoint
42188                             .getFiles(fileId)
42189                             .$promise
42190                             .then(function (result) {
42191                             var status = result.status;
42192                             if (status === 'success') {
42193                                 _this.files = result.info;
42194                             }
42195                             else {
42196                                 console.log(result.message);
42197                             }
42198                         });
42199                     };
42200                     CommandController.prototype.debug = function () {
42201                         var div = angular.element(this.$window.document).find("div");
42202                         var consoleTag;
42203                         var parametersTag;
42204                         angular.forEach(div, function (v) {
42205                             if (v.className === "panel-body console") {
42206                                 consoleTag = v;
42207                             }
42208                             else if (v.className === "row parameters-console") {
42209                                 parametersTag = v;
42210                             }
42211                         });
42212                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
42213                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
42214                         consoleTag.style.height = consoleHeight;
42215                         consoleTag.style.width = consoleWidth;
42216                     };
42217                     CommandController.prototype.help = function () {
42218                         this.APIEndPoint
42219                             .help(this.name)
42220                             .then(function (result) {
42221                             console.log(result);
42222                         });
42223                     };
42224                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
42225                     return CommandController;
42226                 })();
42227                 directives.CommandController = CommandController;
42228             })(directives = app.directives || (app.directives = {}));
42229         })(app || (app = {}));
42230         var app;
42231         (function (app) {
42232             var directives;
42233             (function (directives) {
42234                 var HeaderMenu = (function () {
42235                     function HeaderMenu() {
42236                         this.restrict = 'E';
42237                         this.replace = true;
42238                         this.templateUrl = 'templates/header-menu.html';
42239                         this.controller = 'HeaderMenuController';
42240                         this.controllerAs = 'hmc';
42241                         this.scope = true;
42242                     }
42243                     HeaderMenu.Factory = function () {
42244                         var directive = function () {
42245                             return new HeaderMenu();
42246                         };
42247                         return directive;
42248                     };
42249                     return HeaderMenu;
42250                 })();
42251                 directives.HeaderMenu = HeaderMenu;
42252                 var HeaderMenuController = (function () {
42253                     function HeaderMenuController($state) {
42254                         this.$state = $state;
42255                         this.isExecution = this.$state.current.name === 'execution';
42256                         this.isWorkspace = this.$state.current.name === 'workspace';
42257                         this.isHistory = this.$state.current.name === 'history';
42258                     }
42259                     HeaderMenuController.prototype.transit = function (state) {
42260                         this.$state.go(state);
42261                     };
42262                     HeaderMenuController.$inject = ['$state'];
42263                     return HeaderMenuController;
42264                 })();
42265                 directives.HeaderMenuController = HeaderMenuController;
42266             })(directives = app.directives || (app.directives = {}));
42267         })(app || (app = {}));
42268         var app;
42269         (function (app) {
42270             var directives;
42271             (function (directives) {
42272                 var Option = (function () {
42273                     function Option() {
42274                         this.restrict = 'E';
42275                         this.replace = true;
42276                         this.controller = 'optionController';
42277                         this.bindToController = {
42278                             info: '=',
42279                             files: '='
42280                         };
42281                         this.scope = true;
42282                         this.templateUrl = 'templates/option.html';
42283                         this.controllerAs = 'ctrl';
42284                     }
42285                     Option.Factory = function () {
42286                         var directive = function () {
42287                             return new Option();
42288                         };
42289                         directive.$inject = [];
42290                         return directive;
42291                     };
42292                     return Option;
42293                 })();
42294                 directives.Option = Option;
42295                 var OptionController = (function () {
42296                     function OptionController() {
42297                         var controller = this;
42298                         angular.forEach(controller.info.arg, function (arg) {
42299                             if (arg.initialValue) {
42300                                 if (arg.formType === 'number') {
42301                                     arg.input = parseInt(arg.initialValue);
42302                                 }
42303                                 else {
42304                                     arg.input = arg.initialValue;
42305                                 }
42306                             }
42307                         });
42308                     }
42309                     OptionController.$inject = [];
42310                     return OptionController;
42311                 })();
42312                 directives.OptionController = OptionController;
42313             })(directives = app.directives || (app.directives = {}));
42314         })(app || (app = {}));
42315         var app;
42316         (function (app) {
42317             var directives;
42318             (function (directives) {
42319                 var Directory = (function () {
42320                     function Directory() {
42321                         this.restrict = 'E';
42322                         this.replace = true;
42323                         this.controller = 'directoryController';
42324                         this.controllerAs = 'ctrl';
42325                         this.bindToController = {
42326                             info: '=',
42327                             add: '&',
42328                             list: '=',
42329                             files: '='
42330                         };
42331                         this.templateUrl = 'templates/directory.html';
42332                     }
42333                     Directory.Factory = function () {
42334                         var directive = function () {
42335                             return new Directory();
42336                         };
42337                         return directive;
42338                     };
42339                     return Directory;
42340                 })();
42341                 directives.Directory = Directory;
42342                 var DirectoryController = (function () {
42343                     function DirectoryController(APIEndPoint, $scope) {
42344                         this.APIEndPoint = APIEndPoint;
42345                         this.$scope = $scope;
42346                         var controller = this;
42347                         this.APIEndPoint
42348                             .getFiles(this.info.fileId)
42349                             .$promise
42350                             .then(function (result) {
42351                             if (result.status === 'success') {
42352                                 controller.files = result.info;
42353                                 angular.forEach(result.info, function (file) {
42354                                     if (file.fileType === '0') {
42355                                         var o = file;
42356                                         if (controller.info.path === '/') {
42357                                             o.path = '/' + file.name;
42358                                         }
42359                                         else {
42360                                             o.path = controller.info.path + '/' + file.name;
42361                                         }
42362                                         controller.add()(o, controller.list);
42363                                     }
42364                                 });
42365                             }
42366                             ;
42367                         });
42368                     }
42369                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
42370                     return DirectoryController;
42371                 })();
42372                 directives.DirectoryController = DirectoryController;
42373             })(directives = app.directives || (app.directives = {}));
42374         })(app || (app = {}));
42375         var app;
42376         (function (app) {
42377             var directives;
42378             (function (directives) {
42379                 var Upload = (function () {
42380                     function Upload() {
42381                         this.restrict = 'E';
42382                         this.replace = true;
42383                         this.scope = true;
42384                         this.controller = 'UploadController';
42385                         this.controllerAs = 'ctrl';
42386                         this.bindToController = {
42387                             index: '=',
42388                             name: '=',
42389                             remove: '&',
42390                             list: '='
42391                         };
42392                         this.templateUrl = 'templates/upload.html';
42393                         console.log("templates/upload.html-constructor");
42394                     }
42395                     Upload.Factory = function () {
42396                         var directive = function () {
42397                             return new Upload();
42398                         };
42399                         directive.$inject = [];
42400                         return directive;
42401                     };
42402                     return Upload;
42403                 })();
42404                 directives.Upload = Upload;
42405                 var UploadController = (function () {
42406                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
42407                         this.APIEndPoint = APIEndPoint;
42408                         this.$scope = $scope;
42409                         this.MyModal = MyModal;
42410                         this.WebSocket = WebSocket;
42411                         this.$window = $window;
42412                         this.$rootScope = $rootScope;
42413                         this.Console = Console;
42414                         var controller = this;
42415                         console.log("directive.upload-constructor");
42416                     }
42417                     UploadController.prototype.submit = function () {
42418                         console.log("submit: function not supported¥n");
42419                     };
42420                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
42421                     return UploadController;
42422                 })();
42423                 directives.UploadController = UploadController;
42424             })(directives = app.directives || (app.directives = {}));
42425         })(app || (app = {}));
42426         var app;
42427         (function (app) {
42428             var controllers;
42429             (function (controllers) {
42430                 var Execution = (function () {
42431                     function Execution(MyModal, $scope) {
42432                         this.MyModal = MyModal;
42433                         this.$scope = $scope;
42434                         this.commandInfoList = [];
42435                     }
42436                     ;
42437                     Execution.prototype.add = function () {
42438                         this.$scope.$broadcast('close');
42439                         var commandInfoList = this.commandInfoList;
42440                         var commandInstance = this.MyModal.selectCommand();
42441                         commandInstance
42442                             .result
42443                             .then(function (command) {
42444                             commandInfoList.push(new app.declares.CommandInfo(command));
42445                         });
42446                     };
42447                     Execution.prototype.open = function () {
42448                         var result = this.MyModal.open('SelectCommand');
42449                         console.log(result);
42450                     };
42451                     Execution.prototype.remove = function (index, list) {
42452                         list.splice(index, 1);
42453                     };
42454                     Execution.prototype.close = function () {
42455                         console.log("close");
42456                     };
42457                     Execution.$inject = ['MyModal', '$scope'];
42458                     return Execution;
42459                 })();
42460                 controllers.Execution = Execution;
42461             })(controllers = app.controllers || (app.controllers = {}));
42462         })(app || (app = {}));
42463         var app;
42464         (function (app) {
42465             var controllers;
42466             (function (controllers) {
42467                 var Workspace = (function () {
42468                     function Workspace($scope, APIEndPoint, MyModal) {
42469                         this.$scope = $scope;
42470                         this.APIEndPoint = APIEndPoint;
42471                         this.MyModal = MyModal;
42472                         this.directoryList = [];
42473                         var controller = this;
42474                         var directoryList = this.directoryList;
42475                         var o = {
42476                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
42477                             name: '',
42478                             parentId: '',
42479                             fileType: '',
42480                             createdAt: '',
42481                             updatedAt: '',
42482                             path: '/'
42483                         };
42484                         directoryList.push(o);
42485                     }
42486                     Workspace.prototype.addDirectory = function (info, directoryList) {
42487                         directoryList.push(info);
42488                     };
42489                     Workspace.prototype.upload = function () {
42490                         this.MyModal.upload();
42491                     };
42492                     Workspace.prototype.debug = function () {
42493                         this.MyModal.preview();
42494                     };
42495                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
42496                     return Workspace;
42497                 })();
42498                 controllers.Workspace = Workspace;
42499             })(controllers = app.controllers || (app.controllers = {}));
42500         })(app || (app = {}));
42501         var app;
42502         (function (app) {
42503             var controllers;
42504             (function (controllers) {
42505                 var History = (function () {
42506                     function History($scope) {
42507                         this.page = "History";
42508                     }
42509                     History.$inject = ['$scope'];
42510                     return History;
42511                 })();
42512                 controllers.History = History;
42513             })(controllers = app.controllers || (app.controllers = {}));
42514         })(app || (app = {}));
42515         var app;
42516         (function (app) {
42517             var controllers;
42518             (function (controllers) {
42519                 var SelectCommand = (function () {
42520                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
42521                         this.APIEndPoint = APIEndPoint;
42522                         this.$modalInstance = $modalInstance;
42523                         var controller = this;
42524                         this.APIEndPoint
42525                             .getTags()
42526                             .$promise.then(function (result) {
42527                             controller.tags = result.info;
42528                         });
42529                         this.APIEndPoint
42530                             .getCommands()
42531                             .$promise.then(function (result) {
42532                             controller.commands = result.info;
42533                         });
42534                         this.currentTag = 'all';
42535                     }
42536                     SelectCommand.prototype.changeTag = function (tag) {
42537                         this.currentTag = tag;
42538                     };
42539                     SelectCommand.prototype.selectCommand = function (command) {
42540                         this.$modalInstance.close(command);
42541                     };
42542                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42543                     return SelectCommand;
42544                 })();
42545                 controllers.SelectCommand = SelectCommand;
42546             })(controllers = app.controllers || (app.controllers = {}));
42547         })(app || (app = {}));
42548         var app;
42549         (function (app) {
42550             var controllers;
42551             (function (controllers) {
42552                 var Upload = (function () {
42553                     function Upload($scope, APIEndPoint, $modalInstance) {
42554                         this.APIEndPoint = APIEndPoint;
42555                         this.$modalInstance = $modalInstance;
42556                         var controller = this;
42557                         console.log('controller.upload-controllers');
42558                     }
42559                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42560                     return Upload;
42561                 })();
42562                 controllers.Upload = Upload;
42563             })(controllers = app.controllers || (app.controllers = {}));
42564         })(app || (app = {}));
42565         var app;
42566         (function (app) {
42567             var controllers;
42568             (function (controllers) {
42569                 var Preview = (function () {
42570                     function Preview($scope, APIEndPoint, $modalInstance) {
42571                         this.APIEndPoint = APIEndPoint;
42572                         this.$modalInstance = $modalInstance;
42573                         var controller = this;
42574                         console.log('preview');
42575                     }
42576                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
42577                     return Preview;
42578                 })();
42579                 controllers.Preview = Preview;
42580             })(controllers = app.controllers || (app.controllers = {}));
42581         })(app || (app = {}));
42582         var filters;
42583         (function (filters) {
42584             function Tag() {
42585                 return function (commands, tag) {
42586                     var result = [];
42587                     angular.forEach(commands, function (command) {
42588                         var flag = false;
42589                         angular.forEach(command.tags, function (value) {
42590                             if (tag === value)
42591                                 flag = true;
42592                         });
42593                         if (flag)
42594                             result.push(command);
42595                     });
42596                     return result;
42597                 };
42598             }
42599             filters.Tag = Tag;
42600         })(filters || (filters = {}));
42601         var app;
42602         (function (app) {
42603             'use strict';
42604             var appName = 'zephyr';
42605             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
42606             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
42607                 $urlRouterProvider.otherwise('/execution');
42608                 $locationProvider.html5Mode({
42609                     enabled: true,
42610                     requireBase: false
42611                 });
42612                 $stateProvider
42613                     .state('execution', {
42614                     url: '/execution',
42615                     templateUrl: 'templates/execution.html',
42616                     controller: 'executionController',
42617                     controllerAs: 'c'
42618                 })
42619                     .state('workspace', {
42620                     url: '/workspace',
42621                     templateUrl: 'templates/workspace.html',
42622                     controller: 'workspaceController',
42623                     controllerAs: 'c'
42624                 })
42625                     .state('history', {
42626                     url: '/history',
42627                     templateUrl: 'templates/history.html',
42628                     controller: 'historyController',
42629                     controllerAs: 'c'
42630                 });
42631             });
42632             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
42633             app.zephyr.service('MyModal', app.services.MyModal);
42634             app.zephyr.service('WebSocket', app.services.WebSocket);
42635             app.zephyr.service('Console', app.services.Console);
42636             app.zephyr.filter('Tag', filters.Tag);
42637             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
42638             app.zephyr.controller('previewController', app.controllers.Preview);
42639             app.zephyr.controller('uploadController', app.controllers.Upload);
42640             app.zephyr.controller('executionController', app.controllers.Execution);
42641             app.zephyr.controller('workspaceController', app.controllers.Workspace);
42642             app.zephyr.controller('historyController', app.controllers.History);
42643             app.zephyr.controller('commandController', app.directives.CommandController);
42644             app.zephyr.controller('optionController', app.directives.OptionController);
42645             app.zephyr.controller('directoryController', app.directives.DirectoryController);
42646             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
42647             app.zephyr.controller('uploadController', app.directives.UploadController);
42648             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
42649             app.zephyr.directive('command', app.directives.Command.Factory());
42650             app.zephyr.directive('option', app.directives.Option.Factory());
42651             app.zephyr.directive('directory', app.directives.Directory.Factory());
42652         })(app || (app = {}));
42653
42654
42655 /***/ },
42656 /* 9 */
42657 /***/ function(module, exports) {
42658
42659         var app;
42660         (function (app) {
42661             var declares;
42662             (function (declares) {
42663                 var CommandInfo = (function () {
42664                     function CommandInfo(name) {
42665                         this.name = name;
42666                     }
42667                     return CommandInfo;
42668                 })();
42669                 declares.CommandInfo = CommandInfo;
42670             })(declares = app.declares || (app.declares = {}));
42671         })(app || (app = {}));
42672         var app;
42673         (function (app) {
42674             var services;
42675             (function (services) {
42676                 var APIEndPoint = (function () {
42677                     function APIEndPoint($resource, $http) {
42678                         this.$resource = $resource;
42679                         this.$http = $http;
42680                     }
42681                     APIEndPoint.prototype.resource = function (endPoint, data) {
42682                         var customAction = {
42683                             method: 'GET',
42684                             isArray: false
42685                         };
42686                         var execute = {
42687                             method: 'POST',
42688                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
42689                         };
42690                         return this.$resource(endPoint, {}, { execute: execute });
42691                     };
42692                     APIEndPoint.prototype.getOptionControlFile = function (command) {
42693                         var endPoint = '/api/v1/optionControlFile/' + command;
42694                         return this.resource(endPoint, {}).get();
42695                     };
42696                     APIEndPoint.prototype.getFiles = function (fileId) {
42697                         var endPoint = '/api/v1/workspace';
42698                         if (fileId) {
42699                             endPoint += '/' + fileId;
42700                         }
42701                         return this.resource(endPoint, {}).get();
42702                     };
42703                     APIEndPoint.prototype.getDirectories = function () {
42704                         var endPoint = '/api/v1/all/workspace/directory';
42705                         return this.resource(endPoint, {}).get();
42706                     };
42707                     APIEndPoint.prototype.getTags = function () {
42708                         var endPoint = '/api/v1/tagList';
42709                         return this.resource(endPoint, {}).get();
42710                     };
42711                     APIEndPoint.prototype.getCommands = function () {
42712                         var endPoint = '/api/v1/commandList';
42713                         return this.resource(endPoint, {}).get();
42714                     };
42715                     APIEndPoint.prototype.execute = function (data) {
42716                         var endPoint = '/api/v1/execution';
42717                         var fd = new FormData();
42718                         fd.append('data', data);
42719                         return this.$http.post(endPoint, fd, {
42720                             headers: { 'Content-Type': undefined },
42721                             transformRequest: angular.identity
42722                         });
42723                     };
42724                     APIEndPoint.prototype.debug = function () {
42725                         var endPoint = '/api/v1/debug';
42726                         return this.$http.get(endPoint);
42727                     };
42728                     APIEndPoint.prototype.upload = function () {
42729                         var endPoint = '/api/v1/upload';
42730                         return this.$http.get(endPoint);
42731                     };
42732                     APIEndPoint.prototype.help = function (command) {
42733                         var endPoint = '/api/v1/help/' + command;
42734                         return this.$http.get(endPoint);
42735                     };
42736                     return APIEndPoint;
42737                 })();
42738                 services.APIEndPoint = APIEndPoint;
42739             })(services = app.services || (app.services = {}));
42740         })(app || (app = {}));
42741         var app;
42742         (function (app) {
42743             var services;
42744             (function (services) {
42745                 var MyModal = (function () {
42746                     function MyModal($uibModal) {
42747                         this.$uibModal = $uibModal;
42748                         this.modalOption = {
42749                             backdrop: true,
42750                             controller: null,
42751                             templateUrl: null,
42752                             size: null
42753                         };
42754                     }
42755                     MyModal.prototype.open = function (modalName) {
42756                         if (modalName === 'SelectCommand') {
42757                             this.modalOption.templateUrl = 'templates/select-command.html';
42758                             this.modalOption.size = 'lg';
42759                         }
42760                         return this.$uibModal.open(this.modalOption);
42761                     };
42762                     MyModal.prototype.selectCommand = function () {
42763                         this.modalOption.templateUrl = 'templates/select-command.html';
42764                         this.modalOption.controller = 'selectCommandController';
42765                         this.modalOption.controllerAs = 'c';
42766                         this.modalOption.size = 'lg';
42767                         return this.$uibModal.open(this.modalOption);
42768                     };
42769                     MyModal.prototype.preview = function () {
42770                         this.modalOption.templateUrl = 'templates/preview.html';
42771                         this.modalOption.controller = 'previewController';
42772                         this.modalOption.controllerAs = 'c';
42773                         this.modalOption.size = 'lg';
42774                         return this.$uibModal.open(this.modalOption);
42775                     };
42776                     MyModal.prototype.upload = function () {
42777                         this.modalOption.templateUrl = 'templates/upload.html';
42778                         this.modalOption.controller = 'uploadController';
42779                         this.modalOption.controllerAs = 'c';
42780                         this.modalOption.size = 'lg';
42781                         return this.$uibModal.open(this.modalOption);
42782                     };
42783                     MyModal.$inject = ['$uibModal'];
42784                     return MyModal;
42785                 })();
42786                 services.MyModal = MyModal;
42787             })(services = app.services || (app.services = {}));
42788         })(app || (app = {}));
42789         var app;
42790         (function (app) {
42791             var services;
42792             (function (services) {
42793                 var WebSocket = (function () {
42794                     function WebSocket($rootScope) {
42795                         this.$rootScope = $rootScope;
42796                         this.socket = io.connect();
42797                     }
42798                     WebSocket.prototype.on = function (eventName, callback) {
42799                         var socket = this.socket;
42800                         var rootScope = this.$rootScope;
42801                         socket.on(eventName, function () {
42802                             var args = arguments;
42803                             rootScope.$apply(function () {
42804                                 callback.apply(socket, args);
42805                             });
42806                         });
42807                     };
42808                     WebSocket.prototype.emit = function (eventName, data, callback) {
42809                         var socket = this.socket;
42810                         var rootScope = this.$rootScope;
42811                         this.socket.emit(eventName, data, function () {
42812                             var args = arguments;
42813                             rootScope.$apply(function () {
42814                                 if (callback)
42815                                     callback.apply(socket, args);
42816                             });
42817                         });
42818                     };
42819                     return WebSocket;
42820                 })();
42821                 services.WebSocket = WebSocket;
42822             })(services = app.services || (app.services = {}));
42823         })(app || (app = {}));
42824         var app;
42825         (function (app) {
42826             var services;
42827             (function (services) {
42828                 var Console = (function () {
42829                     function Console(WebSocket, $rootScope) {
42830                         this.WebSocket = WebSocket;
42831                         this.$rootScope = $rootScope;
42832                         this.WebSocket = WebSocket;
42833                         this.$rootScope = $rootScope;
42834                         this.directiveIDs = [];
42835                         var directiveIDs = this.directiveIDs;
42836                         this.WebSocket.on('console', function (d) {
42837                             var id = d.id;
42838                             var message = d.message;
42839                             if (directiveIDs.indexOf(id) > -1) {
42840                                 $rootScope.$emit(id, message);
42841                             }
42842                         });
42843                     }
42844                     Console.prototype.addDirective = function (id) {
42845                         if (!(this.directiveIDs.indexOf(id) > -1)) {
42846                             this.directiveIDs.push(id);
42847                         }
42848                     };
42849                     Console.prototype.removeDirective = function (id) {
42850                         var i = this.directiveIDs.indexOf(id);
42851                         if (i > -1) {
42852                             this.directiveIDs.splice(i, 1);
42853                         }
42854                     };
42855                     Console.prototype.showIDs = function () {
42856                         console.log(this.directiveIDs);
42857                     };
42858                     return Console;
42859                 })();
42860                 services.Console = Console;
42861             })(services = app.services || (app.services = {}));
42862         })(app || (app = {}));
42863         var app;
42864         (function (app) {
42865             var directives;
42866             (function (directives) {
42867                 var Command = (function () {
42868                     function Command() {
42869                         this.restrict = 'E';
42870                         this.replace = true;
42871                         this.scope = true;
42872                         this.controller = 'commandController';
42873                         this.controllerAs = 'ctrl';
42874                         this.bindToController = {
42875                             index: '=',
42876                             name: '=',
42877                             remove: '&',
42878                             list: '='
42879                         };
42880                         this.templateUrl = 'templates/command.html';
42881                     }
42882                     Command.Factory = function () {
42883                         var directive = function () {
42884                             return new Command();
42885                         };
42886                         directive.$inject = [];
42887                         return directive;
42888                     };
42889                     return Command;
42890                 })();
42891                 directives.Command = Command;
42892                 var CommandController = (function () {
42893                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
42894                         this.APIEndPoint = APIEndPoint;
42895                         this.$scope = $scope;
42896                         this.MyModal = MyModal;
42897                         this.WebSocket = WebSocket;
42898                         this.$window = $window;
42899                         this.$rootScope = $rootScope;
42900                         this.Console = Console;
42901                         var controller = this;
42902                         this.APIEndPoint
42903                             .getOptionControlFile(this.name)
42904                             .$promise
42905                             .then(function (result) {
42906                             controller.options = result.info;
42907                         });
42908                         this.APIEndPoint
42909                             .getDirectories()
42910                             .$promise
42911                             .then(function (result) {
42912                             controller.dirs = result.info;
42913                         });
42914                         this.heading = "[" + this.index + "]: dcdFilePrint";
42915                         this.isOpen = true;
42916                         this.$scope.$on('close', function () {
42917                             controller.isOpen = false;
42918                         });
42919                         function guid() {
42920                             function s4() {
42921                                 return Math.floor((1 + Math.random()) * 0x10000)
42922                                     .toString(16)
42923                                     .substring(1);
42924                             }
42925                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
42926                                 s4() + '-' + s4() + s4() + s4();
42927                         }
42928                         this.uuid = guid();
42929                         this.Console.addDirective(this.uuid);
42930                         this.Console.showIDs();
42931                     }
42932                     CommandController.prototype.submit = function () {
42933                         var opt = [];
42934                         angular.forEach(this.options, function (option) {
42935                             var obj = {
42936                                 name: option.option,
42937                                 arguments: []
42938                             };
42939                             angular.forEach(option.arg, function (arg) {
42940                                 if (arg.input) {
42941                                     if (typeof arg.input === 'object') {
42942                                         obj.arguments.push(arg.input.name);
42943                                     }
42944                                     else {
42945                                         obj.arguments.push(arg.input);
42946                                     }
42947                                 }
42948                             });
42949                             if (obj.arguments.length > 0) {
42950                                 opt.push(obj);
42951                             }
42952                         });
42953                         var execObj = {
42954                             command: this.name,
42955                             workspace: this.workspace.fileId,
42956                             options: opt
42957                         };
42958                         this.APIEndPoint
42959                             .execute(JSON.stringify(execObj))
42960                             .then(function (result) {
42961                             console.log(result);
42962                         });
42963                     };
42964                     CommandController.prototype.removeMySelf = function (index) {
42965                         this.$scope.$destroy();
42966                         this.Console.removeDirective(this.uuid);
42967                         this.remove()(index, this.list);
42968                         this.Console.showIDs();
42969                     };
42970                     CommandController.prototype.reloadFiles = function () {
42971                         var _this = this;
42972                         var fileId = this.workspace.fileId;
42973                         this.APIEndPoint
42974                             .getFiles(fileId)
42975                             .$promise
42976                             .then(function (result) {
42977                             var status = result.status;
42978                             if (status === 'success') {
42979                                 _this.files = result.info;
42980                             }
42981                             else {
42982                                 console.log(result.message);
42983                             }
42984                         });
42985                     };
42986                     CommandController.prototype.debug = function () {
42987                         var div = angular.element(this.$window.document).find("div");
42988                         var consoleTag;
42989                         var parametersTag;
42990                         angular.forEach(div, function (v) {
42991                             if (v.className === "panel-body console") {
42992                                 consoleTag = v;
42993                             }
42994                             else if (v.className === "row parameters-console") {
42995                                 parametersTag = v;
42996                             }
42997                         });
42998                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
42999                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
43000                         consoleTag.style.height = consoleHeight;
43001                         consoleTag.style.width = consoleWidth;
43002                     };
43003                     CommandController.prototype.help = function () {
43004                         this.APIEndPoint
43005                             .help(this.name)
43006                             .then(function (result) {
43007                             console.log(result);
43008                         });
43009                     };
43010                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
43011                     return CommandController;
43012                 })();
43013                 directives.CommandController = CommandController;
43014             })(directives = app.directives || (app.directives = {}));
43015         })(app || (app = {}));
43016         var app;
43017         (function (app) {
43018             var directives;
43019             (function (directives) {
43020                 var HeaderMenu = (function () {
43021                     function HeaderMenu() {
43022                         this.restrict = 'E';
43023                         this.replace = true;
43024                         this.templateUrl = 'templates/header-menu.html';
43025                         this.controller = 'HeaderMenuController';
43026                         this.controllerAs = 'hmc';
43027                         this.scope = true;
43028                     }
43029                     HeaderMenu.Factory = function () {
43030                         var directive = function () {
43031                             return new HeaderMenu();
43032                         };
43033                         return directive;
43034                     };
43035                     return HeaderMenu;
43036                 })();
43037                 directives.HeaderMenu = HeaderMenu;
43038                 var HeaderMenuController = (function () {
43039                     function HeaderMenuController($state) {
43040                         this.$state = $state;
43041                         this.isExecution = this.$state.current.name === 'execution';
43042                         this.isWorkspace = this.$state.current.name === 'workspace';
43043                         this.isHistory = this.$state.current.name === 'history';
43044                     }
43045                     HeaderMenuController.prototype.transit = function (state) {
43046                         this.$state.go(state);
43047                     };
43048                     HeaderMenuController.$inject = ['$state'];
43049                     return HeaderMenuController;
43050                 })();
43051                 directives.HeaderMenuController = HeaderMenuController;
43052             })(directives = app.directives || (app.directives = {}));
43053         })(app || (app = {}));
43054         var app;
43055         (function (app) {
43056             var directives;
43057             (function (directives) {
43058                 var Option = (function () {
43059                     function Option() {
43060                         this.restrict = 'E';
43061                         this.replace = true;
43062                         this.controller = 'optionController';
43063                         this.bindToController = {
43064                             info: '=',
43065                             files: '='
43066                         };
43067                         this.scope = true;
43068                         this.templateUrl = 'templates/option.html';
43069                         this.controllerAs = 'ctrl';
43070                     }
43071                     Option.Factory = function () {
43072                         var directive = function () {
43073                             return new Option();
43074                         };
43075                         directive.$inject = [];
43076                         return directive;
43077                     };
43078                     return Option;
43079                 })();
43080                 directives.Option = Option;
43081                 var OptionController = (function () {
43082                     function OptionController() {
43083                         var controller = this;
43084                         angular.forEach(controller.info.arg, function (arg) {
43085                             if (arg.initialValue) {
43086                                 if (arg.formType === 'number') {
43087                                     arg.input = parseInt(arg.initialValue);
43088                                 }
43089                                 else {
43090                                     arg.input = arg.initialValue;
43091                                 }
43092                             }
43093                         });
43094                     }
43095                     OptionController.$inject = [];
43096                     return OptionController;
43097                 })();
43098                 directives.OptionController = OptionController;
43099             })(directives = app.directives || (app.directives = {}));
43100         })(app || (app = {}));
43101         var app;
43102         (function (app) {
43103             var directives;
43104             (function (directives) {
43105                 var Directory = (function () {
43106                     function Directory() {
43107                         this.restrict = 'E';
43108                         this.replace = true;
43109                         this.controller = 'directoryController';
43110                         this.controllerAs = 'ctrl';
43111                         this.bindToController = {
43112                             info: '=',
43113                             add: '&',
43114                             list: '=',
43115                             files: '='
43116                         };
43117                         this.templateUrl = 'templates/directory.html';
43118                     }
43119                     Directory.Factory = function () {
43120                         var directive = function () {
43121                             return new Directory();
43122                         };
43123                         return directive;
43124                     };
43125                     return Directory;
43126                 })();
43127                 directives.Directory = Directory;
43128                 var DirectoryController = (function () {
43129                     function DirectoryController(APIEndPoint, $scope) {
43130                         this.APIEndPoint = APIEndPoint;
43131                         this.$scope = $scope;
43132                         var controller = this;
43133                         this.APIEndPoint
43134                             .getFiles(this.info.fileId)
43135                             .$promise
43136                             .then(function (result) {
43137                             if (result.status === 'success') {
43138                                 controller.files = result.info;
43139                                 angular.forEach(result.info, function (file) {
43140                                     if (file.fileType === '0') {
43141                                         var o = file;
43142                                         if (controller.info.path === '/') {
43143                                             o.path = '/' + file.name;
43144                                         }
43145                                         else {
43146                                             o.path = controller.info.path + '/' + file.name;
43147                                         }
43148                                         controller.add()(o, controller.list);
43149                                     }
43150                                 });
43151                             }
43152                             ;
43153                         });
43154                     }
43155                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
43156                     return DirectoryController;
43157                 })();
43158                 directives.DirectoryController = DirectoryController;
43159             })(directives = app.directives || (app.directives = {}));
43160         })(app || (app = {}));
43161         var app;
43162         (function (app) {
43163             var directives;
43164             (function (directives) {
43165                 var Upload = (function () {
43166                     function Upload() {
43167                         this.restrict = 'E';
43168                         this.replace = true;
43169                         this.scope = true;
43170                         this.controller = 'UploadController';
43171                         this.controllerAs = 'ctrl';
43172                         this.bindToController = {
43173                             index: '=',
43174                             name: '=',
43175                             remove: '&',
43176                             list: '='
43177                         };
43178                         this.templateUrl = 'templates/upload.html';
43179                         console.log("templates/upload.html-constructor");
43180                     }
43181                     Upload.Factory = function () {
43182                         var directive = function () {
43183                             return new Upload();
43184                         };
43185                         directive.$inject = [];
43186                         return directive;
43187                     };
43188                     return Upload;
43189                 })();
43190                 directives.Upload = Upload;
43191                 var UploadController = (function () {
43192                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
43193                         this.APIEndPoint = APIEndPoint;
43194                         this.$scope = $scope;
43195                         this.MyModal = MyModal;
43196                         this.WebSocket = WebSocket;
43197                         this.$window = $window;
43198                         this.$rootScope = $rootScope;
43199                         this.Console = Console;
43200                         var controller = this;
43201                         console.log("directive.upload-constructor");
43202                     }
43203                     UploadController.prototype.submit = function () {
43204                         console.log("submit: function not supported¥n");
43205                     };
43206                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
43207                     return UploadController;
43208                 })();
43209                 directives.UploadController = UploadController;
43210             })(directives = app.directives || (app.directives = {}));
43211         })(app || (app = {}));
43212         var app;
43213         (function (app) {
43214             var controllers;
43215             (function (controllers) {
43216                 var Execution = (function () {
43217                     function Execution(MyModal, $scope) {
43218                         this.MyModal = MyModal;
43219                         this.$scope = $scope;
43220                         this.commandInfoList = [];
43221                     }
43222                     ;
43223                     Execution.prototype.add = function () {
43224                         this.$scope.$broadcast('close');
43225                         var commandInfoList = this.commandInfoList;
43226                         var commandInstance = this.MyModal.selectCommand();
43227                         commandInstance
43228                             .result
43229                             .then(function (command) {
43230                             commandInfoList.push(new app.declares.CommandInfo(command));
43231                         });
43232                     };
43233                     Execution.prototype.open = function () {
43234                         var result = this.MyModal.open('SelectCommand');
43235                         console.log(result);
43236                     };
43237                     Execution.prototype.remove = function (index, list) {
43238                         list.splice(index, 1);
43239                     };
43240                     Execution.prototype.close = function () {
43241                         console.log("close");
43242                     };
43243                     Execution.$inject = ['MyModal', '$scope'];
43244                     return Execution;
43245                 })();
43246                 controllers.Execution = Execution;
43247             })(controllers = app.controllers || (app.controllers = {}));
43248         })(app || (app = {}));
43249         var app;
43250         (function (app) {
43251             var controllers;
43252             (function (controllers) {
43253                 var Workspace = (function () {
43254                     function Workspace($scope, APIEndPoint, MyModal) {
43255                         this.$scope = $scope;
43256                         this.APIEndPoint = APIEndPoint;
43257                         this.MyModal = MyModal;
43258                         this.directoryList = [];
43259                         var controller = this;
43260                         var directoryList = this.directoryList;
43261                         var o = {
43262                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
43263                             name: '',
43264                             parentId: '',
43265                             fileType: '',
43266                             createdAt: '',
43267                             updatedAt: '',
43268                             path: '/'
43269                         };
43270                         directoryList.push(o);
43271                     }
43272                     Workspace.prototype.addDirectory = function (info, directoryList) {
43273                         directoryList.push(info);
43274                     };
43275                     Workspace.prototype.upload = function () {
43276                         this.MyModal.upload();
43277                     };
43278                     Workspace.prototype.debug = function () {
43279                         this.MyModal.preview();
43280                     };
43281                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
43282                     return Workspace;
43283                 })();
43284                 controllers.Workspace = Workspace;
43285             })(controllers = app.controllers || (app.controllers = {}));
43286         })(app || (app = {}));
43287         var app;
43288         (function (app) {
43289             var controllers;
43290             (function (controllers) {
43291                 var History = (function () {
43292                     function History($scope) {
43293                         this.page = "History";
43294                     }
43295                     History.$inject = ['$scope'];
43296                     return History;
43297                 })();
43298                 controllers.History = History;
43299             })(controllers = app.controllers || (app.controllers = {}));
43300         })(app || (app = {}));
43301         var app;
43302         (function (app) {
43303             var controllers;
43304             (function (controllers) {
43305                 var SelectCommand = (function () {
43306                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
43307                         this.APIEndPoint = APIEndPoint;
43308                         this.$modalInstance = $modalInstance;
43309                         var controller = this;
43310                         this.APIEndPoint
43311                             .getTags()
43312                             .$promise.then(function (result) {
43313                             controller.tags = result.info;
43314                         });
43315                         this.APIEndPoint
43316                             .getCommands()
43317                             .$promise.then(function (result) {
43318                             controller.commands = result.info;
43319                         });
43320                         this.currentTag = 'all';
43321                     }
43322                     SelectCommand.prototype.changeTag = function (tag) {
43323                         this.currentTag = tag;
43324                     };
43325                     SelectCommand.prototype.selectCommand = function (command) {
43326                         this.$modalInstance.close(command);
43327                     };
43328                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43329                     return SelectCommand;
43330                 })();
43331                 controllers.SelectCommand = SelectCommand;
43332             })(controllers = app.controllers || (app.controllers = {}));
43333         })(app || (app = {}));
43334         var app;
43335         (function (app) {
43336             var controllers;
43337             (function (controllers) {
43338                 var Upload = (function () {
43339                     function Upload($scope, APIEndPoint, $modalInstance) {
43340                         this.APIEndPoint = APIEndPoint;
43341                         this.$modalInstance = $modalInstance;
43342                         var controller = this;
43343                         console.log('controller.upload-controllers');
43344                     }
43345                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43346                     return Upload;
43347                 })();
43348                 controllers.Upload = Upload;
43349             })(controllers = app.controllers || (app.controllers = {}));
43350         })(app || (app = {}));
43351         var app;
43352         (function (app) {
43353             var controllers;
43354             (function (controllers) {
43355                 var Preview = (function () {
43356                     function Preview($scope, APIEndPoint, $modalInstance) {
43357                         this.APIEndPoint = APIEndPoint;
43358                         this.$modalInstance = $modalInstance;
43359                         var controller = this;
43360                         console.log('preview');
43361                     }
43362                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
43363                     return Preview;
43364                 })();
43365                 controllers.Preview = Preview;
43366             })(controllers = app.controllers || (app.controllers = {}));
43367         })(app || (app = {}));
43368         var filters;
43369         (function (filters) {
43370             function Tag() {
43371                 return function (commands, tag) {
43372                     var result = [];
43373                     angular.forEach(commands, function (command) {
43374                         var flag = false;
43375                         angular.forEach(command.tags, function (value) {
43376                             if (tag === value)
43377                                 flag = true;
43378                         });
43379                         if (flag)
43380                             result.push(command);
43381                     });
43382                     return result;
43383                 };
43384             }
43385             filters.Tag = Tag;
43386         })(filters || (filters = {}));
43387         var app;
43388         (function (app) {
43389             'use strict';
43390             var appName = 'zephyr';
43391             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
43392             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
43393                 $urlRouterProvider.otherwise('/execution');
43394                 $locationProvider.html5Mode({
43395                     enabled: true,
43396                     requireBase: false
43397                 });
43398                 $stateProvider
43399                     .state('execution', {
43400                     url: '/execution',
43401                     templateUrl: 'templates/execution.html',
43402                     controller: 'executionController',
43403                     controllerAs: 'c'
43404                 })
43405                     .state('workspace', {
43406                     url: '/workspace',
43407                     templateUrl: 'templates/workspace.html',
43408                     controller: 'workspaceController',
43409                     controllerAs: 'c'
43410                 })
43411                     .state('history', {
43412                     url: '/history',
43413                     templateUrl: 'templates/history.html',
43414                     controller: 'historyController',
43415                     controllerAs: 'c'
43416                 });
43417             });
43418             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
43419             app.zephyr.service('MyModal', app.services.MyModal);
43420             app.zephyr.service('WebSocket', app.services.WebSocket);
43421             app.zephyr.service('Console', app.services.Console);
43422             app.zephyr.filter('Tag', filters.Tag);
43423             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
43424             app.zephyr.controller('previewController', app.controllers.Preview);
43425             app.zephyr.controller('uploadController', app.controllers.Upload);
43426             app.zephyr.controller('executionController', app.controllers.Execution);
43427             app.zephyr.controller('workspaceController', app.controllers.Workspace);
43428             app.zephyr.controller('historyController', app.controllers.History);
43429             app.zephyr.controller('commandController', app.directives.CommandController);
43430             app.zephyr.controller('optionController', app.directives.OptionController);
43431             app.zephyr.controller('directoryController', app.directives.DirectoryController);
43432             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
43433             app.zephyr.controller('uploadController', app.directives.UploadController);
43434             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
43435             app.zephyr.directive('command', app.directives.Command.Factory());
43436             app.zephyr.directive('option', app.directives.Option.Factory());
43437             app.zephyr.directive('directory', app.directives.Directory.Factory());
43438         })(app || (app = {}));
43439
43440
43441 /***/ },
43442 /* 10 */
43443 /***/ function(module, exports) {
43444
43445         var app;
43446         (function (app) {
43447             var declares;
43448             (function (declares) {
43449                 var CommandInfo = (function () {
43450                     function CommandInfo(name) {
43451                         this.name = name;
43452                     }
43453                     return CommandInfo;
43454                 })();
43455                 declares.CommandInfo = CommandInfo;
43456             })(declares = app.declares || (app.declares = {}));
43457         })(app || (app = {}));
43458         var app;
43459         (function (app) {
43460             var services;
43461             (function (services) {
43462                 var APIEndPoint = (function () {
43463                     function APIEndPoint($resource, $http) {
43464                         this.$resource = $resource;
43465                         this.$http = $http;
43466                     }
43467                     APIEndPoint.prototype.resource = function (endPoint, data) {
43468                         var customAction = {
43469                             method: 'GET',
43470                             isArray: false
43471                         };
43472                         var execute = {
43473                             method: 'POST',
43474                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
43475                         };
43476                         return this.$resource(endPoint, {}, { execute: execute });
43477                     };
43478                     APIEndPoint.prototype.getOptionControlFile = function (command) {
43479                         var endPoint = '/api/v1/optionControlFile/' + command;
43480                         return this.resource(endPoint, {}).get();
43481                     };
43482                     APIEndPoint.prototype.getFiles = function (fileId) {
43483                         var endPoint = '/api/v1/workspace';
43484                         if (fileId) {
43485                             endPoint += '/' + fileId;
43486                         }
43487                         return this.resource(endPoint, {}).get();
43488                     };
43489                     APIEndPoint.prototype.getDirectories = function () {
43490                         var endPoint = '/api/v1/all/workspace/directory';
43491                         return this.resource(endPoint, {}).get();
43492                     };
43493                     APIEndPoint.prototype.getTags = function () {
43494                         var endPoint = '/api/v1/tagList';
43495                         return this.resource(endPoint, {}).get();
43496                     };
43497                     APIEndPoint.prototype.getCommands = function () {
43498                         var endPoint = '/api/v1/commandList';
43499                         return this.resource(endPoint, {}).get();
43500                     };
43501                     APIEndPoint.prototype.execute = function (data) {
43502                         var endPoint = '/api/v1/execution';
43503                         var fd = new FormData();
43504                         fd.append('data', data);
43505                         return this.$http.post(endPoint, fd, {
43506                             headers: { 'Content-Type': undefined },
43507                             transformRequest: angular.identity
43508                         });
43509                     };
43510                     APIEndPoint.prototype.debug = function () {
43511                         var endPoint = '/api/v1/debug';
43512                         return this.$http.get(endPoint);
43513                     };
43514                     APIEndPoint.prototype.upload = function () {
43515                         var endPoint = '/api/v1/upload';
43516                         return this.$http.get(endPoint);
43517                     };
43518                     APIEndPoint.prototype.help = function (command) {
43519                         var endPoint = '/api/v1/help/' + command;
43520                         return this.$http.get(endPoint);
43521                     };
43522                     return APIEndPoint;
43523                 })();
43524                 services.APIEndPoint = APIEndPoint;
43525             })(services = app.services || (app.services = {}));
43526         })(app || (app = {}));
43527         var app;
43528         (function (app) {
43529             var services;
43530             (function (services) {
43531                 var MyModal = (function () {
43532                     function MyModal($uibModal) {
43533                         this.$uibModal = $uibModal;
43534                         this.modalOption = {
43535                             backdrop: true,
43536                             controller: null,
43537                             templateUrl: null,
43538                             size: null
43539                         };
43540                     }
43541                     MyModal.prototype.open = function (modalName) {
43542                         if (modalName === 'SelectCommand') {
43543                             this.modalOption.templateUrl = 'templates/select-command.html';
43544                             this.modalOption.size = 'lg';
43545                         }
43546                         return this.$uibModal.open(this.modalOption);
43547                     };
43548                     MyModal.prototype.selectCommand = function () {
43549                         this.modalOption.templateUrl = 'templates/select-command.html';
43550                         this.modalOption.controller = 'selectCommandController';
43551                         this.modalOption.controllerAs = 'c';
43552                         this.modalOption.size = 'lg';
43553                         return this.$uibModal.open(this.modalOption);
43554                     };
43555                     MyModal.prototype.preview = function () {
43556                         this.modalOption.templateUrl = 'templates/preview.html';
43557                         this.modalOption.controller = 'previewController';
43558                         this.modalOption.controllerAs = 'c';
43559                         this.modalOption.size = 'lg';
43560                         return this.$uibModal.open(this.modalOption);
43561                     };
43562                     MyModal.prototype.upload = function () {
43563                         this.modalOption.templateUrl = 'templates/upload.html';
43564                         this.modalOption.controller = 'uploadController';
43565                         this.modalOption.controllerAs = 'c';
43566                         this.modalOption.size = 'lg';
43567                         return this.$uibModal.open(this.modalOption);
43568                     };
43569                     MyModal.$inject = ['$uibModal'];
43570                     return MyModal;
43571                 })();
43572                 services.MyModal = MyModal;
43573             })(services = app.services || (app.services = {}));
43574         })(app || (app = {}));
43575         var app;
43576         (function (app) {
43577             var services;
43578             (function (services) {
43579                 var WebSocket = (function () {
43580                     function WebSocket($rootScope) {
43581                         this.$rootScope = $rootScope;
43582                         this.socket = io.connect();
43583                     }
43584                     WebSocket.prototype.on = function (eventName, callback) {
43585                         var socket = this.socket;
43586                         var rootScope = this.$rootScope;
43587                         socket.on(eventName, function () {
43588                             var args = arguments;
43589                             rootScope.$apply(function () {
43590                                 callback.apply(socket, args);
43591                             });
43592                         });
43593                     };
43594                     WebSocket.prototype.emit = function (eventName, data, callback) {
43595                         var socket = this.socket;
43596                         var rootScope = this.$rootScope;
43597                         this.socket.emit(eventName, data, function () {
43598                             var args = arguments;
43599                             rootScope.$apply(function () {
43600                                 if (callback)
43601                                     callback.apply(socket, args);
43602                             });
43603                         });
43604                     };
43605                     return WebSocket;
43606                 })();
43607                 services.WebSocket = WebSocket;
43608             })(services = app.services || (app.services = {}));
43609         })(app || (app = {}));
43610         var app;
43611         (function (app) {
43612             var services;
43613             (function (services) {
43614                 var Console = (function () {
43615                     function Console(WebSocket, $rootScope) {
43616                         this.WebSocket = WebSocket;
43617                         this.$rootScope = $rootScope;
43618                         this.WebSocket = WebSocket;
43619                         this.$rootScope = $rootScope;
43620                         this.directiveIDs = [];
43621                         var directiveIDs = this.directiveIDs;
43622                         this.WebSocket.on('console', function (d) {
43623                             var id = d.id;
43624                             var message = d.message;
43625                             if (directiveIDs.indexOf(id) > -1) {
43626                                 $rootScope.$emit(id, message);
43627                             }
43628                         });
43629                     }
43630                     Console.prototype.addDirective = function (id) {
43631                         if (!(this.directiveIDs.indexOf(id) > -1)) {
43632                             this.directiveIDs.push(id);
43633                         }
43634                     };
43635                     Console.prototype.removeDirective = function (id) {
43636                         var i = this.directiveIDs.indexOf(id);
43637                         if (i > -1) {
43638                             this.directiveIDs.splice(i, 1);
43639                         }
43640                     };
43641                     Console.prototype.showIDs = function () {
43642                         console.log(this.directiveIDs);
43643                     };
43644                     return Console;
43645                 })();
43646                 services.Console = Console;
43647             })(services = app.services || (app.services = {}));
43648         })(app || (app = {}));
43649         var app;
43650         (function (app) {
43651             var directives;
43652             (function (directives) {
43653                 var Command = (function () {
43654                     function Command() {
43655                         this.restrict = 'E';
43656                         this.replace = true;
43657                         this.scope = true;
43658                         this.controller = 'commandController';
43659                         this.controllerAs = 'ctrl';
43660                         this.bindToController = {
43661                             index: '=',
43662                             name: '=',
43663                             remove: '&',
43664                             list: '='
43665                         };
43666                         this.templateUrl = 'templates/command.html';
43667                     }
43668                     Command.Factory = function () {
43669                         var directive = function () {
43670                             return new Command();
43671                         };
43672                         directive.$inject = [];
43673                         return directive;
43674                     };
43675                     return Command;
43676                 })();
43677                 directives.Command = Command;
43678                 var CommandController = (function () {
43679                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
43680                         this.APIEndPoint = APIEndPoint;
43681                         this.$scope = $scope;
43682                         this.MyModal = MyModal;
43683                         this.WebSocket = WebSocket;
43684                         this.$window = $window;
43685                         this.$rootScope = $rootScope;
43686                         this.Console = Console;
43687                         var controller = this;
43688                         this.APIEndPoint
43689                             .getOptionControlFile(this.name)
43690                             .$promise
43691                             .then(function (result) {
43692                             controller.options = result.info;
43693                         });
43694                         this.APIEndPoint
43695                             .getDirectories()
43696                             .$promise
43697                             .then(function (result) {
43698                             controller.dirs = result.info;
43699                         });
43700                         this.heading = "[" + this.index + "]: dcdFilePrint";
43701                         this.isOpen = true;
43702                         this.$scope.$on('close', function () {
43703                             controller.isOpen = false;
43704                         });
43705                         function guid() {
43706                             function s4() {
43707                                 return Math.floor((1 + Math.random()) * 0x10000)
43708                                     .toString(16)
43709                                     .substring(1);
43710                             }
43711                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
43712                                 s4() + '-' + s4() + s4() + s4();
43713                         }
43714                         this.uuid = guid();
43715                         this.Console.addDirective(this.uuid);
43716                         this.Console.showIDs();
43717                     }
43718                     CommandController.prototype.submit = function () {
43719                         var opt = [];
43720                         angular.forEach(this.options, function (option) {
43721                             var obj = {
43722                                 name: option.option,
43723                                 arguments: []
43724                             };
43725                             angular.forEach(option.arg, function (arg) {
43726                                 if (arg.input) {
43727                                     if (typeof arg.input === 'object') {
43728                                         obj.arguments.push(arg.input.name);
43729                                     }
43730                                     else {
43731                                         obj.arguments.push(arg.input);
43732                                     }
43733                                 }
43734                             });
43735                             if (obj.arguments.length > 0) {
43736                                 opt.push(obj);
43737                             }
43738                         });
43739                         var execObj = {
43740                             command: this.name,
43741                             workspace: this.workspace.fileId,
43742                             options: opt
43743                         };
43744                         this.APIEndPoint
43745                             .execute(JSON.stringify(execObj))
43746                             .then(function (result) {
43747                             console.log(result);
43748                         });
43749                     };
43750                     CommandController.prototype.removeMySelf = function (index) {
43751                         this.$scope.$destroy();
43752                         this.Console.removeDirective(this.uuid);
43753                         this.remove()(index, this.list);
43754                         this.Console.showIDs();
43755                     };
43756                     CommandController.prototype.reloadFiles = function () {
43757                         var _this = this;
43758                         var fileId = this.workspace.fileId;
43759                         this.APIEndPoint
43760                             .getFiles(fileId)
43761                             .$promise
43762                             .then(function (result) {
43763                             var status = result.status;
43764                             if (status === 'success') {
43765                                 _this.files = result.info;
43766                             }
43767                             else {
43768                                 console.log(result.message);
43769                             }
43770                         });
43771                     };
43772                     CommandController.prototype.debug = function () {
43773                         var div = angular.element(this.$window.document).find("div");
43774                         var consoleTag;
43775                         var parametersTag;
43776                         angular.forEach(div, function (v) {
43777                             if (v.className === "panel-body console") {
43778                                 consoleTag = v;
43779                             }
43780                             else if (v.className === "row parameters-console") {
43781                                 parametersTag = v;
43782                             }
43783                         });
43784                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
43785                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
43786                         consoleTag.style.height = consoleHeight;
43787                         consoleTag.style.width = consoleWidth;
43788                     };
43789                     CommandController.prototype.help = function () {
43790                         this.APIEndPoint
43791                             .help(this.name)
43792                             .then(function (result) {
43793                             console.log(result);
43794                         });
43795                     };
43796                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
43797                     return CommandController;
43798                 })();
43799                 directives.CommandController = CommandController;
43800             })(directives = app.directives || (app.directives = {}));
43801         })(app || (app = {}));
43802         var app;
43803         (function (app) {
43804             var directives;
43805             (function (directives) {
43806                 var HeaderMenu = (function () {
43807                     function HeaderMenu() {
43808                         this.restrict = 'E';
43809                         this.replace = true;
43810                         this.templateUrl = 'templates/header-menu.html';
43811                         this.controller = 'HeaderMenuController';
43812                         this.controllerAs = 'hmc';
43813                         this.scope = true;
43814                     }
43815                     HeaderMenu.Factory = function () {
43816                         var directive = function () {
43817                             return new HeaderMenu();
43818                         };
43819                         return directive;
43820                     };
43821                     return HeaderMenu;
43822                 })();
43823                 directives.HeaderMenu = HeaderMenu;
43824                 var HeaderMenuController = (function () {
43825                     function HeaderMenuController($state) {
43826                         this.$state = $state;
43827                         this.isExecution = this.$state.current.name === 'execution';
43828                         this.isWorkspace = this.$state.current.name === 'workspace';
43829                         this.isHistory = this.$state.current.name === 'history';
43830                     }
43831                     HeaderMenuController.prototype.transit = function (state) {
43832                         this.$state.go(state);
43833                     };
43834                     HeaderMenuController.$inject = ['$state'];
43835                     return HeaderMenuController;
43836                 })();
43837                 directives.HeaderMenuController = HeaderMenuController;
43838             })(directives = app.directives || (app.directives = {}));
43839         })(app || (app = {}));
43840         var app;
43841         (function (app) {
43842             var directives;
43843             (function (directives) {
43844                 var Option = (function () {
43845                     function Option() {
43846                         this.restrict = 'E';
43847                         this.replace = true;
43848                         this.controller = 'optionController';
43849                         this.bindToController = {
43850                             info: '=',
43851                             files: '='
43852                         };
43853                         this.scope = true;
43854                         this.templateUrl = 'templates/option.html';
43855                         this.controllerAs = 'ctrl';
43856                     }
43857                     Option.Factory = function () {
43858                         var directive = function () {
43859                             return new Option();
43860                         };
43861                         directive.$inject = [];
43862                         return directive;
43863                     };
43864                     return Option;
43865                 })();
43866                 directives.Option = Option;
43867                 var OptionController = (function () {
43868                     function OptionController() {
43869                         var controller = this;
43870                         angular.forEach(controller.info.arg, function (arg) {
43871                             if (arg.initialValue) {
43872                                 if (arg.formType === 'number') {
43873                                     arg.input = parseInt(arg.initialValue);
43874                                 }
43875                                 else {
43876                                     arg.input = arg.initialValue;
43877                                 }
43878                             }
43879                         });
43880                     }
43881                     OptionController.$inject = [];
43882                     return OptionController;
43883                 })();
43884                 directives.OptionController = OptionController;
43885             })(directives = app.directives || (app.directives = {}));
43886         })(app || (app = {}));
43887         var app;
43888         (function (app) {
43889             var directives;
43890             (function (directives) {
43891                 var Directory = (function () {
43892                     function Directory() {
43893                         this.restrict = 'E';
43894                         this.replace = true;
43895                         this.controller = 'directoryController';
43896                         this.controllerAs = 'ctrl';
43897                         this.bindToController = {
43898                             info: '=',
43899                             add: '&',
43900                             list: '=',
43901                             files: '='
43902                         };
43903                         this.templateUrl = 'templates/directory.html';
43904                     }
43905                     Directory.Factory = function () {
43906                         var directive = function () {
43907                             return new Directory();
43908                         };
43909                         return directive;
43910                     };
43911                     return Directory;
43912                 })();
43913                 directives.Directory = Directory;
43914                 var DirectoryController = (function () {
43915                     function DirectoryController(APIEndPoint, $scope) {
43916                         this.APIEndPoint = APIEndPoint;
43917                         this.$scope = $scope;
43918                         var controller = this;
43919                         this.APIEndPoint
43920                             .getFiles(this.info.fileId)
43921                             .$promise
43922                             .then(function (result) {
43923                             if (result.status === 'success') {
43924                                 controller.files = result.info;
43925                                 angular.forEach(result.info, function (file) {
43926                                     if (file.fileType === '0') {
43927                                         var o = file;
43928                                         if (controller.info.path === '/') {
43929                                             o.path = '/' + file.name;
43930                                         }
43931                                         else {
43932                                             o.path = controller.info.path + '/' + file.name;
43933                                         }
43934                                         controller.add()(o, controller.list);
43935                                     }
43936                                 });
43937                             }
43938                             ;
43939                         });
43940                     }
43941                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
43942                     return DirectoryController;
43943                 })();
43944                 directives.DirectoryController = DirectoryController;
43945             })(directives = app.directives || (app.directives = {}));
43946         })(app || (app = {}));
43947         var app;
43948         (function (app) {
43949             var directives;
43950             (function (directives) {
43951                 var Upload = (function () {
43952                     function Upload() {
43953                         this.restrict = 'E';
43954                         this.replace = true;
43955                         this.scope = true;
43956                         this.controller = 'UploadController';
43957                         this.controllerAs = 'ctrl';
43958                         this.bindToController = {
43959                             index: '=',
43960                             name: '=',
43961                             remove: '&',
43962                             list: '='
43963                         };
43964                         this.templateUrl = 'templates/upload.html';
43965                         console.log("templates/upload.html-constructor");
43966                     }
43967                     Upload.Factory = function () {
43968                         var directive = function () {
43969                             return new Upload();
43970                         };
43971                         directive.$inject = [];
43972                         return directive;
43973                     };
43974                     return Upload;
43975                 })();
43976                 directives.Upload = Upload;
43977                 var UploadController = (function () {
43978                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
43979                         this.APIEndPoint = APIEndPoint;
43980                         this.$scope = $scope;
43981                         this.MyModal = MyModal;
43982                         this.WebSocket = WebSocket;
43983                         this.$window = $window;
43984                         this.$rootScope = $rootScope;
43985                         this.Console = Console;
43986                         var controller = this;
43987                         console.log("directive.upload-constructor");
43988                     }
43989                     UploadController.prototype.submit = function () {
43990                         console.log("submit: function not supported¥n");
43991                     };
43992                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
43993                     return UploadController;
43994                 })();
43995                 directives.UploadController = UploadController;
43996             })(directives = app.directives || (app.directives = {}));
43997         })(app || (app = {}));
43998         var app;
43999         (function (app) {
44000             var controllers;
44001             (function (controllers) {
44002                 var Execution = (function () {
44003                     function Execution(MyModal, $scope) {
44004                         this.MyModal = MyModal;
44005                         this.$scope = $scope;
44006                         this.commandInfoList = [];
44007                     }
44008                     ;
44009                     Execution.prototype.add = function () {
44010                         this.$scope.$broadcast('close');
44011                         var commandInfoList = this.commandInfoList;
44012                         var commandInstance = this.MyModal.selectCommand();
44013                         commandInstance
44014                             .result
44015                             .then(function (command) {
44016                             commandInfoList.push(new app.declares.CommandInfo(command));
44017                         });
44018                     };
44019                     Execution.prototype.open = function () {
44020                         var result = this.MyModal.open('SelectCommand');
44021                         console.log(result);
44022                     };
44023                     Execution.prototype.remove = function (index, list) {
44024                         list.splice(index, 1);
44025                     };
44026                     Execution.prototype.close = function () {
44027                         console.log("close");
44028                     };
44029                     Execution.$inject = ['MyModal', '$scope'];
44030                     return Execution;
44031                 })();
44032                 controllers.Execution = Execution;
44033             })(controllers = app.controllers || (app.controllers = {}));
44034         })(app || (app = {}));
44035         var app;
44036         (function (app) {
44037             var controllers;
44038             (function (controllers) {
44039                 var Workspace = (function () {
44040                     function Workspace($scope, APIEndPoint, MyModal) {
44041                         this.$scope = $scope;
44042                         this.APIEndPoint = APIEndPoint;
44043                         this.MyModal = MyModal;
44044                         this.directoryList = [];
44045                         var controller = this;
44046                         var directoryList = this.directoryList;
44047                         var o = {
44048                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
44049                             name: '',
44050                             parentId: '',
44051                             fileType: '',
44052                             createdAt: '',
44053                             updatedAt: '',
44054                             path: '/'
44055                         };
44056                         directoryList.push(o);
44057                     }
44058                     Workspace.prototype.addDirectory = function (info, directoryList) {
44059                         directoryList.push(info);
44060                     };
44061                     Workspace.prototype.upload = function () {
44062                         this.MyModal.upload();
44063                     };
44064                     Workspace.prototype.debug = function () {
44065                         this.MyModal.preview();
44066                     };
44067                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
44068                     return Workspace;
44069                 })();
44070                 controllers.Workspace = Workspace;
44071             })(controllers = app.controllers || (app.controllers = {}));
44072         })(app || (app = {}));
44073         var app;
44074         (function (app) {
44075             var controllers;
44076             (function (controllers) {
44077                 var History = (function () {
44078                     function History($scope) {
44079                         this.page = "History";
44080                     }
44081                     History.$inject = ['$scope'];
44082                     return History;
44083                 })();
44084                 controllers.History = History;
44085             })(controllers = app.controllers || (app.controllers = {}));
44086         })(app || (app = {}));
44087         var app;
44088         (function (app) {
44089             var controllers;
44090             (function (controllers) {
44091                 var SelectCommand = (function () {
44092                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
44093                         this.APIEndPoint = APIEndPoint;
44094                         this.$modalInstance = $modalInstance;
44095                         var controller = this;
44096                         this.APIEndPoint
44097                             .getTags()
44098                             .$promise.then(function (result) {
44099                             controller.tags = result.info;
44100                         });
44101                         this.APIEndPoint
44102                             .getCommands()
44103                             .$promise.then(function (result) {
44104                             controller.commands = result.info;
44105                         });
44106                         this.currentTag = 'all';
44107                     }
44108                     SelectCommand.prototype.changeTag = function (tag) {
44109                         this.currentTag = tag;
44110                     };
44111                     SelectCommand.prototype.selectCommand = function (command) {
44112                         this.$modalInstance.close(command);
44113                     };
44114                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44115                     return SelectCommand;
44116                 })();
44117                 controllers.SelectCommand = SelectCommand;
44118             })(controllers = app.controllers || (app.controllers = {}));
44119         })(app || (app = {}));
44120         var app;
44121         (function (app) {
44122             var controllers;
44123             (function (controllers) {
44124                 var Upload = (function () {
44125                     function Upload($scope, APIEndPoint, $modalInstance) {
44126                         this.APIEndPoint = APIEndPoint;
44127                         this.$modalInstance = $modalInstance;
44128                         var controller = this;
44129                         console.log('controller.upload-controllers');
44130                     }
44131                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44132                     return Upload;
44133                 })();
44134                 controllers.Upload = Upload;
44135             })(controllers = app.controllers || (app.controllers = {}));
44136         })(app || (app = {}));
44137         var app;
44138         (function (app) {
44139             var controllers;
44140             (function (controllers) {
44141                 var Preview = (function () {
44142                     function Preview($scope, APIEndPoint, $modalInstance) {
44143                         this.APIEndPoint = APIEndPoint;
44144                         this.$modalInstance = $modalInstance;
44145                         var controller = this;
44146                         console.log('preview');
44147                     }
44148                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44149                     return Preview;
44150                 })();
44151                 controllers.Preview = Preview;
44152             })(controllers = app.controllers || (app.controllers = {}));
44153         })(app || (app = {}));
44154         var filters;
44155         (function (filters) {
44156             function Tag() {
44157                 return function (commands, tag) {
44158                     var result = [];
44159                     angular.forEach(commands, function (command) {
44160                         var flag = false;
44161                         angular.forEach(command.tags, function (value) {
44162                             if (tag === value)
44163                                 flag = true;
44164                         });
44165                         if (flag)
44166                             result.push(command);
44167                     });
44168                     return result;
44169                 };
44170             }
44171             filters.Tag = Tag;
44172         })(filters || (filters = {}));
44173         var app;
44174         (function (app) {
44175             'use strict';
44176             var appName = 'zephyr';
44177             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
44178             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
44179                 $urlRouterProvider.otherwise('/execution');
44180                 $locationProvider.html5Mode({
44181                     enabled: true,
44182                     requireBase: false
44183                 });
44184                 $stateProvider
44185                     .state('execution', {
44186                     url: '/execution',
44187                     templateUrl: 'templates/execution.html',
44188                     controller: 'executionController',
44189                     controllerAs: 'c'
44190                 })
44191                     .state('workspace', {
44192                     url: '/workspace',
44193                     templateUrl: 'templates/workspace.html',
44194                     controller: 'workspaceController',
44195                     controllerAs: 'c'
44196                 })
44197                     .state('history', {
44198                     url: '/history',
44199                     templateUrl: 'templates/history.html',
44200                     controller: 'historyController',
44201                     controllerAs: 'c'
44202                 });
44203             });
44204             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
44205             app.zephyr.service('MyModal', app.services.MyModal);
44206             app.zephyr.service('WebSocket', app.services.WebSocket);
44207             app.zephyr.service('Console', app.services.Console);
44208             app.zephyr.filter('Tag', filters.Tag);
44209             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
44210             app.zephyr.controller('previewController', app.controllers.Preview);
44211             app.zephyr.controller('uploadController', app.controllers.Upload);
44212             app.zephyr.controller('executionController', app.controllers.Execution);
44213             app.zephyr.controller('workspaceController', app.controllers.Workspace);
44214             app.zephyr.controller('historyController', app.controllers.History);
44215             app.zephyr.controller('commandController', app.directives.CommandController);
44216             app.zephyr.controller('optionController', app.directives.OptionController);
44217             app.zephyr.controller('directoryController', app.directives.DirectoryController);
44218             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
44219             app.zephyr.controller('uploadController', app.directives.UploadController);
44220             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
44221             app.zephyr.directive('command', app.directives.Command.Factory());
44222             app.zephyr.directive('option', app.directives.Option.Factory());
44223             app.zephyr.directive('directory', app.directives.Directory.Factory());
44224         })(app || (app = {}));
44225
44226
44227 /***/ },
44228 /* 11 */
44229 /***/ function(module, exports) {
44230
44231         var app;
44232         (function (app) {
44233             var declares;
44234             (function (declares) {
44235                 var CommandInfo = (function () {
44236                     function CommandInfo(name) {
44237                         this.name = name;
44238                     }
44239                     return CommandInfo;
44240                 })();
44241                 declares.CommandInfo = CommandInfo;
44242             })(declares = app.declares || (app.declares = {}));
44243         })(app || (app = {}));
44244         var app;
44245         (function (app) {
44246             var services;
44247             (function (services) {
44248                 var APIEndPoint = (function () {
44249                     function APIEndPoint($resource, $http) {
44250                         this.$resource = $resource;
44251                         this.$http = $http;
44252                     }
44253                     APIEndPoint.prototype.resource = function (endPoint, data) {
44254                         var customAction = {
44255                             method: 'GET',
44256                             isArray: false
44257                         };
44258                         var execute = {
44259                             method: 'POST',
44260                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
44261                         };
44262                         return this.$resource(endPoint, {}, { execute: execute });
44263                     };
44264                     APIEndPoint.prototype.getOptionControlFile = function (command) {
44265                         var endPoint = '/api/v1/optionControlFile/' + command;
44266                         return this.resource(endPoint, {}).get();
44267                     };
44268                     APIEndPoint.prototype.getFiles = function (fileId) {
44269                         var endPoint = '/api/v1/workspace';
44270                         if (fileId) {
44271                             endPoint += '/' + fileId;
44272                         }
44273                         return this.resource(endPoint, {}).get();
44274                     };
44275                     APIEndPoint.prototype.getDirectories = function () {
44276                         var endPoint = '/api/v1/all/workspace/directory';
44277                         return this.resource(endPoint, {}).get();
44278                     };
44279                     APIEndPoint.prototype.getTags = function () {
44280                         var endPoint = '/api/v1/tagList';
44281                         return this.resource(endPoint, {}).get();
44282                     };
44283                     APIEndPoint.prototype.getCommands = function () {
44284                         var endPoint = '/api/v1/commandList';
44285                         return this.resource(endPoint, {}).get();
44286                     };
44287                     APIEndPoint.prototype.execute = function (data) {
44288                         var endPoint = '/api/v1/execution';
44289                         var fd = new FormData();
44290                         fd.append('data', data);
44291                         return this.$http.post(endPoint, fd, {
44292                             headers: { 'Content-Type': undefined },
44293                             transformRequest: angular.identity
44294                         });
44295                     };
44296                     APIEndPoint.prototype.debug = function () {
44297                         var endPoint = '/api/v1/debug';
44298                         return this.$http.get(endPoint);
44299                     };
44300                     APIEndPoint.prototype.upload = function () {
44301                         var endPoint = '/api/v1/upload';
44302                         return this.$http.get(endPoint);
44303                     };
44304                     APIEndPoint.prototype.help = function (command) {
44305                         var endPoint = '/api/v1/help/' + command;
44306                         return this.$http.get(endPoint);
44307                     };
44308                     return APIEndPoint;
44309                 })();
44310                 services.APIEndPoint = APIEndPoint;
44311             })(services = app.services || (app.services = {}));
44312         })(app || (app = {}));
44313         var app;
44314         (function (app) {
44315             var services;
44316             (function (services) {
44317                 var MyModal = (function () {
44318                     function MyModal($uibModal) {
44319                         this.$uibModal = $uibModal;
44320                         this.modalOption = {
44321                             backdrop: true,
44322                             controller: null,
44323                             templateUrl: null,
44324                             size: null
44325                         };
44326                     }
44327                     MyModal.prototype.open = function (modalName) {
44328                         if (modalName === 'SelectCommand') {
44329                             this.modalOption.templateUrl = 'templates/select-command.html';
44330                             this.modalOption.size = 'lg';
44331                         }
44332                         return this.$uibModal.open(this.modalOption);
44333                     };
44334                     MyModal.prototype.selectCommand = function () {
44335                         this.modalOption.templateUrl = 'templates/select-command.html';
44336                         this.modalOption.controller = 'selectCommandController';
44337                         this.modalOption.controllerAs = 'c';
44338                         this.modalOption.size = 'lg';
44339                         return this.$uibModal.open(this.modalOption);
44340                     };
44341                     MyModal.prototype.preview = function () {
44342                         this.modalOption.templateUrl = 'templates/preview.html';
44343                         this.modalOption.controller = 'previewController';
44344                         this.modalOption.controllerAs = 'c';
44345                         this.modalOption.size = 'lg';
44346                         return this.$uibModal.open(this.modalOption);
44347                     };
44348                     MyModal.prototype.upload = function () {
44349                         this.modalOption.templateUrl = 'templates/upload.html';
44350                         this.modalOption.controller = 'uploadController';
44351                         this.modalOption.controllerAs = 'c';
44352                         this.modalOption.size = 'lg';
44353                         return this.$uibModal.open(this.modalOption);
44354                     };
44355                     MyModal.$inject = ['$uibModal'];
44356                     return MyModal;
44357                 })();
44358                 services.MyModal = MyModal;
44359             })(services = app.services || (app.services = {}));
44360         })(app || (app = {}));
44361         var app;
44362         (function (app) {
44363             var services;
44364             (function (services) {
44365                 var WebSocket = (function () {
44366                     function WebSocket($rootScope) {
44367                         this.$rootScope = $rootScope;
44368                         this.socket = io.connect();
44369                     }
44370                     WebSocket.prototype.on = function (eventName, callback) {
44371                         var socket = this.socket;
44372                         var rootScope = this.$rootScope;
44373                         socket.on(eventName, function () {
44374                             var args = arguments;
44375                             rootScope.$apply(function () {
44376                                 callback.apply(socket, args);
44377                             });
44378                         });
44379                     };
44380                     WebSocket.prototype.emit = function (eventName, data, callback) {
44381                         var socket = this.socket;
44382                         var rootScope = this.$rootScope;
44383                         this.socket.emit(eventName, data, function () {
44384                             var args = arguments;
44385                             rootScope.$apply(function () {
44386                                 if (callback)
44387                                     callback.apply(socket, args);
44388                             });
44389                         });
44390                     };
44391                     return WebSocket;
44392                 })();
44393                 services.WebSocket = WebSocket;
44394             })(services = app.services || (app.services = {}));
44395         })(app || (app = {}));
44396         var app;
44397         (function (app) {
44398             var services;
44399             (function (services) {
44400                 var Console = (function () {
44401                     function Console(WebSocket, $rootScope) {
44402                         this.WebSocket = WebSocket;
44403                         this.$rootScope = $rootScope;
44404                         this.WebSocket = WebSocket;
44405                         this.$rootScope = $rootScope;
44406                         this.directiveIDs = [];
44407                         var directiveIDs = this.directiveIDs;
44408                         this.WebSocket.on('console', function (d) {
44409                             var id = d.id;
44410                             var message = d.message;
44411                             if (directiveIDs.indexOf(id) > -1) {
44412                                 $rootScope.$emit(id, message);
44413                             }
44414                         });
44415                     }
44416                     Console.prototype.addDirective = function (id) {
44417                         if (!(this.directiveIDs.indexOf(id) > -1)) {
44418                             this.directiveIDs.push(id);
44419                         }
44420                     };
44421                     Console.prototype.removeDirective = function (id) {
44422                         var i = this.directiveIDs.indexOf(id);
44423                         if (i > -1) {
44424                             this.directiveIDs.splice(i, 1);
44425                         }
44426                     };
44427                     Console.prototype.showIDs = function () {
44428                         console.log(this.directiveIDs);
44429                     };
44430                     return Console;
44431                 })();
44432                 services.Console = Console;
44433             })(services = app.services || (app.services = {}));
44434         })(app || (app = {}));
44435         var app;
44436         (function (app) {
44437             var directives;
44438             (function (directives) {
44439                 var Command = (function () {
44440                     function Command() {
44441                         this.restrict = 'E';
44442                         this.replace = true;
44443                         this.scope = true;
44444                         this.controller = 'commandController';
44445                         this.controllerAs = 'ctrl';
44446                         this.bindToController = {
44447                             index: '=',
44448                             name: '=',
44449                             remove: '&',
44450                             list: '='
44451                         };
44452                         this.templateUrl = 'templates/command.html';
44453                     }
44454                     Command.Factory = function () {
44455                         var directive = function () {
44456                             return new Command();
44457                         };
44458                         directive.$inject = [];
44459                         return directive;
44460                     };
44461                     return Command;
44462                 })();
44463                 directives.Command = Command;
44464                 var CommandController = (function () {
44465                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
44466                         this.APIEndPoint = APIEndPoint;
44467                         this.$scope = $scope;
44468                         this.MyModal = MyModal;
44469                         this.WebSocket = WebSocket;
44470                         this.$window = $window;
44471                         this.$rootScope = $rootScope;
44472                         this.Console = Console;
44473                         var controller = this;
44474                         this.APIEndPoint
44475                             .getOptionControlFile(this.name)
44476                             .$promise
44477                             .then(function (result) {
44478                             controller.options = result.info;
44479                         });
44480                         this.APIEndPoint
44481                             .getDirectories()
44482                             .$promise
44483                             .then(function (result) {
44484                             controller.dirs = result.info;
44485                         });
44486                         this.heading = "[" + this.index + "]: dcdFilePrint";
44487                         this.isOpen = true;
44488                         this.$scope.$on('close', function () {
44489                             controller.isOpen = false;
44490                         });
44491                         function guid() {
44492                             function s4() {
44493                                 return Math.floor((1 + Math.random()) * 0x10000)
44494                                     .toString(16)
44495                                     .substring(1);
44496                             }
44497                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
44498                                 s4() + '-' + s4() + s4() + s4();
44499                         }
44500                         this.uuid = guid();
44501                         this.Console.addDirective(this.uuid);
44502                         this.Console.showIDs();
44503                     }
44504                     CommandController.prototype.submit = function () {
44505                         var opt = [];
44506                         angular.forEach(this.options, function (option) {
44507                             var obj = {
44508                                 name: option.option,
44509                                 arguments: []
44510                             };
44511                             angular.forEach(option.arg, function (arg) {
44512                                 if (arg.input) {
44513                                     if (typeof arg.input === 'object') {
44514                                         obj.arguments.push(arg.input.name);
44515                                     }
44516                                     else {
44517                                         obj.arguments.push(arg.input);
44518                                     }
44519                                 }
44520                             });
44521                             if (obj.arguments.length > 0) {
44522                                 opt.push(obj);
44523                             }
44524                         });
44525                         var execObj = {
44526                             command: this.name,
44527                             workspace: this.workspace.fileId,
44528                             options: opt
44529                         };
44530                         this.APIEndPoint
44531                             .execute(JSON.stringify(execObj))
44532                             .then(function (result) {
44533                             console.log(result);
44534                         });
44535                     };
44536                     CommandController.prototype.removeMySelf = function (index) {
44537                         this.$scope.$destroy();
44538                         this.Console.removeDirective(this.uuid);
44539                         this.remove()(index, this.list);
44540                         this.Console.showIDs();
44541                     };
44542                     CommandController.prototype.reloadFiles = function () {
44543                         var _this = this;
44544                         var fileId = this.workspace.fileId;
44545                         this.APIEndPoint
44546                             .getFiles(fileId)
44547                             .$promise
44548                             .then(function (result) {
44549                             var status = result.status;
44550                             if (status === 'success') {
44551                                 _this.files = result.info;
44552                             }
44553                             else {
44554                                 console.log(result.message);
44555                             }
44556                         });
44557                     };
44558                     CommandController.prototype.debug = function () {
44559                         var div = angular.element(this.$window.document).find("div");
44560                         var consoleTag;
44561                         var parametersTag;
44562                         angular.forEach(div, function (v) {
44563                             if (v.className === "panel-body console") {
44564                                 consoleTag = v;
44565                             }
44566                             else if (v.className === "row parameters-console") {
44567                                 parametersTag = v;
44568                             }
44569                         });
44570                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
44571                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
44572                         consoleTag.style.height = consoleHeight;
44573                         consoleTag.style.width = consoleWidth;
44574                     };
44575                     CommandController.prototype.help = function () {
44576                         this.APIEndPoint
44577                             .help(this.name)
44578                             .then(function (result) {
44579                             console.log(result);
44580                         });
44581                     };
44582                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
44583                     return CommandController;
44584                 })();
44585                 directives.CommandController = CommandController;
44586             })(directives = app.directives || (app.directives = {}));
44587         })(app || (app = {}));
44588         var app;
44589         (function (app) {
44590             var directives;
44591             (function (directives) {
44592                 var HeaderMenu = (function () {
44593                     function HeaderMenu() {
44594                         this.restrict = 'E';
44595                         this.replace = true;
44596                         this.templateUrl = 'templates/header-menu.html';
44597                         this.controller = 'HeaderMenuController';
44598                         this.controllerAs = 'hmc';
44599                         this.scope = true;
44600                     }
44601                     HeaderMenu.Factory = function () {
44602                         var directive = function () {
44603                             return new HeaderMenu();
44604                         };
44605                         return directive;
44606                     };
44607                     return HeaderMenu;
44608                 })();
44609                 directives.HeaderMenu = HeaderMenu;
44610                 var HeaderMenuController = (function () {
44611                     function HeaderMenuController($state) {
44612                         this.$state = $state;
44613                         this.isExecution = this.$state.current.name === 'execution';
44614                         this.isWorkspace = this.$state.current.name === 'workspace';
44615                         this.isHistory = this.$state.current.name === 'history';
44616                     }
44617                     HeaderMenuController.prototype.transit = function (state) {
44618                         this.$state.go(state);
44619                     };
44620                     HeaderMenuController.$inject = ['$state'];
44621                     return HeaderMenuController;
44622                 })();
44623                 directives.HeaderMenuController = HeaderMenuController;
44624             })(directives = app.directives || (app.directives = {}));
44625         })(app || (app = {}));
44626         var app;
44627         (function (app) {
44628             var directives;
44629             (function (directives) {
44630                 var Option = (function () {
44631                     function Option() {
44632                         this.restrict = 'E';
44633                         this.replace = true;
44634                         this.controller = 'optionController';
44635                         this.bindToController = {
44636                             info: '=',
44637                             files: '='
44638                         };
44639                         this.scope = true;
44640                         this.templateUrl = 'templates/option.html';
44641                         this.controllerAs = 'ctrl';
44642                     }
44643                     Option.Factory = function () {
44644                         var directive = function () {
44645                             return new Option();
44646                         };
44647                         directive.$inject = [];
44648                         return directive;
44649                     };
44650                     return Option;
44651                 })();
44652                 directives.Option = Option;
44653                 var OptionController = (function () {
44654                     function OptionController() {
44655                         var controller = this;
44656                         angular.forEach(controller.info.arg, function (arg) {
44657                             if (arg.initialValue) {
44658                                 if (arg.formType === 'number') {
44659                                     arg.input = parseInt(arg.initialValue);
44660                                 }
44661                                 else {
44662                                     arg.input = arg.initialValue;
44663                                 }
44664                             }
44665                         });
44666                     }
44667                     OptionController.$inject = [];
44668                     return OptionController;
44669                 })();
44670                 directives.OptionController = OptionController;
44671             })(directives = app.directives || (app.directives = {}));
44672         })(app || (app = {}));
44673         var app;
44674         (function (app) {
44675             var directives;
44676             (function (directives) {
44677                 var Directory = (function () {
44678                     function Directory() {
44679                         this.restrict = 'E';
44680                         this.replace = true;
44681                         this.controller = 'directoryController';
44682                         this.controllerAs = 'ctrl';
44683                         this.bindToController = {
44684                             info: '=',
44685                             add: '&',
44686                             list: '=',
44687                             files: '='
44688                         };
44689                         this.templateUrl = 'templates/directory.html';
44690                     }
44691                     Directory.Factory = function () {
44692                         var directive = function () {
44693                             return new Directory();
44694                         };
44695                         return directive;
44696                     };
44697                     return Directory;
44698                 })();
44699                 directives.Directory = Directory;
44700                 var DirectoryController = (function () {
44701                     function DirectoryController(APIEndPoint, $scope) {
44702                         this.APIEndPoint = APIEndPoint;
44703                         this.$scope = $scope;
44704                         var controller = this;
44705                         this.APIEndPoint
44706                             .getFiles(this.info.fileId)
44707                             .$promise
44708                             .then(function (result) {
44709                             if (result.status === 'success') {
44710                                 controller.files = result.info;
44711                                 angular.forEach(result.info, function (file) {
44712                                     if (file.fileType === '0') {
44713                                         var o = file;
44714                                         if (controller.info.path === '/') {
44715                                             o.path = '/' + file.name;
44716                                         }
44717                                         else {
44718                                             o.path = controller.info.path + '/' + file.name;
44719                                         }
44720                                         controller.add()(o, controller.list);
44721                                     }
44722                                 });
44723                             }
44724                             ;
44725                         });
44726                     }
44727                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
44728                     return DirectoryController;
44729                 })();
44730                 directives.DirectoryController = DirectoryController;
44731             })(directives = app.directives || (app.directives = {}));
44732         })(app || (app = {}));
44733         var app;
44734         (function (app) {
44735             var directives;
44736             (function (directives) {
44737                 var Upload = (function () {
44738                     function Upload() {
44739                         this.restrict = 'E';
44740                         this.replace = true;
44741                         this.scope = true;
44742                         this.controller = 'UploadController';
44743                         this.controllerAs = 'ctrl';
44744                         this.bindToController = {
44745                             index: '=',
44746                             name: '=',
44747                             remove: '&',
44748                             list: '='
44749                         };
44750                         this.templateUrl = 'templates/upload.html';
44751                         console.log("templates/upload.html-constructor");
44752                     }
44753                     Upload.Factory = function () {
44754                         var directive = function () {
44755                             return new Upload();
44756                         };
44757                         directive.$inject = [];
44758                         return directive;
44759                     };
44760                     return Upload;
44761                 })();
44762                 directives.Upload = Upload;
44763                 var UploadController = (function () {
44764                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
44765                         this.APIEndPoint = APIEndPoint;
44766                         this.$scope = $scope;
44767                         this.MyModal = MyModal;
44768                         this.WebSocket = WebSocket;
44769                         this.$window = $window;
44770                         this.$rootScope = $rootScope;
44771                         this.Console = Console;
44772                         var controller = this;
44773                         console.log("directive.upload-constructor");
44774                     }
44775                     UploadController.prototype.submit = function () {
44776                         console.log("submit: function not supported¥n");
44777                     };
44778                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
44779                     return UploadController;
44780                 })();
44781                 directives.UploadController = UploadController;
44782             })(directives = app.directives || (app.directives = {}));
44783         })(app || (app = {}));
44784         var app;
44785         (function (app) {
44786             var controllers;
44787             (function (controllers) {
44788                 var Execution = (function () {
44789                     function Execution(MyModal, $scope) {
44790                         this.MyModal = MyModal;
44791                         this.$scope = $scope;
44792                         this.commandInfoList = [];
44793                     }
44794                     ;
44795                     Execution.prototype.add = function () {
44796                         this.$scope.$broadcast('close');
44797                         var commandInfoList = this.commandInfoList;
44798                         var commandInstance = this.MyModal.selectCommand();
44799                         commandInstance
44800                             .result
44801                             .then(function (command) {
44802                             commandInfoList.push(new app.declares.CommandInfo(command));
44803                         });
44804                     };
44805                     Execution.prototype.open = function () {
44806                         var result = this.MyModal.open('SelectCommand');
44807                         console.log(result);
44808                     };
44809                     Execution.prototype.remove = function (index, list) {
44810                         list.splice(index, 1);
44811                     };
44812                     Execution.prototype.close = function () {
44813                         console.log("close");
44814                     };
44815                     Execution.$inject = ['MyModal', '$scope'];
44816                     return Execution;
44817                 })();
44818                 controllers.Execution = Execution;
44819             })(controllers = app.controllers || (app.controllers = {}));
44820         })(app || (app = {}));
44821         var app;
44822         (function (app) {
44823             var controllers;
44824             (function (controllers) {
44825                 var Workspace = (function () {
44826                     function Workspace($scope, APIEndPoint, MyModal) {
44827                         this.$scope = $scope;
44828                         this.APIEndPoint = APIEndPoint;
44829                         this.MyModal = MyModal;
44830                         this.directoryList = [];
44831                         var controller = this;
44832                         var directoryList = this.directoryList;
44833                         var o = {
44834                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
44835                             name: '',
44836                             parentId: '',
44837                             fileType: '',
44838                             createdAt: '',
44839                             updatedAt: '',
44840                             path: '/'
44841                         };
44842                         directoryList.push(o);
44843                     }
44844                     Workspace.prototype.addDirectory = function (info, directoryList) {
44845                         directoryList.push(info);
44846                     };
44847                     Workspace.prototype.upload = function () {
44848                         this.MyModal.upload();
44849                     };
44850                     Workspace.prototype.debug = function () {
44851                         this.MyModal.preview();
44852                     };
44853                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
44854                     return Workspace;
44855                 })();
44856                 controllers.Workspace = Workspace;
44857             })(controllers = app.controllers || (app.controllers = {}));
44858         })(app || (app = {}));
44859         var app;
44860         (function (app) {
44861             var controllers;
44862             (function (controllers) {
44863                 var History = (function () {
44864                     function History($scope) {
44865                         this.page = "History";
44866                     }
44867                     History.$inject = ['$scope'];
44868                     return History;
44869                 })();
44870                 controllers.History = History;
44871             })(controllers = app.controllers || (app.controllers = {}));
44872         })(app || (app = {}));
44873         var app;
44874         (function (app) {
44875             var controllers;
44876             (function (controllers) {
44877                 var SelectCommand = (function () {
44878                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
44879                         this.APIEndPoint = APIEndPoint;
44880                         this.$modalInstance = $modalInstance;
44881                         var controller = this;
44882                         this.APIEndPoint
44883                             .getTags()
44884                             .$promise.then(function (result) {
44885                             controller.tags = result.info;
44886                         });
44887                         this.APIEndPoint
44888                             .getCommands()
44889                             .$promise.then(function (result) {
44890                             controller.commands = result.info;
44891                         });
44892                         this.currentTag = 'all';
44893                     }
44894                     SelectCommand.prototype.changeTag = function (tag) {
44895                         this.currentTag = tag;
44896                     };
44897                     SelectCommand.prototype.selectCommand = function (command) {
44898                         this.$modalInstance.close(command);
44899                     };
44900                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44901                     return SelectCommand;
44902                 })();
44903                 controllers.SelectCommand = SelectCommand;
44904             })(controllers = app.controllers || (app.controllers = {}));
44905         })(app || (app = {}));
44906         var app;
44907         (function (app) {
44908             var controllers;
44909             (function (controllers) {
44910                 var Upload = (function () {
44911                     function Upload($scope, APIEndPoint, $modalInstance) {
44912                         this.APIEndPoint = APIEndPoint;
44913                         this.$modalInstance = $modalInstance;
44914                         var controller = this;
44915                         console.log('controller.upload-controllers');
44916                     }
44917                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44918                     return Upload;
44919                 })();
44920                 controllers.Upload = Upload;
44921             })(controllers = app.controllers || (app.controllers = {}));
44922         })(app || (app = {}));
44923         var app;
44924         (function (app) {
44925             var controllers;
44926             (function (controllers) {
44927                 var Preview = (function () {
44928                     function Preview($scope, APIEndPoint, $modalInstance) {
44929                         this.APIEndPoint = APIEndPoint;
44930                         this.$modalInstance = $modalInstance;
44931                         var controller = this;
44932                         console.log('preview');
44933                     }
44934                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
44935                     return Preview;
44936                 })();
44937                 controllers.Preview = Preview;
44938             })(controllers = app.controllers || (app.controllers = {}));
44939         })(app || (app = {}));
44940         var filters;
44941         (function (filters) {
44942             function Tag() {
44943                 return function (commands, tag) {
44944                     var result = [];
44945                     angular.forEach(commands, function (command) {
44946                         var flag = false;
44947                         angular.forEach(command.tags, function (value) {
44948                             if (tag === value)
44949                                 flag = true;
44950                         });
44951                         if (flag)
44952                             result.push(command);
44953                     });
44954                     return result;
44955                 };
44956             }
44957             filters.Tag = Tag;
44958         })(filters || (filters = {}));
44959         var app;
44960         (function (app) {
44961             'use strict';
44962             var appName = 'zephyr';
44963             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
44964             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
44965                 $urlRouterProvider.otherwise('/execution');
44966                 $locationProvider.html5Mode({
44967                     enabled: true,
44968                     requireBase: false
44969                 });
44970                 $stateProvider
44971                     .state('execution', {
44972                     url: '/execution',
44973                     templateUrl: 'templates/execution.html',
44974                     controller: 'executionController',
44975                     controllerAs: 'c'
44976                 })
44977                     .state('workspace', {
44978                     url: '/workspace',
44979                     templateUrl: 'templates/workspace.html',
44980                     controller: 'workspaceController',
44981                     controllerAs: 'c'
44982                 })
44983                     .state('history', {
44984                     url: '/history',
44985                     templateUrl: 'templates/history.html',
44986                     controller: 'historyController',
44987                     controllerAs: 'c'
44988                 });
44989             });
44990             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
44991             app.zephyr.service('MyModal', app.services.MyModal);
44992             app.zephyr.service('WebSocket', app.services.WebSocket);
44993             app.zephyr.service('Console', app.services.Console);
44994             app.zephyr.filter('Tag', filters.Tag);
44995             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
44996             app.zephyr.controller('previewController', app.controllers.Preview);
44997             app.zephyr.controller('uploadController', app.controllers.Upload);
44998             app.zephyr.controller('executionController', app.controllers.Execution);
44999             app.zephyr.controller('workspaceController', app.controllers.Workspace);
45000             app.zephyr.controller('historyController', app.controllers.History);
45001             app.zephyr.controller('commandController', app.directives.CommandController);
45002             app.zephyr.controller('optionController', app.directives.OptionController);
45003             app.zephyr.controller('directoryController', app.directives.DirectoryController);
45004             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
45005             app.zephyr.controller('uploadController', app.directives.UploadController);
45006             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
45007             app.zephyr.directive('command', app.directives.Command.Factory());
45008             app.zephyr.directive('option', app.directives.Option.Factory());
45009             app.zephyr.directive('directory', app.directives.Directory.Factory());
45010         })(app || (app = {}));
45011
45012
45013 /***/ },
45014 /* 12 */
45015 /***/ function(module, exports) {
45016
45017         var app;
45018         (function (app) {
45019             var declares;
45020             (function (declares) {
45021                 var CommandInfo = (function () {
45022                     function CommandInfo(name) {
45023                         this.name = name;
45024                     }
45025                     return CommandInfo;
45026                 })();
45027                 declares.CommandInfo = CommandInfo;
45028             })(declares = app.declares || (app.declares = {}));
45029         })(app || (app = {}));
45030         var app;
45031         (function (app) {
45032             var services;
45033             (function (services) {
45034                 var APIEndPoint = (function () {
45035                     function APIEndPoint($resource, $http) {
45036                         this.$resource = $resource;
45037                         this.$http = $http;
45038                     }
45039                     APIEndPoint.prototype.resource = function (endPoint, data) {
45040                         var customAction = {
45041                             method: 'GET',
45042                             isArray: false
45043                         };
45044                         var execute = {
45045                             method: 'POST',
45046                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
45047                         };
45048                         return this.$resource(endPoint, {}, { execute: execute });
45049                     };
45050                     APIEndPoint.prototype.getOptionControlFile = function (command) {
45051                         var endPoint = '/api/v1/optionControlFile/' + command;
45052                         return this.resource(endPoint, {}).get();
45053                     };
45054                     APIEndPoint.prototype.getFiles = function (fileId) {
45055                         var endPoint = '/api/v1/workspace';
45056                         if (fileId) {
45057                             endPoint += '/' + fileId;
45058                         }
45059                         return this.resource(endPoint, {}).get();
45060                     };
45061                     APIEndPoint.prototype.getDirectories = function () {
45062                         var endPoint = '/api/v1/all/workspace/directory';
45063                         return this.resource(endPoint, {}).get();
45064                     };
45065                     APIEndPoint.prototype.getTags = function () {
45066                         var endPoint = '/api/v1/tagList';
45067                         return this.resource(endPoint, {}).get();
45068                     };
45069                     APIEndPoint.prototype.getCommands = function () {
45070                         var endPoint = '/api/v1/commandList';
45071                         return this.resource(endPoint, {}).get();
45072                     };
45073                     APIEndPoint.prototype.execute = function (data) {
45074                         var endPoint = '/api/v1/execution';
45075                         var fd = new FormData();
45076                         fd.append('data', data);
45077                         return this.$http.post(endPoint, fd, {
45078                             headers: { 'Content-Type': undefined },
45079                             transformRequest: angular.identity
45080                         });
45081                     };
45082                     APIEndPoint.prototype.debug = function () {
45083                         var endPoint = '/api/v1/debug';
45084                         return this.$http.get(endPoint);
45085                     };
45086                     APIEndPoint.prototype.upload = function () {
45087                         var endPoint = '/api/v1/upload';
45088                         return this.$http.get(endPoint);
45089                     };
45090                     APIEndPoint.prototype.help = function (command) {
45091                         var endPoint = '/api/v1/help/' + command;
45092                         return this.$http.get(endPoint);
45093                     };
45094                     return APIEndPoint;
45095                 })();
45096                 services.APIEndPoint = APIEndPoint;
45097             })(services = app.services || (app.services = {}));
45098         })(app || (app = {}));
45099         var app;
45100         (function (app) {
45101             var services;
45102             (function (services) {
45103                 var MyModal = (function () {
45104                     function MyModal($uibModal) {
45105                         this.$uibModal = $uibModal;
45106                         this.modalOption = {
45107                             backdrop: true,
45108                             controller: null,
45109                             templateUrl: null,
45110                             size: null
45111                         };
45112                     }
45113                     MyModal.prototype.open = function (modalName) {
45114                         if (modalName === 'SelectCommand') {
45115                             this.modalOption.templateUrl = 'templates/select-command.html';
45116                             this.modalOption.size = 'lg';
45117                         }
45118                         return this.$uibModal.open(this.modalOption);
45119                     };
45120                     MyModal.prototype.selectCommand = function () {
45121                         this.modalOption.templateUrl = 'templates/select-command.html';
45122                         this.modalOption.controller = 'selectCommandController';
45123                         this.modalOption.controllerAs = 'c';
45124                         this.modalOption.size = 'lg';
45125                         return this.$uibModal.open(this.modalOption);
45126                     };
45127                     MyModal.prototype.preview = function () {
45128                         this.modalOption.templateUrl = 'templates/preview.html';
45129                         this.modalOption.controller = 'previewController';
45130                         this.modalOption.controllerAs = 'c';
45131                         this.modalOption.size = 'lg';
45132                         return this.$uibModal.open(this.modalOption);
45133                     };
45134                     MyModal.prototype.upload = function () {
45135                         this.modalOption.templateUrl = 'templates/upload.html';
45136                         this.modalOption.controller = 'uploadController';
45137                         this.modalOption.controllerAs = 'c';
45138                         this.modalOption.size = 'lg';
45139                         return this.$uibModal.open(this.modalOption);
45140                     };
45141                     MyModal.$inject = ['$uibModal'];
45142                     return MyModal;
45143                 })();
45144                 services.MyModal = MyModal;
45145             })(services = app.services || (app.services = {}));
45146         })(app || (app = {}));
45147         var app;
45148         (function (app) {
45149             var services;
45150             (function (services) {
45151                 var WebSocket = (function () {
45152                     function WebSocket($rootScope) {
45153                         this.$rootScope = $rootScope;
45154                         this.socket = io.connect();
45155                     }
45156                     WebSocket.prototype.on = function (eventName, callback) {
45157                         var socket = this.socket;
45158                         var rootScope = this.$rootScope;
45159                         socket.on(eventName, function () {
45160                             var args = arguments;
45161                             rootScope.$apply(function () {
45162                                 callback.apply(socket, args);
45163                             });
45164                         });
45165                     };
45166                     WebSocket.prototype.emit = function (eventName, data, callback) {
45167                         var socket = this.socket;
45168                         var rootScope = this.$rootScope;
45169                         this.socket.emit(eventName, data, function () {
45170                             var args = arguments;
45171                             rootScope.$apply(function () {
45172                                 if (callback)
45173                                     callback.apply(socket, args);
45174                             });
45175                         });
45176                     };
45177                     return WebSocket;
45178                 })();
45179                 services.WebSocket = WebSocket;
45180             })(services = app.services || (app.services = {}));
45181         })(app || (app = {}));
45182         var app;
45183         (function (app) {
45184             var services;
45185             (function (services) {
45186                 var Console = (function () {
45187                     function Console(WebSocket, $rootScope) {
45188                         this.WebSocket = WebSocket;
45189                         this.$rootScope = $rootScope;
45190                         this.WebSocket = WebSocket;
45191                         this.$rootScope = $rootScope;
45192                         this.directiveIDs = [];
45193                         var directiveIDs = this.directiveIDs;
45194                         this.WebSocket.on('console', function (d) {
45195                             var id = d.id;
45196                             var message = d.message;
45197                             if (directiveIDs.indexOf(id) > -1) {
45198                                 $rootScope.$emit(id, message);
45199                             }
45200                         });
45201                     }
45202                     Console.prototype.addDirective = function (id) {
45203                         if (!(this.directiveIDs.indexOf(id) > -1)) {
45204                             this.directiveIDs.push(id);
45205                         }
45206                     };
45207                     Console.prototype.removeDirective = function (id) {
45208                         var i = this.directiveIDs.indexOf(id);
45209                         if (i > -1) {
45210                             this.directiveIDs.splice(i, 1);
45211                         }
45212                     };
45213                     Console.prototype.showIDs = function () {
45214                         console.log(this.directiveIDs);
45215                     };
45216                     return Console;
45217                 })();
45218                 services.Console = Console;
45219             })(services = app.services || (app.services = {}));
45220         })(app || (app = {}));
45221         var app;
45222         (function (app) {
45223             var directives;
45224             (function (directives) {
45225                 var Command = (function () {
45226                     function Command() {
45227                         this.restrict = 'E';
45228                         this.replace = true;
45229                         this.scope = true;
45230                         this.controller = 'commandController';
45231                         this.controllerAs = 'ctrl';
45232                         this.bindToController = {
45233                             index: '=',
45234                             name: '=',
45235                             remove: '&',
45236                             list: '='
45237                         };
45238                         this.templateUrl = 'templates/command.html';
45239                     }
45240                     Command.Factory = function () {
45241                         var directive = function () {
45242                             return new Command();
45243                         };
45244                         directive.$inject = [];
45245                         return directive;
45246                     };
45247                     return Command;
45248                 })();
45249                 directives.Command = Command;
45250                 var CommandController = (function () {
45251                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
45252                         this.APIEndPoint = APIEndPoint;
45253                         this.$scope = $scope;
45254                         this.MyModal = MyModal;
45255                         this.WebSocket = WebSocket;
45256                         this.$window = $window;
45257                         this.$rootScope = $rootScope;
45258                         this.Console = Console;
45259                         var controller = this;
45260                         this.APIEndPoint
45261                             .getOptionControlFile(this.name)
45262                             .$promise
45263                             .then(function (result) {
45264                             controller.options = result.info;
45265                         });
45266                         this.APIEndPoint
45267                             .getDirectories()
45268                             .$promise
45269                             .then(function (result) {
45270                             controller.dirs = result.info;
45271                         });
45272                         this.heading = "[" + this.index + "]: dcdFilePrint";
45273                         this.isOpen = true;
45274                         this.$scope.$on('close', function () {
45275                             controller.isOpen = false;
45276                         });
45277                         function guid() {
45278                             function s4() {
45279                                 return Math.floor((1 + Math.random()) * 0x10000)
45280                                     .toString(16)
45281                                     .substring(1);
45282                             }
45283                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
45284                                 s4() + '-' + s4() + s4() + s4();
45285                         }
45286                         this.uuid = guid();
45287                         this.Console.addDirective(this.uuid);
45288                         this.Console.showIDs();
45289                     }
45290                     CommandController.prototype.submit = function () {
45291                         var opt = [];
45292                         angular.forEach(this.options, function (option) {
45293                             var obj = {
45294                                 name: option.option,
45295                                 arguments: []
45296                             };
45297                             angular.forEach(option.arg, function (arg) {
45298                                 if (arg.input) {
45299                                     if (typeof arg.input === 'object') {
45300                                         obj.arguments.push(arg.input.name);
45301                                     }
45302                                     else {
45303                                         obj.arguments.push(arg.input);
45304                                     }
45305                                 }
45306                             });
45307                             if (obj.arguments.length > 0) {
45308                                 opt.push(obj);
45309                             }
45310                         });
45311                         var execObj = {
45312                             command: this.name,
45313                             workspace: this.workspace.fileId,
45314                             options: opt
45315                         };
45316                         this.APIEndPoint
45317                             .execute(JSON.stringify(execObj))
45318                             .then(function (result) {
45319                             console.log(result);
45320                         });
45321                     };
45322                     CommandController.prototype.removeMySelf = function (index) {
45323                         this.$scope.$destroy();
45324                         this.Console.removeDirective(this.uuid);
45325                         this.remove()(index, this.list);
45326                         this.Console.showIDs();
45327                     };
45328                     CommandController.prototype.reloadFiles = function () {
45329                         var _this = this;
45330                         var fileId = this.workspace.fileId;
45331                         this.APIEndPoint
45332                             .getFiles(fileId)
45333                             .$promise
45334                             .then(function (result) {
45335                             var status = result.status;
45336                             if (status === 'success') {
45337                                 _this.files = result.info;
45338                             }
45339                             else {
45340                                 console.log(result.message);
45341                             }
45342                         });
45343                     };
45344                     CommandController.prototype.debug = function () {
45345                         var div = angular.element(this.$window.document).find("div");
45346                         var consoleTag;
45347                         var parametersTag;
45348                         angular.forEach(div, function (v) {
45349                             if (v.className === "panel-body console") {
45350                                 consoleTag = v;
45351                             }
45352                             else if (v.className === "row parameters-console") {
45353                                 parametersTag = v;
45354                             }
45355                         });
45356                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
45357                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
45358                         consoleTag.style.height = consoleHeight;
45359                         consoleTag.style.width = consoleWidth;
45360                     };
45361                     CommandController.prototype.help = function () {
45362                         this.APIEndPoint
45363                             .help(this.name)
45364                             .then(function (result) {
45365                             console.log(result);
45366                         });
45367                     };
45368                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
45369                     return CommandController;
45370                 })();
45371                 directives.CommandController = CommandController;
45372             })(directives = app.directives || (app.directives = {}));
45373         })(app || (app = {}));
45374         var app;
45375         (function (app) {
45376             var directives;
45377             (function (directives) {
45378                 var HeaderMenu = (function () {
45379                     function HeaderMenu() {
45380                         this.restrict = 'E';
45381                         this.replace = true;
45382                         this.templateUrl = 'templates/header-menu.html';
45383                         this.controller = 'HeaderMenuController';
45384                         this.controllerAs = 'hmc';
45385                         this.scope = true;
45386                     }
45387                     HeaderMenu.Factory = function () {
45388                         var directive = function () {
45389                             return new HeaderMenu();
45390                         };
45391                         return directive;
45392                     };
45393                     return HeaderMenu;
45394                 })();
45395                 directives.HeaderMenu = HeaderMenu;
45396                 var HeaderMenuController = (function () {
45397                     function HeaderMenuController($state) {
45398                         this.$state = $state;
45399                         this.isExecution = this.$state.current.name === 'execution';
45400                         this.isWorkspace = this.$state.current.name === 'workspace';
45401                         this.isHistory = this.$state.current.name === 'history';
45402                     }
45403                     HeaderMenuController.prototype.transit = function (state) {
45404                         this.$state.go(state);
45405                     };
45406                     HeaderMenuController.$inject = ['$state'];
45407                     return HeaderMenuController;
45408                 })();
45409                 directives.HeaderMenuController = HeaderMenuController;
45410             })(directives = app.directives || (app.directives = {}));
45411         })(app || (app = {}));
45412         var app;
45413         (function (app) {
45414             var directives;
45415             (function (directives) {
45416                 var Option = (function () {
45417                     function Option() {
45418                         this.restrict = 'E';
45419                         this.replace = true;
45420                         this.controller = 'optionController';
45421                         this.bindToController = {
45422                             info: '=',
45423                             files: '='
45424                         };
45425                         this.scope = true;
45426                         this.templateUrl = 'templates/option.html';
45427                         this.controllerAs = 'ctrl';
45428                     }
45429                     Option.Factory = function () {
45430                         var directive = function () {
45431                             return new Option();
45432                         };
45433                         directive.$inject = [];
45434                         return directive;
45435                     };
45436                     return Option;
45437                 })();
45438                 directives.Option = Option;
45439                 var OptionController = (function () {
45440                     function OptionController() {
45441                         var controller = this;
45442                         angular.forEach(controller.info.arg, function (arg) {
45443                             if (arg.initialValue) {
45444                                 if (arg.formType === 'number') {
45445                                     arg.input = parseInt(arg.initialValue);
45446                                 }
45447                                 else {
45448                                     arg.input = arg.initialValue;
45449                                 }
45450                             }
45451                         });
45452                     }
45453                     OptionController.$inject = [];
45454                     return OptionController;
45455                 })();
45456                 directives.OptionController = OptionController;
45457             })(directives = app.directives || (app.directives = {}));
45458         })(app || (app = {}));
45459         var app;
45460         (function (app) {
45461             var directives;
45462             (function (directives) {
45463                 var Directory = (function () {
45464                     function Directory() {
45465                         this.restrict = 'E';
45466                         this.replace = true;
45467                         this.controller = 'directoryController';
45468                         this.controllerAs = 'ctrl';
45469                         this.bindToController = {
45470                             info: '=',
45471                             add: '&',
45472                             list: '=',
45473                             files: '='
45474                         };
45475                         this.templateUrl = 'templates/directory.html';
45476                     }
45477                     Directory.Factory = function () {
45478                         var directive = function () {
45479                             return new Directory();
45480                         };
45481                         return directive;
45482                     };
45483                     return Directory;
45484                 })();
45485                 directives.Directory = Directory;
45486                 var DirectoryController = (function () {
45487                     function DirectoryController(APIEndPoint, $scope) {
45488                         this.APIEndPoint = APIEndPoint;
45489                         this.$scope = $scope;
45490                         var controller = this;
45491                         this.APIEndPoint
45492                             .getFiles(this.info.fileId)
45493                             .$promise
45494                             .then(function (result) {
45495                             if (result.status === 'success') {
45496                                 controller.files = result.info;
45497                                 angular.forEach(result.info, function (file) {
45498                                     if (file.fileType === '0') {
45499                                         var o = file;
45500                                         if (controller.info.path === '/') {
45501                                             o.path = '/' + file.name;
45502                                         }
45503                                         else {
45504                                             o.path = controller.info.path + '/' + file.name;
45505                                         }
45506                                         controller.add()(o, controller.list);
45507                                     }
45508                                 });
45509                             }
45510                             ;
45511                         });
45512                     }
45513                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
45514                     return DirectoryController;
45515                 })();
45516                 directives.DirectoryController = DirectoryController;
45517             })(directives = app.directives || (app.directives = {}));
45518         })(app || (app = {}));
45519         var app;
45520         (function (app) {
45521             var directives;
45522             (function (directives) {
45523                 var Upload = (function () {
45524                     function Upload() {
45525                         this.restrict = 'E';
45526                         this.replace = true;
45527                         this.scope = true;
45528                         this.controller = 'UploadController';
45529                         this.controllerAs = 'ctrl';
45530                         this.bindToController = {
45531                             index: '=',
45532                             name: '=',
45533                             remove: '&',
45534                             list: '='
45535                         };
45536                         this.templateUrl = 'templates/upload.html';
45537                         console.log("templates/upload.html-constructor");
45538                     }
45539                     Upload.Factory = function () {
45540                         var directive = function () {
45541                             return new Upload();
45542                         };
45543                         directive.$inject = [];
45544                         return directive;
45545                     };
45546                     return Upload;
45547                 })();
45548                 directives.Upload = Upload;
45549                 var UploadController = (function () {
45550                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
45551                         this.APIEndPoint = APIEndPoint;
45552                         this.$scope = $scope;
45553                         this.MyModal = MyModal;
45554                         this.WebSocket = WebSocket;
45555                         this.$window = $window;
45556                         this.$rootScope = $rootScope;
45557                         this.Console = Console;
45558                         var controller = this;
45559                         console.log("directive.upload-constructor");
45560                     }
45561                     UploadController.prototype.submit = function () {
45562                         console.log("submit: function not supported¥n");
45563                     };
45564                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
45565                     return UploadController;
45566                 })();
45567                 directives.UploadController = UploadController;
45568             })(directives = app.directives || (app.directives = {}));
45569         })(app || (app = {}));
45570         var app;
45571         (function (app) {
45572             var controllers;
45573             (function (controllers) {
45574                 var Execution = (function () {
45575                     function Execution(MyModal, $scope) {
45576                         this.MyModal = MyModal;
45577                         this.$scope = $scope;
45578                         this.commandInfoList = [];
45579                     }
45580                     ;
45581                     Execution.prototype.add = function () {
45582                         this.$scope.$broadcast('close');
45583                         var commandInfoList = this.commandInfoList;
45584                         var commandInstance = this.MyModal.selectCommand();
45585                         commandInstance
45586                             .result
45587                             .then(function (command) {
45588                             commandInfoList.push(new app.declares.CommandInfo(command));
45589                         });
45590                     };
45591                     Execution.prototype.open = function () {
45592                         var result = this.MyModal.open('SelectCommand');
45593                         console.log(result);
45594                     };
45595                     Execution.prototype.remove = function (index, list) {
45596                         list.splice(index, 1);
45597                     };
45598                     Execution.prototype.close = function () {
45599                         console.log("close");
45600                     };
45601                     Execution.$inject = ['MyModal', '$scope'];
45602                     return Execution;
45603                 })();
45604                 controllers.Execution = Execution;
45605             })(controllers = app.controllers || (app.controllers = {}));
45606         })(app || (app = {}));
45607         var app;
45608         (function (app) {
45609             var controllers;
45610             (function (controllers) {
45611                 var Workspace = (function () {
45612                     function Workspace($scope, APIEndPoint, MyModal) {
45613                         this.$scope = $scope;
45614                         this.APIEndPoint = APIEndPoint;
45615                         this.MyModal = MyModal;
45616                         this.directoryList = [];
45617                         var controller = this;
45618                         var directoryList = this.directoryList;
45619                         var o = {
45620                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
45621                             name: '',
45622                             parentId: '',
45623                             fileType: '',
45624                             createdAt: '',
45625                             updatedAt: '',
45626                             path: '/'
45627                         };
45628                         directoryList.push(o);
45629                     }
45630                     Workspace.prototype.addDirectory = function (info, directoryList) {
45631                         directoryList.push(info);
45632                     };
45633                     Workspace.prototype.upload = function () {
45634                         this.MyModal.upload();
45635                     };
45636                     Workspace.prototype.debug = function () {
45637                         this.MyModal.preview();
45638                     };
45639                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
45640                     return Workspace;
45641                 })();
45642                 controllers.Workspace = Workspace;
45643             })(controllers = app.controllers || (app.controllers = {}));
45644         })(app || (app = {}));
45645         var app;
45646         (function (app) {
45647             var controllers;
45648             (function (controllers) {
45649                 var History = (function () {
45650                     function History($scope) {
45651                         this.page = "History";
45652                     }
45653                     History.$inject = ['$scope'];
45654                     return History;
45655                 })();
45656                 controllers.History = History;
45657             })(controllers = app.controllers || (app.controllers = {}));
45658         })(app || (app = {}));
45659         var app;
45660         (function (app) {
45661             var controllers;
45662             (function (controllers) {
45663                 var SelectCommand = (function () {
45664                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
45665                         this.APIEndPoint = APIEndPoint;
45666                         this.$modalInstance = $modalInstance;
45667                         var controller = this;
45668                         this.APIEndPoint
45669                             .getTags()
45670                             .$promise.then(function (result) {
45671                             controller.tags = result.info;
45672                         });
45673                         this.APIEndPoint
45674                             .getCommands()
45675                             .$promise.then(function (result) {
45676                             controller.commands = result.info;
45677                         });
45678                         this.currentTag = 'all';
45679                     }
45680                     SelectCommand.prototype.changeTag = function (tag) {
45681                         this.currentTag = tag;
45682                     };
45683                     SelectCommand.prototype.selectCommand = function (command) {
45684                         this.$modalInstance.close(command);
45685                     };
45686                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45687                     return SelectCommand;
45688                 })();
45689                 controllers.SelectCommand = SelectCommand;
45690             })(controllers = app.controllers || (app.controllers = {}));
45691         })(app || (app = {}));
45692         var app;
45693         (function (app) {
45694             var controllers;
45695             (function (controllers) {
45696                 var Upload = (function () {
45697                     function Upload($scope, APIEndPoint, $modalInstance) {
45698                         this.APIEndPoint = APIEndPoint;
45699                         this.$modalInstance = $modalInstance;
45700                         var controller = this;
45701                         console.log('controller.upload-controllers');
45702                     }
45703                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45704                     return Upload;
45705                 })();
45706                 controllers.Upload = Upload;
45707             })(controllers = app.controllers || (app.controllers = {}));
45708         })(app || (app = {}));
45709         var app;
45710         (function (app) {
45711             var controllers;
45712             (function (controllers) {
45713                 var Preview = (function () {
45714                     function Preview($scope, APIEndPoint, $modalInstance) {
45715                         this.APIEndPoint = APIEndPoint;
45716                         this.$modalInstance = $modalInstance;
45717                         var controller = this;
45718                         console.log('preview');
45719                     }
45720                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
45721                     return Preview;
45722                 })();
45723                 controllers.Preview = Preview;
45724             })(controllers = app.controllers || (app.controllers = {}));
45725         })(app || (app = {}));
45726         var filters;
45727         (function (filters) {
45728             function Tag() {
45729                 return function (commands, tag) {
45730                     var result = [];
45731                     angular.forEach(commands, function (command) {
45732                         var flag = false;
45733                         angular.forEach(command.tags, function (value) {
45734                             if (tag === value)
45735                                 flag = true;
45736                         });
45737                         if (flag)
45738                             result.push(command);
45739                     });
45740                     return result;
45741                 };
45742             }
45743             filters.Tag = Tag;
45744         })(filters || (filters = {}));
45745         var app;
45746         (function (app) {
45747             'use strict';
45748             var appName = 'zephyr';
45749             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
45750             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
45751                 $urlRouterProvider.otherwise('/execution');
45752                 $locationProvider.html5Mode({
45753                     enabled: true,
45754                     requireBase: false
45755                 });
45756                 $stateProvider
45757                     .state('execution', {
45758                     url: '/execution',
45759                     templateUrl: 'templates/execution.html',
45760                     controller: 'executionController',
45761                     controllerAs: 'c'
45762                 })
45763                     .state('workspace', {
45764                     url: '/workspace',
45765                     templateUrl: 'templates/workspace.html',
45766                     controller: 'workspaceController',
45767                     controllerAs: 'c'
45768                 })
45769                     .state('history', {
45770                     url: '/history',
45771                     templateUrl: 'templates/history.html',
45772                     controller: 'historyController',
45773                     controllerAs: 'c'
45774                 });
45775             });
45776             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
45777             app.zephyr.service('MyModal', app.services.MyModal);
45778             app.zephyr.service('WebSocket', app.services.WebSocket);
45779             app.zephyr.service('Console', app.services.Console);
45780             app.zephyr.filter('Tag', filters.Tag);
45781             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
45782             app.zephyr.controller('previewController', app.controllers.Preview);
45783             app.zephyr.controller('uploadController', app.controllers.Upload);
45784             app.zephyr.controller('executionController', app.controllers.Execution);
45785             app.zephyr.controller('workspaceController', app.controllers.Workspace);
45786             app.zephyr.controller('historyController', app.controllers.History);
45787             app.zephyr.controller('commandController', app.directives.CommandController);
45788             app.zephyr.controller('optionController', app.directives.OptionController);
45789             app.zephyr.controller('directoryController', app.directives.DirectoryController);
45790             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
45791             app.zephyr.controller('uploadController', app.directives.UploadController);
45792             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
45793             app.zephyr.directive('command', app.directives.Command.Factory());
45794             app.zephyr.directive('option', app.directives.Option.Factory());
45795             app.zephyr.directive('directory', app.directives.Directory.Factory());
45796         })(app || (app = {}));
45797
45798
45799 /***/ },
45800 /* 13 */
45801 /***/ function(module, exports) {
45802
45803         var app;
45804         (function (app) {
45805             var declares;
45806             (function (declares) {
45807                 var CommandInfo = (function () {
45808                     function CommandInfo(name) {
45809                         this.name = name;
45810                     }
45811                     return CommandInfo;
45812                 })();
45813                 declares.CommandInfo = CommandInfo;
45814             })(declares = app.declares || (app.declares = {}));
45815         })(app || (app = {}));
45816         var app;
45817         (function (app) {
45818             var services;
45819             (function (services) {
45820                 var APIEndPoint = (function () {
45821                     function APIEndPoint($resource, $http) {
45822                         this.$resource = $resource;
45823                         this.$http = $http;
45824                     }
45825                     APIEndPoint.prototype.resource = function (endPoint, data) {
45826                         var customAction = {
45827                             method: 'GET',
45828                             isArray: false
45829                         };
45830                         var execute = {
45831                             method: 'POST',
45832                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
45833                         };
45834                         return this.$resource(endPoint, {}, { execute: execute });
45835                     };
45836                     APIEndPoint.prototype.getOptionControlFile = function (command) {
45837                         var endPoint = '/api/v1/optionControlFile/' + command;
45838                         return this.resource(endPoint, {}).get();
45839                     };
45840                     APIEndPoint.prototype.getFiles = function (fileId) {
45841                         var endPoint = '/api/v1/workspace';
45842                         if (fileId) {
45843                             endPoint += '/' + fileId;
45844                         }
45845                         return this.resource(endPoint, {}).get();
45846                     };
45847                     APIEndPoint.prototype.getDirectories = function () {
45848                         var endPoint = '/api/v1/all/workspace/directory';
45849                         return this.resource(endPoint, {}).get();
45850                     };
45851                     APIEndPoint.prototype.getTags = function () {
45852                         var endPoint = '/api/v1/tagList';
45853                         return this.resource(endPoint, {}).get();
45854                     };
45855                     APIEndPoint.prototype.getCommands = function () {
45856                         var endPoint = '/api/v1/commandList';
45857                         return this.resource(endPoint, {}).get();
45858                     };
45859                     APIEndPoint.prototype.execute = function (data) {
45860                         var endPoint = '/api/v1/execution';
45861                         var fd = new FormData();
45862                         fd.append('data', data);
45863                         return this.$http.post(endPoint, fd, {
45864                             headers: { 'Content-Type': undefined },
45865                             transformRequest: angular.identity
45866                         });
45867                     };
45868                     APIEndPoint.prototype.debug = function () {
45869                         var endPoint = '/api/v1/debug';
45870                         return this.$http.get(endPoint);
45871                     };
45872                     APIEndPoint.prototype.upload = function () {
45873                         var endPoint = '/api/v1/upload';
45874                         return this.$http.get(endPoint);
45875                     };
45876                     APIEndPoint.prototype.help = function (command) {
45877                         var endPoint = '/api/v1/help/' + command;
45878                         return this.$http.get(endPoint);
45879                     };
45880                     return APIEndPoint;
45881                 })();
45882                 services.APIEndPoint = APIEndPoint;
45883             })(services = app.services || (app.services = {}));
45884         })(app || (app = {}));
45885         var app;
45886         (function (app) {
45887             var services;
45888             (function (services) {
45889                 var MyModal = (function () {
45890                     function MyModal($uibModal) {
45891                         this.$uibModal = $uibModal;
45892                         this.modalOption = {
45893                             backdrop: true,
45894                             controller: null,
45895                             templateUrl: null,
45896                             size: null
45897                         };
45898                     }
45899                     MyModal.prototype.open = function (modalName) {
45900                         if (modalName === 'SelectCommand') {
45901                             this.modalOption.templateUrl = 'templates/select-command.html';
45902                             this.modalOption.size = 'lg';
45903                         }
45904                         return this.$uibModal.open(this.modalOption);
45905                     };
45906                     MyModal.prototype.selectCommand = function () {
45907                         this.modalOption.templateUrl = 'templates/select-command.html';
45908                         this.modalOption.controller = 'selectCommandController';
45909                         this.modalOption.controllerAs = 'c';
45910                         this.modalOption.size = 'lg';
45911                         return this.$uibModal.open(this.modalOption);
45912                     };
45913                     MyModal.prototype.preview = function () {
45914                         this.modalOption.templateUrl = 'templates/preview.html';
45915                         this.modalOption.controller = 'previewController';
45916                         this.modalOption.controllerAs = 'c';
45917                         this.modalOption.size = 'lg';
45918                         return this.$uibModal.open(this.modalOption);
45919                     };
45920                     MyModal.prototype.upload = function () {
45921                         this.modalOption.templateUrl = 'templates/upload.html';
45922                         this.modalOption.controller = 'uploadController';
45923                         this.modalOption.controllerAs = 'c';
45924                         this.modalOption.size = 'lg';
45925                         return this.$uibModal.open(this.modalOption);
45926                     };
45927                     MyModal.$inject = ['$uibModal'];
45928                     return MyModal;
45929                 })();
45930                 services.MyModal = MyModal;
45931             })(services = app.services || (app.services = {}));
45932         })(app || (app = {}));
45933         var app;
45934         (function (app) {
45935             var services;
45936             (function (services) {
45937                 var WebSocket = (function () {
45938                     function WebSocket($rootScope) {
45939                         this.$rootScope = $rootScope;
45940                         this.socket = io.connect();
45941                     }
45942                     WebSocket.prototype.on = function (eventName, callback) {
45943                         var socket = this.socket;
45944                         var rootScope = this.$rootScope;
45945                         socket.on(eventName, function () {
45946                             var args = arguments;
45947                             rootScope.$apply(function () {
45948                                 callback.apply(socket, args);
45949                             });
45950                         });
45951                     };
45952                     WebSocket.prototype.emit = function (eventName, data, callback) {
45953                         var socket = this.socket;
45954                         var rootScope = this.$rootScope;
45955                         this.socket.emit(eventName, data, function () {
45956                             var args = arguments;
45957                             rootScope.$apply(function () {
45958                                 if (callback)
45959                                     callback.apply(socket, args);
45960                             });
45961                         });
45962                     };
45963                     return WebSocket;
45964                 })();
45965                 services.WebSocket = WebSocket;
45966             })(services = app.services || (app.services = {}));
45967         })(app || (app = {}));
45968         var app;
45969         (function (app) {
45970             var services;
45971             (function (services) {
45972                 var Console = (function () {
45973                     function Console(WebSocket, $rootScope) {
45974                         this.WebSocket = WebSocket;
45975                         this.$rootScope = $rootScope;
45976                         this.WebSocket = WebSocket;
45977                         this.$rootScope = $rootScope;
45978                         this.directiveIDs = [];
45979                         var directiveIDs = this.directiveIDs;
45980                         this.WebSocket.on('console', function (d) {
45981                             var id = d.id;
45982                             var message = d.message;
45983                             if (directiveIDs.indexOf(id) > -1) {
45984                                 $rootScope.$emit(id, message);
45985                             }
45986                         });
45987                     }
45988                     Console.prototype.addDirective = function (id) {
45989                         if (!(this.directiveIDs.indexOf(id) > -1)) {
45990                             this.directiveIDs.push(id);
45991                         }
45992                     };
45993                     Console.prototype.removeDirective = function (id) {
45994                         var i = this.directiveIDs.indexOf(id);
45995                         if (i > -1) {
45996                             this.directiveIDs.splice(i, 1);
45997                         }
45998                     };
45999                     Console.prototype.showIDs = function () {
46000                         console.log(this.directiveIDs);
46001                     };
46002                     return Console;
46003                 })();
46004                 services.Console = Console;
46005             })(services = app.services || (app.services = {}));
46006         })(app || (app = {}));
46007         var app;
46008         (function (app) {
46009             var directives;
46010             (function (directives) {
46011                 var Command = (function () {
46012                     function Command() {
46013                         this.restrict = 'E';
46014                         this.replace = true;
46015                         this.scope = true;
46016                         this.controller = 'commandController';
46017                         this.controllerAs = 'ctrl';
46018                         this.bindToController = {
46019                             index: '=',
46020                             name: '=',
46021                             remove: '&',
46022                             list: '='
46023                         };
46024                         this.templateUrl = 'templates/command.html';
46025                     }
46026                     Command.Factory = function () {
46027                         var directive = function () {
46028                             return new Command();
46029                         };
46030                         directive.$inject = [];
46031                         return directive;
46032                     };
46033                     return Command;
46034                 })();
46035                 directives.Command = Command;
46036                 var CommandController = (function () {
46037                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
46038                         this.APIEndPoint = APIEndPoint;
46039                         this.$scope = $scope;
46040                         this.MyModal = MyModal;
46041                         this.WebSocket = WebSocket;
46042                         this.$window = $window;
46043                         this.$rootScope = $rootScope;
46044                         this.Console = Console;
46045                         var controller = this;
46046                         this.APIEndPoint
46047                             .getOptionControlFile(this.name)
46048                             .$promise
46049                             .then(function (result) {
46050                             controller.options = result.info;
46051                         });
46052                         this.APIEndPoint
46053                             .getDirectories()
46054                             .$promise
46055                             .then(function (result) {
46056                             controller.dirs = result.info;
46057                         });
46058                         this.heading = "[" + this.index + "]: dcdFilePrint";
46059                         this.isOpen = true;
46060                         this.$scope.$on('close', function () {
46061                             controller.isOpen = false;
46062                         });
46063                         function guid() {
46064                             function s4() {
46065                                 return Math.floor((1 + Math.random()) * 0x10000)
46066                                     .toString(16)
46067                                     .substring(1);
46068                             }
46069                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
46070                                 s4() + '-' + s4() + s4() + s4();
46071                         }
46072                         this.uuid = guid();
46073                         this.Console.addDirective(this.uuid);
46074                         this.Console.showIDs();
46075                     }
46076                     CommandController.prototype.submit = function () {
46077                         var opt = [];
46078                         angular.forEach(this.options, function (option) {
46079                             var obj = {
46080                                 name: option.option,
46081                                 arguments: []
46082                             };
46083                             angular.forEach(option.arg, function (arg) {
46084                                 if (arg.input) {
46085                                     if (typeof arg.input === 'object') {
46086                                         obj.arguments.push(arg.input.name);
46087                                     }
46088                                     else {
46089                                         obj.arguments.push(arg.input);
46090                                     }
46091                                 }
46092                             });
46093                             if (obj.arguments.length > 0) {
46094                                 opt.push(obj);
46095                             }
46096                         });
46097                         var execObj = {
46098                             command: this.name,
46099                             workspace: this.workspace.fileId,
46100                             options: opt
46101                         };
46102                         this.APIEndPoint
46103                             .execute(JSON.stringify(execObj))
46104                             .then(function (result) {
46105                             console.log(result);
46106                         });
46107                     };
46108                     CommandController.prototype.removeMySelf = function (index) {
46109                         this.$scope.$destroy();
46110                         this.Console.removeDirective(this.uuid);
46111                         this.remove()(index, this.list);
46112                         this.Console.showIDs();
46113                     };
46114                     CommandController.prototype.reloadFiles = function () {
46115                         var _this = this;
46116                         var fileId = this.workspace.fileId;
46117                         this.APIEndPoint
46118                             .getFiles(fileId)
46119                             .$promise
46120                             .then(function (result) {
46121                             var status = result.status;
46122                             if (status === 'success') {
46123                                 _this.files = result.info;
46124                             }
46125                             else {
46126                                 console.log(result.message);
46127                             }
46128                         });
46129                     };
46130                     CommandController.prototype.debug = function () {
46131                         var div = angular.element(this.$window.document).find("div");
46132                         var consoleTag;
46133                         var parametersTag;
46134                         angular.forEach(div, function (v) {
46135                             if (v.className === "panel-body console") {
46136                                 consoleTag = v;
46137                             }
46138                             else if (v.className === "row parameters-console") {
46139                                 parametersTag = v;
46140                             }
46141                         });
46142                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
46143                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
46144                         consoleTag.style.height = consoleHeight;
46145                         consoleTag.style.width = consoleWidth;
46146                     };
46147                     CommandController.prototype.help = function () {
46148                         this.APIEndPoint
46149                             .help(this.name)
46150                             .then(function (result) {
46151                             console.log(result);
46152                         });
46153                     };
46154                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
46155                     return CommandController;
46156                 })();
46157                 directives.CommandController = CommandController;
46158             })(directives = app.directives || (app.directives = {}));
46159         })(app || (app = {}));
46160         var app;
46161         (function (app) {
46162             var directives;
46163             (function (directives) {
46164                 var HeaderMenu = (function () {
46165                     function HeaderMenu() {
46166                         this.restrict = 'E';
46167                         this.replace = true;
46168                         this.templateUrl = 'templates/header-menu.html';
46169                         this.controller = 'HeaderMenuController';
46170                         this.controllerAs = 'hmc';
46171                         this.scope = true;
46172                     }
46173                     HeaderMenu.Factory = function () {
46174                         var directive = function () {
46175                             return new HeaderMenu();
46176                         };
46177                         return directive;
46178                     };
46179                     return HeaderMenu;
46180                 })();
46181                 directives.HeaderMenu = HeaderMenu;
46182                 var HeaderMenuController = (function () {
46183                     function HeaderMenuController($state) {
46184                         this.$state = $state;
46185                         this.isExecution = this.$state.current.name === 'execution';
46186                         this.isWorkspace = this.$state.current.name === 'workspace';
46187                         this.isHistory = this.$state.current.name === 'history';
46188                     }
46189                     HeaderMenuController.prototype.transit = function (state) {
46190                         this.$state.go(state);
46191                     };
46192                     HeaderMenuController.$inject = ['$state'];
46193                     return HeaderMenuController;
46194                 })();
46195                 directives.HeaderMenuController = HeaderMenuController;
46196             })(directives = app.directives || (app.directives = {}));
46197         })(app || (app = {}));
46198         var app;
46199         (function (app) {
46200             var directives;
46201             (function (directives) {
46202                 var Option = (function () {
46203                     function Option() {
46204                         this.restrict = 'E';
46205                         this.replace = true;
46206                         this.controller = 'optionController';
46207                         this.bindToController = {
46208                             info: '=',
46209                             files: '='
46210                         };
46211                         this.scope = true;
46212                         this.templateUrl = 'templates/option.html';
46213                         this.controllerAs = 'ctrl';
46214                     }
46215                     Option.Factory = function () {
46216                         var directive = function () {
46217                             return new Option();
46218                         };
46219                         directive.$inject = [];
46220                         return directive;
46221                     };
46222                     return Option;
46223                 })();
46224                 directives.Option = Option;
46225                 var OptionController = (function () {
46226                     function OptionController() {
46227                         var controller = this;
46228                         angular.forEach(controller.info.arg, function (arg) {
46229                             if (arg.initialValue) {
46230                                 if (arg.formType === 'number') {
46231                                     arg.input = parseInt(arg.initialValue);
46232                                 }
46233                                 else {
46234                                     arg.input = arg.initialValue;
46235                                 }
46236                             }
46237                         });
46238                     }
46239                     OptionController.$inject = [];
46240                     return OptionController;
46241                 })();
46242                 directives.OptionController = OptionController;
46243             })(directives = app.directives || (app.directives = {}));
46244         })(app || (app = {}));
46245         var app;
46246         (function (app) {
46247             var directives;
46248             (function (directives) {
46249                 var Directory = (function () {
46250                     function Directory() {
46251                         this.restrict = 'E';
46252                         this.replace = true;
46253                         this.controller = 'directoryController';
46254                         this.controllerAs = 'ctrl';
46255                         this.bindToController = {
46256                             info: '=',
46257                             add: '&',
46258                             list: '=',
46259                             files: '='
46260                         };
46261                         this.templateUrl = 'templates/directory.html';
46262                     }
46263                     Directory.Factory = function () {
46264                         var directive = function () {
46265                             return new Directory();
46266                         };
46267                         return directive;
46268                     };
46269                     return Directory;
46270                 })();
46271                 directives.Directory = Directory;
46272                 var DirectoryController = (function () {
46273                     function DirectoryController(APIEndPoint, $scope) {
46274                         this.APIEndPoint = APIEndPoint;
46275                         this.$scope = $scope;
46276                         var controller = this;
46277                         this.APIEndPoint
46278                             .getFiles(this.info.fileId)
46279                             .$promise
46280                             .then(function (result) {
46281                             if (result.status === 'success') {
46282                                 controller.files = result.info;
46283                                 angular.forEach(result.info, function (file) {
46284                                     if (file.fileType === '0') {
46285                                         var o = file;
46286                                         if (controller.info.path === '/') {
46287                                             o.path = '/' + file.name;
46288                                         }
46289                                         else {
46290                                             o.path = controller.info.path + '/' + file.name;
46291                                         }
46292                                         controller.add()(o, controller.list);
46293                                     }
46294                                 });
46295                             }
46296                             ;
46297                         });
46298                     }
46299                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
46300                     return DirectoryController;
46301                 })();
46302                 directives.DirectoryController = DirectoryController;
46303             })(directives = app.directives || (app.directives = {}));
46304         })(app || (app = {}));
46305         var app;
46306         (function (app) {
46307             var directives;
46308             (function (directives) {
46309                 var Upload = (function () {
46310                     function Upload() {
46311                         this.restrict = 'E';
46312                         this.replace = true;
46313                         this.scope = true;
46314                         this.controller = 'UploadController';
46315                         this.controllerAs = 'ctrl';
46316                         this.bindToController = {
46317                             index: '=',
46318                             name: '=',
46319                             remove: '&',
46320                             list: '='
46321                         };
46322                         this.templateUrl = 'templates/upload.html';
46323                         console.log("templates/upload.html-constructor");
46324                     }
46325                     Upload.Factory = function () {
46326                         var directive = function () {
46327                             return new Upload();
46328                         };
46329                         directive.$inject = [];
46330                         return directive;
46331                     };
46332                     return Upload;
46333                 })();
46334                 directives.Upload = Upload;
46335                 var UploadController = (function () {
46336                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
46337                         this.APIEndPoint = APIEndPoint;
46338                         this.$scope = $scope;
46339                         this.MyModal = MyModal;
46340                         this.WebSocket = WebSocket;
46341                         this.$window = $window;
46342                         this.$rootScope = $rootScope;
46343                         this.Console = Console;
46344                         var controller = this;
46345                         console.log("directive.upload-constructor");
46346                     }
46347                     UploadController.prototype.submit = function () {
46348                         console.log("submit: function not supported¥n");
46349                     };
46350                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
46351                     return UploadController;
46352                 })();
46353                 directives.UploadController = UploadController;
46354             })(directives = app.directives || (app.directives = {}));
46355         })(app || (app = {}));
46356         var app;
46357         (function (app) {
46358             var controllers;
46359             (function (controllers) {
46360                 var Execution = (function () {
46361                     function Execution(MyModal, $scope) {
46362                         this.MyModal = MyModal;
46363                         this.$scope = $scope;
46364                         this.commandInfoList = [];
46365                     }
46366                     ;
46367                     Execution.prototype.add = function () {
46368                         this.$scope.$broadcast('close');
46369                         var commandInfoList = this.commandInfoList;
46370                         var commandInstance = this.MyModal.selectCommand();
46371                         commandInstance
46372                             .result
46373                             .then(function (command) {
46374                             commandInfoList.push(new app.declares.CommandInfo(command));
46375                         });
46376                     };
46377                     Execution.prototype.open = function () {
46378                         var result = this.MyModal.open('SelectCommand');
46379                         console.log(result);
46380                     };
46381                     Execution.prototype.remove = function (index, list) {
46382                         list.splice(index, 1);
46383                     };
46384                     Execution.prototype.close = function () {
46385                         console.log("close");
46386                     };
46387                     Execution.$inject = ['MyModal', '$scope'];
46388                     return Execution;
46389                 })();
46390                 controllers.Execution = Execution;
46391             })(controllers = app.controllers || (app.controllers = {}));
46392         })(app || (app = {}));
46393         var app;
46394         (function (app) {
46395             var controllers;
46396             (function (controllers) {
46397                 var Workspace = (function () {
46398                     function Workspace($scope, APIEndPoint, MyModal) {
46399                         this.$scope = $scope;
46400                         this.APIEndPoint = APIEndPoint;
46401                         this.MyModal = MyModal;
46402                         this.directoryList = [];
46403                         var controller = this;
46404                         var directoryList = this.directoryList;
46405                         var o = {
46406                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
46407                             name: '',
46408                             parentId: '',
46409                             fileType: '',
46410                             createdAt: '',
46411                             updatedAt: '',
46412                             path: '/'
46413                         };
46414                         directoryList.push(o);
46415                     }
46416                     Workspace.prototype.addDirectory = function (info, directoryList) {
46417                         directoryList.push(info);
46418                     };
46419                     Workspace.prototype.upload = function () {
46420                         this.MyModal.upload();
46421                     };
46422                     Workspace.prototype.debug = function () {
46423                         this.MyModal.preview();
46424                     };
46425                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
46426                     return Workspace;
46427                 })();
46428                 controllers.Workspace = Workspace;
46429             })(controllers = app.controllers || (app.controllers = {}));
46430         })(app || (app = {}));
46431         var app;
46432         (function (app) {
46433             var controllers;
46434             (function (controllers) {
46435                 var History = (function () {
46436                     function History($scope) {
46437                         this.page = "History";
46438                     }
46439                     History.$inject = ['$scope'];
46440                     return History;
46441                 })();
46442                 controllers.History = History;
46443             })(controllers = app.controllers || (app.controllers = {}));
46444         })(app || (app = {}));
46445         var app;
46446         (function (app) {
46447             var controllers;
46448             (function (controllers) {
46449                 var SelectCommand = (function () {
46450                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
46451                         this.APIEndPoint = APIEndPoint;
46452                         this.$modalInstance = $modalInstance;
46453                         var controller = this;
46454                         this.APIEndPoint
46455                             .getTags()
46456                             .$promise.then(function (result) {
46457                             controller.tags = result.info;
46458                         });
46459                         this.APIEndPoint
46460                             .getCommands()
46461                             .$promise.then(function (result) {
46462                             controller.commands = result.info;
46463                         });
46464                         this.currentTag = 'all';
46465                     }
46466                     SelectCommand.prototype.changeTag = function (tag) {
46467                         this.currentTag = tag;
46468                     };
46469                     SelectCommand.prototype.selectCommand = function (command) {
46470                         this.$modalInstance.close(command);
46471                     };
46472                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46473                     return SelectCommand;
46474                 })();
46475                 controllers.SelectCommand = SelectCommand;
46476             })(controllers = app.controllers || (app.controllers = {}));
46477         })(app || (app = {}));
46478         var app;
46479         (function (app) {
46480             var controllers;
46481             (function (controllers) {
46482                 var Upload = (function () {
46483                     function Upload($scope, APIEndPoint, $modalInstance) {
46484                         this.APIEndPoint = APIEndPoint;
46485                         this.$modalInstance = $modalInstance;
46486                         var controller = this;
46487                         console.log('controller.upload-controllers');
46488                     }
46489                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46490                     return Upload;
46491                 })();
46492                 controllers.Upload = Upload;
46493             })(controllers = app.controllers || (app.controllers = {}));
46494         })(app || (app = {}));
46495         var app;
46496         (function (app) {
46497             var controllers;
46498             (function (controllers) {
46499                 var Preview = (function () {
46500                     function Preview($scope, APIEndPoint, $modalInstance) {
46501                         this.APIEndPoint = APIEndPoint;
46502                         this.$modalInstance = $modalInstance;
46503                         var controller = this;
46504                         console.log('preview');
46505                     }
46506                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
46507                     return Preview;
46508                 })();
46509                 controllers.Preview = Preview;
46510             })(controllers = app.controllers || (app.controllers = {}));
46511         })(app || (app = {}));
46512         var filters;
46513         (function (filters) {
46514             function Tag() {
46515                 return function (commands, tag) {
46516                     var result = [];
46517                     angular.forEach(commands, function (command) {
46518                         var flag = false;
46519                         angular.forEach(command.tags, function (value) {
46520                             if (tag === value)
46521                                 flag = true;
46522                         });
46523                         if (flag)
46524                             result.push(command);
46525                     });
46526                     return result;
46527                 };
46528             }
46529             filters.Tag = Tag;
46530         })(filters || (filters = {}));
46531         var app;
46532         (function (app) {
46533             'use strict';
46534             var appName = 'zephyr';
46535             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
46536             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
46537                 $urlRouterProvider.otherwise('/execution');
46538                 $locationProvider.html5Mode({
46539                     enabled: true,
46540                     requireBase: false
46541                 });
46542                 $stateProvider
46543                     .state('execution', {
46544                     url: '/execution',
46545                     templateUrl: 'templates/execution.html',
46546                     controller: 'executionController',
46547                     controllerAs: 'c'
46548                 })
46549                     .state('workspace', {
46550                     url: '/workspace',
46551                     templateUrl: 'templates/workspace.html',
46552                     controller: 'workspaceController',
46553                     controllerAs: 'c'
46554                 })
46555                     .state('history', {
46556                     url: '/history',
46557                     templateUrl: 'templates/history.html',
46558                     controller: 'historyController',
46559                     controllerAs: 'c'
46560                 });
46561             });
46562             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
46563             app.zephyr.service('MyModal', app.services.MyModal);
46564             app.zephyr.service('WebSocket', app.services.WebSocket);
46565             app.zephyr.service('Console', app.services.Console);
46566             app.zephyr.filter('Tag', filters.Tag);
46567             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
46568             app.zephyr.controller('previewController', app.controllers.Preview);
46569             app.zephyr.controller('uploadController', app.controllers.Upload);
46570             app.zephyr.controller('executionController', app.controllers.Execution);
46571             app.zephyr.controller('workspaceController', app.controllers.Workspace);
46572             app.zephyr.controller('historyController', app.controllers.History);
46573             app.zephyr.controller('commandController', app.directives.CommandController);
46574             app.zephyr.controller('optionController', app.directives.OptionController);
46575             app.zephyr.controller('directoryController', app.directives.DirectoryController);
46576             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
46577             app.zephyr.controller('uploadController', app.directives.UploadController);
46578             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
46579             app.zephyr.directive('command', app.directives.Command.Factory());
46580             app.zephyr.directive('option', app.directives.Option.Factory());
46581             app.zephyr.directive('directory', app.directives.Directory.Factory());
46582         })(app || (app = {}));
46583
46584
46585 /***/ },
46586 /* 14 */
46587 /***/ function(module, exports) {
46588
46589         var app;
46590         (function (app) {
46591             var declares;
46592             (function (declares) {
46593                 var CommandInfo = (function () {
46594                     function CommandInfo(name) {
46595                         this.name = name;
46596                     }
46597                     return CommandInfo;
46598                 })();
46599                 declares.CommandInfo = CommandInfo;
46600             })(declares = app.declares || (app.declares = {}));
46601         })(app || (app = {}));
46602         var app;
46603         (function (app) {
46604             var services;
46605             (function (services) {
46606                 var APIEndPoint = (function () {
46607                     function APIEndPoint($resource, $http) {
46608                         this.$resource = $resource;
46609                         this.$http = $http;
46610                     }
46611                     APIEndPoint.prototype.resource = function (endPoint, data) {
46612                         var customAction = {
46613                             method: 'GET',
46614                             isArray: false
46615                         };
46616                         var execute = {
46617                             method: 'POST',
46618                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
46619                         };
46620                         return this.$resource(endPoint, {}, { execute: execute });
46621                     };
46622                     APIEndPoint.prototype.getOptionControlFile = function (command) {
46623                         var endPoint = '/api/v1/optionControlFile/' + command;
46624                         return this.resource(endPoint, {}).get();
46625                     };
46626                     APIEndPoint.prototype.getFiles = function (fileId) {
46627                         var endPoint = '/api/v1/workspace';
46628                         if (fileId) {
46629                             endPoint += '/' + fileId;
46630                         }
46631                         return this.resource(endPoint, {}).get();
46632                     };
46633                     APIEndPoint.prototype.getDirectories = function () {
46634                         var endPoint = '/api/v1/all/workspace/directory';
46635                         return this.resource(endPoint, {}).get();
46636                     };
46637                     APIEndPoint.prototype.getTags = function () {
46638                         var endPoint = '/api/v1/tagList';
46639                         return this.resource(endPoint, {}).get();
46640                     };
46641                     APIEndPoint.prototype.getCommands = function () {
46642                         var endPoint = '/api/v1/commandList';
46643                         return this.resource(endPoint, {}).get();
46644                     };
46645                     APIEndPoint.prototype.execute = function (data) {
46646                         var endPoint = '/api/v1/execution';
46647                         var fd = new FormData();
46648                         fd.append('data', data);
46649                         return this.$http.post(endPoint, fd, {
46650                             headers: { 'Content-Type': undefined },
46651                             transformRequest: angular.identity
46652                         });
46653                     };
46654                     APIEndPoint.prototype.debug = function () {
46655                         var endPoint = '/api/v1/debug';
46656                         return this.$http.get(endPoint);
46657                     };
46658                     APIEndPoint.prototype.upload = function () {
46659                         var endPoint = '/api/v1/upload';
46660                         return this.$http.get(endPoint);
46661                     };
46662                     APIEndPoint.prototype.help = function (command) {
46663                         var endPoint = '/api/v1/help/' + command;
46664                         return this.$http.get(endPoint);
46665                     };
46666                     return APIEndPoint;
46667                 })();
46668                 services.APIEndPoint = APIEndPoint;
46669             })(services = app.services || (app.services = {}));
46670         })(app || (app = {}));
46671         var app;
46672         (function (app) {
46673             var services;
46674             (function (services) {
46675                 var MyModal = (function () {
46676                     function MyModal($uibModal) {
46677                         this.$uibModal = $uibModal;
46678                         this.modalOption = {
46679                             backdrop: true,
46680                             controller: null,
46681                             templateUrl: null,
46682                             size: null
46683                         };
46684                     }
46685                     MyModal.prototype.open = function (modalName) {
46686                         if (modalName === 'SelectCommand') {
46687                             this.modalOption.templateUrl = 'templates/select-command.html';
46688                             this.modalOption.size = 'lg';
46689                         }
46690                         return this.$uibModal.open(this.modalOption);
46691                     };
46692                     MyModal.prototype.selectCommand = function () {
46693                         this.modalOption.templateUrl = 'templates/select-command.html';
46694                         this.modalOption.controller = 'selectCommandController';
46695                         this.modalOption.controllerAs = 'c';
46696                         this.modalOption.size = 'lg';
46697                         return this.$uibModal.open(this.modalOption);
46698                     };
46699                     MyModal.prototype.preview = function () {
46700                         this.modalOption.templateUrl = 'templates/preview.html';
46701                         this.modalOption.controller = 'previewController';
46702                         this.modalOption.controllerAs = 'c';
46703                         this.modalOption.size = 'lg';
46704                         return this.$uibModal.open(this.modalOption);
46705                     };
46706                     MyModal.prototype.upload = function () {
46707                         this.modalOption.templateUrl = 'templates/upload.html';
46708                         this.modalOption.controller = 'uploadController';
46709                         this.modalOption.controllerAs = 'c';
46710                         this.modalOption.size = 'lg';
46711                         return this.$uibModal.open(this.modalOption);
46712                     };
46713                     MyModal.$inject = ['$uibModal'];
46714                     return MyModal;
46715                 })();
46716                 services.MyModal = MyModal;
46717             })(services = app.services || (app.services = {}));
46718         })(app || (app = {}));
46719         var app;
46720         (function (app) {
46721             var services;
46722             (function (services) {
46723                 var WebSocket = (function () {
46724                     function WebSocket($rootScope) {
46725                         this.$rootScope = $rootScope;
46726                         this.socket = io.connect();
46727                     }
46728                     WebSocket.prototype.on = function (eventName, callback) {
46729                         var socket = this.socket;
46730                         var rootScope = this.$rootScope;
46731                         socket.on(eventName, function () {
46732                             var args = arguments;
46733                             rootScope.$apply(function () {
46734                                 callback.apply(socket, args);
46735                             });
46736                         });
46737                     };
46738                     WebSocket.prototype.emit = function (eventName, data, callback) {
46739                         var socket = this.socket;
46740                         var rootScope = this.$rootScope;
46741                         this.socket.emit(eventName, data, function () {
46742                             var args = arguments;
46743                             rootScope.$apply(function () {
46744                                 if (callback)
46745                                     callback.apply(socket, args);
46746                             });
46747                         });
46748                     };
46749                     return WebSocket;
46750                 })();
46751                 services.WebSocket = WebSocket;
46752             })(services = app.services || (app.services = {}));
46753         })(app || (app = {}));
46754         var app;
46755         (function (app) {
46756             var services;
46757             (function (services) {
46758                 var Console = (function () {
46759                     function Console(WebSocket, $rootScope) {
46760                         this.WebSocket = WebSocket;
46761                         this.$rootScope = $rootScope;
46762                         this.WebSocket = WebSocket;
46763                         this.$rootScope = $rootScope;
46764                         this.directiveIDs = [];
46765                         var directiveIDs = this.directiveIDs;
46766                         this.WebSocket.on('console', function (d) {
46767                             var id = d.id;
46768                             var message = d.message;
46769                             if (directiveIDs.indexOf(id) > -1) {
46770                                 $rootScope.$emit(id, message);
46771                             }
46772                         });
46773                     }
46774                     Console.prototype.addDirective = function (id) {
46775                         if (!(this.directiveIDs.indexOf(id) > -1)) {
46776                             this.directiveIDs.push(id);
46777                         }
46778                     };
46779                     Console.prototype.removeDirective = function (id) {
46780                         var i = this.directiveIDs.indexOf(id);
46781                         if (i > -1) {
46782                             this.directiveIDs.splice(i, 1);
46783                         }
46784                     };
46785                     Console.prototype.showIDs = function () {
46786                         console.log(this.directiveIDs);
46787                     };
46788                     return Console;
46789                 })();
46790                 services.Console = Console;
46791             })(services = app.services || (app.services = {}));
46792         })(app || (app = {}));
46793         var app;
46794         (function (app) {
46795             var directives;
46796             (function (directives) {
46797                 var Command = (function () {
46798                     function Command() {
46799                         this.restrict = 'E';
46800                         this.replace = true;
46801                         this.scope = true;
46802                         this.controller = 'commandController';
46803                         this.controllerAs = 'ctrl';
46804                         this.bindToController = {
46805                             index: '=',
46806                             name: '=',
46807                             remove: '&',
46808                             list: '='
46809                         };
46810                         this.templateUrl = 'templates/command.html';
46811                     }
46812                     Command.Factory = function () {
46813                         var directive = function () {
46814                             return new Command();
46815                         };
46816                         directive.$inject = [];
46817                         return directive;
46818                     };
46819                     return Command;
46820                 })();
46821                 directives.Command = Command;
46822                 var CommandController = (function () {
46823                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
46824                         this.APIEndPoint = APIEndPoint;
46825                         this.$scope = $scope;
46826                         this.MyModal = MyModal;
46827                         this.WebSocket = WebSocket;
46828                         this.$window = $window;
46829                         this.$rootScope = $rootScope;
46830                         this.Console = Console;
46831                         var controller = this;
46832                         this.APIEndPoint
46833                             .getOptionControlFile(this.name)
46834                             .$promise
46835                             .then(function (result) {
46836                             controller.options = result.info;
46837                         });
46838                         this.APIEndPoint
46839                             .getDirectories()
46840                             .$promise
46841                             .then(function (result) {
46842                             controller.dirs = result.info;
46843                         });
46844                         this.heading = "[" + this.index + "]: dcdFilePrint";
46845                         this.isOpen = true;
46846                         this.$scope.$on('close', function () {
46847                             controller.isOpen = false;
46848                         });
46849                         function guid() {
46850                             function s4() {
46851                                 return Math.floor((1 + Math.random()) * 0x10000)
46852                                     .toString(16)
46853                                     .substring(1);
46854                             }
46855                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
46856                                 s4() + '-' + s4() + s4() + s4();
46857                         }
46858                         this.uuid = guid();
46859                         this.Console.addDirective(this.uuid);
46860                         this.Console.showIDs();
46861                     }
46862                     CommandController.prototype.submit = function () {
46863                         var opt = [];
46864                         angular.forEach(this.options, function (option) {
46865                             var obj = {
46866                                 name: option.option,
46867                                 arguments: []
46868                             };
46869                             angular.forEach(option.arg, function (arg) {
46870                                 if (arg.input) {
46871                                     if (typeof arg.input === 'object') {
46872                                         obj.arguments.push(arg.input.name);
46873                                     }
46874                                     else {
46875                                         obj.arguments.push(arg.input);
46876                                     }
46877                                 }
46878                             });
46879                             if (obj.arguments.length > 0) {
46880                                 opt.push(obj);
46881                             }
46882                         });
46883                         var execObj = {
46884                             command: this.name,
46885                             workspace: this.workspace.fileId,
46886                             options: opt
46887                         };
46888                         this.APIEndPoint
46889                             .execute(JSON.stringify(execObj))
46890                             .then(function (result) {
46891                             console.log(result);
46892                         });
46893                     };
46894                     CommandController.prototype.removeMySelf = function (index) {
46895                         this.$scope.$destroy();
46896                         this.Console.removeDirective(this.uuid);
46897                         this.remove()(index, this.list);
46898                         this.Console.showIDs();
46899                     };
46900                     CommandController.prototype.reloadFiles = function () {
46901                         var _this = this;
46902                         var fileId = this.workspace.fileId;
46903                         this.APIEndPoint
46904                             .getFiles(fileId)
46905                             .$promise
46906                             .then(function (result) {
46907                             var status = result.status;
46908                             if (status === 'success') {
46909                                 _this.files = result.info;
46910                             }
46911                             else {
46912                                 console.log(result.message);
46913                             }
46914                         });
46915                     };
46916                     CommandController.prototype.debug = function () {
46917                         var div = angular.element(this.$window.document).find("div");
46918                         var consoleTag;
46919                         var parametersTag;
46920                         angular.forEach(div, function (v) {
46921                             if (v.className === "panel-body console") {
46922                                 consoleTag = v;
46923                             }
46924                             else if (v.className === "row parameters-console") {
46925                                 parametersTag = v;
46926                             }
46927                         });
46928                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
46929                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
46930                         consoleTag.style.height = consoleHeight;
46931                         consoleTag.style.width = consoleWidth;
46932                     };
46933                     CommandController.prototype.help = function () {
46934                         this.APIEndPoint
46935                             .help(this.name)
46936                             .then(function (result) {
46937                             console.log(result);
46938                         });
46939                     };
46940                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
46941                     return CommandController;
46942                 })();
46943                 directives.CommandController = CommandController;
46944             })(directives = app.directives || (app.directives = {}));
46945         })(app || (app = {}));
46946         var app;
46947         (function (app) {
46948             var directives;
46949             (function (directives) {
46950                 var HeaderMenu = (function () {
46951                     function HeaderMenu() {
46952                         this.restrict = 'E';
46953                         this.replace = true;
46954                         this.templateUrl = 'templates/header-menu.html';
46955                         this.controller = 'HeaderMenuController';
46956                         this.controllerAs = 'hmc';
46957                         this.scope = true;
46958                     }
46959                     HeaderMenu.Factory = function () {
46960                         var directive = function () {
46961                             return new HeaderMenu();
46962                         };
46963                         return directive;
46964                     };
46965                     return HeaderMenu;
46966                 })();
46967                 directives.HeaderMenu = HeaderMenu;
46968                 var HeaderMenuController = (function () {
46969                     function HeaderMenuController($state) {
46970                         this.$state = $state;
46971                         this.isExecution = this.$state.current.name === 'execution';
46972                         this.isWorkspace = this.$state.current.name === 'workspace';
46973                         this.isHistory = this.$state.current.name === 'history';
46974                     }
46975                     HeaderMenuController.prototype.transit = function (state) {
46976                         this.$state.go(state);
46977                     };
46978                     HeaderMenuController.$inject = ['$state'];
46979                     return HeaderMenuController;
46980                 })();
46981                 directives.HeaderMenuController = HeaderMenuController;
46982             })(directives = app.directives || (app.directives = {}));
46983         })(app || (app = {}));
46984         var app;
46985         (function (app) {
46986             var directives;
46987             (function (directives) {
46988                 var Option = (function () {
46989                     function Option() {
46990                         this.restrict = 'E';
46991                         this.replace = true;
46992                         this.controller = 'optionController';
46993                         this.bindToController = {
46994                             info: '=',
46995                             files: '='
46996                         };
46997                         this.scope = true;
46998                         this.templateUrl = 'templates/option.html';
46999                         this.controllerAs = 'ctrl';
47000                     }
47001                     Option.Factory = function () {
47002                         var directive = function () {
47003                             return new Option();
47004                         };
47005                         directive.$inject = [];
47006                         return directive;
47007                     };
47008                     return Option;
47009                 })();
47010                 directives.Option = Option;
47011                 var OptionController = (function () {
47012                     function OptionController() {
47013                         var controller = this;
47014                         angular.forEach(controller.info.arg, function (arg) {
47015                             if (arg.initialValue) {
47016                                 if (arg.formType === 'number') {
47017                                     arg.input = parseInt(arg.initialValue);
47018                                 }
47019                                 else {
47020                                     arg.input = arg.initialValue;
47021                                 }
47022                             }
47023                         });
47024                     }
47025                     OptionController.$inject = [];
47026                     return OptionController;
47027                 })();
47028                 directives.OptionController = OptionController;
47029             })(directives = app.directives || (app.directives = {}));
47030         })(app || (app = {}));
47031         var app;
47032         (function (app) {
47033             var directives;
47034             (function (directives) {
47035                 var Directory = (function () {
47036                     function Directory() {
47037                         this.restrict = 'E';
47038                         this.replace = true;
47039                         this.controller = 'directoryController';
47040                         this.controllerAs = 'ctrl';
47041                         this.bindToController = {
47042                             info: '=',
47043                             add: '&',
47044                             list: '=',
47045                             files: '='
47046                         };
47047                         this.templateUrl = 'templates/directory.html';
47048                     }
47049                     Directory.Factory = function () {
47050                         var directive = function () {
47051                             return new Directory();
47052                         };
47053                         return directive;
47054                     };
47055                     return Directory;
47056                 })();
47057                 directives.Directory = Directory;
47058                 var DirectoryController = (function () {
47059                     function DirectoryController(APIEndPoint, $scope) {
47060                         this.APIEndPoint = APIEndPoint;
47061                         this.$scope = $scope;
47062                         var controller = this;
47063                         this.APIEndPoint
47064                             .getFiles(this.info.fileId)
47065                             .$promise
47066                             .then(function (result) {
47067                             if (result.status === 'success') {
47068                                 controller.files = result.info;
47069                                 angular.forEach(result.info, function (file) {
47070                                     if (file.fileType === '0') {
47071                                         var o = file;
47072                                         if (controller.info.path === '/') {
47073                                             o.path = '/' + file.name;
47074                                         }
47075                                         else {
47076                                             o.path = controller.info.path + '/' + file.name;
47077                                         }
47078                                         controller.add()(o, controller.list);
47079                                     }
47080                                 });
47081                             }
47082                             ;
47083                         });
47084                     }
47085                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
47086                     return DirectoryController;
47087                 })();
47088                 directives.DirectoryController = DirectoryController;
47089             })(directives = app.directives || (app.directives = {}));
47090         })(app || (app = {}));
47091         var app;
47092         (function (app) {
47093             var directives;
47094             (function (directives) {
47095                 var Upload = (function () {
47096                     function Upload() {
47097                         this.restrict = 'E';
47098                         this.replace = true;
47099                         this.scope = true;
47100                         this.controller = 'UploadController';
47101                         this.controllerAs = 'ctrl';
47102                         this.bindToController = {
47103                             index: '=',
47104                             name: '=',
47105                             remove: '&',
47106                             list: '='
47107                         };
47108                         this.templateUrl = 'templates/upload.html';
47109                         console.log("templates/upload.html-constructor");
47110                     }
47111                     Upload.Factory = function () {
47112                         var directive = function () {
47113                             return new Upload();
47114                         };
47115                         directive.$inject = [];
47116                         return directive;
47117                     };
47118                     return Upload;
47119                 })();
47120                 directives.Upload = Upload;
47121                 var UploadController = (function () {
47122                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
47123                         this.APIEndPoint = APIEndPoint;
47124                         this.$scope = $scope;
47125                         this.MyModal = MyModal;
47126                         this.WebSocket = WebSocket;
47127                         this.$window = $window;
47128                         this.$rootScope = $rootScope;
47129                         this.Console = Console;
47130                         var controller = this;
47131                         console.log("directive.upload-constructor");
47132                     }
47133                     UploadController.prototype.submit = function () {
47134                         console.log("submit: function not supported¥n");
47135                     };
47136                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
47137                     return UploadController;
47138                 })();
47139                 directives.UploadController = UploadController;
47140             })(directives = app.directives || (app.directives = {}));
47141         })(app || (app = {}));
47142         var app;
47143         (function (app) {
47144             var controllers;
47145             (function (controllers) {
47146                 var Execution = (function () {
47147                     function Execution(MyModal, $scope) {
47148                         this.MyModal = MyModal;
47149                         this.$scope = $scope;
47150                         this.commandInfoList = [];
47151                     }
47152                     ;
47153                     Execution.prototype.add = function () {
47154                         this.$scope.$broadcast('close');
47155                         var commandInfoList = this.commandInfoList;
47156                         var commandInstance = this.MyModal.selectCommand();
47157                         commandInstance
47158                             .result
47159                             .then(function (command) {
47160                             commandInfoList.push(new app.declares.CommandInfo(command));
47161                         });
47162                     };
47163                     Execution.prototype.open = function () {
47164                         var result = this.MyModal.open('SelectCommand');
47165                         console.log(result);
47166                     };
47167                     Execution.prototype.remove = function (index, list) {
47168                         list.splice(index, 1);
47169                     };
47170                     Execution.prototype.close = function () {
47171                         console.log("close");
47172                     };
47173                     Execution.$inject = ['MyModal', '$scope'];
47174                     return Execution;
47175                 })();
47176                 controllers.Execution = Execution;
47177             })(controllers = app.controllers || (app.controllers = {}));
47178         })(app || (app = {}));
47179         var app;
47180         (function (app) {
47181             var controllers;
47182             (function (controllers) {
47183                 var Workspace = (function () {
47184                     function Workspace($scope, APIEndPoint, MyModal) {
47185                         this.$scope = $scope;
47186                         this.APIEndPoint = APIEndPoint;
47187                         this.MyModal = MyModal;
47188                         this.directoryList = [];
47189                         var controller = this;
47190                         var directoryList = this.directoryList;
47191                         var o = {
47192                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
47193                             name: '',
47194                             parentId: '',
47195                             fileType: '',
47196                             createdAt: '',
47197                             updatedAt: '',
47198                             path: '/'
47199                         };
47200                         directoryList.push(o);
47201                     }
47202                     Workspace.prototype.addDirectory = function (info, directoryList) {
47203                         directoryList.push(info);
47204                     };
47205                     Workspace.prototype.upload = function () {
47206                         this.MyModal.upload();
47207                     };
47208                     Workspace.prototype.debug = function () {
47209                         this.MyModal.preview();
47210                     };
47211                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
47212                     return Workspace;
47213                 })();
47214                 controllers.Workspace = Workspace;
47215             })(controllers = app.controllers || (app.controllers = {}));
47216         })(app || (app = {}));
47217         var app;
47218         (function (app) {
47219             var controllers;
47220             (function (controllers) {
47221                 var History = (function () {
47222                     function History($scope) {
47223                         this.page = "History";
47224                     }
47225                     History.$inject = ['$scope'];
47226                     return History;
47227                 })();
47228                 controllers.History = History;
47229             })(controllers = app.controllers || (app.controllers = {}));
47230         })(app || (app = {}));
47231         var app;
47232         (function (app) {
47233             var controllers;
47234             (function (controllers) {
47235                 var SelectCommand = (function () {
47236                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
47237                         this.APIEndPoint = APIEndPoint;
47238                         this.$modalInstance = $modalInstance;
47239                         var controller = this;
47240                         this.APIEndPoint
47241                             .getTags()
47242                             .$promise.then(function (result) {
47243                             controller.tags = result.info;
47244                         });
47245                         this.APIEndPoint
47246                             .getCommands()
47247                             .$promise.then(function (result) {
47248                             controller.commands = result.info;
47249                         });
47250                         this.currentTag = 'all';
47251                     }
47252                     SelectCommand.prototype.changeTag = function (tag) {
47253                         this.currentTag = tag;
47254                     };
47255                     SelectCommand.prototype.selectCommand = function (command) {
47256                         this.$modalInstance.close(command);
47257                     };
47258                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47259                     return SelectCommand;
47260                 })();
47261                 controllers.SelectCommand = SelectCommand;
47262             })(controllers = app.controllers || (app.controllers = {}));
47263         })(app || (app = {}));
47264         var app;
47265         (function (app) {
47266             var controllers;
47267             (function (controllers) {
47268                 var Upload = (function () {
47269                     function Upload($scope, APIEndPoint, $modalInstance) {
47270                         this.APIEndPoint = APIEndPoint;
47271                         this.$modalInstance = $modalInstance;
47272                         var controller = this;
47273                         console.log('controller.upload-controllers');
47274                     }
47275                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47276                     return Upload;
47277                 })();
47278                 controllers.Upload = Upload;
47279             })(controllers = app.controllers || (app.controllers = {}));
47280         })(app || (app = {}));
47281         var app;
47282         (function (app) {
47283             var controllers;
47284             (function (controllers) {
47285                 var Preview = (function () {
47286                     function Preview($scope, APIEndPoint, $modalInstance) {
47287                         this.APIEndPoint = APIEndPoint;
47288                         this.$modalInstance = $modalInstance;
47289                         var controller = this;
47290                         console.log('preview');
47291                     }
47292                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
47293                     return Preview;
47294                 })();
47295                 controllers.Preview = Preview;
47296             })(controllers = app.controllers || (app.controllers = {}));
47297         })(app || (app = {}));
47298         var filters;
47299         (function (filters) {
47300             function Tag() {
47301                 return function (commands, tag) {
47302                     var result = [];
47303                     angular.forEach(commands, function (command) {
47304                         var flag = false;
47305                         angular.forEach(command.tags, function (value) {
47306                             if (tag === value)
47307                                 flag = true;
47308                         });
47309                         if (flag)
47310                             result.push(command);
47311                     });
47312                     return result;
47313                 };
47314             }
47315             filters.Tag = Tag;
47316         })(filters || (filters = {}));
47317         var app;
47318         (function (app) {
47319             'use strict';
47320             var appName = 'zephyr';
47321             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
47322             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
47323                 $urlRouterProvider.otherwise('/execution');
47324                 $locationProvider.html5Mode({
47325                     enabled: true,
47326                     requireBase: false
47327                 });
47328                 $stateProvider
47329                     .state('execution', {
47330                     url: '/execution',
47331                     templateUrl: 'templates/execution.html',
47332                     controller: 'executionController',
47333                     controllerAs: 'c'
47334                 })
47335                     .state('workspace', {
47336                     url: '/workspace',
47337                     templateUrl: 'templates/workspace.html',
47338                     controller: 'workspaceController',
47339                     controllerAs: 'c'
47340                 })
47341                     .state('history', {
47342                     url: '/history',
47343                     templateUrl: 'templates/history.html',
47344                     controller: 'historyController',
47345                     controllerAs: 'c'
47346                 });
47347             });
47348             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
47349             app.zephyr.service('MyModal', app.services.MyModal);
47350             app.zephyr.service('WebSocket', app.services.WebSocket);
47351             app.zephyr.service('Console', app.services.Console);
47352             app.zephyr.filter('Tag', filters.Tag);
47353             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
47354             app.zephyr.controller('previewController', app.controllers.Preview);
47355             app.zephyr.controller('uploadController', app.controllers.Upload);
47356             app.zephyr.controller('executionController', app.controllers.Execution);
47357             app.zephyr.controller('workspaceController', app.controllers.Workspace);
47358             app.zephyr.controller('historyController', app.controllers.History);
47359             app.zephyr.controller('commandController', app.directives.CommandController);
47360             app.zephyr.controller('optionController', app.directives.OptionController);
47361             app.zephyr.controller('directoryController', app.directives.DirectoryController);
47362             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
47363             app.zephyr.controller('uploadController', app.directives.UploadController);
47364             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
47365             app.zephyr.directive('command', app.directives.Command.Factory());
47366             app.zephyr.directive('option', app.directives.Option.Factory());
47367             app.zephyr.directive('directory', app.directives.Directory.Factory());
47368         })(app || (app = {}));
47369
47370
47371 /***/ },
47372 /* 15 */
47373 /***/ function(module, exports) {
47374
47375         var app;
47376         (function (app) {
47377             var declares;
47378             (function (declares) {
47379                 var CommandInfo = (function () {
47380                     function CommandInfo(name) {
47381                         this.name = name;
47382                     }
47383                     return CommandInfo;
47384                 })();
47385                 declares.CommandInfo = CommandInfo;
47386             })(declares = app.declares || (app.declares = {}));
47387         })(app || (app = {}));
47388         var app;
47389         (function (app) {
47390             var services;
47391             (function (services) {
47392                 var APIEndPoint = (function () {
47393                     function APIEndPoint($resource, $http) {
47394                         this.$resource = $resource;
47395                         this.$http = $http;
47396                     }
47397                     APIEndPoint.prototype.resource = function (endPoint, data) {
47398                         var customAction = {
47399                             method: 'GET',
47400                             isArray: false
47401                         };
47402                         var execute = {
47403                             method: 'POST',
47404                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
47405                         };
47406                         return this.$resource(endPoint, {}, { execute: execute });
47407                     };
47408                     APIEndPoint.prototype.getOptionControlFile = function (command) {
47409                         var endPoint = '/api/v1/optionControlFile/' + command;
47410                         return this.resource(endPoint, {}).get();
47411                     };
47412                     APIEndPoint.prototype.getFiles = function (fileId) {
47413                         var endPoint = '/api/v1/workspace';
47414                         if (fileId) {
47415                             endPoint += '/' + fileId;
47416                         }
47417                         return this.resource(endPoint, {}).get();
47418                     };
47419                     APIEndPoint.prototype.getDirectories = function () {
47420                         var endPoint = '/api/v1/all/workspace/directory';
47421                         return this.resource(endPoint, {}).get();
47422                     };
47423                     APIEndPoint.prototype.getTags = function () {
47424                         var endPoint = '/api/v1/tagList';
47425                         return this.resource(endPoint, {}).get();
47426                     };
47427                     APIEndPoint.prototype.getCommands = function () {
47428                         var endPoint = '/api/v1/commandList';
47429                         return this.resource(endPoint, {}).get();
47430                     };
47431                     APIEndPoint.prototype.execute = function (data) {
47432                         var endPoint = '/api/v1/execution';
47433                         var fd = new FormData();
47434                         fd.append('data', data);
47435                         return this.$http.post(endPoint, fd, {
47436                             headers: { 'Content-Type': undefined },
47437                             transformRequest: angular.identity
47438                         });
47439                     };
47440                     APIEndPoint.prototype.debug = function () {
47441                         var endPoint = '/api/v1/debug';
47442                         return this.$http.get(endPoint);
47443                     };
47444                     APIEndPoint.prototype.upload = function () {
47445                         var endPoint = '/api/v1/upload';
47446                         return this.$http.get(endPoint);
47447                     };
47448                     APIEndPoint.prototype.help = function (command) {
47449                         var endPoint = '/api/v1/help/' + command;
47450                         return this.$http.get(endPoint);
47451                     };
47452                     return APIEndPoint;
47453                 })();
47454                 services.APIEndPoint = APIEndPoint;
47455             })(services = app.services || (app.services = {}));
47456         })(app || (app = {}));
47457         var app;
47458         (function (app) {
47459             var services;
47460             (function (services) {
47461                 var MyModal = (function () {
47462                     function MyModal($uibModal) {
47463                         this.$uibModal = $uibModal;
47464                         this.modalOption = {
47465                             backdrop: true,
47466                             controller: null,
47467                             templateUrl: null,
47468                             size: null
47469                         };
47470                     }
47471                     MyModal.prototype.open = function (modalName) {
47472                         if (modalName === 'SelectCommand') {
47473                             this.modalOption.templateUrl = 'templates/select-command.html';
47474                             this.modalOption.size = 'lg';
47475                         }
47476                         return this.$uibModal.open(this.modalOption);
47477                     };
47478                     MyModal.prototype.selectCommand = function () {
47479                         this.modalOption.templateUrl = 'templates/select-command.html';
47480                         this.modalOption.controller = 'selectCommandController';
47481                         this.modalOption.controllerAs = 'c';
47482                         this.modalOption.size = 'lg';
47483                         return this.$uibModal.open(this.modalOption);
47484                     };
47485                     MyModal.prototype.preview = function () {
47486                         this.modalOption.templateUrl = 'templates/preview.html';
47487                         this.modalOption.controller = 'previewController';
47488                         this.modalOption.controllerAs = 'c';
47489                         this.modalOption.size = 'lg';
47490                         return this.$uibModal.open(this.modalOption);
47491                     };
47492                     MyModal.prototype.upload = function () {
47493                         this.modalOption.templateUrl = 'templates/upload.html';
47494                         this.modalOption.controller = 'uploadController';
47495                         this.modalOption.controllerAs = 'c';
47496                         this.modalOption.size = 'lg';
47497                         return this.$uibModal.open(this.modalOption);
47498                     };
47499                     MyModal.$inject = ['$uibModal'];
47500                     return MyModal;
47501                 })();
47502                 services.MyModal = MyModal;
47503             })(services = app.services || (app.services = {}));
47504         })(app || (app = {}));
47505         var app;
47506         (function (app) {
47507             var services;
47508             (function (services) {
47509                 var WebSocket = (function () {
47510                     function WebSocket($rootScope) {
47511                         this.$rootScope = $rootScope;
47512                         this.socket = io.connect();
47513                     }
47514                     WebSocket.prototype.on = function (eventName, callback) {
47515                         var socket = this.socket;
47516                         var rootScope = this.$rootScope;
47517                         socket.on(eventName, function () {
47518                             var args = arguments;
47519                             rootScope.$apply(function () {
47520                                 callback.apply(socket, args);
47521                             });
47522                         });
47523                     };
47524                     WebSocket.prototype.emit = function (eventName, data, callback) {
47525                         var socket = this.socket;
47526                         var rootScope = this.$rootScope;
47527                         this.socket.emit(eventName, data, function () {
47528                             var args = arguments;
47529                             rootScope.$apply(function () {
47530                                 if (callback)
47531                                     callback.apply(socket, args);
47532                             });
47533                         });
47534                     };
47535                     return WebSocket;
47536                 })();
47537                 services.WebSocket = WebSocket;
47538             })(services = app.services || (app.services = {}));
47539         })(app || (app = {}));
47540         var app;
47541         (function (app) {
47542             var services;
47543             (function (services) {
47544                 var Console = (function () {
47545                     function Console(WebSocket, $rootScope) {
47546                         this.WebSocket = WebSocket;
47547                         this.$rootScope = $rootScope;
47548                         this.WebSocket = WebSocket;
47549                         this.$rootScope = $rootScope;
47550                         this.directiveIDs = [];
47551                         var directiveIDs = this.directiveIDs;
47552                         this.WebSocket.on('console', function (d) {
47553                             var id = d.id;
47554                             var message = d.message;
47555                             if (directiveIDs.indexOf(id) > -1) {
47556                                 $rootScope.$emit(id, message);
47557                             }
47558                         });
47559                     }
47560                     Console.prototype.addDirective = function (id) {
47561                         if (!(this.directiveIDs.indexOf(id) > -1)) {
47562                             this.directiveIDs.push(id);
47563                         }
47564                     };
47565                     Console.prototype.removeDirective = function (id) {
47566                         var i = this.directiveIDs.indexOf(id);
47567                         if (i > -1) {
47568                             this.directiveIDs.splice(i, 1);
47569                         }
47570                     };
47571                     Console.prototype.showIDs = function () {
47572                         console.log(this.directiveIDs);
47573                     };
47574                     return Console;
47575                 })();
47576                 services.Console = Console;
47577             })(services = app.services || (app.services = {}));
47578         })(app || (app = {}));
47579         var app;
47580         (function (app) {
47581             var directives;
47582             (function (directives) {
47583                 var Command = (function () {
47584                     function Command() {
47585                         this.restrict = 'E';
47586                         this.replace = true;
47587                         this.scope = true;
47588                         this.controller = 'commandController';
47589                         this.controllerAs = 'ctrl';
47590                         this.bindToController = {
47591                             index: '=',
47592                             name: '=',
47593                             remove: '&',
47594                             list: '='
47595                         };
47596                         this.templateUrl = 'templates/command.html';
47597                     }
47598                     Command.Factory = function () {
47599                         var directive = function () {
47600                             return new Command();
47601                         };
47602                         directive.$inject = [];
47603                         return directive;
47604                     };
47605                     return Command;
47606                 })();
47607                 directives.Command = Command;
47608                 var CommandController = (function () {
47609                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
47610                         this.APIEndPoint = APIEndPoint;
47611                         this.$scope = $scope;
47612                         this.MyModal = MyModal;
47613                         this.WebSocket = WebSocket;
47614                         this.$window = $window;
47615                         this.$rootScope = $rootScope;
47616                         this.Console = Console;
47617                         var controller = this;
47618                         this.APIEndPoint
47619                             .getOptionControlFile(this.name)
47620                             .$promise
47621                             .then(function (result) {
47622                             controller.options = result.info;
47623                         });
47624                         this.APIEndPoint
47625                             .getDirectories()
47626                             .$promise
47627                             .then(function (result) {
47628                             controller.dirs = result.info;
47629                         });
47630                         this.heading = "[" + this.index + "]: dcdFilePrint";
47631                         this.isOpen = true;
47632                         this.$scope.$on('close', function () {
47633                             controller.isOpen = false;
47634                         });
47635                         function guid() {
47636                             function s4() {
47637                                 return Math.floor((1 + Math.random()) * 0x10000)
47638                                     .toString(16)
47639                                     .substring(1);
47640                             }
47641                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
47642                                 s4() + '-' + s4() + s4() + s4();
47643                         }
47644                         this.uuid = guid();
47645                         this.Console.addDirective(this.uuid);
47646                         this.Console.showIDs();
47647                     }
47648                     CommandController.prototype.submit = function () {
47649                         var opt = [];
47650                         angular.forEach(this.options, function (option) {
47651                             var obj = {
47652                                 name: option.option,
47653                                 arguments: []
47654                             };
47655                             angular.forEach(option.arg, function (arg) {
47656                                 if (arg.input) {
47657                                     if (typeof arg.input === 'object') {
47658                                         obj.arguments.push(arg.input.name);
47659                                     }
47660                                     else {
47661                                         obj.arguments.push(arg.input);
47662                                     }
47663                                 }
47664                             });
47665                             if (obj.arguments.length > 0) {
47666                                 opt.push(obj);
47667                             }
47668                         });
47669                         var execObj = {
47670                             command: this.name,
47671                             workspace: this.workspace.fileId,
47672                             options: opt
47673                         };
47674                         this.APIEndPoint
47675                             .execute(JSON.stringify(execObj))
47676                             .then(function (result) {
47677                             console.log(result);
47678                         });
47679                     };
47680                     CommandController.prototype.removeMySelf = function (index) {
47681                         this.$scope.$destroy();
47682                         this.Console.removeDirective(this.uuid);
47683                         this.remove()(index, this.list);
47684                         this.Console.showIDs();
47685                     };
47686                     CommandController.prototype.reloadFiles = function () {
47687                         var _this = this;
47688                         var fileId = this.workspace.fileId;
47689                         this.APIEndPoint
47690                             .getFiles(fileId)
47691                             .$promise
47692                             .then(function (result) {
47693                             var status = result.status;
47694                             if (status === 'success') {
47695                                 _this.files = result.info;
47696                             }
47697                             else {
47698                                 console.log(result.message);
47699                             }
47700                         });
47701                     };
47702                     CommandController.prototype.debug = function () {
47703                         var div = angular.element(this.$window.document).find("div");
47704                         var consoleTag;
47705                         var parametersTag;
47706                         angular.forEach(div, function (v) {
47707                             if (v.className === "panel-body console") {
47708                                 consoleTag = v;
47709                             }
47710                             else if (v.className === "row parameters-console") {
47711                                 parametersTag = v;
47712                             }
47713                         });
47714                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
47715                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
47716                         consoleTag.style.height = consoleHeight;
47717                         consoleTag.style.width = consoleWidth;
47718                     };
47719                     CommandController.prototype.help = function () {
47720                         this.APIEndPoint
47721                             .help(this.name)
47722                             .then(function (result) {
47723                             console.log(result);
47724                         });
47725                     };
47726                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
47727                     return CommandController;
47728                 })();
47729                 directives.CommandController = CommandController;
47730             })(directives = app.directives || (app.directives = {}));
47731         })(app || (app = {}));
47732         var app;
47733         (function (app) {
47734             var directives;
47735             (function (directives) {
47736                 var HeaderMenu = (function () {
47737                     function HeaderMenu() {
47738                         this.restrict = 'E';
47739                         this.replace = true;
47740                         this.templateUrl = 'templates/header-menu.html';
47741                         this.controller = 'HeaderMenuController';
47742                         this.controllerAs = 'hmc';
47743                         this.scope = true;
47744                     }
47745                     HeaderMenu.Factory = function () {
47746                         var directive = function () {
47747                             return new HeaderMenu();
47748                         };
47749                         return directive;
47750                     };
47751                     return HeaderMenu;
47752                 })();
47753                 directives.HeaderMenu = HeaderMenu;
47754                 var HeaderMenuController = (function () {
47755                     function HeaderMenuController($state) {
47756                         this.$state = $state;
47757                         this.isExecution = this.$state.current.name === 'execution';
47758                         this.isWorkspace = this.$state.current.name === 'workspace';
47759                         this.isHistory = this.$state.current.name === 'history';
47760                     }
47761                     HeaderMenuController.prototype.transit = function (state) {
47762                         this.$state.go(state);
47763                     };
47764                     HeaderMenuController.$inject = ['$state'];
47765                     return HeaderMenuController;
47766                 })();
47767                 directives.HeaderMenuController = HeaderMenuController;
47768             })(directives = app.directives || (app.directives = {}));
47769         })(app || (app = {}));
47770         var app;
47771         (function (app) {
47772             var directives;
47773             (function (directives) {
47774                 var Option = (function () {
47775                     function Option() {
47776                         this.restrict = 'E';
47777                         this.replace = true;
47778                         this.controller = 'optionController';
47779                         this.bindToController = {
47780                             info: '=',
47781                             files: '='
47782                         };
47783                         this.scope = true;
47784                         this.templateUrl = 'templates/option.html';
47785                         this.controllerAs = 'ctrl';
47786                     }
47787                     Option.Factory = function () {
47788                         var directive = function () {
47789                             return new Option();
47790                         };
47791                         directive.$inject = [];
47792                         return directive;
47793                     };
47794                     return Option;
47795                 })();
47796                 directives.Option = Option;
47797                 var OptionController = (function () {
47798                     function OptionController() {
47799                         var controller = this;
47800                         angular.forEach(controller.info.arg, function (arg) {
47801                             if (arg.initialValue) {
47802                                 if (arg.formType === 'number') {
47803                                     arg.input = parseInt(arg.initialValue);
47804                                 }
47805                                 else {
47806                                     arg.input = arg.initialValue;
47807                                 }
47808                             }
47809                         });
47810                     }
47811                     OptionController.$inject = [];
47812                     return OptionController;
47813                 })();
47814                 directives.OptionController = OptionController;
47815             })(directives = app.directives || (app.directives = {}));
47816         })(app || (app = {}));
47817         var app;
47818         (function (app) {
47819             var directives;
47820             (function (directives) {
47821                 var Directory = (function () {
47822                     function Directory() {
47823                         this.restrict = 'E';
47824                         this.replace = true;
47825                         this.controller = 'directoryController';
47826                         this.controllerAs = 'ctrl';
47827                         this.bindToController = {
47828                             info: '=',
47829                             add: '&',
47830                             list: '=',
47831                             files: '='
47832                         };
47833                         this.templateUrl = 'templates/directory.html';
47834                     }
47835                     Directory.Factory = function () {
47836                         var directive = function () {
47837                             return new Directory();
47838                         };
47839                         return directive;
47840                     };
47841                     return Directory;
47842                 })();
47843                 directives.Directory = Directory;
47844                 var DirectoryController = (function () {
47845                     function DirectoryController(APIEndPoint, $scope) {
47846                         this.APIEndPoint = APIEndPoint;
47847                         this.$scope = $scope;
47848                         var controller = this;
47849                         this.APIEndPoint
47850                             .getFiles(this.info.fileId)
47851                             .$promise
47852                             .then(function (result) {
47853                             if (result.status === 'success') {
47854                                 controller.files = result.info;
47855                                 angular.forEach(result.info, function (file) {
47856                                     if (file.fileType === '0') {
47857                                         var o = file;
47858                                         if (controller.info.path === '/') {
47859                                             o.path = '/' + file.name;
47860                                         }
47861                                         else {
47862                                             o.path = controller.info.path + '/' + file.name;
47863                                         }
47864                                         controller.add()(o, controller.list);
47865                                     }
47866                                 });
47867                             }
47868                             ;
47869                         });
47870                     }
47871                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
47872                     return DirectoryController;
47873                 })();
47874                 directives.DirectoryController = DirectoryController;
47875             })(directives = app.directives || (app.directives = {}));
47876         })(app || (app = {}));
47877         var app;
47878         (function (app) {
47879             var directives;
47880             (function (directives) {
47881                 var Upload = (function () {
47882                     function Upload() {
47883                         this.restrict = 'E';
47884                         this.replace = true;
47885                         this.scope = true;
47886                         this.controller = 'UploadController';
47887                         this.controllerAs = 'ctrl';
47888                         this.bindToController = {
47889                             index: '=',
47890                             name: '=',
47891                             remove: '&',
47892                             list: '='
47893                         };
47894                         this.templateUrl = 'templates/upload.html';
47895                         console.log("templates/upload.html-constructor");
47896                     }
47897                     Upload.Factory = function () {
47898                         var directive = function () {
47899                             return new Upload();
47900                         };
47901                         directive.$inject = [];
47902                         return directive;
47903                     };
47904                     return Upload;
47905                 })();
47906                 directives.Upload = Upload;
47907                 var UploadController = (function () {
47908                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
47909                         this.APIEndPoint = APIEndPoint;
47910                         this.$scope = $scope;
47911                         this.MyModal = MyModal;
47912                         this.WebSocket = WebSocket;
47913                         this.$window = $window;
47914                         this.$rootScope = $rootScope;
47915                         this.Console = Console;
47916                         var controller = this;
47917                         console.log("directive.upload-constructor");
47918                     }
47919                     UploadController.prototype.submit = function () {
47920                         console.log("submit: function not supported¥n");
47921                     };
47922                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
47923                     return UploadController;
47924                 })();
47925                 directives.UploadController = UploadController;
47926             })(directives = app.directives || (app.directives = {}));
47927         })(app || (app = {}));
47928         var app;
47929         (function (app) {
47930             var controllers;
47931             (function (controllers) {
47932                 var Execution = (function () {
47933                     function Execution(MyModal, $scope) {
47934                         this.MyModal = MyModal;
47935                         this.$scope = $scope;
47936                         this.commandInfoList = [];
47937                     }
47938                     ;
47939                     Execution.prototype.add = function () {
47940                         this.$scope.$broadcast('close');
47941                         var commandInfoList = this.commandInfoList;
47942                         var commandInstance = this.MyModal.selectCommand();
47943                         commandInstance
47944                             .result
47945                             .then(function (command) {
47946                             commandInfoList.push(new app.declares.CommandInfo(command));
47947                         });
47948                     };
47949                     Execution.prototype.open = function () {
47950                         var result = this.MyModal.open('SelectCommand');
47951                         console.log(result);
47952                     };
47953                     Execution.prototype.remove = function (index, list) {
47954                         list.splice(index, 1);
47955                     };
47956                     Execution.prototype.close = function () {
47957                         console.log("close");
47958                     };
47959                     Execution.$inject = ['MyModal', '$scope'];
47960                     return Execution;
47961                 })();
47962                 controllers.Execution = Execution;
47963             })(controllers = app.controllers || (app.controllers = {}));
47964         })(app || (app = {}));
47965         var app;
47966         (function (app) {
47967             var controllers;
47968             (function (controllers) {
47969                 var Workspace = (function () {
47970                     function Workspace($scope, APIEndPoint, MyModal) {
47971                         this.$scope = $scope;
47972                         this.APIEndPoint = APIEndPoint;
47973                         this.MyModal = MyModal;
47974                         this.directoryList = [];
47975                         var controller = this;
47976                         var directoryList = this.directoryList;
47977                         var o = {
47978                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
47979                             name: '',
47980                             parentId: '',
47981                             fileType: '',
47982                             createdAt: '',
47983                             updatedAt: '',
47984                             path: '/'
47985                         };
47986                         directoryList.push(o);
47987                     }
47988                     Workspace.prototype.addDirectory = function (info, directoryList) {
47989                         directoryList.push(info);
47990                     };
47991                     Workspace.prototype.upload = function () {
47992                         this.MyModal.upload();
47993                     };
47994                     Workspace.prototype.debug = function () {
47995                         this.MyModal.preview();
47996                     };
47997                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
47998                     return Workspace;
47999                 })();
48000                 controllers.Workspace = Workspace;
48001             })(controllers = app.controllers || (app.controllers = {}));
48002         })(app || (app = {}));
48003         var app;
48004         (function (app) {
48005             var controllers;
48006             (function (controllers) {
48007                 var History = (function () {
48008                     function History($scope) {
48009                         this.page = "History";
48010                     }
48011                     History.$inject = ['$scope'];
48012                     return History;
48013                 })();
48014                 controllers.History = History;
48015             })(controllers = app.controllers || (app.controllers = {}));
48016         })(app || (app = {}));
48017         var app;
48018         (function (app) {
48019             var controllers;
48020             (function (controllers) {
48021                 var SelectCommand = (function () {
48022                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
48023                         this.APIEndPoint = APIEndPoint;
48024                         this.$modalInstance = $modalInstance;
48025                         var controller = this;
48026                         this.APIEndPoint
48027                             .getTags()
48028                             .$promise.then(function (result) {
48029                             controller.tags = result.info;
48030                         });
48031                         this.APIEndPoint
48032                             .getCommands()
48033                             .$promise.then(function (result) {
48034                             controller.commands = result.info;
48035                         });
48036                         this.currentTag = 'all';
48037                     }
48038                     SelectCommand.prototype.changeTag = function (tag) {
48039                         this.currentTag = tag;
48040                     };
48041                     SelectCommand.prototype.selectCommand = function (command) {
48042                         this.$modalInstance.close(command);
48043                     };
48044                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48045                     return SelectCommand;
48046                 })();
48047                 controllers.SelectCommand = SelectCommand;
48048             })(controllers = app.controllers || (app.controllers = {}));
48049         })(app || (app = {}));
48050         var app;
48051         (function (app) {
48052             var controllers;
48053             (function (controllers) {
48054                 var Upload = (function () {
48055                     function Upload($scope, APIEndPoint, $modalInstance) {
48056                         this.APIEndPoint = APIEndPoint;
48057                         this.$modalInstance = $modalInstance;
48058                         var controller = this;
48059                         console.log('controller.upload-controllers');
48060                     }
48061                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48062                     return Upload;
48063                 })();
48064                 controllers.Upload = Upload;
48065             })(controllers = app.controllers || (app.controllers = {}));
48066         })(app || (app = {}));
48067         var app;
48068         (function (app) {
48069             var controllers;
48070             (function (controllers) {
48071                 var Preview = (function () {
48072                     function Preview($scope, APIEndPoint, $modalInstance) {
48073                         this.APIEndPoint = APIEndPoint;
48074                         this.$modalInstance = $modalInstance;
48075                         var controller = this;
48076                         console.log('preview');
48077                     }
48078                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48079                     return Preview;
48080                 })();
48081                 controllers.Preview = Preview;
48082             })(controllers = app.controllers || (app.controllers = {}));
48083         })(app || (app = {}));
48084         var filters;
48085         (function (filters) {
48086             function Tag() {
48087                 return function (commands, tag) {
48088                     var result = [];
48089                     angular.forEach(commands, function (command) {
48090                         var flag = false;
48091                         angular.forEach(command.tags, function (value) {
48092                             if (tag === value)
48093                                 flag = true;
48094                         });
48095                         if (flag)
48096                             result.push(command);
48097                     });
48098                     return result;
48099                 };
48100             }
48101             filters.Tag = Tag;
48102         })(filters || (filters = {}));
48103         var app;
48104         (function (app) {
48105             'use strict';
48106             var appName = 'zephyr';
48107             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
48108             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
48109                 $urlRouterProvider.otherwise('/execution');
48110                 $locationProvider.html5Mode({
48111                     enabled: true,
48112                     requireBase: false
48113                 });
48114                 $stateProvider
48115                     .state('execution', {
48116                     url: '/execution',
48117                     templateUrl: 'templates/execution.html',
48118                     controller: 'executionController',
48119                     controllerAs: 'c'
48120                 })
48121                     .state('workspace', {
48122                     url: '/workspace',
48123                     templateUrl: 'templates/workspace.html',
48124                     controller: 'workspaceController',
48125                     controllerAs: 'c'
48126                 })
48127                     .state('history', {
48128                     url: '/history',
48129                     templateUrl: 'templates/history.html',
48130                     controller: 'historyController',
48131                     controllerAs: 'c'
48132                 });
48133             });
48134             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
48135             app.zephyr.service('MyModal', app.services.MyModal);
48136             app.zephyr.service('WebSocket', app.services.WebSocket);
48137             app.zephyr.service('Console', app.services.Console);
48138             app.zephyr.filter('Tag', filters.Tag);
48139             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
48140             app.zephyr.controller('previewController', app.controllers.Preview);
48141             app.zephyr.controller('uploadController', app.controllers.Upload);
48142             app.zephyr.controller('executionController', app.controllers.Execution);
48143             app.zephyr.controller('workspaceController', app.controllers.Workspace);
48144             app.zephyr.controller('historyController', app.controllers.History);
48145             app.zephyr.controller('commandController', app.directives.CommandController);
48146             app.zephyr.controller('optionController', app.directives.OptionController);
48147             app.zephyr.controller('directoryController', app.directives.DirectoryController);
48148             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
48149             app.zephyr.controller('uploadController', app.directives.UploadController);
48150             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
48151             app.zephyr.directive('command', app.directives.Command.Factory());
48152             app.zephyr.directive('option', app.directives.Option.Factory());
48153             app.zephyr.directive('directory', app.directives.Directory.Factory());
48154         })(app || (app = {}));
48155
48156
48157 /***/ },
48158 /* 16 */
48159 /***/ function(module, exports) {
48160
48161         var app;
48162         (function (app) {
48163             var declares;
48164             (function (declares) {
48165                 var CommandInfo = (function () {
48166                     function CommandInfo(name) {
48167                         this.name = name;
48168                     }
48169                     return CommandInfo;
48170                 })();
48171                 declares.CommandInfo = CommandInfo;
48172             })(declares = app.declares || (app.declares = {}));
48173         })(app || (app = {}));
48174         var app;
48175         (function (app) {
48176             var services;
48177             (function (services) {
48178                 var APIEndPoint = (function () {
48179                     function APIEndPoint($resource, $http) {
48180                         this.$resource = $resource;
48181                         this.$http = $http;
48182                     }
48183                     APIEndPoint.prototype.resource = function (endPoint, data) {
48184                         var customAction = {
48185                             method: 'GET',
48186                             isArray: false
48187                         };
48188                         var execute = {
48189                             method: 'POST',
48190                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
48191                         };
48192                         return this.$resource(endPoint, {}, { execute: execute });
48193                     };
48194                     APIEndPoint.prototype.getOptionControlFile = function (command) {
48195                         var endPoint = '/api/v1/optionControlFile/' + command;
48196                         return this.resource(endPoint, {}).get();
48197                     };
48198                     APIEndPoint.prototype.getFiles = function (fileId) {
48199                         var endPoint = '/api/v1/workspace';
48200                         if (fileId) {
48201                             endPoint += '/' + fileId;
48202                         }
48203                         return this.resource(endPoint, {}).get();
48204                     };
48205                     APIEndPoint.prototype.getDirectories = function () {
48206                         var endPoint = '/api/v1/all/workspace/directory';
48207                         return this.resource(endPoint, {}).get();
48208                     };
48209                     APIEndPoint.prototype.getTags = function () {
48210                         var endPoint = '/api/v1/tagList';
48211                         return this.resource(endPoint, {}).get();
48212                     };
48213                     APIEndPoint.prototype.getCommands = function () {
48214                         var endPoint = '/api/v1/commandList';
48215                         return this.resource(endPoint, {}).get();
48216                     };
48217                     APIEndPoint.prototype.execute = function (data) {
48218                         var endPoint = '/api/v1/execution';
48219                         var fd = new FormData();
48220                         fd.append('data', data);
48221                         return this.$http.post(endPoint, fd, {
48222                             headers: { 'Content-Type': undefined },
48223                             transformRequest: angular.identity
48224                         });
48225                     };
48226                     APIEndPoint.prototype.debug = function () {
48227                         var endPoint = '/api/v1/debug';
48228                         return this.$http.get(endPoint);
48229                     };
48230                     APIEndPoint.prototype.upload = function () {
48231                         var endPoint = '/api/v1/upload';
48232                         return this.$http.get(endPoint);
48233                     };
48234                     APIEndPoint.prototype.help = function (command) {
48235                         var endPoint = '/api/v1/help/' + command;
48236                         return this.$http.get(endPoint);
48237                     };
48238                     return APIEndPoint;
48239                 })();
48240                 services.APIEndPoint = APIEndPoint;
48241             })(services = app.services || (app.services = {}));
48242         })(app || (app = {}));
48243         var app;
48244         (function (app) {
48245             var services;
48246             (function (services) {
48247                 var MyModal = (function () {
48248                     function MyModal($uibModal) {
48249                         this.$uibModal = $uibModal;
48250                         this.modalOption = {
48251                             backdrop: true,
48252                             controller: null,
48253                             templateUrl: null,
48254                             size: null
48255                         };
48256                     }
48257                     MyModal.prototype.open = function (modalName) {
48258                         if (modalName === 'SelectCommand') {
48259                             this.modalOption.templateUrl = 'templates/select-command.html';
48260                             this.modalOption.size = 'lg';
48261                         }
48262                         return this.$uibModal.open(this.modalOption);
48263                     };
48264                     MyModal.prototype.selectCommand = function () {
48265                         this.modalOption.templateUrl = 'templates/select-command.html';
48266                         this.modalOption.controller = 'selectCommandController';
48267                         this.modalOption.controllerAs = 'c';
48268                         this.modalOption.size = 'lg';
48269                         return this.$uibModal.open(this.modalOption);
48270                     };
48271                     MyModal.prototype.preview = function () {
48272                         this.modalOption.templateUrl = 'templates/preview.html';
48273                         this.modalOption.controller = 'previewController';
48274                         this.modalOption.controllerAs = 'c';
48275                         this.modalOption.size = 'lg';
48276                         return this.$uibModal.open(this.modalOption);
48277                     };
48278                     MyModal.prototype.upload = function () {
48279                         this.modalOption.templateUrl = 'templates/upload.html';
48280                         this.modalOption.controller = 'uploadController';
48281                         this.modalOption.controllerAs = 'c';
48282                         this.modalOption.size = 'lg';
48283                         return this.$uibModal.open(this.modalOption);
48284                     };
48285                     MyModal.$inject = ['$uibModal'];
48286                     return MyModal;
48287                 })();
48288                 services.MyModal = MyModal;
48289             })(services = app.services || (app.services = {}));
48290         })(app || (app = {}));
48291         var app;
48292         (function (app) {
48293             var services;
48294             (function (services) {
48295                 var WebSocket = (function () {
48296                     function WebSocket($rootScope) {
48297                         this.$rootScope = $rootScope;
48298                         this.socket = io.connect();
48299                     }
48300                     WebSocket.prototype.on = function (eventName, callback) {
48301                         var socket = this.socket;
48302                         var rootScope = this.$rootScope;
48303                         socket.on(eventName, function () {
48304                             var args = arguments;
48305                             rootScope.$apply(function () {
48306                                 callback.apply(socket, args);
48307                             });
48308                         });
48309                     };
48310                     WebSocket.prototype.emit = function (eventName, data, callback) {
48311                         var socket = this.socket;
48312                         var rootScope = this.$rootScope;
48313                         this.socket.emit(eventName, data, function () {
48314                             var args = arguments;
48315                             rootScope.$apply(function () {
48316                                 if (callback)
48317                                     callback.apply(socket, args);
48318                             });
48319                         });
48320                     };
48321                     return WebSocket;
48322                 })();
48323                 services.WebSocket = WebSocket;
48324             })(services = app.services || (app.services = {}));
48325         })(app || (app = {}));
48326         var app;
48327         (function (app) {
48328             var services;
48329             (function (services) {
48330                 var Console = (function () {
48331                     function Console(WebSocket, $rootScope) {
48332                         this.WebSocket = WebSocket;
48333                         this.$rootScope = $rootScope;
48334                         this.WebSocket = WebSocket;
48335                         this.$rootScope = $rootScope;
48336                         this.directiveIDs = [];
48337                         var directiveIDs = this.directiveIDs;
48338                         this.WebSocket.on('console', function (d) {
48339                             var id = d.id;
48340                             var message = d.message;
48341                             if (directiveIDs.indexOf(id) > -1) {
48342                                 $rootScope.$emit(id, message);
48343                             }
48344                         });
48345                     }
48346                     Console.prototype.addDirective = function (id) {
48347                         if (!(this.directiveIDs.indexOf(id) > -1)) {
48348                             this.directiveIDs.push(id);
48349                         }
48350                     };
48351                     Console.prototype.removeDirective = function (id) {
48352                         var i = this.directiveIDs.indexOf(id);
48353                         if (i > -1) {
48354                             this.directiveIDs.splice(i, 1);
48355                         }
48356                     };
48357                     Console.prototype.showIDs = function () {
48358                         console.log(this.directiveIDs);
48359                     };
48360                     return Console;
48361                 })();
48362                 services.Console = Console;
48363             })(services = app.services || (app.services = {}));
48364         })(app || (app = {}));
48365         var app;
48366         (function (app) {
48367             var directives;
48368             (function (directives) {
48369                 var Command = (function () {
48370                     function Command() {
48371                         this.restrict = 'E';
48372                         this.replace = true;
48373                         this.scope = true;
48374                         this.controller = 'commandController';
48375                         this.controllerAs = 'ctrl';
48376                         this.bindToController = {
48377                             index: '=',
48378                             name: '=',
48379                             remove: '&',
48380                             list: '='
48381                         };
48382                         this.templateUrl = 'templates/command.html';
48383                     }
48384                     Command.Factory = function () {
48385                         var directive = function () {
48386                             return new Command();
48387                         };
48388                         directive.$inject = [];
48389                         return directive;
48390                     };
48391                     return Command;
48392                 })();
48393                 directives.Command = Command;
48394                 var CommandController = (function () {
48395                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
48396                         this.APIEndPoint = APIEndPoint;
48397                         this.$scope = $scope;
48398                         this.MyModal = MyModal;
48399                         this.WebSocket = WebSocket;
48400                         this.$window = $window;
48401                         this.$rootScope = $rootScope;
48402                         this.Console = Console;
48403                         var controller = this;
48404                         this.APIEndPoint
48405                             .getOptionControlFile(this.name)
48406                             .$promise
48407                             .then(function (result) {
48408                             controller.options = result.info;
48409                         });
48410                         this.APIEndPoint
48411                             .getDirectories()
48412                             .$promise
48413                             .then(function (result) {
48414                             controller.dirs = result.info;
48415                         });
48416                         this.heading = "[" + this.index + "]: dcdFilePrint";
48417                         this.isOpen = true;
48418                         this.$scope.$on('close', function () {
48419                             controller.isOpen = false;
48420                         });
48421                         function guid() {
48422                             function s4() {
48423                                 return Math.floor((1 + Math.random()) * 0x10000)
48424                                     .toString(16)
48425                                     .substring(1);
48426                             }
48427                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
48428                                 s4() + '-' + s4() + s4() + s4();
48429                         }
48430                         this.uuid = guid();
48431                         this.Console.addDirective(this.uuid);
48432                         this.Console.showIDs();
48433                     }
48434                     CommandController.prototype.submit = function () {
48435                         var opt = [];
48436                         angular.forEach(this.options, function (option) {
48437                             var obj = {
48438                                 name: option.option,
48439                                 arguments: []
48440                             };
48441                             angular.forEach(option.arg, function (arg) {
48442                                 if (arg.input) {
48443                                     if (typeof arg.input === 'object') {
48444                                         obj.arguments.push(arg.input.name);
48445                                     }
48446                                     else {
48447                                         obj.arguments.push(arg.input);
48448                                     }
48449                                 }
48450                             });
48451                             if (obj.arguments.length > 0) {
48452                                 opt.push(obj);
48453                             }
48454                         });
48455                         var execObj = {
48456                             command: this.name,
48457                             workspace: this.workspace.fileId,
48458                             options: opt
48459                         };
48460                         this.APIEndPoint
48461                             .execute(JSON.stringify(execObj))
48462                             .then(function (result) {
48463                             console.log(result);
48464                         });
48465                     };
48466                     CommandController.prototype.removeMySelf = function (index) {
48467                         this.$scope.$destroy();
48468                         this.Console.removeDirective(this.uuid);
48469                         this.remove()(index, this.list);
48470                         this.Console.showIDs();
48471                     };
48472                     CommandController.prototype.reloadFiles = function () {
48473                         var _this = this;
48474                         var fileId = this.workspace.fileId;
48475                         this.APIEndPoint
48476                             .getFiles(fileId)
48477                             .$promise
48478                             .then(function (result) {
48479                             var status = result.status;
48480                             if (status === 'success') {
48481                                 _this.files = result.info;
48482                             }
48483                             else {
48484                                 console.log(result.message);
48485                             }
48486                         });
48487                     };
48488                     CommandController.prototype.debug = function () {
48489                         var div = angular.element(this.$window.document).find("div");
48490                         var consoleTag;
48491                         var parametersTag;
48492                         angular.forEach(div, function (v) {
48493                             if (v.className === "panel-body console") {
48494                                 consoleTag = v;
48495                             }
48496                             else if (v.className === "row parameters-console") {
48497                                 parametersTag = v;
48498                             }
48499                         });
48500                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
48501                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
48502                         consoleTag.style.height = consoleHeight;
48503                         consoleTag.style.width = consoleWidth;
48504                     };
48505                     CommandController.prototype.help = function () {
48506                         this.APIEndPoint
48507                             .help(this.name)
48508                             .then(function (result) {
48509                             console.log(result);
48510                         });
48511                     };
48512                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
48513                     return CommandController;
48514                 })();
48515                 directives.CommandController = CommandController;
48516             })(directives = app.directives || (app.directives = {}));
48517         })(app || (app = {}));
48518         var app;
48519         (function (app) {
48520             var directives;
48521             (function (directives) {
48522                 var HeaderMenu = (function () {
48523                     function HeaderMenu() {
48524                         this.restrict = 'E';
48525                         this.replace = true;
48526                         this.templateUrl = 'templates/header-menu.html';
48527                         this.controller = 'HeaderMenuController';
48528                         this.controllerAs = 'hmc';
48529                         this.scope = true;
48530                     }
48531                     HeaderMenu.Factory = function () {
48532                         var directive = function () {
48533                             return new HeaderMenu();
48534                         };
48535                         return directive;
48536                     };
48537                     return HeaderMenu;
48538                 })();
48539                 directives.HeaderMenu = HeaderMenu;
48540                 var HeaderMenuController = (function () {
48541                     function HeaderMenuController($state) {
48542                         this.$state = $state;
48543                         this.isExecution = this.$state.current.name === 'execution';
48544                         this.isWorkspace = this.$state.current.name === 'workspace';
48545                         this.isHistory = this.$state.current.name === 'history';
48546                     }
48547                     HeaderMenuController.prototype.transit = function (state) {
48548                         this.$state.go(state);
48549                     };
48550                     HeaderMenuController.$inject = ['$state'];
48551                     return HeaderMenuController;
48552                 })();
48553                 directives.HeaderMenuController = HeaderMenuController;
48554             })(directives = app.directives || (app.directives = {}));
48555         })(app || (app = {}));
48556         var app;
48557         (function (app) {
48558             var directives;
48559             (function (directives) {
48560                 var Option = (function () {
48561                     function Option() {
48562                         this.restrict = 'E';
48563                         this.replace = true;
48564                         this.controller = 'optionController';
48565                         this.bindToController = {
48566                             info: '=',
48567                             files: '='
48568                         };
48569                         this.scope = true;
48570                         this.templateUrl = 'templates/option.html';
48571                         this.controllerAs = 'ctrl';
48572                     }
48573                     Option.Factory = function () {
48574                         var directive = function () {
48575                             return new Option();
48576                         };
48577                         directive.$inject = [];
48578                         return directive;
48579                     };
48580                     return Option;
48581                 })();
48582                 directives.Option = Option;
48583                 var OptionController = (function () {
48584                     function OptionController() {
48585                         var controller = this;
48586                         angular.forEach(controller.info.arg, function (arg) {
48587                             if (arg.initialValue) {
48588                                 if (arg.formType === 'number') {
48589                                     arg.input = parseInt(arg.initialValue);
48590                                 }
48591                                 else {
48592                                     arg.input = arg.initialValue;
48593                                 }
48594                             }
48595                         });
48596                     }
48597                     OptionController.$inject = [];
48598                     return OptionController;
48599                 })();
48600                 directives.OptionController = OptionController;
48601             })(directives = app.directives || (app.directives = {}));
48602         })(app || (app = {}));
48603         var app;
48604         (function (app) {
48605             var directives;
48606             (function (directives) {
48607                 var Directory = (function () {
48608                     function Directory() {
48609                         this.restrict = 'E';
48610                         this.replace = true;
48611                         this.controller = 'directoryController';
48612                         this.controllerAs = 'ctrl';
48613                         this.bindToController = {
48614                             info: '=',
48615                             add: '&',
48616                             list: '=',
48617                             files: '='
48618                         };
48619                         this.templateUrl = 'templates/directory.html';
48620                     }
48621                     Directory.Factory = function () {
48622                         var directive = function () {
48623                             return new Directory();
48624                         };
48625                         return directive;
48626                     };
48627                     return Directory;
48628                 })();
48629                 directives.Directory = Directory;
48630                 var DirectoryController = (function () {
48631                     function DirectoryController(APIEndPoint, $scope) {
48632                         this.APIEndPoint = APIEndPoint;
48633                         this.$scope = $scope;
48634                         var controller = this;
48635                         this.APIEndPoint
48636                             .getFiles(this.info.fileId)
48637                             .$promise
48638                             .then(function (result) {
48639                             if (result.status === 'success') {
48640                                 controller.files = result.info;
48641                                 angular.forEach(result.info, function (file) {
48642                                     if (file.fileType === '0') {
48643                                         var o = file;
48644                                         if (controller.info.path === '/') {
48645                                             o.path = '/' + file.name;
48646                                         }
48647                                         else {
48648                                             o.path = controller.info.path + '/' + file.name;
48649                                         }
48650                                         controller.add()(o, controller.list);
48651                                     }
48652                                 });
48653                             }
48654                             ;
48655                         });
48656                     }
48657                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
48658                     return DirectoryController;
48659                 })();
48660                 directives.DirectoryController = DirectoryController;
48661             })(directives = app.directives || (app.directives = {}));
48662         })(app || (app = {}));
48663         var app;
48664         (function (app) {
48665             var directives;
48666             (function (directives) {
48667                 var Upload = (function () {
48668                     function Upload() {
48669                         this.restrict = 'E';
48670                         this.replace = true;
48671                         this.scope = true;
48672                         this.controller = 'UploadController';
48673                         this.controllerAs = 'ctrl';
48674                         this.bindToController = {
48675                             index: '=',
48676                             name: '=',
48677                             remove: '&',
48678                             list: '='
48679                         };
48680                         this.templateUrl = 'templates/upload.html';
48681                         console.log("templates/upload.html-constructor");
48682                     }
48683                     Upload.Factory = function () {
48684                         var directive = function () {
48685                             return new Upload();
48686                         };
48687                         directive.$inject = [];
48688                         return directive;
48689                     };
48690                     return Upload;
48691                 })();
48692                 directives.Upload = Upload;
48693                 var UploadController = (function () {
48694                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
48695                         this.APIEndPoint = APIEndPoint;
48696                         this.$scope = $scope;
48697                         this.MyModal = MyModal;
48698                         this.WebSocket = WebSocket;
48699                         this.$window = $window;
48700                         this.$rootScope = $rootScope;
48701                         this.Console = Console;
48702                         var controller = this;
48703                         console.log("directive.upload-constructor");
48704                     }
48705                     UploadController.prototype.submit = function () {
48706                         console.log("submit: function not supported¥n");
48707                     };
48708                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
48709                     return UploadController;
48710                 })();
48711                 directives.UploadController = UploadController;
48712             })(directives = app.directives || (app.directives = {}));
48713         })(app || (app = {}));
48714         var app;
48715         (function (app) {
48716             var controllers;
48717             (function (controllers) {
48718                 var Execution = (function () {
48719                     function Execution(MyModal, $scope) {
48720                         this.MyModal = MyModal;
48721                         this.$scope = $scope;
48722                         this.commandInfoList = [];
48723                     }
48724                     ;
48725                     Execution.prototype.add = function () {
48726                         this.$scope.$broadcast('close');
48727                         var commandInfoList = this.commandInfoList;
48728                         var commandInstance = this.MyModal.selectCommand();
48729                         commandInstance
48730                             .result
48731                             .then(function (command) {
48732                             commandInfoList.push(new app.declares.CommandInfo(command));
48733                         });
48734                     };
48735                     Execution.prototype.open = function () {
48736                         var result = this.MyModal.open('SelectCommand');
48737                         console.log(result);
48738                     };
48739                     Execution.prototype.remove = function (index, list) {
48740                         list.splice(index, 1);
48741                     };
48742                     Execution.prototype.close = function () {
48743                         console.log("close");
48744                     };
48745                     Execution.$inject = ['MyModal', '$scope'];
48746                     return Execution;
48747                 })();
48748                 controllers.Execution = Execution;
48749             })(controllers = app.controllers || (app.controllers = {}));
48750         })(app || (app = {}));
48751         var app;
48752         (function (app) {
48753             var controllers;
48754             (function (controllers) {
48755                 var Workspace = (function () {
48756                     function Workspace($scope, APIEndPoint, MyModal) {
48757                         this.$scope = $scope;
48758                         this.APIEndPoint = APIEndPoint;
48759                         this.MyModal = MyModal;
48760                         this.directoryList = [];
48761                         var controller = this;
48762                         var directoryList = this.directoryList;
48763                         var o = {
48764                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
48765                             name: '',
48766                             parentId: '',
48767                             fileType: '',
48768                             createdAt: '',
48769                             updatedAt: '',
48770                             path: '/'
48771                         };
48772                         directoryList.push(o);
48773                     }
48774                     Workspace.prototype.addDirectory = function (info, directoryList) {
48775                         directoryList.push(info);
48776                     };
48777                     Workspace.prototype.upload = function () {
48778                         this.MyModal.upload();
48779                     };
48780                     Workspace.prototype.debug = function () {
48781                         this.MyModal.preview();
48782                     };
48783                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
48784                     return Workspace;
48785                 })();
48786                 controllers.Workspace = Workspace;
48787             })(controllers = app.controllers || (app.controllers = {}));
48788         })(app || (app = {}));
48789         var app;
48790         (function (app) {
48791             var controllers;
48792             (function (controllers) {
48793                 var History = (function () {
48794                     function History($scope) {
48795                         this.page = "History";
48796                     }
48797                     History.$inject = ['$scope'];
48798                     return History;
48799                 })();
48800                 controllers.History = History;
48801             })(controllers = app.controllers || (app.controllers = {}));
48802         })(app || (app = {}));
48803         var app;
48804         (function (app) {
48805             var controllers;
48806             (function (controllers) {
48807                 var SelectCommand = (function () {
48808                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
48809                         this.APIEndPoint = APIEndPoint;
48810                         this.$modalInstance = $modalInstance;
48811                         var controller = this;
48812                         this.APIEndPoint
48813                             .getTags()
48814                             .$promise.then(function (result) {
48815                             controller.tags = result.info;
48816                         });
48817                         this.APIEndPoint
48818                             .getCommands()
48819                             .$promise.then(function (result) {
48820                             controller.commands = result.info;
48821                         });
48822                         this.currentTag = 'all';
48823                     }
48824                     SelectCommand.prototype.changeTag = function (tag) {
48825                         this.currentTag = tag;
48826                     };
48827                     SelectCommand.prototype.selectCommand = function (command) {
48828                         this.$modalInstance.close(command);
48829                     };
48830                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48831                     return SelectCommand;
48832                 })();
48833                 controllers.SelectCommand = SelectCommand;
48834             })(controllers = app.controllers || (app.controllers = {}));
48835         })(app || (app = {}));
48836         var app;
48837         (function (app) {
48838             var controllers;
48839             (function (controllers) {
48840                 var Upload = (function () {
48841                     function Upload($scope, APIEndPoint, $modalInstance) {
48842                         this.APIEndPoint = APIEndPoint;
48843                         this.$modalInstance = $modalInstance;
48844                         var controller = this;
48845                         console.log('controller.upload-controllers');
48846                     }
48847                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48848                     return Upload;
48849                 })();
48850                 controllers.Upload = Upload;
48851             })(controllers = app.controllers || (app.controllers = {}));
48852         })(app || (app = {}));
48853         var app;
48854         (function (app) {
48855             var controllers;
48856             (function (controllers) {
48857                 var Preview = (function () {
48858                     function Preview($scope, APIEndPoint, $modalInstance) {
48859                         this.APIEndPoint = APIEndPoint;
48860                         this.$modalInstance = $modalInstance;
48861                         var controller = this;
48862                         console.log('preview');
48863                     }
48864                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
48865                     return Preview;
48866                 })();
48867                 controllers.Preview = Preview;
48868             })(controllers = app.controllers || (app.controllers = {}));
48869         })(app || (app = {}));
48870         var filters;
48871         (function (filters) {
48872             function Tag() {
48873                 return function (commands, tag) {
48874                     var result = [];
48875                     angular.forEach(commands, function (command) {
48876                         var flag = false;
48877                         angular.forEach(command.tags, function (value) {
48878                             if (tag === value)
48879                                 flag = true;
48880                         });
48881                         if (flag)
48882                             result.push(command);
48883                     });
48884                     return result;
48885                 };
48886             }
48887             filters.Tag = Tag;
48888         })(filters || (filters = {}));
48889         var app;
48890         (function (app) {
48891             'use strict';
48892             var appName = 'zephyr';
48893             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
48894             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
48895                 $urlRouterProvider.otherwise('/execution');
48896                 $locationProvider.html5Mode({
48897                     enabled: true,
48898                     requireBase: false
48899                 });
48900                 $stateProvider
48901                     .state('execution', {
48902                     url: '/execution',
48903                     templateUrl: 'templates/execution.html',
48904                     controller: 'executionController',
48905                     controllerAs: 'c'
48906                 })
48907                     .state('workspace', {
48908                     url: '/workspace',
48909                     templateUrl: 'templates/workspace.html',
48910                     controller: 'workspaceController',
48911                     controllerAs: 'c'
48912                 })
48913                     .state('history', {
48914                     url: '/history',
48915                     templateUrl: 'templates/history.html',
48916                     controller: 'historyController',
48917                     controllerAs: 'c'
48918                 });
48919             });
48920             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
48921             app.zephyr.service('MyModal', app.services.MyModal);
48922             app.zephyr.service('WebSocket', app.services.WebSocket);
48923             app.zephyr.service('Console', app.services.Console);
48924             app.zephyr.filter('Tag', filters.Tag);
48925             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
48926             app.zephyr.controller('previewController', app.controllers.Preview);
48927             app.zephyr.controller('uploadController', app.controllers.Upload);
48928             app.zephyr.controller('executionController', app.controllers.Execution);
48929             app.zephyr.controller('workspaceController', app.controllers.Workspace);
48930             app.zephyr.controller('historyController', app.controllers.History);
48931             app.zephyr.controller('commandController', app.directives.CommandController);
48932             app.zephyr.controller('optionController', app.directives.OptionController);
48933             app.zephyr.controller('directoryController', app.directives.DirectoryController);
48934             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
48935             app.zephyr.controller('uploadController', app.directives.UploadController);
48936             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
48937             app.zephyr.directive('command', app.directives.Command.Factory());
48938             app.zephyr.directive('option', app.directives.Option.Factory());
48939             app.zephyr.directive('directory', app.directives.Directory.Factory());
48940         })(app || (app = {}));
48941
48942
48943 /***/ },
48944 /* 17 */
48945 /***/ function(module, exports) {
48946
48947         var app;
48948         (function (app) {
48949             var declares;
48950             (function (declares) {
48951                 var CommandInfo = (function () {
48952                     function CommandInfo(name) {
48953                         this.name = name;
48954                     }
48955                     return CommandInfo;
48956                 })();
48957                 declares.CommandInfo = CommandInfo;
48958             })(declares = app.declares || (app.declares = {}));
48959         })(app || (app = {}));
48960         var app;
48961         (function (app) {
48962             var services;
48963             (function (services) {
48964                 var APIEndPoint = (function () {
48965                     function APIEndPoint($resource, $http) {
48966                         this.$resource = $resource;
48967                         this.$http = $http;
48968                     }
48969                     APIEndPoint.prototype.resource = function (endPoint, data) {
48970                         var customAction = {
48971                             method: 'GET',
48972                             isArray: false
48973                         };
48974                         var execute = {
48975                             method: 'POST',
48976                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
48977                         };
48978                         return this.$resource(endPoint, {}, { execute: execute });
48979                     };
48980                     APIEndPoint.prototype.getOptionControlFile = function (command) {
48981                         var endPoint = '/api/v1/optionControlFile/' + command;
48982                         return this.resource(endPoint, {}).get();
48983                     };
48984                     APIEndPoint.prototype.getFiles = function (fileId) {
48985                         var endPoint = '/api/v1/workspace';
48986                         if (fileId) {
48987                             endPoint += '/' + fileId;
48988                         }
48989                         return this.resource(endPoint, {}).get();
48990                     };
48991                     APIEndPoint.prototype.getDirectories = function () {
48992                         var endPoint = '/api/v1/all/workspace/directory';
48993                         return this.resource(endPoint, {}).get();
48994                     };
48995                     APIEndPoint.prototype.getTags = function () {
48996                         var endPoint = '/api/v1/tagList';
48997                         return this.resource(endPoint, {}).get();
48998                     };
48999                     APIEndPoint.prototype.getCommands = function () {
49000                         var endPoint = '/api/v1/commandList';
49001                         return this.resource(endPoint, {}).get();
49002                     };
49003                     APIEndPoint.prototype.execute = function (data) {
49004                         var endPoint = '/api/v1/execution';
49005                         var fd = new FormData();
49006                         fd.append('data', data);
49007                         return this.$http.post(endPoint, fd, {
49008                             headers: { 'Content-Type': undefined },
49009                             transformRequest: angular.identity
49010                         });
49011                     };
49012                     APIEndPoint.prototype.debug = function () {
49013                         var endPoint = '/api/v1/debug';
49014                         return this.$http.get(endPoint);
49015                     };
49016                     APIEndPoint.prototype.upload = function () {
49017                         var endPoint = '/api/v1/upload';
49018                         return this.$http.get(endPoint);
49019                     };
49020                     APIEndPoint.prototype.help = function (command) {
49021                         var endPoint = '/api/v1/help/' + command;
49022                         return this.$http.get(endPoint);
49023                     };
49024                     return APIEndPoint;
49025                 })();
49026                 services.APIEndPoint = APIEndPoint;
49027             })(services = app.services || (app.services = {}));
49028         })(app || (app = {}));
49029         var app;
49030         (function (app) {
49031             var services;
49032             (function (services) {
49033                 var MyModal = (function () {
49034                     function MyModal($uibModal) {
49035                         this.$uibModal = $uibModal;
49036                         this.modalOption = {
49037                             backdrop: true,
49038                             controller: null,
49039                             templateUrl: null,
49040                             size: null
49041                         };
49042                     }
49043                     MyModal.prototype.open = function (modalName) {
49044                         if (modalName === 'SelectCommand') {
49045                             this.modalOption.templateUrl = 'templates/select-command.html';
49046                             this.modalOption.size = 'lg';
49047                         }
49048                         return this.$uibModal.open(this.modalOption);
49049                     };
49050                     MyModal.prototype.selectCommand = function () {
49051                         this.modalOption.templateUrl = 'templates/select-command.html';
49052                         this.modalOption.controller = 'selectCommandController';
49053                         this.modalOption.controllerAs = 'c';
49054                         this.modalOption.size = 'lg';
49055                         return this.$uibModal.open(this.modalOption);
49056                     };
49057                     MyModal.prototype.preview = function () {
49058                         this.modalOption.templateUrl = 'templates/preview.html';
49059                         this.modalOption.controller = 'previewController';
49060                         this.modalOption.controllerAs = 'c';
49061                         this.modalOption.size = 'lg';
49062                         return this.$uibModal.open(this.modalOption);
49063                     };
49064                     MyModal.prototype.upload = function () {
49065                         this.modalOption.templateUrl = 'templates/upload.html';
49066                         this.modalOption.controller = 'uploadController';
49067                         this.modalOption.controllerAs = 'c';
49068                         this.modalOption.size = 'lg';
49069                         return this.$uibModal.open(this.modalOption);
49070                     };
49071                     MyModal.$inject = ['$uibModal'];
49072                     return MyModal;
49073                 })();
49074                 services.MyModal = MyModal;
49075             })(services = app.services || (app.services = {}));
49076         })(app || (app = {}));
49077         var app;
49078         (function (app) {
49079             var services;
49080             (function (services) {
49081                 var WebSocket = (function () {
49082                     function WebSocket($rootScope) {
49083                         this.$rootScope = $rootScope;
49084                         this.socket = io.connect();
49085                     }
49086                     WebSocket.prototype.on = function (eventName, callback) {
49087                         var socket = this.socket;
49088                         var rootScope = this.$rootScope;
49089                         socket.on(eventName, function () {
49090                             var args = arguments;
49091                             rootScope.$apply(function () {
49092                                 callback.apply(socket, args);
49093                             });
49094                         });
49095                     };
49096                     WebSocket.prototype.emit = function (eventName, data, callback) {
49097                         var socket = this.socket;
49098                         var rootScope = this.$rootScope;
49099                         this.socket.emit(eventName, data, function () {
49100                             var args = arguments;
49101                             rootScope.$apply(function () {
49102                                 if (callback)
49103                                     callback.apply(socket, args);
49104                             });
49105                         });
49106                     };
49107                     return WebSocket;
49108                 })();
49109                 services.WebSocket = WebSocket;
49110             })(services = app.services || (app.services = {}));
49111         })(app || (app = {}));
49112         var app;
49113         (function (app) {
49114             var services;
49115             (function (services) {
49116                 var Console = (function () {
49117                     function Console(WebSocket, $rootScope) {
49118                         this.WebSocket = WebSocket;
49119                         this.$rootScope = $rootScope;
49120                         this.WebSocket = WebSocket;
49121                         this.$rootScope = $rootScope;
49122                         this.directiveIDs = [];
49123                         var directiveIDs = this.directiveIDs;
49124                         this.WebSocket.on('console', function (d) {
49125                             var id = d.id;
49126                             var message = d.message;
49127                             if (directiveIDs.indexOf(id) > -1) {
49128                                 $rootScope.$emit(id, message);
49129                             }
49130                         });
49131                     }
49132                     Console.prototype.addDirective = function (id) {
49133                         if (!(this.directiveIDs.indexOf(id) > -1)) {
49134                             this.directiveIDs.push(id);
49135                         }
49136                     };
49137                     Console.prototype.removeDirective = function (id) {
49138                         var i = this.directiveIDs.indexOf(id);
49139                         if (i > -1) {
49140                             this.directiveIDs.splice(i, 1);
49141                         }
49142                     };
49143                     Console.prototype.showIDs = function () {
49144                         console.log(this.directiveIDs);
49145                     };
49146                     return Console;
49147                 })();
49148                 services.Console = Console;
49149             })(services = app.services || (app.services = {}));
49150         })(app || (app = {}));
49151         var app;
49152         (function (app) {
49153             var directives;
49154             (function (directives) {
49155                 var Command = (function () {
49156                     function Command() {
49157                         this.restrict = 'E';
49158                         this.replace = true;
49159                         this.scope = true;
49160                         this.controller = 'commandController';
49161                         this.controllerAs = 'ctrl';
49162                         this.bindToController = {
49163                             index: '=',
49164                             name: '=',
49165                             remove: '&',
49166                             list: '='
49167                         };
49168                         this.templateUrl = 'templates/command.html';
49169                     }
49170                     Command.Factory = function () {
49171                         var directive = function () {
49172                             return new Command();
49173                         };
49174                         directive.$inject = [];
49175                         return directive;
49176                     };
49177                     return Command;
49178                 })();
49179                 directives.Command = Command;
49180                 var CommandController = (function () {
49181                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
49182                         this.APIEndPoint = APIEndPoint;
49183                         this.$scope = $scope;
49184                         this.MyModal = MyModal;
49185                         this.WebSocket = WebSocket;
49186                         this.$window = $window;
49187                         this.$rootScope = $rootScope;
49188                         this.Console = Console;
49189                         var controller = this;
49190                         this.APIEndPoint
49191                             .getOptionControlFile(this.name)
49192                             .$promise
49193                             .then(function (result) {
49194                             controller.options = result.info;
49195                         });
49196                         this.APIEndPoint
49197                             .getDirectories()
49198                             .$promise
49199                             .then(function (result) {
49200                             controller.dirs = result.info;
49201                         });
49202                         this.heading = "[" + this.index + "]: dcdFilePrint";
49203                         this.isOpen = true;
49204                         this.$scope.$on('close', function () {
49205                             controller.isOpen = false;
49206                         });
49207                         function guid() {
49208                             function s4() {
49209                                 return Math.floor((1 + Math.random()) * 0x10000)
49210                                     .toString(16)
49211                                     .substring(1);
49212                             }
49213                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
49214                                 s4() + '-' + s4() + s4() + s4();
49215                         }
49216                         this.uuid = guid();
49217                         this.Console.addDirective(this.uuid);
49218                         this.Console.showIDs();
49219                     }
49220                     CommandController.prototype.submit = function () {
49221                         var opt = [];
49222                         angular.forEach(this.options, function (option) {
49223                             var obj = {
49224                                 name: option.option,
49225                                 arguments: []
49226                             };
49227                             angular.forEach(option.arg, function (arg) {
49228                                 if (arg.input) {
49229                                     if (typeof arg.input === 'object') {
49230                                         obj.arguments.push(arg.input.name);
49231                                     }
49232                                     else {
49233                                         obj.arguments.push(arg.input);
49234                                     }
49235                                 }
49236                             });
49237                             if (obj.arguments.length > 0) {
49238                                 opt.push(obj);
49239                             }
49240                         });
49241                         var execObj = {
49242                             command: this.name,
49243                             workspace: this.workspace.fileId,
49244                             options: opt
49245                         };
49246                         this.APIEndPoint
49247                             .execute(JSON.stringify(execObj))
49248                             .then(function (result) {
49249                             console.log(result);
49250                         });
49251                     };
49252                     CommandController.prototype.removeMySelf = function (index) {
49253                         this.$scope.$destroy();
49254                         this.Console.removeDirective(this.uuid);
49255                         this.remove()(index, this.list);
49256                         this.Console.showIDs();
49257                     };
49258                     CommandController.prototype.reloadFiles = function () {
49259                         var _this = this;
49260                         var fileId = this.workspace.fileId;
49261                         this.APIEndPoint
49262                             .getFiles(fileId)
49263                             .$promise
49264                             .then(function (result) {
49265                             var status = result.status;
49266                             if (status === 'success') {
49267                                 _this.files = result.info;
49268                             }
49269                             else {
49270                                 console.log(result.message);
49271                             }
49272                         });
49273                     };
49274                     CommandController.prototype.debug = function () {
49275                         var div = angular.element(this.$window.document).find("div");
49276                         var consoleTag;
49277                         var parametersTag;
49278                         angular.forEach(div, function (v) {
49279                             if (v.className === "panel-body console") {
49280                                 consoleTag = v;
49281                             }
49282                             else if (v.className === "row parameters-console") {
49283                                 parametersTag = v;
49284                             }
49285                         });
49286                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
49287                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
49288                         consoleTag.style.height = consoleHeight;
49289                         consoleTag.style.width = consoleWidth;
49290                     };
49291                     CommandController.prototype.help = function () {
49292                         this.APIEndPoint
49293                             .help(this.name)
49294                             .then(function (result) {
49295                             console.log(result);
49296                         });
49297                     };
49298                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
49299                     return CommandController;
49300                 })();
49301                 directives.CommandController = CommandController;
49302             })(directives = app.directives || (app.directives = {}));
49303         })(app || (app = {}));
49304         var app;
49305         (function (app) {
49306             var directives;
49307             (function (directives) {
49308                 var HeaderMenu = (function () {
49309                     function HeaderMenu() {
49310                         this.restrict = 'E';
49311                         this.replace = true;
49312                         this.templateUrl = 'templates/header-menu.html';
49313                         this.controller = 'HeaderMenuController';
49314                         this.controllerAs = 'hmc';
49315                         this.scope = true;
49316                     }
49317                     HeaderMenu.Factory = function () {
49318                         var directive = function () {
49319                             return new HeaderMenu();
49320                         };
49321                         return directive;
49322                     };
49323                     return HeaderMenu;
49324                 })();
49325                 directives.HeaderMenu = HeaderMenu;
49326                 var HeaderMenuController = (function () {
49327                     function HeaderMenuController($state) {
49328                         this.$state = $state;
49329                         this.isExecution = this.$state.current.name === 'execution';
49330                         this.isWorkspace = this.$state.current.name === 'workspace';
49331                         this.isHistory = this.$state.current.name === 'history';
49332                     }
49333                     HeaderMenuController.prototype.transit = function (state) {
49334                         this.$state.go(state);
49335                     };
49336                     HeaderMenuController.$inject = ['$state'];
49337                     return HeaderMenuController;
49338                 })();
49339                 directives.HeaderMenuController = HeaderMenuController;
49340             })(directives = app.directives || (app.directives = {}));
49341         })(app || (app = {}));
49342         var app;
49343         (function (app) {
49344             var directives;
49345             (function (directives) {
49346                 var Option = (function () {
49347                     function Option() {
49348                         this.restrict = 'E';
49349                         this.replace = true;
49350                         this.controller = 'optionController';
49351                         this.bindToController = {
49352                             info: '=',
49353                             files: '='
49354                         };
49355                         this.scope = true;
49356                         this.templateUrl = 'templates/option.html';
49357                         this.controllerAs = 'ctrl';
49358                     }
49359                     Option.Factory = function () {
49360                         var directive = function () {
49361                             return new Option();
49362                         };
49363                         directive.$inject = [];
49364                         return directive;
49365                     };
49366                     return Option;
49367                 })();
49368                 directives.Option = Option;
49369                 var OptionController = (function () {
49370                     function OptionController() {
49371                         var controller = this;
49372                         angular.forEach(controller.info.arg, function (arg) {
49373                             if (arg.initialValue) {
49374                                 if (arg.formType === 'number') {
49375                                     arg.input = parseInt(arg.initialValue);
49376                                 }
49377                                 else {
49378                                     arg.input = arg.initialValue;
49379                                 }
49380                             }
49381                         });
49382                     }
49383                     OptionController.$inject = [];
49384                     return OptionController;
49385                 })();
49386                 directives.OptionController = OptionController;
49387             })(directives = app.directives || (app.directives = {}));
49388         })(app || (app = {}));
49389         var app;
49390         (function (app) {
49391             var directives;
49392             (function (directives) {
49393                 var Directory = (function () {
49394                     function Directory() {
49395                         this.restrict = 'E';
49396                         this.replace = true;
49397                         this.controller = 'directoryController';
49398                         this.controllerAs = 'ctrl';
49399                         this.bindToController = {
49400                             info: '=',
49401                             add: '&',
49402                             list: '=',
49403                             files: '='
49404                         };
49405                         this.templateUrl = 'templates/directory.html';
49406                     }
49407                     Directory.Factory = function () {
49408                         var directive = function () {
49409                             return new Directory();
49410                         };
49411                         return directive;
49412                     };
49413                     return Directory;
49414                 })();
49415                 directives.Directory = Directory;
49416                 var DirectoryController = (function () {
49417                     function DirectoryController(APIEndPoint, $scope) {
49418                         this.APIEndPoint = APIEndPoint;
49419                         this.$scope = $scope;
49420                         var controller = this;
49421                         this.APIEndPoint
49422                             .getFiles(this.info.fileId)
49423                             .$promise
49424                             .then(function (result) {
49425                             if (result.status === 'success') {
49426                                 controller.files = result.info;
49427                                 angular.forEach(result.info, function (file) {
49428                                     if (file.fileType === '0') {
49429                                         var o = file;
49430                                         if (controller.info.path === '/') {
49431                                             o.path = '/' + file.name;
49432                                         }
49433                                         else {
49434                                             o.path = controller.info.path + '/' + file.name;
49435                                         }
49436                                         controller.add()(o, controller.list);
49437                                     }
49438                                 });
49439                             }
49440                             ;
49441                         });
49442                     }
49443                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
49444                     return DirectoryController;
49445                 })();
49446                 directives.DirectoryController = DirectoryController;
49447             })(directives = app.directives || (app.directives = {}));
49448         })(app || (app = {}));
49449         var app;
49450         (function (app) {
49451             var directives;
49452             (function (directives) {
49453                 var Upload = (function () {
49454                     function Upload() {
49455                         this.restrict = 'E';
49456                         this.replace = true;
49457                         this.scope = true;
49458                         this.controller = 'UploadController';
49459                         this.controllerAs = 'ctrl';
49460                         this.bindToController = {
49461                             index: '=',
49462                             name: '=',
49463                             remove: '&',
49464                             list: '='
49465                         };
49466                         this.templateUrl = 'templates/upload.html';
49467                         console.log("templates/upload.html-constructor");
49468                     }
49469                     Upload.Factory = function () {
49470                         var directive = function () {
49471                             return new Upload();
49472                         };
49473                         directive.$inject = [];
49474                         return directive;
49475                     };
49476                     return Upload;
49477                 })();
49478                 directives.Upload = Upload;
49479                 var UploadController = (function () {
49480                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
49481                         this.APIEndPoint = APIEndPoint;
49482                         this.$scope = $scope;
49483                         this.MyModal = MyModal;
49484                         this.WebSocket = WebSocket;
49485                         this.$window = $window;
49486                         this.$rootScope = $rootScope;
49487                         this.Console = Console;
49488                         var controller = this;
49489                         console.log("directive.upload-constructor");
49490                     }
49491                     UploadController.prototype.submit = function () {
49492                         console.log("submit: function not supported¥n");
49493                     };
49494                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
49495                     return UploadController;
49496                 })();
49497                 directives.UploadController = UploadController;
49498             })(directives = app.directives || (app.directives = {}));
49499         })(app || (app = {}));
49500         var app;
49501         (function (app) {
49502             var controllers;
49503             (function (controllers) {
49504                 var Execution = (function () {
49505                     function Execution(MyModal, $scope) {
49506                         this.MyModal = MyModal;
49507                         this.$scope = $scope;
49508                         this.commandInfoList = [];
49509                     }
49510                     ;
49511                     Execution.prototype.add = function () {
49512                         this.$scope.$broadcast('close');
49513                         var commandInfoList = this.commandInfoList;
49514                         var commandInstance = this.MyModal.selectCommand();
49515                         commandInstance
49516                             .result
49517                             .then(function (command) {
49518                             commandInfoList.push(new app.declares.CommandInfo(command));
49519                         });
49520                     };
49521                     Execution.prototype.open = function () {
49522                         var result = this.MyModal.open('SelectCommand');
49523                         console.log(result);
49524                     };
49525                     Execution.prototype.remove = function (index, list) {
49526                         list.splice(index, 1);
49527                     };
49528                     Execution.prototype.close = function () {
49529                         console.log("close");
49530                     };
49531                     Execution.$inject = ['MyModal', '$scope'];
49532                     return Execution;
49533                 })();
49534                 controllers.Execution = Execution;
49535             })(controllers = app.controllers || (app.controllers = {}));
49536         })(app || (app = {}));
49537         var app;
49538         (function (app) {
49539             var controllers;
49540             (function (controllers) {
49541                 var Workspace = (function () {
49542                     function Workspace($scope, APIEndPoint, MyModal) {
49543                         this.$scope = $scope;
49544                         this.APIEndPoint = APIEndPoint;
49545                         this.MyModal = MyModal;
49546                         this.directoryList = [];
49547                         var controller = this;
49548                         var directoryList = this.directoryList;
49549                         var o = {
49550                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
49551                             name: '',
49552                             parentId: '',
49553                             fileType: '',
49554                             createdAt: '',
49555                             updatedAt: '',
49556                             path: '/'
49557                         };
49558                         directoryList.push(o);
49559                     }
49560                     Workspace.prototype.addDirectory = function (info, directoryList) {
49561                         directoryList.push(info);
49562                     };
49563                     Workspace.prototype.upload = function () {
49564                         this.MyModal.upload();
49565                     };
49566                     Workspace.prototype.debug = function () {
49567                         this.MyModal.preview();
49568                     };
49569                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
49570                     return Workspace;
49571                 })();
49572                 controllers.Workspace = Workspace;
49573             })(controllers = app.controllers || (app.controllers = {}));
49574         })(app || (app = {}));
49575         var app;
49576         (function (app) {
49577             var controllers;
49578             (function (controllers) {
49579                 var History = (function () {
49580                     function History($scope) {
49581                         this.page = "History";
49582                     }
49583                     History.$inject = ['$scope'];
49584                     return History;
49585                 })();
49586                 controllers.History = History;
49587             })(controllers = app.controllers || (app.controllers = {}));
49588         })(app || (app = {}));
49589         var app;
49590         (function (app) {
49591             var controllers;
49592             (function (controllers) {
49593                 var SelectCommand = (function () {
49594                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
49595                         this.APIEndPoint = APIEndPoint;
49596                         this.$modalInstance = $modalInstance;
49597                         var controller = this;
49598                         this.APIEndPoint
49599                             .getTags()
49600                             .$promise.then(function (result) {
49601                             controller.tags = result.info;
49602                         });
49603                         this.APIEndPoint
49604                             .getCommands()
49605                             .$promise.then(function (result) {
49606                             controller.commands = result.info;
49607                         });
49608                         this.currentTag = 'all';
49609                     }
49610                     SelectCommand.prototype.changeTag = function (tag) {
49611                         this.currentTag = tag;
49612                     };
49613                     SelectCommand.prototype.selectCommand = function (command) {
49614                         this.$modalInstance.close(command);
49615                     };
49616                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49617                     return SelectCommand;
49618                 })();
49619                 controllers.SelectCommand = SelectCommand;
49620             })(controllers = app.controllers || (app.controllers = {}));
49621         })(app || (app = {}));
49622         var app;
49623         (function (app) {
49624             var controllers;
49625             (function (controllers) {
49626                 var Upload = (function () {
49627                     function Upload($scope, APIEndPoint, $modalInstance) {
49628                         this.APIEndPoint = APIEndPoint;
49629                         this.$modalInstance = $modalInstance;
49630                         var controller = this;
49631                         console.log('controller.upload-controllers');
49632                     }
49633                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49634                     return Upload;
49635                 })();
49636                 controllers.Upload = Upload;
49637             })(controllers = app.controllers || (app.controllers = {}));
49638         })(app || (app = {}));
49639         var app;
49640         (function (app) {
49641             var controllers;
49642             (function (controllers) {
49643                 var Preview = (function () {
49644                     function Preview($scope, APIEndPoint, $modalInstance) {
49645                         this.APIEndPoint = APIEndPoint;
49646                         this.$modalInstance = $modalInstance;
49647                         var controller = this;
49648                         console.log('preview');
49649                     }
49650                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
49651                     return Preview;
49652                 })();
49653                 controllers.Preview = Preview;
49654             })(controllers = app.controllers || (app.controllers = {}));
49655         })(app || (app = {}));
49656         var filters;
49657         (function (filters) {
49658             function Tag() {
49659                 return function (commands, tag) {
49660                     var result = [];
49661                     angular.forEach(commands, function (command) {
49662                         var flag = false;
49663                         angular.forEach(command.tags, function (value) {
49664                             if (tag === value)
49665                                 flag = true;
49666                         });
49667                         if (flag)
49668                             result.push(command);
49669                     });
49670                     return result;
49671                 };
49672             }
49673             filters.Tag = Tag;
49674         })(filters || (filters = {}));
49675         var app;
49676         (function (app) {
49677             'use strict';
49678             var appName = 'zephyr';
49679             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
49680             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
49681                 $urlRouterProvider.otherwise('/execution');
49682                 $locationProvider.html5Mode({
49683                     enabled: true,
49684                     requireBase: false
49685                 });
49686                 $stateProvider
49687                     .state('execution', {
49688                     url: '/execution',
49689                     templateUrl: 'templates/execution.html',
49690                     controller: 'executionController',
49691                     controllerAs: 'c'
49692                 })
49693                     .state('workspace', {
49694                     url: '/workspace',
49695                     templateUrl: 'templates/workspace.html',
49696                     controller: 'workspaceController',
49697                     controllerAs: 'c'
49698                 })
49699                     .state('history', {
49700                     url: '/history',
49701                     templateUrl: 'templates/history.html',
49702                     controller: 'historyController',
49703                     controllerAs: 'c'
49704                 });
49705             });
49706             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
49707             app.zephyr.service('MyModal', app.services.MyModal);
49708             app.zephyr.service('WebSocket', app.services.WebSocket);
49709             app.zephyr.service('Console', app.services.Console);
49710             app.zephyr.filter('Tag', filters.Tag);
49711             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
49712             app.zephyr.controller('previewController', app.controllers.Preview);
49713             app.zephyr.controller('uploadController', app.controllers.Upload);
49714             app.zephyr.controller('executionController', app.controllers.Execution);
49715             app.zephyr.controller('workspaceController', app.controllers.Workspace);
49716             app.zephyr.controller('historyController', app.controllers.History);
49717             app.zephyr.controller('commandController', app.directives.CommandController);
49718             app.zephyr.controller('optionController', app.directives.OptionController);
49719             app.zephyr.controller('directoryController', app.directives.DirectoryController);
49720             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
49721             app.zephyr.controller('uploadController', app.directives.UploadController);
49722             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
49723             app.zephyr.directive('command', app.directives.Command.Factory());
49724             app.zephyr.directive('option', app.directives.Option.Factory());
49725             app.zephyr.directive('directory', app.directives.Directory.Factory());
49726         })(app || (app = {}));
49727
49728
49729 /***/ },
49730 /* 18 */
49731 /***/ function(module, exports) {
49732
49733         var app;
49734         (function (app) {
49735             var declares;
49736             (function (declares) {
49737                 var CommandInfo = (function () {
49738                     function CommandInfo(name) {
49739                         this.name = name;
49740                     }
49741                     return CommandInfo;
49742                 })();
49743                 declares.CommandInfo = CommandInfo;
49744             })(declares = app.declares || (app.declares = {}));
49745         })(app || (app = {}));
49746         var app;
49747         (function (app) {
49748             var services;
49749             (function (services) {
49750                 var APIEndPoint = (function () {
49751                     function APIEndPoint($resource, $http) {
49752                         this.$resource = $resource;
49753                         this.$http = $http;
49754                     }
49755                     APIEndPoint.prototype.resource = function (endPoint, data) {
49756                         var customAction = {
49757                             method: 'GET',
49758                             isArray: false
49759                         };
49760                         var execute = {
49761                             method: 'POST',
49762                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
49763                         };
49764                         return this.$resource(endPoint, {}, { execute: execute });
49765                     };
49766                     APIEndPoint.prototype.getOptionControlFile = function (command) {
49767                         var endPoint = '/api/v1/optionControlFile/' + command;
49768                         return this.resource(endPoint, {}).get();
49769                     };
49770                     APIEndPoint.prototype.getFiles = function (fileId) {
49771                         var endPoint = '/api/v1/workspace';
49772                         if (fileId) {
49773                             endPoint += '/' + fileId;
49774                         }
49775                         return this.resource(endPoint, {}).get();
49776                     };
49777                     APIEndPoint.prototype.getDirectories = function () {
49778                         var endPoint = '/api/v1/all/workspace/directory';
49779                         return this.resource(endPoint, {}).get();
49780                     };
49781                     APIEndPoint.prototype.getTags = function () {
49782                         var endPoint = '/api/v1/tagList';
49783                         return this.resource(endPoint, {}).get();
49784                     };
49785                     APIEndPoint.prototype.getCommands = function () {
49786                         var endPoint = '/api/v1/commandList';
49787                         return this.resource(endPoint, {}).get();
49788                     };
49789                     APIEndPoint.prototype.execute = function (data) {
49790                         var endPoint = '/api/v1/execution';
49791                         var fd = new FormData();
49792                         fd.append('data', data);
49793                         return this.$http.post(endPoint, fd, {
49794                             headers: { 'Content-Type': undefined },
49795                             transformRequest: angular.identity
49796                         });
49797                     };
49798                     APIEndPoint.prototype.debug = function () {
49799                         var endPoint = '/api/v1/debug';
49800                         return this.$http.get(endPoint);
49801                     };
49802                     APIEndPoint.prototype.upload = function () {
49803                         var endPoint = '/api/v1/upload';
49804                         return this.$http.get(endPoint);
49805                     };
49806                     APIEndPoint.prototype.help = function (command) {
49807                         var endPoint = '/api/v1/help/' + command;
49808                         return this.$http.get(endPoint);
49809                     };
49810                     return APIEndPoint;
49811                 })();
49812                 services.APIEndPoint = APIEndPoint;
49813             })(services = app.services || (app.services = {}));
49814         })(app || (app = {}));
49815         var app;
49816         (function (app) {
49817             var services;
49818             (function (services) {
49819                 var MyModal = (function () {
49820                     function MyModal($uibModal) {
49821                         this.$uibModal = $uibModal;
49822                         this.modalOption = {
49823                             backdrop: true,
49824                             controller: null,
49825                             templateUrl: null,
49826                             size: null
49827                         };
49828                     }
49829                     MyModal.prototype.open = function (modalName) {
49830                         if (modalName === 'SelectCommand') {
49831                             this.modalOption.templateUrl = 'templates/select-command.html';
49832                             this.modalOption.size = 'lg';
49833                         }
49834                         return this.$uibModal.open(this.modalOption);
49835                     };
49836                     MyModal.prototype.selectCommand = function () {
49837                         this.modalOption.templateUrl = 'templates/select-command.html';
49838                         this.modalOption.controller = 'selectCommandController';
49839                         this.modalOption.controllerAs = 'c';
49840                         this.modalOption.size = 'lg';
49841                         return this.$uibModal.open(this.modalOption);
49842                     };
49843                     MyModal.prototype.preview = function () {
49844                         this.modalOption.templateUrl = 'templates/preview.html';
49845                         this.modalOption.controller = 'previewController';
49846                         this.modalOption.controllerAs = 'c';
49847                         this.modalOption.size = 'lg';
49848                         return this.$uibModal.open(this.modalOption);
49849                     };
49850                     MyModal.prototype.upload = function () {
49851                         this.modalOption.templateUrl = 'templates/upload.html';
49852                         this.modalOption.controller = 'uploadController';
49853                         this.modalOption.controllerAs = 'c';
49854                         this.modalOption.size = 'lg';
49855                         return this.$uibModal.open(this.modalOption);
49856                     };
49857                     MyModal.$inject = ['$uibModal'];
49858                     return MyModal;
49859                 })();
49860                 services.MyModal = MyModal;
49861             })(services = app.services || (app.services = {}));
49862         })(app || (app = {}));
49863         var app;
49864         (function (app) {
49865             var services;
49866             (function (services) {
49867                 var WebSocket = (function () {
49868                     function WebSocket($rootScope) {
49869                         this.$rootScope = $rootScope;
49870                         this.socket = io.connect();
49871                     }
49872                     WebSocket.prototype.on = function (eventName, callback) {
49873                         var socket = this.socket;
49874                         var rootScope = this.$rootScope;
49875                         socket.on(eventName, function () {
49876                             var args = arguments;
49877                             rootScope.$apply(function () {
49878                                 callback.apply(socket, args);
49879                             });
49880                         });
49881                     };
49882                     WebSocket.prototype.emit = function (eventName, data, callback) {
49883                         var socket = this.socket;
49884                         var rootScope = this.$rootScope;
49885                         this.socket.emit(eventName, data, function () {
49886                             var args = arguments;
49887                             rootScope.$apply(function () {
49888                                 if (callback)
49889                                     callback.apply(socket, args);
49890                             });
49891                         });
49892                     };
49893                     return WebSocket;
49894                 })();
49895                 services.WebSocket = WebSocket;
49896             })(services = app.services || (app.services = {}));
49897         })(app || (app = {}));
49898         var app;
49899         (function (app) {
49900             var services;
49901             (function (services) {
49902                 var Console = (function () {
49903                     function Console(WebSocket, $rootScope) {
49904                         this.WebSocket = WebSocket;
49905                         this.$rootScope = $rootScope;
49906                         this.WebSocket = WebSocket;
49907                         this.$rootScope = $rootScope;
49908                         this.directiveIDs = [];
49909                         var directiveIDs = this.directiveIDs;
49910                         this.WebSocket.on('console', function (d) {
49911                             var id = d.id;
49912                             var message = d.message;
49913                             if (directiveIDs.indexOf(id) > -1) {
49914                                 $rootScope.$emit(id, message);
49915                             }
49916                         });
49917                     }
49918                     Console.prototype.addDirective = function (id) {
49919                         if (!(this.directiveIDs.indexOf(id) > -1)) {
49920                             this.directiveIDs.push(id);
49921                         }
49922                     };
49923                     Console.prototype.removeDirective = function (id) {
49924                         var i = this.directiveIDs.indexOf(id);
49925                         if (i > -1) {
49926                             this.directiveIDs.splice(i, 1);
49927                         }
49928                     };
49929                     Console.prototype.showIDs = function () {
49930                         console.log(this.directiveIDs);
49931                     };
49932                     return Console;
49933                 })();
49934                 services.Console = Console;
49935             })(services = app.services || (app.services = {}));
49936         })(app || (app = {}));
49937         var app;
49938         (function (app) {
49939             var directives;
49940             (function (directives) {
49941                 var Command = (function () {
49942                     function Command() {
49943                         this.restrict = 'E';
49944                         this.replace = true;
49945                         this.scope = true;
49946                         this.controller = 'commandController';
49947                         this.controllerAs = 'ctrl';
49948                         this.bindToController = {
49949                             index: '=',
49950                             name: '=',
49951                             remove: '&',
49952                             list: '='
49953                         };
49954                         this.templateUrl = 'templates/command.html';
49955                     }
49956                     Command.Factory = function () {
49957                         var directive = function () {
49958                             return new Command();
49959                         };
49960                         directive.$inject = [];
49961                         return directive;
49962                     };
49963                     return Command;
49964                 })();
49965                 directives.Command = Command;
49966                 var CommandController = (function () {
49967                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
49968                         this.APIEndPoint = APIEndPoint;
49969                         this.$scope = $scope;
49970                         this.MyModal = MyModal;
49971                         this.WebSocket = WebSocket;
49972                         this.$window = $window;
49973                         this.$rootScope = $rootScope;
49974                         this.Console = Console;
49975                         var controller = this;
49976                         this.APIEndPoint
49977                             .getOptionControlFile(this.name)
49978                             .$promise
49979                             .then(function (result) {
49980                             controller.options = result.info;
49981                         });
49982                         this.APIEndPoint
49983                             .getDirectories()
49984                             .$promise
49985                             .then(function (result) {
49986                             controller.dirs = result.info;
49987                         });
49988                         this.heading = "[" + this.index + "]: dcdFilePrint";
49989                         this.isOpen = true;
49990                         this.$scope.$on('close', function () {
49991                             controller.isOpen = false;
49992                         });
49993                         function guid() {
49994                             function s4() {
49995                                 return Math.floor((1 + Math.random()) * 0x10000)
49996                                     .toString(16)
49997                                     .substring(1);
49998                             }
49999                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
50000                                 s4() + '-' + s4() + s4() + s4();
50001                         }
50002                         this.uuid = guid();
50003                         this.Console.addDirective(this.uuid);
50004                         this.Console.showIDs();
50005                     }
50006                     CommandController.prototype.submit = function () {
50007                         var opt = [];
50008                         angular.forEach(this.options, function (option) {
50009                             var obj = {
50010                                 name: option.option,
50011                                 arguments: []
50012                             };
50013                             angular.forEach(option.arg, function (arg) {
50014                                 if (arg.input) {
50015                                     if (typeof arg.input === 'object') {
50016                                         obj.arguments.push(arg.input.name);
50017                                     }
50018                                     else {
50019                                         obj.arguments.push(arg.input);
50020                                     }
50021                                 }
50022                             });
50023                             if (obj.arguments.length > 0) {
50024                                 opt.push(obj);
50025                             }
50026                         });
50027                         var execObj = {
50028                             command: this.name,
50029                             workspace: this.workspace.fileId,
50030                             options: opt
50031                         };
50032                         this.APIEndPoint
50033                             .execute(JSON.stringify(execObj))
50034                             .then(function (result) {
50035                             console.log(result);
50036                         });
50037                     };
50038                     CommandController.prototype.removeMySelf = function (index) {
50039                         this.$scope.$destroy();
50040                         this.Console.removeDirective(this.uuid);
50041                         this.remove()(index, this.list);
50042                         this.Console.showIDs();
50043                     };
50044                     CommandController.prototype.reloadFiles = function () {
50045                         var _this = this;
50046                         var fileId = this.workspace.fileId;
50047                         this.APIEndPoint
50048                             .getFiles(fileId)
50049                             .$promise
50050                             .then(function (result) {
50051                             var status = result.status;
50052                             if (status === 'success') {
50053                                 _this.files = result.info;
50054                             }
50055                             else {
50056                                 console.log(result.message);
50057                             }
50058                         });
50059                     };
50060                     CommandController.prototype.debug = function () {
50061                         var div = angular.element(this.$window.document).find("div");
50062                         var consoleTag;
50063                         var parametersTag;
50064                         angular.forEach(div, function (v) {
50065                             if (v.className === "panel-body console") {
50066                                 consoleTag = v;
50067                             }
50068                             else if (v.className === "row parameters-console") {
50069                                 parametersTag = v;
50070                             }
50071                         });
50072                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
50073                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
50074                         consoleTag.style.height = consoleHeight;
50075                         consoleTag.style.width = consoleWidth;
50076                     };
50077                     CommandController.prototype.help = function () {
50078                         this.APIEndPoint
50079                             .help(this.name)
50080                             .then(function (result) {
50081                             console.log(result);
50082                         });
50083                     };
50084                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
50085                     return CommandController;
50086                 })();
50087                 directives.CommandController = CommandController;
50088             })(directives = app.directives || (app.directives = {}));
50089         })(app || (app = {}));
50090         var app;
50091         (function (app) {
50092             var directives;
50093             (function (directives) {
50094                 var HeaderMenu = (function () {
50095                     function HeaderMenu() {
50096                         this.restrict = 'E';
50097                         this.replace = true;
50098                         this.templateUrl = 'templates/header-menu.html';
50099                         this.controller = 'HeaderMenuController';
50100                         this.controllerAs = 'hmc';
50101                         this.scope = true;
50102                     }
50103                     HeaderMenu.Factory = function () {
50104                         var directive = function () {
50105                             return new HeaderMenu();
50106                         };
50107                         return directive;
50108                     };
50109                     return HeaderMenu;
50110                 })();
50111                 directives.HeaderMenu = HeaderMenu;
50112                 var HeaderMenuController = (function () {
50113                     function HeaderMenuController($state) {
50114                         this.$state = $state;
50115                         this.isExecution = this.$state.current.name === 'execution';
50116                         this.isWorkspace = this.$state.current.name === 'workspace';
50117                         this.isHistory = this.$state.current.name === 'history';
50118                     }
50119                     HeaderMenuController.prototype.transit = function (state) {
50120                         this.$state.go(state);
50121                     };
50122                     HeaderMenuController.$inject = ['$state'];
50123                     return HeaderMenuController;
50124                 })();
50125                 directives.HeaderMenuController = HeaderMenuController;
50126             })(directives = app.directives || (app.directives = {}));
50127         })(app || (app = {}));
50128         var app;
50129         (function (app) {
50130             var directives;
50131             (function (directives) {
50132                 var Option = (function () {
50133                     function Option() {
50134                         this.restrict = 'E';
50135                         this.replace = true;
50136                         this.controller = 'optionController';
50137                         this.bindToController = {
50138                             info: '=',
50139                             files: '='
50140                         };
50141                         this.scope = true;
50142                         this.templateUrl = 'templates/option.html';
50143                         this.controllerAs = 'ctrl';
50144                     }
50145                     Option.Factory = function () {
50146                         var directive = function () {
50147                             return new Option();
50148                         };
50149                         directive.$inject = [];
50150                         return directive;
50151                     };
50152                     return Option;
50153                 })();
50154                 directives.Option = Option;
50155                 var OptionController = (function () {
50156                     function OptionController() {
50157                         var controller = this;
50158                         angular.forEach(controller.info.arg, function (arg) {
50159                             if (arg.initialValue) {
50160                                 if (arg.formType === 'number') {
50161                                     arg.input = parseInt(arg.initialValue);
50162                                 }
50163                                 else {
50164                                     arg.input = arg.initialValue;
50165                                 }
50166                             }
50167                         });
50168                     }
50169                     OptionController.$inject = [];
50170                     return OptionController;
50171                 })();
50172                 directives.OptionController = OptionController;
50173             })(directives = app.directives || (app.directives = {}));
50174         })(app || (app = {}));
50175         var app;
50176         (function (app) {
50177             var directives;
50178             (function (directives) {
50179                 var Directory = (function () {
50180                     function Directory() {
50181                         this.restrict = 'E';
50182                         this.replace = true;
50183                         this.controller = 'directoryController';
50184                         this.controllerAs = 'ctrl';
50185                         this.bindToController = {
50186                             info: '=',
50187                             add: '&',
50188                             list: '=',
50189                             files: '='
50190                         };
50191                         this.templateUrl = 'templates/directory.html';
50192                     }
50193                     Directory.Factory = function () {
50194                         var directive = function () {
50195                             return new Directory();
50196                         };
50197                         return directive;
50198                     };
50199                     return Directory;
50200                 })();
50201                 directives.Directory = Directory;
50202                 var DirectoryController = (function () {
50203                     function DirectoryController(APIEndPoint, $scope) {
50204                         this.APIEndPoint = APIEndPoint;
50205                         this.$scope = $scope;
50206                         var controller = this;
50207                         this.APIEndPoint
50208                             .getFiles(this.info.fileId)
50209                             .$promise
50210                             .then(function (result) {
50211                             if (result.status === 'success') {
50212                                 controller.files = result.info;
50213                                 angular.forEach(result.info, function (file) {
50214                                     if (file.fileType === '0') {
50215                                         var o = file;
50216                                         if (controller.info.path === '/') {
50217                                             o.path = '/' + file.name;
50218                                         }
50219                                         else {
50220                                             o.path = controller.info.path + '/' + file.name;
50221                                         }
50222                                         controller.add()(o, controller.list);
50223                                     }
50224                                 });
50225                             }
50226                             ;
50227                         });
50228                     }
50229                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
50230                     return DirectoryController;
50231                 })();
50232                 directives.DirectoryController = DirectoryController;
50233             })(directives = app.directives || (app.directives = {}));
50234         })(app || (app = {}));
50235         var app;
50236         (function (app) {
50237             var directives;
50238             (function (directives) {
50239                 var Upload = (function () {
50240                     function Upload() {
50241                         this.restrict = 'E';
50242                         this.replace = true;
50243                         this.scope = true;
50244                         this.controller = 'UploadController';
50245                         this.controllerAs = 'ctrl';
50246                         this.bindToController = {
50247                             index: '=',
50248                             name: '=',
50249                             remove: '&',
50250                             list: '='
50251                         };
50252                         this.templateUrl = 'templates/upload.html';
50253                         console.log("templates/upload.html-constructor");
50254                     }
50255                     Upload.Factory = function () {
50256                         var directive = function () {
50257                             return new Upload();
50258                         };
50259                         directive.$inject = [];
50260                         return directive;
50261                     };
50262                     return Upload;
50263                 })();
50264                 directives.Upload = Upload;
50265                 var UploadController = (function () {
50266                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
50267                         this.APIEndPoint = APIEndPoint;
50268                         this.$scope = $scope;
50269                         this.MyModal = MyModal;
50270                         this.WebSocket = WebSocket;
50271                         this.$window = $window;
50272                         this.$rootScope = $rootScope;
50273                         this.Console = Console;
50274                         var controller = this;
50275                         console.log("directive.upload-constructor");
50276                     }
50277                     UploadController.prototype.submit = function () {
50278                         console.log("submit: function not supported¥n");
50279                     };
50280                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
50281                     return UploadController;
50282                 })();
50283                 directives.UploadController = UploadController;
50284             })(directives = app.directives || (app.directives = {}));
50285         })(app || (app = {}));
50286         var app;
50287         (function (app) {
50288             var controllers;
50289             (function (controllers) {
50290                 var Execution = (function () {
50291                     function Execution(MyModal, $scope) {
50292                         this.MyModal = MyModal;
50293                         this.$scope = $scope;
50294                         this.commandInfoList = [];
50295                     }
50296                     ;
50297                     Execution.prototype.add = function () {
50298                         this.$scope.$broadcast('close');
50299                         var commandInfoList = this.commandInfoList;
50300                         var commandInstance = this.MyModal.selectCommand();
50301                         commandInstance
50302                             .result
50303                             .then(function (command) {
50304                             commandInfoList.push(new app.declares.CommandInfo(command));
50305                         });
50306                     };
50307                     Execution.prototype.open = function () {
50308                         var result = this.MyModal.open('SelectCommand');
50309                         console.log(result);
50310                     };
50311                     Execution.prototype.remove = function (index, list) {
50312                         list.splice(index, 1);
50313                     };
50314                     Execution.prototype.close = function () {
50315                         console.log("close");
50316                     };
50317                     Execution.$inject = ['MyModal', '$scope'];
50318                     return Execution;
50319                 })();
50320                 controllers.Execution = Execution;
50321             })(controllers = app.controllers || (app.controllers = {}));
50322         })(app || (app = {}));
50323         var app;
50324         (function (app) {
50325             var controllers;
50326             (function (controllers) {
50327                 var Workspace = (function () {
50328                     function Workspace($scope, APIEndPoint, MyModal) {
50329                         this.$scope = $scope;
50330                         this.APIEndPoint = APIEndPoint;
50331                         this.MyModal = MyModal;
50332                         this.directoryList = [];
50333                         var controller = this;
50334                         var directoryList = this.directoryList;
50335                         var o = {
50336                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
50337                             name: '',
50338                             parentId: '',
50339                             fileType: '',
50340                             createdAt: '',
50341                             updatedAt: '',
50342                             path: '/'
50343                         };
50344                         directoryList.push(o);
50345                     }
50346                     Workspace.prototype.addDirectory = function (info, directoryList) {
50347                         directoryList.push(info);
50348                     };
50349                     Workspace.prototype.upload = function () {
50350                         this.MyModal.upload();
50351                     };
50352                     Workspace.prototype.debug = function () {
50353                         this.MyModal.preview();
50354                     };
50355                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
50356                     return Workspace;
50357                 })();
50358                 controllers.Workspace = Workspace;
50359             })(controllers = app.controllers || (app.controllers = {}));
50360         })(app || (app = {}));
50361         var app;
50362         (function (app) {
50363             var controllers;
50364             (function (controllers) {
50365                 var History = (function () {
50366                     function History($scope) {
50367                         this.page = "History";
50368                     }
50369                     History.$inject = ['$scope'];
50370                     return History;
50371                 })();
50372                 controllers.History = History;
50373             })(controllers = app.controllers || (app.controllers = {}));
50374         })(app || (app = {}));
50375         var app;
50376         (function (app) {
50377             var controllers;
50378             (function (controllers) {
50379                 var SelectCommand = (function () {
50380                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
50381                         this.APIEndPoint = APIEndPoint;
50382                         this.$modalInstance = $modalInstance;
50383                         var controller = this;
50384                         this.APIEndPoint
50385                             .getTags()
50386                             .$promise.then(function (result) {
50387                             controller.tags = result.info;
50388                         });
50389                         this.APIEndPoint
50390                             .getCommands()
50391                             .$promise.then(function (result) {
50392                             controller.commands = result.info;
50393                         });
50394                         this.currentTag = 'all';
50395                     }
50396                     SelectCommand.prototype.changeTag = function (tag) {
50397                         this.currentTag = tag;
50398                     };
50399                     SelectCommand.prototype.selectCommand = function (command) {
50400                         this.$modalInstance.close(command);
50401                     };
50402                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50403                     return SelectCommand;
50404                 })();
50405                 controllers.SelectCommand = SelectCommand;
50406             })(controllers = app.controllers || (app.controllers = {}));
50407         })(app || (app = {}));
50408         var app;
50409         (function (app) {
50410             var controllers;
50411             (function (controllers) {
50412                 var Upload = (function () {
50413                     function Upload($scope, APIEndPoint, $modalInstance) {
50414                         this.APIEndPoint = APIEndPoint;
50415                         this.$modalInstance = $modalInstance;
50416                         var controller = this;
50417                         console.log('controller.upload-controllers');
50418                     }
50419                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50420                     return Upload;
50421                 })();
50422                 controllers.Upload = Upload;
50423             })(controllers = app.controllers || (app.controllers = {}));
50424         })(app || (app = {}));
50425         var app;
50426         (function (app) {
50427             var controllers;
50428             (function (controllers) {
50429                 var Preview = (function () {
50430                     function Preview($scope, APIEndPoint, $modalInstance) {
50431                         this.APIEndPoint = APIEndPoint;
50432                         this.$modalInstance = $modalInstance;
50433                         var controller = this;
50434                         console.log('preview');
50435                     }
50436                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
50437                     return Preview;
50438                 })();
50439                 controllers.Preview = Preview;
50440             })(controllers = app.controllers || (app.controllers = {}));
50441         })(app || (app = {}));
50442         var filters;
50443         (function (filters) {
50444             function Tag() {
50445                 return function (commands, tag) {
50446                     var result = [];
50447                     angular.forEach(commands, function (command) {
50448                         var flag = false;
50449                         angular.forEach(command.tags, function (value) {
50450                             if (tag === value)
50451                                 flag = true;
50452                         });
50453                         if (flag)
50454                             result.push(command);
50455                     });
50456                     return result;
50457                 };
50458             }
50459             filters.Tag = Tag;
50460         })(filters || (filters = {}));
50461         var app;
50462         (function (app) {
50463             'use strict';
50464             var appName = 'zephyr';
50465             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
50466             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
50467                 $urlRouterProvider.otherwise('/execution');
50468                 $locationProvider.html5Mode({
50469                     enabled: true,
50470                     requireBase: false
50471                 });
50472                 $stateProvider
50473                     .state('execution', {
50474                     url: '/execution',
50475                     templateUrl: 'templates/execution.html',
50476                     controller: 'executionController',
50477                     controllerAs: 'c'
50478                 })
50479                     .state('workspace', {
50480                     url: '/workspace',
50481                     templateUrl: 'templates/workspace.html',
50482                     controller: 'workspaceController',
50483                     controllerAs: 'c'
50484                 })
50485                     .state('history', {
50486                     url: '/history',
50487                     templateUrl: 'templates/history.html',
50488                     controller: 'historyController',
50489                     controllerAs: 'c'
50490                 });
50491             });
50492             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
50493             app.zephyr.service('MyModal', app.services.MyModal);
50494             app.zephyr.service('WebSocket', app.services.WebSocket);
50495             app.zephyr.service('Console', app.services.Console);
50496             app.zephyr.filter('Tag', filters.Tag);
50497             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
50498             app.zephyr.controller('previewController', app.controllers.Preview);
50499             app.zephyr.controller('uploadController', app.controllers.Upload);
50500             app.zephyr.controller('executionController', app.controllers.Execution);
50501             app.zephyr.controller('workspaceController', app.controllers.Workspace);
50502             app.zephyr.controller('historyController', app.controllers.History);
50503             app.zephyr.controller('commandController', app.directives.CommandController);
50504             app.zephyr.controller('optionController', app.directives.OptionController);
50505             app.zephyr.controller('directoryController', app.directives.DirectoryController);
50506             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
50507             app.zephyr.controller('uploadController', app.directives.UploadController);
50508             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
50509             app.zephyr.directive('command', app.directives.Command.Factory());
50510             app.zephyr.directive('option', app.directives.Option.Factory());
50511             app.zephyr.directive('directory', app.directives.Directory.Factory());
50512         })(app || (app = {}));
50513
50514
50515 /***/ },
50516 /* 19 */
50517 /***/ function(module, exports) {
50518
50519         var app;
50520         (function (app) {
50521             var declares;
50522             (function (declares) {
50523                 var CommandInfo = (function () {
50524                     function CommandInfo(name) {
50525                         this.name = name;
50526                     }
50527                     return CommandInfo;
50528                 })();
50529                 declares.CommandInfo = CommandInfo;
50530             })(declares = app.declares || (app.declares = {}));
50531         })(app || (app = {}));
50532         var app;
50533         (function (app) {
50534             var services;
50535             (function (services) {
50536                 var APIEndPoint = (function () {
50537                     function APIEndPoint($resource, $http) {
50538                         this.$resource = $resource;
50539                         this.$http = $http;
50540                     }
50541                     APIEndPoint.prototype.resource = function (endPoint, data) {
50542                         var customAction = {
50543                             method: 'GET',
50544                             isArray: false
50545                         };
50546                         var execute = {
50547                             method: 'POST',
50548                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
50549                         };
50550                         return this.$resource(endPoint, {}, { execute: execute });
50551                     };
50552                     APIEndPoint.prototype.getOptionControlFile = function (command) {
50553                         var endPoint = '/api/v1/optionControlFile/' + command;
50554                         return this.resource(endPoint, {}).get();
50555                     };
50556                     APIEndPoint.prototype.getFiles = function (fileId) {
50557                         var endPoint = '/api/v1/workspace';
50558                         if (fileId) {
50559                             endPoint += '/' + fileId;
50560                         }
50561                         return this.resource(endPoint, {}).get();
50562                     };
50563                     APIEndPoint.prototype.getDirectories = function () {
50564                         var endPoint = '/api/v1/all/workspace/directory';
50565                         return this.resource(endPoint, {}).get();
50566                     };
50567                     APIEndPoint.prototype.getTags = function () {
50568                         var endPoint = '/api/v1/tagList';
50569                         return this.resource(endPoint, {}).get();
50570                     };
50571                     APIEndPoint.prototype.getCommands = function () {
50572                         var endPoint = '/api/v1/commandList';
50573                         return this.resource(endPoint, {}).get();
50574                     };
50575                     APIEndPoint.prototype.execute = function (data) {
50576                         var endPoint = '/api/v1/execution';
50577                         var fd = new FormData();
50578                         fd.append('data', data);
50579                         return this.$http.post(endPoint, fd, {
50580                             headers: { 'Content-Type': undefined },
50581                             transformRequest: angular.identity
50582                         });
50583                     };
50584                     APIEndPoint.prototype.debug = function () {
50585                         var endPoint = '/api/v1/debug';
50586                         return this.$http.get(endPoint);
50587                     };
50588                     APIEndPoint.prototype.upload = function () {
50589                         var endPoint = '/api/v1/upload';
50590                         return this.$http.get(endPoint);
50591                     };
50592                     APIEndPoint.prototype.help = function (command) {
50593                         var endPoint = '/api/v1/help/' + command;
50594                         return this.$http.get(endPoint);
50595                     };
50596                     return APIEndPoint;
50597                 })();
50598                 services.APIEndPoint = APIEndPoint;
50599             })(services = app.services || (app.services = {}));
50600         })(app || (app = {}));
50601         var app;
50602         (function (app) {
50603             var services;
50604             (function (services) {
50605                 var MyModal = (function () {
50606                     function MyModal($uibModal) {
50607                         this.$uibModal = $uibModal;
50608                         this.modalOption = {
50609                             backdrop: true,
50610                             controller: null,
50611                             templateUrl: null,
50612                             size: null
50613                         };
50614                     }
50615                     MyModal.prototype.open = function (modalName) {
50616                         if (modalName === 'SelectCommand') {
50617                             this.modalOption.templateUrl = 'templates/select-command.html';
50618                             this.modalOption.size = 'lg';
50619                         }
50620                         return this.$uibModal.open(this.modalOption);
50621                     };
50622                     MyModal.prototype.selectCommand = function () {
50623                         this.modalOption.templateUrl = 'templates/select-command.html';
50624                         this.modalOption.controller = 'selectCommandController';
50625                         this.modalOption.controllerAs = 'c';
50626                         this.modalOption.size = 'lg';
50627                         return this.$uibModal.open(this.modalOption);
50628                     };
50629                     MyModal.prototype.preview = function () {
50630                         this.modalOption.templateUrl = 'templates/preview.html';
50631                         this.modalOption.controller = 'previewController';
50632                         this.modalOption.controllerAs = 'c';
50633                         this.modalOption.size = 'lg';
50634                         return this.$uibModal.open(this.modalOption);
50635                     };
50636                     MyModal.prototype.upload = function () {
50637                         this.modalOption.templateUrl = 'templates/upload.html';
50638                         this.modalOption.controller = 'uploadController';
50639                         this.modalOption.controllerAs = 'c';
50640                         this.modalOption.size = 'lg';
50641                         return this.$uibModal.open(this.modalOption);
50642                     };
50643                     MyModal.$inject = ['$uibModal'];
50644                     return MyModal;
50645                 })();
50646                 services.MyModal = MyModal;
50647             })(services = app.services || (app.services = {}));
50648         })(app || (app = {}));
50649         var app;
50650         (function (app) {
50651             var services;
50652             (function (services) {
50653                 var WebSocket = (function () {
50654                     function WebSocket($rootScope) {
50655                         this.$rootScope = $rootScope;
50656                         this.socket = io.connect();
50657                     }
50658                     WebSocket.prototype.on = function (eventName, callback) {
50659                         var socket = this.socket;
50660                         var rootScope = this.$rootScope;
50661                         socket.on(eventName, function () {
50662                             var args = arguments;
50663                             rootScope.$apply(function () {
50664                                 callback.apply(socket, args);
50665                             });
50666                         });
50667                     };
50668                     WebSocket.prototype.emit = function (eventName, data, callback) {
50669                         var socket = this.socket;
50670                         var rootScope = this.$rootScope;
50671                         this.socket.emit(eventName, data, function () {
50672                             var args = arguments;
50673                             rootScope.$apply(function () {
50674                                 if (callback)
50675                                     callback.apply(socket, args);
50676                             });
50677                         });
50678                     };
50679                     return WebSocket;
50680                 })();
50681                 services.WebSocket = WebSocket;
50682             })(services = app.services || (app.services = {}));
50683         })(app || (app = {}));
50684         var app;
50685         (function (app) {
50686             var services;
50687             (function (services) {
50688                 var Console = (function () {
50689                     function Console(WebSocket, $rootScope) {
50690                         this.WebSocket = WebSocket;
50691                         this.$rootScope = $rootScope;
50692                         this.WebSocket = WebSocket;
50693                         this.$rootScope = $rootScope;
50694                         this.directiveIDs = [];
50695                         var directiveIDs = this.directiveIDs;
50696                         this.WebSocket.on('console', function (d) {
50697                             var id = d.id;
50698                             var message = d.message;
50699                             if (directiveIDs.indexOf(id) > -1) {
50700                                 $rootScope.$emit(id, message);
50701                             }
50702                         });
50703                     }
50704                     Console.prototype.addDirective = function (id) {
50705                         if (!(this.directiveIDs.indexOf(id) > -1)) {
50706                             this.directiveIDs.push(id);
50707                         }
50708                     };
50709                     Console.prototype.removeDirective = function (id) {
50710                         var i = this.directiveIDs.indexOf(id);
50711                         if (i > -1) {
50712                             this.directiveIDs.splice(i, 1);
50713                         }
50714                     };
50715                     Console.prototype.showIDs = function () {
50716                         console.log(this.directiveIDs);
50717                     };
50718                     return Console;
50719                 })();
50720                 services.Console = Console;
50721             })(services = app.services || (app.services = {}));
50722         })(app || (app = {}));
50723         var app;
50724         (function (app) {
50725             var directives;
50726             (function (directives) {
50727                 var Command = (function () {
50728                     function Command() {
50729                         this.restrict = 'E';
50730                         this.replace = true;
50731                         this.scope = true;
50732                         this.controller = 'commandController';
50733                         this.controllerAs = 'ctrl';
50734                         this.bindToController = {
50735                             index: '=',
50736                             name: '=',
50737                             remove: '&',
50738                             list: '='
50739                         };
50740                         this.templateUrl = 'templates/command.html';
50741                     }
50742                     Command.Factory = function () {
50743                         var directive = function () {
50744                             return new Command();
50745                         };
50746                         directive.$inject = [];
50747                         return directive;
50748                     };
50749                     return Command;
50750                 })();
50751                 directives.Command = Command;
50752                 var CommandController = (function () {
50753                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
50754                         this.APIEndPoint = APIEndPoint;
50755                         this.$scope = $scope;
50756                         this.MyModal = MyModal;
50757                         this.WebSocket = WebSocket;
50758                         this.$window = $window;
50759                         this.$rootScope = $rootScope;
50760                         this.Console = Console;
50761                         var controller = this;
50762                         this.APIEndPoint
50763                             .getOptionControlFile(this.name)
50764                             .$promise
50765                             .then(function (result) {
50766                             controller.options = result.info;
50767                         });
50768                         this.APIEndPoint
50769                             .getDirectories()
50770                             .$promise
50771                             .then(function (result) {
50772                             controller.dirs = result.info;
50773                         });
50774                         this.heading = "[" + this.index + "]: dcdFilePrint";
50775                         this.isOpen = true;
50776                         this.$scope.$on('close', function () {
50777                             controller.isOpen = false;
50778                         });
50779                         function guid() {
50780                             function s4() {
50781                                 return Math.floor((1 + Math.random()) * 0x10000)
50782                                     .toString(16)
50783                                     .substring(1);
50784                             }
50785                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
50786                                 s4() + '-' + s4() + s4() + s4();
50787                         }
50788                         this.uuid = guid();
50789                         this.Console.addDirective(this.uuid);
50790                         this.Console.showIDs();
50791                     }
50792                     CommandController.prototype.submit = function () {
50793                         var opt = [];
50794                         angular.forEach(this.options, function (option) {
50795                             var obj = {
50796                                 name: option.option,
50797                                 arguments: []
50798                             };
50799                             angular.forEach(option.arg, function (arg) {
50800                                 if (arg.input) {
50801                                     if (typeof arg.input === 'object') {
50802                                         obj.arguments.push(arg.input.name);
50803                                     }
50804                                     else {
50805                                         obj.arguments.push(arg.input);
50806                                     }
50807                                 }
50808                             });
50809                             if (obj.arguments.length > 0) {
50810                                 opt.push(obj);
50811                             }
50812                         });
50813                         var execObj = {
50814                             command: this.name,
50815                             workspace: this.workspace.fileId,
50816                             options: opt
50817                         };
50818                         this.APIEndPoint
50819                             .execute(JSON.stringify(execObj))
50820                             .then(function (result) {
50821                             console.log(result);
50822                         });
50823                     };
50824                     CommandController.prototype.removeMySelf = function (index) {
50825                         this.$scope.$destroy();
50826                         this.Console.removeDirective(this.uuid);
50827                         this.remove()(index, this.list);
50828                         this.Console.showIDs();
50829                     };
50830                     CommandController.prototype.reloadFiles = function () {
50831                         var _this = this;
50832                         var fileId = this.workspace.fileId;
50833                         this.APIEndPoint
50834                             .getFiles(fileId)
50835                             .$promise
50836                             .then(function (result) {
50837                             var status = result.status;
50838                             if (status === 'success') {
50839                                 _this.files = result.info;
50840                             }
50841                             else {
50842                                 console.log(result.message);
50843                             }
50844                         });
50845                     };
50846                     CommandController.prototype.debug = function () {
50847                         var div = angular.element(this.$window.document).find("div");
50848                         var consoleTag;
50849                         var parametersTag;
50850                         angular.forEach(div, function (v) {
50851                             if (v.className === "panel-body console") {
50852                                 consoleTag = v;
50853                             }
50854                             else if (v.className === "row parameters-console") {
50855                                 parametersTag = v;
50856                             }
50857                         });
50858                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
50859                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
50860                         consoleTag.style.height = consoleHeight;
50861                         consoleTag.style.width = consoleWidth;
50862                     };
50863                     CommandController.prototype.help = function () {
50864                         this.APIEndPoint
50865                             .help(this.name)
50866                             .then(function (result) {
50867                             console.log(result);
50868                         });
50869                     };
50870                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
50871                     return CommandController;
50872                 })();
50873                 directives.CommandController = CommandController;
50874             })(directives = app.directives || (app.directives = {}));
50875         })(app || (app = {}));
50876         var app;
50877         (function (app) {
50878             var directives;
50879             (function (directives) {
50880                 var HeaderMenu = (function () {
50881                     function HeaderMenu() {
50882                         this.restrict = 'E';
50883                         this.replace = true;
50884                         this.templateUrl = 'templates/header-menu.html';
50885                         this.controller = 'HeaderMenuController';
50886                         this.controllerAs = 'hmc';
50887                         this.scope = true;
50888                     }
50889                     HeaderMenu.Factory = function () {
50890                         var directive = function () {
50891                             return new HeaderMenu();
50892                         };
50893                         return directive;
50894                     };
50895                     return HeaderMenu;
50896                 })();
50897                 directives.HeaderMenu = HeaderMenu;
50898                 var HeaderMenuController = (function () {
50899                     function HeaderMenuController($state) {
50900                         this.$state = $state;
50901                         this.isExecution = this.$state.current.name === 'execution';
50902                         this.isWorkspace = this.$state.current.name === 'workspace';
50903                         this.isHistory = this.$state.current.name === 'history';
50904                     }
50905                     HeaderMenuController.prototype.transit = function (state) {
50906                         this.$state.go(state);
50907                     };
50908                     HeaderMenuController.$inject = ['$state'];
50909                     return HeaderMenuController;
50910                 })();
50911                 directives.HeaderMenuController = HeaderMenuController;
50912             })(directives = app.directives || (app.directives = {}));
50913         })(app || (app = {}));
50914         var app;
50915         (function (app) {
50916             var directives;
50917             (function (directives) {
50918                 var Option = (function () {
50919                     function Option() {
50920                         this.restrict = 'E';
50921                         this.replace = true;
50922                         this.controller = 'optionController';
50923                         this.bindToController = {
50924                             info: '=',
50925                             files: '='
50926                         };
50927                         this.scope = true;
50928                         this.templateUrl = 'templates/option.html';
50929                         this.controllerAs = 'ctrl';
50930                     }
50931                     Option.Factory = function () {
50932                         var directive = function () {
50933                             return new Option();
50934                         };
50935                         directive.$inject = [];
50936                         return directive;
50937                     };
50938                     return Option;
50939                 })();
50940                 directives.Option = Option;
50941                 var OptionController = (function () {
50942                     function OptionController() {
50943                         var controller = this;
50944                         angular.forEach(controller.info.arg, function (arg) {
50945                             if (arg.initialValue) {
50946                                 if (arg.formType === 'number') {
50947                                     arg.input = parseInt(arg.initialValue);
50948                                 }
50949                                 else {
50950                                     arg.input = arg.initialValue;
50951                                 }
50952                             }
50953                         });
50954                     }
50955                     OptionController.$inject = [];
50956                     return OptionController;
50957                 })();
50958                 directives.OptionController = OptionController;
50959             })(directives = app.directives || (app.directives = {}));
50960         })(app || (app = {}));
50961         var app;
50962         (function (app) {
50963             var directives;
50964             (function (directives) {
50965                 var Directory = (function () {
50966                     function Directory() {
50967                         this.restrict = 'E';
50968                         this.replace = true;
50969                         this.controller = 'directoryController';
50970                         this.controllerAs = 'ctrl';
50971                         this.bindToController = {
50972                             info: '=',
50973                             add: '&',
50974                             list: '=',
50975                             files: '='
50976                         };
50977                         this.templateUrl = 'templates/directory.html';
50978                     }
50979                     Directory.Factory = function () {
50980                         var directive = function () {
50981                             return new Directory();
50982                         };
50983                         return directive;
50984                     };
50985                     return Directory;
50986                 })();
50987                 directives.Directory = Directory;
50988                 var DirectoryController = (function () {
50989                     function DirectoryController(APIEndPoint, $scope) {
50990                         this.APIEndPoint = APIEndPoint;
50991                         this.$scope = $scope;
50992                         var controller = this;
50993                         this.APIEndPoint
50994                             .getFiles(this.info.fileId)
50995                             .$promise
50996                             .then(function (result) {
50997                             if (result.status === 'success') {
50998                                 controller.files = result.info;
50999                                 angular.forEach(result.info, function (file) {
51000                                     if (file.fileType === '0') {
51001                                         var o = file;
51002                                         if (controller.info.path === '/') {
51003                                             o.path = '/' + file.name;
51004                                         }
51005                                         else {
51006                                             o.path = controller.info.path + '/' + file.name;
51007                                         }
51008                                         controller.add()(o, controller.list);
51009                                     }
51010                                 });
51011                             }
51012                             ;
51013                         });
51014                     }
51015                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
51016                     return DirectoryController;
51017                 })();
51018                 directives.DirectoryController = DirectoryController;
51019             })(directives = app.directives || (app.directives = {}));
51020         })(app || (app = {}));
51021         var app;
51022         (function (app) {
51023             var directives;
51024             (function (directives) {
51025                 var Upload = (function () {
51026                     function Upload() {
51027                         this.restrict = 'E';
51028                         this.replace = true;
51029                         this.scope = true;
51030                         this.controller = 'UploadController';
51031                         this.controllerAs = 'ctrl';
51032                         this.bindToController = {
51033                             index: '=',
51034                             name: '=',
51035                             remove: '&',
51036                             list: '='
51037                         };
51038                         this.templateUrl = 'templates/upload.html';
51039                         console.log("templates/upload.html-constructor");
51040                     }
51041                     Upload.Factory = function () {
51042                         var directive = function () {
51043                             return new Upload();
51044                         };
51045                         directive.$inject = [];
51046                         return directive;
51047                     };
51048                     return Upload;
51049                 })();
51050                 directives.Upload = Upload;
51051                 var UploadController = (function () {
51052                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
51053                         this.APIEndPoint = APIEndPoint;
51054                         this.$scope = $scope;
51055                         this.MyModal = MyModal;
51056                         this.WebSocket = WebSocket;
51057                         this.$window = $window;
51058                         this.$rootScope = $rootScope;
51059                         this.Console = Console;
51060                         var controller = this;
51061                         console.log("directive.upload-constructor");
51062                     }
51063                     UploadController.prototype.submit = function () {
51064                         console.log("submit: function not supported¥n");
51065                     };
51066                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
51067                     return UploadController;
51068                 })();
51069                 directives.UploadController = UploadController;
51070             })(directives = app.directives || (app.directives = {}));
51071         })(app || (app = {}));
51072         var app;
51073         (function (app) {
51074             var controllers;
51075             (function (controllers) {
51076                 var Execution = (function () {
51077                     function Execution(MyModal, $scope) {
51078                         this.MyModal = MyModal;
51079                         this.$scope = $scope;
51080                         this.commandInfoList = [];
51081                     }
51082                     ;
51083                     Execution.prototype.add = function () {
51084                         this.$scope.$broadcast('close');
51085                         var commandInfoList = this.commandInfoList;
51086                         var commandInstance = this.MyModal.selectCommand();
51087                         commandInstance
51088                             .result
51089                             .then(function (command) {
51090                             commandInfoList.push(new app.declares.CommandInfo(command));
51091                         });
51092                     };
51093                     Execution.prototype.open = function () {
51094                         var result = this.MyModal.open('SelectCommand');
51095                         console.log(result);
51096                     };
51097                     Execution.prototype.remove = function (index, list) {
51098                         list.splice(index, 1);
51099                     };
51100                     Execution.prototype.close = function () {
51101                         console.log("close");
51102                     };
51103                     Execution.$inject = ['MyModal', '$scope'];
51104                     return Execution;
51105                 })();
51106                 controllers.Execution = Execution;
51107             })(controllers = app.controllers || (app.controllers = {}));
51108         })(app || (app = {}));
51109         var app;
51110         (function (app) {
51111             var controllers;
51112             (function (controllers) {
51113                 var Workspace = (function () {
51114                     function Workspace($scope, APIEndPoint, MyModal) {
51115                         this.$scope = $scope;
51116                         this.APIEndPoint = APIEndPoint;
51117                         this.MyModal = MyModal;
51118                         this.directoryList = [];
51119                         var controller = this;
51120                         var directoryList = this.directoryList;
51121                         var o = {
51122                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
51123                             name: '',
51124                             parentId: '',
51125                             fileType: '',
51126                             createdAt: '',
51127                             updatedAt: '',
51128                             path: '/'
51129                         };
51130                         directoryList.push(o);
51131                     }
51132                     Workspace.prototype.addDirectory = function (info, directoryList) {
51133                         directoryList.push(info);
51134                     };
51135                     Workspace.prototype.upload = function () {
51136                         this.MyModal.upload();
51137                     };
51138                     Workspace.prototype.debug = function () {
51139                         this.MyModal.preview();
51140                     };
51141                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
51142                     return Workspace;
51143                 })();
51144                 controllers.Workspace = Workspace;
51145             })(controllers = app.controllers || (app.controllers = {}));
51146         })(app || (app = {}));
51147         var app;
51148         (function (app) {
51149             var controllers;
51150             (function (controllers) {
51151                 var History = (function () {
51152                     function History($scope) {
51153                         this.page = "History";
51154                     }
51155                     History.$inject = ['$scope'];
51156                     return History;
51157                 })();
51158                 controllers.History = History;
51159             })(controllers = app.controllers || (app.controllers = {}));
51160         })(app || (app = {}));
51161         var app;
51162         (function (app) {
51163             var controllers;
51164             (function (controllers) {
51165                 var SelectCommand = (function () {
51166                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
51167                         this.APIEndPoint = APIEndPoint;
51168                         this.$modalInstance = $modalInstance;
51169                         var controller = this;
51170                         this.APIEndPoint
51171                             .getTags()
51172                             .$promise.then(function (result) {
51173                             controller.tags = result.info;
51174                         });
51175                         this.APIEndPoint
51176                             .getCommands()
51177                             .$promise.then(function (result) {
51178                             controller.commands = result.info;
51179                         });
51180                         this.currentTag = 'all';
51181                     }
51182                     SelectCommand.prototype.changeTag = function (tag) {
51183                         this.currentTag = tag;
51184                     };
51185                     SelectCommand.prototype.selectCommand = function (command) {
51186                         this.$modalInstance.close(command);
51187                     };
51188                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51189                     return SelectCommand;
51190                 })();
51191                 controllers.SelectCommand = SelectCommand;
51192             })(controllers = app.controllers || (app.controllers = {}));
51193         })(app || (app = {}));
51194         var app;
51195         (function (app) {
51196             var controllers;
51197             (function (controllers) {
51198                 var Upload = (function () {
51199                     function Upload($scope, APIEndPoint, $modalInstance) {
51200                         this.APIEndPoint = APIEndPoint;
51201                         this.$modalInstance = $modalInstance;
51202                         var controller = this;
51203                         console.log('controller.upload-controllers');
51204                     }
51205                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51206                     return Upload;
51207                 })();
51208                 controllers.Upload = Upload;
51209             })(controllers = app.controllers || (app.controllers = {}));
51210         })(app || (app = {}));
51211         var app;
51212         (function (app) {
51213             var controllers;
51214             (function (controllers) {
51215                 var Preview = (function () {
51216                     function Preview($scope, APIEndPoint, $modalInstance) {
51217                         this.APIEndPoint = APIEndPoint;
51218                         this.$modalInstance = $modalInstance;
51219                         var controller = this;
51220                         console.log('preview');
51221                     }
51222                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51223                     return Preview;
51224                 })();
51225                 controllers.Preview = Preview;
51226             })(controllers = app.controllers || (app.controllers = {}));
51227         })(app || (app = {}));
51228         var filters;
51229         (function (filters) {
51230             function Tag() {
51231                 return function (commands, tag) {
51232                     var result = [];
51233                     angular.forEach(commands, function (command) {
51234                         var flag = false;
51235                         angular.forEach(command.tags, function (value) {
51236                             if (tag === value)
51237                                 flag = true;
51238                         });
51239                         if (flag)
51240                             result.push(command);
51241                     });
51242                     return result;
51243                 };
51244             }
51245             filters.Tag = Tag;
51246         })(filters || (filters = {}));
51247         var app;
51248         (function (app) {
51249             'use strict';
51250             var appName = 'zephyr';
51251             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
51252             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
51253                 $urlRouterProvider.otherwise('/execution');
51254                 $locationProvider.html5Mode({
51255                     enabled: true,
51256                     requireBase: false
51257                 });
51258                 $stateProvider
51259                     .state('execution', {
51260                     url: '/execution',
51261                     templateUrl: 'templates/execution.html',
51262                     controller: 'executionController',
51263                     controllerAs: 'c'
51264                 })
51265                     .state('workspace', {
51266                     url: '/workspace',
51267                     templateUrl: 'templates/workspace.html',
51268                     controller: 'workspaceController',
51269                     controllerAs: 'c'
51270                 })
51271                     .state('history', {
51272                     url: '/history',
51273                     templateUrl: 'templates/history.html',
51274                     controller: 'historyController',
51275                     controllerAs: 'c'
51276                 });
51277             });
51278             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
51279             app.zephyr.service('MyModal', app.services.MyModal);
51280             app.zephyr.service('WebSocket', app.services.WebSocket);
51281             app.zephyr.service('Console', app.services.Console);
51282             app.zephyr.filter('Tag', filters.Tag);
51283             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
51284             app.zephyr.controller('previewController', app.controllers.Preview);
51285             app.zephyr.controller('uploadController', app.controllers.Upload);
51286             app.zephyr.controller('executionController', app.controllers.Execution);
51287             app.zephyr.controller('workspaceController', app.controllers.Workspace);
51288             app.zephyr.controller('historyController', app.controllers.History);
51289             app.zephyr.controller('commandController', app.directives.CommandController);
51290             app.zephyr.controller('optionController', app.directives.OptionController);
51291             app.zephyr.controller('directoryController', app.directives.DirectoryController);
51292             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
51293             app.zephyr.controller('uploadController', app.directives.UploadController);
51294             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
51295             app.zephyr.directive('command', app.directives.Command.Factory());
51296             app.zephyr.directive('option', app.directives.Option.Factory());
51297             app.zephyr.directive('directory', app.directives.Directory.Factory());
51298         })(app || (app = {}));
51299
51300
51301 /***/ },
51302 /* 20 */
51303 /***/ function(module, exports) {
51304
51305         var app;
51306         (function (app) {
51307             var declares;
51308             (function (declares) {
51309                 var CommandInfo = (function () {
51310                     function CommandInfo(name) {
51311                         this.name = name;
51312                     }
51313                     return CommandInfo;
51314                 })();
51315                 declares.CommandInfo = CommandInfo;
51316             })(declares = app.declares || (app.declares = {}));
51317         })(app || (app = {}));
51318         var app;
51319         (function (app) {
51320             var services;
51321             (function (services) {
51322                 var APIEndPoint = (function () {
51323                     function APIEndPoint($resource, $http) {
51324                         this.$resource = $resource;
51325                         this.$http = $http;
51326                     }
51327                     APIEndPoint.prototype.resource = function (endPoint, data) {
51328                         var customAction = {
51329                             method: 'GET',
51330                             isArray: false
51331                         };
51332                         var execute = {
51333                             method: 'POST',
51334                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
51335                         };
51336                         return this.$resource(endPoint, {}, { execute: execute });
51337                     };
51338                     APIEndPoint.prototype.getOptionControlFile = function (command) {
51339                         var endPoint = '/api/v1/optionControlFile/' + command;
51340                         return this.resource(endPoint, {}).get();
51341                     };
51342                     APIEndPoint.prototype.getFiles = function (fileId) {
51343                         var endPoint = '/api/v1/workspace';
51344                         if (fileId) {
51345                             endPoint += '/' + fileId;
51346                         }
51347                         return this.resource(endPoint, {}).get();
51348                     };
51349                     APIEndPoint.prototype.getDirectories = function () {
51350                         var endPoint = '/api/v1/all/workspace/directory';
51351                         return this.resource(endPoint, {}).get();
51352                     };
51353                     APIEndPoint.prototype.getTags = function () {
51354                         var endPoint = '/api/v1/tagList';
51355                         return this.resource(endPoint, {}).get();
51356                     };
51357                     APIEndPoint.prototype.getCommands = function () {
51358                         var endPoint = '/api/v1/commandList';
51359                         return this.resource(endPoint, {}).get();
51360                     };
51361                     APIEndPoint.prototype.execute = function (data) {
51362                         var endPoint = '/api/v1/execution';
51363                         var fd = new FormData();
51364                         fd.append('data', data);
51365                         return this.$http.post(endPoint, fd, {
51366                             headers: { 'Content-Type': undefined },
51367                             transformRequest: angular.identity
51368                         });
51369                     };
51370                     APIEndPoint.prototype.debug = function () {
51371                         var endPoint = '/api/v1/debug';
51372                         return this.$http.get(endPoint);
51373                     };
51374                     APIEndPoint.prototype.upload = function () {
51375                         var endPoint = '/api/v1/upload';
51376                         return this.$http.get(endPoint);
51377                     };
51378                     APIEndPoint.prototype.help = function (command) {
51379                         var endPoint = '/api/v1/help/' + command;
51380                         return this.$http.get(endPoint);
51381                     };
51382                     return APIEndPoint;
51383                 })();
51384                 services.APIEndPoint = APIEndPoint;
51385             })(services = app.services || (app.services = {}));
51386         })(app || (app = {}));
51387         var app;
51388         (function (app) {
51389             var services;
51390             (function (services) {
51391                 var MyModal = (function () {
51392                     function MyModal($uibModal) {
51393                         this.$uibModal = $uibModal;
51394                         this.modalOption = {
51395                             backdrop: true,
51396                             controller: null,
51397                             templateUrl: null,
51398                             size: null
51399                         };
51400                     }
51401                     MyModal.prototype.open = function (modalName) {
51402                         if (modalName === 'SelectCommand') {
51403                             this.modalOption.templateUrl = 'templates/select-command.html';
51404                             this.modalOption.size = 'lg';
51405                         }
51406                         return this.$uibModal.open(this.modalOption);
51407                     };
51408                     MyModal.prototype.selectCommand = function () {
51409                         this.modalOption.templateUrl = 'templates/select-command.html';
51410                         this.modalOption.controller = 'selectCommandController';
51411                         this.modalOption.controllerAs = 'c';
51412                         this.modalOption.size = 'lg';
51413                         return this.$uibModal.open(this.modalOption);
51414                     };
51415                     MyModal.prototype.preview = function () {
51416                         this.modalOption.templateUrl = 'templates/preview.html';
51417                         this.modalOption.controller = 'previewController';
51418                         this.modalOption.controllerAs = 'c';
51419                         this.modalOption.size = 'lg';
51420                         return this.$uibModal.open(this.modalOption);
51421                     };
51422                     MyModal.prototype.upload = function () {
51423                         this.modalOption.templateUrl = 'templates/upload.html';
51424                         this.modalOption.controller = 'uploadController';
51425                         this.modalOption.controllerAs = 'c';
51426                         this.modalOption.size = 'lg';
51427                         return this.$uibModal.open(this.modalOption);
51428                     };
51429                     MyModal.$inject = ['$uibModal'];
51430                     return MyModal;
51431                 })();
51432                 services.MyModal = MyModal;
51433             })(services = app.services || (app.services = {}));
51434         })(app || (app = {}));
51435         var app;
51436         (function (app) {
51437             var services;
51438             (function (services) {
51439                 var WebSocket = (function () {
51440                     function WebSocket($rootScope) {
51441                         this.$rootScope = $rootScope;
51442                         this.socket = io.connect();
51443                     }
51444                     WebSocket.prototype.on = function (eventName, callback) {
51445                         var socket = this.socket;
51446                         var rootScope = this.$rootScope;
51447                         socket.on(eventName, function () {
51448                             var args = arguments;
51449                             rootScope.$apply(function () {
51450                                 callback.apply(socket, args);
51451                             });
51452                         });
51453                     };
51454                     WebSocket.prototype.emit = function (eventName, data, callback) {
51455                         var socket = this.socket;
51456                         var rootScope = this.$rootScope;
51457                         this.socket.emit(eventName, data, function () {
51458                             var args = arguments;
51459                             rootScope.$apply(function () {
51460                                 if (callback)
51461                                     callback.apply(socket, args);
51462                             });
51463                         });
51464                     };
51465                     return WebSocket;
51466                 })();
51467                 services.WebSocket = WebSocket;
51468             })(services = app.services || (app.services = {}));
51469         })(app || (app = {}));
51470         var app;
51471         (function (app) {
51472             var services;
51473             (function (services) {
51474                 var Console = (function () {
51475                     function Console(WebSocket, $rootScope) {
51476                         this.WebSocket = WebSocket;
51477                         this.$rootScope = $rootScope;
51478                         this.WebSocket = WebSocket;
51479                         this.$rootScope = $rootScope;
51480                         this.directiveIDs = [];
51481                         var directiveIDs = this.directiveIDs;
51482                         this.WebSocket.on('console', function (d) {
51483                             var id = d.id;
51484                             var message = d.message;
51485                             if (directiveIDs.indexOf(id) > -1) {
51486                                 $rootScope.$emit(id, message);
51487                             }
51488                         });
51489                     }
51490                     Console.prototype.addDirective = function (id) {
51491                         if (!(this.directiveIDs.indexOf(id) > -1)) {
51492                             this.directiveIDs.push(id);
51493                         }
51494                     };
51495                     Console.prototype.removeDirective = function (id) {
51496                         var i = this.directiveIDs.indexOf(id);
51497                         if (i > -1) {
51498                             this.directiveIDs.splice(i, 1);
51499                         }
51500                     };
51501                     Console.prototype.showIDs = function () {
51502                         console.log(this.directiveIDs);
51503                     };
51504                     return Console;
51505                 })();
51506                 services.Console = Console;
51507             })(services = app.services || (app.services = {}));
51508         })(app || (app = {}));
51509         var app;
51510         (function (app) {
51511             var directives;
51512             (function (directives) {
51513                 var Command = (function () {
51514                     function Command() {
51515                         this.restrict = 'E';
51516                         this.replace = true;
51517                         this.scope = true;
51518                         this.controller = 'commandController';
51519                         this.controllerAs = 'ctrl';
51520                         this.bindToController = {
51521                             index: '=',
51522                             name: '=',
51523                             remove: '&',
51524                             list: '='
51525                         };
51526                         this.templateUrl = 'templates/command.html';
51527                     }
51528                     Command.Factory = function () {
51529                         var directive = function () {
51530                             return new Command();
51531                         };
51532                         directive.$inject = [];
51533                         return directive;
51534                     };
51535                     return Command;
51536                 })();
51537                 directives.Command = Command;
51538                 var CommandController = (function () {
51539                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
51540                         this.APIEndPoint = APIEndPoint;
51541                         this.$scope = $scope;
51542                         this.MyModal = MyModal;
51543                         this.WebSocket = WebSocket;
51544                         this.$window = $window;
51545                         this.$rootScope = $rootScope;
51546                         this.Console = Console;
51547                         var controller = this;
51548                         this.APIEndPoint
51549                             .getOptionControlFile(this.name)
51550                             .$promise
51551                             .then(function (result) {
51552                             controller.options = result.info;
51553                         });
51554                         this.APIEndPoint
51555                             .getDirectories()
51556                             .$promise
51557                             .then(function (result) {
51558                             controller.dirs = result.info;
51559                         });
51560                         this.heading = "[" + this.index + "]: dcdFilePrint";
51561                         this.isOpen = true;
51562                         this.$scope.$on('close', function () {
51563                             controller.isOpen = false;
51564                         });
51565                         function guid() {
51566                             function s4() {
51567                                 return Math.floor((1 + Math.random()) * 0x10000)
51568                                     .toString(16)
51569                                     .substring(1);
51570                             }
51571                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
51572                                 s4() + '-' + s4() + s4() + s4();
51573                         }
51574                         this.uuid = guid();
51575                         this.Console.addDirective(this.uuid);
51576                         this.Console.showIDs();
51577                     }
51578                     CommandController.prototype.submit = function () {
51579                         var opt = [];
51580                         angular.forEach(this.options, function (option) {
51581                             var obj = {
51582                                 name: option.option,
51583                                 arguments: []
51584                             };
51585                             angular.forEach(option.arg, function (arg) {
51586                                 if (arg.input) {
51587                                     if (typeof arg.input === 'object') {
51588                                         obj.arguments.push(arg.input.name);
51589                                     }
51590                                     else {
51591                                         obj.arguments.push(arg.input);
51592                                     }
51593                                 }
51594                             });
51595                             if (obj.arguments.length > 0) {
51596                                 opt.push(obj);
51597                             }
51598                         });
51599                         var execObj = {
51600                             command: this.name,
51601                             workspace: this.workspace.fileId,
51602                             options: opt
51603                         };
51604                         this.APIEndPoint
51605                             .execute(JSON.stringify(execObj))
51606                             .then(function (result) {
51607                             console.log(result);
51608                         });
51609                     };
51610                     CommandController.prototype.removeMySelf = function (index) {
51611                         this.$scope.$destroy();
51612                         this.Console.removeDirective(this.uuid);
51613                         this.remove()(index, this.list);
51614                         this.Console.showIDs();
51615                     };
51616                     CommandController.prototype.reloadFiles = function () {
51617                         var _this = this;
51618                         var fileId = this.workspace.fileId;
51619                         this.APIEndPoint
51620                             .getFiles(fileId)
51621                             .$promise
51622                             .then(function (result) {
51623                             var status = result.status;
51624                             if (status === 'success') {
51625                                 _this.files = result.info;
51626                             }
51627                             else {
51628                                 console.log(result.message);
51629                             }
51630                         });
51631                     };
51632                     CommandController.prototype.debug = function () {
51633                         var div = angular.element(this.$window.document).find("div");
51634                         var consoleTag;
51635                         var parametersTag;
51636                         angular.forEach(div, function (v) {
51637                             if (v.className === "panel-body console") {
51638                                 consoleTag = v;
51639                             }
51640                             else if (v.className === "row parameters-console") {
51641                                 parametersTag = v;
51642                             }
51643                         });
51644                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
51645                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
51646                         consoleTag.style.height = consoleHeight;
51647                         consoleTag.style.width = consoleWidth;
51648                     };
51649                     CommandController.prototype.help = function () {
51650                         this.APIEndPoint
51651                             .help(this.name)
51652                             .then(function (result) {
51653                             console.log(result);
51654                         });
51655                     };
51656                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
51657                     return CommandController;
51658                 })();
51659                 directives.CommandController = CommandController;
51660             })(directives = app.directives || (app.directives = {}));
51661         })(app || (app = {}));
51662         var app;
51663         (function (app) {
51664             var directives;
51665             (function (directives) {
51666                 var HeaderMenu = (function () {
51667                     function HeaderMenu() {
51668                         this.restrict = 'E';
51669                         this.replace = true;
51670                         this.templateUrl = 'templates/header-menu.html';
51671                         this.controller = 'HeaderMenuController';
51672                         this.controllerAs = 'hmc';
51673                         this.scope = true;
51674                     }
51675                     HeaderMenu.Factory = function () {
51676                         var directive = function () {
51677                             return new HeaderMenu();
51678                         };
51679                         return directive;
51680                     };
51681                     return HeaderMenu;
51682                 })();
51683                 directives.HeaderMenu = HeaderMenu;
51684                 var HeaderMenuController = (function () {
51685                     function HeaderMenuController($state) {
51686                         this.$state = $state;
51687                         this.isExecution = this.$state.current.name === 'execution';
51688                         this.isWorkspace = this.$state.current.name === 'workspace';
51689                         this.isHistory = this.$state.current.name === 'history';
51690                     }
51691                     HeaderMenuController.prototype.transit = function (state) {
51692                         this.$state.go(state);
51693                     };
51694                     HeaderMenuController.$inject = ['$state'];
51695                     return HeaderMenuController;
51696                 })();
51697                 directives.HeaderMenuController = HeaderMenuController;
51698             })(directives = app.directives || (app.directives = {}));
51699         })(app || (app = {}));
51700         var app;
51701         (function (app) {
51702             var directives;
51703             (function (directives) {
51704                 var Option = (function () {
51705                     function Option() {
51706                         this.restrict = 'E';
51707                         this.replace = true;
51708                         this.controller = 'optionController';
51709                         this.bindToController = {
51710                             info: '=',
51711                             files: '='
51712                         };
51713                         this.scope = true;
51714                         this.templateUrl = 'templates/option.html';
51715                         this.controllerAs = 'ctrl';
51716                     }
51717                     Option.Factory = function () {
51718                         var directive = function () {
51719                             return new Option();
51720                         };
51721                         directive.$inject = [];
51722                         return directive;
51723                     };
51724                     return Option;
51725                 })();
51726                 directives.Option = Option;
51727                 var OptionController = (function () {
51728                     function OptionController() {
51729                         var controller = this;
51730                         angular.forEach(controller.info.arg, function (arg) {
51731                             if (arg.initialValue) {
51732                                 if (arg.formType === 'number') {
51733                                     arg.input = parseInt(arg.initialValue);
51734                                 }
51735                                 else {
51736                                     arg.input = arg.initialValue;
51737                                 }
51738                             }
51739                         });
51740                     }
51741                     OptionController.$inject = [];
51742                     return OptionController;
51743                 })();
51744                 directives.OptionController = OptionController;
51745             })(directives = app.directives || (app.directives = {}));
51746         })(app || (app = {}));
51747         var app;
51748         (function (app) {
51749             var directives;
51750             (function (directives) {
51751                 var Directory = (function () {
51752                     function Directory() {
51753                         this.restrict = 'E';
51754                         this.replace = true;
51755                         this.controller = 'directoryController';
51756                         this.controllerAs = 'ctrl';
51757                         this.bindToController = {
51758                             info: '=',
51759                             add: '&',
51760                             list: '=',
51761                             files: '='
51762                         };
51763                         this.templateUrl = 'templates/directory.html';
51764                     }
51765                     Directory.Factory = function () {
51766                         var directive = function () {
51767                             return new Directory();
51768                         };
51769                         return directive;
51770                     };
51771                     return Directory;
51772                 })();
51773                 directives.Directory = Directory;
51774                 var DirectoryController = (function () {
51775                     function DirectoryController(APIEndPoint, $scope) {
51776                         this.APIEndPoint = APIEndPoint;
51777                         this.$scope = $scope;
51778                         var controller = this;
51779                         this.APIEndPoint
51780                             .getFiles(this.info.fileId)
51781                             .$promise
51782                             .then(function (result) {
51783                             if (result.status === 'success') {
51784                                 controller.files = result.info;
51785                                 angular.forEach(result.info, function (file) {
51786                                     if (file.fileType === '0') {
51787                                         var o = file;
51788                                         if (controller.info.path === '/') {
51789                                             o.path = '/' + file.name;
51790                                         }
51791                                         else {
51792                                             o.path = controller.info.path + '/' + file.name;
51793                                         }
51794                                         controller.add()(o, controller.list);
51795                                     }
51796                                 });
51797                             }
51798                             ;
51799                         });
51800                     }
51801                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
51802                     return DirectoryController;
51803                 })();
51804                 directives.DirectoryController = DirectoryController;
51805             })(directives = app.directives || (app.directives = {}));
51806         })(app || (app = {}));
51807         var app;
51808         (function (app) {
51809             var directives;
51810             (function (directives) {
51811                 var Upload = (function () {
51812                     function Upload() {
51813                         this.restrict = 'E';
51814                         this.replace = true;
51815                         this.scope = true;
51816                         this.controller = 'UploadController';
51817                         this.controllerAs = 'ctrl';
51818                         this.bindToController = {
51819                             index: '=',
51820                             name: '=',
51821                             remove: '&',
51822                             list: '='
51823                         };
51824                         this.templateUrl = 'templates/upload.html';
51825                         console.log("templates/upload.html-constructor");
51826                     }
51827                     Upload.Factory = function () {
51828                         var directive = function () {
51829                             return new Upload();
51830                         };
51831                         directive.$inject = [];
51832                         return directive;
51833                     };
51834                     return Upload;
51835                 })();
51836                 directives.Upload = Upload;
51837                 var UploadController = (function () {
51838                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
51839                         this.APIEndPoint = APIEndPoint;
51840                         this.$scope = $scope;
51841                         this.MyModal = MyModal;
51842                         this.WebSocket = WebSocket;
51843                         this.$window = $window;
51844                         this.$rootScope = $rootScope;
51845                         this.Console = Console;
51846                         var controller = this;
51847                         console.log("directive.upload-constructor");
51848                     }
51849                     UploadController.prototype.submit = function () {
51850                         console.log("submit: function not supported¥n");
51851                     };
51852                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
51853                     return UploadController;
51854                 })();
51855                 directives.UploadController = UploadController;
51856             })(directives = app.directives || (app.directives = {}));
51857         })(app || (app = {}));
51858         var app;
51859         (function (app) {
51860             var controllers;
51861             (function (controllers) {
51862                 var Execution = (function () {
51863                     function Execution(MyModal, $scope) {
51864                         this.MyModal = MyModal;
51865                         this.$scope = $scope;
51866                         this.commandInfoList = [];
51867                     }
51868                     ;
51869                     Execution.prototype.add = function () {
51870                         this.$scope.$broadcast('close');
51871                         var commandInfoList = this.commandInfoList;
51872                         var commandInstance = this.MyModal.selectCommand();
51873                         commandInstance
51874                             .result
51875                             .then(function (command) {
51876                             commandInfoList.push(new app.declares.CommandInfo(command));
51877                         });
51878                     };
51879                     Execution.prototype.open = function () {
51880                         var result = this.MyModal.open('SelectCommand');
51881                         console.log(result);
51882                     };
51883                     Execution.prototype.remove = function (index, list) {
51884                         list.splice(index, 1);
51885                     };
51886                     Execution.prototype.close = function () {
51887                         console.log("close");
51888                     };
51889                     Execution.$inject = ['MyModal', '$scope'];
51890                     return Execution;
51891                 })();
51892                 controllers.Execution = Execution;
51893             })(controllers = app.controllers || (app.controllers = {}));
51894         })(app || (app = {}));
51895         var app;
51896         (function (app) {
51897             var controllers;
51898             (function (controllers) {
51899                 var Workspace = (function () {
51900                     function Workspace($scope, APIEndPoint, MyModal) {
51901                         this.$scope = $scope;
51902                         this.APIEndPoint = APIEndPoint;
51903                         this.MyModal = MyModal;
51904                         this.directoryList = [];
51905                         var controller = this;
51906                         var directoryList = this.directoryList;
51907                         var o = {
51908                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
51909                             name: '',
51910                             parentId: '',
51911                             fileType: '',
51912                             createdAt: '',
51913                             updatedAt: '',
51914                             path: '/'
51915                         };
51916                         directoryList.push(o);
51917                     }
51918                     Workspace.prototype.addDirectory = function (info, directoryList) {
51919                         directoryList.push(info);
51920                     };
51921                     Workspace.prototype.upload = function () {
51922                         this.MyModal.upload();
51923                     };
51924                     Workspace.prototype.debug = function () {
51925                         this.MyModal.preview();
51926                     };
51927                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
51928                     return Workspace;
51929                 })();
51930                 controllers.Workspace = Workspace;
51931             })(controllers = app.controllers || (app.controllers = {}));
51932         })(app || (app = {}));
51933         var app;
51934         (function (app) {
51935             var controllers;
51936             (function (controllers) {
51937                 var History = (function () {
51938                     function History($scope) {
51939                         this.page = "History";
51940                     }
51941                     History.$inject = ['$scope'];
51942                     return History;
51943                 })();
51944                 controllers.History = History;
51945             })(controllers = app.controllers || (app.controllers = {}));
51946         })(app || (app = {}));
51947         var app;
51948         (function (app) {
51949             var controllers;
51950             (function (controllers) {
51951                 var SelectCommand = (function () {
51952                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
51953                         this.APIEndPoint = APIEndPoint;
51954                         this.$modalInstance = $modalInstance;
51955                         var controller = this;
51956                         this.APIEndPoint
51957                             .getTags()
51958                             .$promise.then(function (result) {
51959                             controller.tags = result.info;
51960                         });
51961                         this.APIEndPoint
51962                             .getCommands()
51963                             .$promise.then(function (result) {
51964                             controller.commands = result.info;
51965                         });
51966                         this.currentTag = 'all';
51967                     }
51968                     SelectCommand.prototype.changeTag = function (tag) {
51969                         this.currentTag = tag;
51970                     };
51971                     SelectCommand.prototype.selectCommand = function (command) {
51972                         this.$modalInstance.close(command);
51973                     };
51974                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51975                     return SelectCommand;
51976                 })();
51977                 controllers.SelectCommand = SelectCommand;
51978             })(controllers = app.controllers || (app.controllers = {}));
51979         })(app || (app = {}));
51980         var app;
51981         (function (app) {
51982             var controllers;
51983             (function (controllers) {
51984                 var Upload = (function () {
51985                     function Upload($scope, APIEndPoint, $modalInstance) {
51986                         this.APIEndPoint = APIEndPoint;
51987                         this.$modalInstance = $modalInstance;
51988                         var controller = this;
51989                         console.log('controller.upload-controllers');
51990                     }
51991                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
51992                     return Upload;
51993                 })();
51994                 controllers.Upload = Upload;
51995             })(controllers = app.controllers || (app.controllers = {}));
51996         })(app || (app = {}));
51997         var app;
51998         (function (app) {
51999             var controllers;
52000             (function (controllers) {
52001                 var Preview = (function () {
52002                     function Preview($scope, APIEndPoint, $modalInstance) {
52003                         this.APIEndPoint = APIEndPoint;
52004                         this.$modalInstance = $modalInstance;
52005                         var controller = this;
52006                         console.log('preview');
52007                     }
52008                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
52009                     return Preview;
52010                 })();
52011                 controllers.Preview = Preview;
52012             })(controllers = app.controllers || (app.controllers = {}));
52013         })(app || (app = {}));
52014         var filters;
52015         (function (filters) {
52016             function Tag() {
52017                 return function (commands, tag) {
52018                     var result = [];
52019                     angular.forEach(commands, function (command) {
52020                         var flag = false;
52021                         angular.forEach(command.tags, function (value) {
52022                             if (tag === value)
52023                                 flag = true;
52024                         });
52025                         if (flag)
52026                             result.push(command);
52027                     });
52028                     return result;
52029                 };
52030             }
52031             filters.Tag = Tag;
52032         })(filters || (filters = {}));
52033         var app;
52034         (function (app) {
52035             'use strict';
52036             var appName = 'zephyr';
52037             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
52038             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
52039                 $urlRouterProvider.otherwise('/execution');
52040                 $locationProvider.html5Mode({
52041                     enabled: true,
52042                     requireBase: false
52043                 });
52044                 $stateProvider
52045                     .state('execution', {
52046                     url: '/execution',
52047                     templateUrl: 'templates/execution.html',
52048                     controller: 'executionController',
52049                     controllerAs: 'c'
52050                 })
52051                     .state('workspace', {
52052                     url: '/workspace',
52053                     templateUrl: 'templates/workspace.html',
52054                     controller: 'workspaceController',
52055                     controllerAs: 'c'
52056                 })
52057                     .state('history', {
52058                     url: '/history',
52059                     templateUrl: 'templates/history.html',
52060                     controller: 'historyController',
52061                     controllerAs: 'c'
52062                 });
52063             });
52064             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
52065             app.zephyr.service('MyModal', app.services.MyModal);
52066             app.zephyr.service('WebSocket', app.services.WebSocket);
52067             app.zephyr.service('Console', app.services.Console);
52068             app.zephyr.filter('Tag', filters.Tag);
52069             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
52070             app.zephyr.controller('previewController', app.controllers.Preview);
52071             app.zephyr.controller('uploadController', app.controllers.Upload);
52072             app.zephyr.controller('executionController', app.controllers.Execution);
52073             app.zephyr.controller('workspaceController', app.controllers.Workspace);
52074             app.zephyr.controller('historyController', app.controllers.History);
52075             app.zephyr.controller('commandController', app.directives.CommandController);
52076             app.zephyr.controller('optionController', app.directives.OptionController);
52077             app.zephyr.controller('directoryController', app.directives.DirectoryController);
52078             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
52079             app.zephyr.controller('uploadController', app.directives.UploadController);
52080             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
52081             app.zephyr.directive('command', app.directives.Command.Factory());
52082             app.zephyr.directive('option', app.directives.Option.Factory());
52083             app.zephyr.directive('directory', app.directives.Directory.Factory());
52084         })(app || (app = {}));
52085
52086
52087 /***/ },
52088 /* 21 */
52089 /***/ function(module, exports) {
52090
52091         var app;
52092         (function (app) {
52093             var declares;
52094             (function (declares) {
52095                 var CommandInfo = (function () {
52096                     function CommandInfo(name) {
52097                         this.name = name;
52098                     }
52099                     return CommandInfo;
52100                 })();
52101                 declares.CommandInfo = CommandInfo;
52102             })(declares = app.declares || (app.declares = {}));
52103         })(app || (app = {}));
52104         var app;
52105         (function (app) {
52106             var services;
52107             (function (services) {
52108                 var APIEndPoint = (function () {
52109                     function APIEndPoint($resource, $http) {
52110                         this.$resource = $resource;
52111                         this.$http = $http;
52112                     }
52113                     APIEndPoint.prototype.resource = function (endPoint, data) {
52114                         var customAction = {
52115                             method: 'GET',
52116                             isArray: false
52117                         };
52118                         var execute = {
52119                             method: 'POST',
52120                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
52121                         };
52122                         return this.$resource(endPoint, {}, { execute: execute });
52123                     };
52124                     APIEndPoint.prototype.getOptionControlFile = function (command) {
52125                         var endPoint = '/api/v1/optionControlFile/' + command;
52126                         return this.resource(endPoint, {}).get();
52127                     };
52128                     APIEndPoint.prototype.getFiles = function (fileId) {
52129                         var endPoint = '/api/v1/workspace';
52130                         if (fileId) {
52131                             endPoint += '/' + fileId;
52132                         }
52133                         return this.resource(endPoint, {}).get();
52134                     };
52135                     APIEndPoint.prototype.getDirectories = function () {
52136                         var endPoint = '/api/v1/all/workspace/directory';
52137                         return this.resource(endPoint, {}).get();
52138                     };
52139                     APIEndPoint.prototype.getTags = function () {
52140                         var endPoint = '/api/v1/tagList';
52141                         return this.resource(endPoint, {}).get();
52142                     };
52143                     APIEndPoint.prototype.getCommands = function () {
52144                         var endPoint = '/api/v1/commandList';
52145                         return this.resource(endPoint, {}).get();
52146                     };
52147                     APIEndPoint.prototype.execute = function (data) {
52148                         var endPoint = '/api/v1/execution';
52149                         var fd = new FormData();
52150                         fd.append('data', data);
52151                         return this.$http.post(endPoint, fd, {
52152                             headers: { 'Content-Type': undefined },
52153                             transformRequest: angular.identity
52154                         });
52155                     };
52156                     APIEndPoint.prototype.debug = function () {
52157                         var endPoint = '/api/v1/debug';
52158                         return this.$http.get(endPoint);
52159                     };
52160                     APIEndPoint.prototype.upload = function () {
52161                         var endPoint = '/api/v1/upload';
52162                         return this.$http.get(endPoint);
52163                     };
52164                     APIEndPoint.prototype.help = function (command) {
52165                         var endPoint = '/api/v1/help/' + command;
52166                         return this.$http.get(endPoint);
52167                     };
52168                     return APIEndPoint;
52169                 })();
52170                 services.APIEndPoint = APIEndPoint;
52171             })(services = app.services || (app.services = {}));
52172         })(app || (app = {}));
52173         var app;
52174         (function (app) {
52175             var services;
52176             (function (services) {
52177                 var MyModal = (function () {
52178                     function MyModal($uibModal) {
52179                         this.$uibModal = $uibModal;
52180                         this.modalOption = {
52181                             backdrop: true,
52182                             controller: null,
52183                             templateUrl: null,
52184                             size: null
52185                         };
52186                     }
52187                     MyModal.prototype.open = function (modalName) {
52188                         if (modalName === 'SelectCommand') {
52189                             this.modalOption.templateUrl = 'templates/select-command.html';
52190                             this.modalOption.size = 'lg';
52191                         }
52192                         return this.$uibModal.open(this.modalOption);
52193                     };
52194                     MyModal.prototype.selectCommand = function () {
52195                         this.modalOption.templateUrl = 'templates/select-command.html';
52196                         this.modalOption.controller = 'selectCommandController';
52197                         this.modalOption.controllerAs = 'c';
52198                         this.modalOption.size = 'lg';
52199                         return this.$uibModal.open(this.modalOption);
52200                     };
52201                     MyModal.prototype.preview = function () {
52202                         this.modalOption.templateUrl = 'templates/preview.html';
52203                         this.modalOption.controller = 'previewController';
52204                         this.modalOption.controllerAs = 'c';
52205                         this.modalOption.size = 'lg';
52206                         return this.$uibModal.open(this.modalOption);
52207                     };
52208                     MyModal.prototype.upload = function () {
52209                         this.modalOption.templateUrl = 'templates/upload.html';
52210                         this.modalOption.controller = 'uploadController';
52211                         this.modalOption.controllerAs = 'c';
52212                         this.modalOption.size = 'lg';
52213                         return this.$uibModal.open(this.modalOption);
52214                     };
52215                     MyModal.$inject = ['$uibModal'];
52216                     return MyModal;
52217                 })();
52218                 services.MyModal = MyModal;
52219             })(services = app.services || (app.services = {}));
52220         })(app || (app = {}));
52221         var app;
52222         (function (app) {
52223             var services;
52224             (function (services) {
52225                 var WebSocket = (function () {
52226                     function WebSocket($rootScope) {
52227                         this.$rootScope = $rootScope;
52228                         this.socket = io.connect();
52229                     }
52230                     WebSocket.prototype.on = function (eventName, callback) {
52231                         var socket = this.socket;
52232                         var rootScope = this.$rootScope;
52233                         socket.on(eventName, function () {
52234                             var args = arguments;
52235                             rootScope.$apply(function () {
52236                                 callback.apply(socket, args);
52237                             });
52238                         });
52239                     };
52240                     WebSocket.prototype.emit = function (eventName, data, callback) {
52241                         var socket = this.socket;
52242                         var rootScope = this.$rootScope;
52243                         this.socket.emit(eventName, data, function () {
52244                             var args = arguments;
52245                             rootScope.$apply(function () {
52246                                 if (callback)
52247                                     callback.apply(socket, args);
52248                             });
52249                         });
52250                     };
52251                     return WebSocket;
52252                 })();
52253                 services.WebSocket = WebSocket;
52254             })(services = app.services || (app.services = {}));
52255         })(app || (app = {}));
52256         var app;
52257         (function (app) {
52258             var services;
52259             (function (services) {
52260                 var Console = (function () {
52261                     function Console(WebSocket, $rootScope) {
52262                         this.WebSocket = WebSocket;
52263                         this.$rootScope = $rootScope;
52264                         this.WebSocket = WebSocket;
52265                         this.$rootScope = $rootScope;
52266                         this.directiveIDs = [];
52267                         var directiveIDs = this.directiveIDs;
52268                         this.WebSocket.on('console', function (d) {
52269                             var id = d.id;
52270                             var message = d.message;
52271                             if (directiveIDs.indexOf(id) > -1) {
52272                                 $rootScope.$emit(id, message);
52273                             }
52274                         });
52275                     }
52276                     Console.prototype.addDirective = function (id) {
52277                         if (!(this.directiveIDs.indexOf(id) > -1)) {
52278                             this.directiveIDs.push(id);
52279                         }
52280                     };
52281                     Console.prototype.removeDirective = function (id) {
52282                         var i = this.directiveIDs.indexOf(id);
52283                         if (i > -1) {
52284                             this.directiveIDs.splice(i, 1);
52285                         }
52286                     };
52287                     Console.prototype.showIDs = function () {
52288                         console.log(this.directiveIDs);
52289                     };
52290                     return Console;
52291                 })();
52292                 services.Console = Console;
52293             })(services = app.services || (app.services = {}));
52294         })(app || (app = {}));
52295         var app;
52296         (function (app) {
52297             var directives;
52298             (function (directives) {
52299                 var Command = (function () {
52300                     function Command() {
52301                         this.restrict = 'E';
52302                         this.replace = true;
52303                         this.scope = true;
52304                         this.controller = 'commandController';
52305                         this.controllerAs = 'ctrl';
52306                         this.bindToController = {
52307                             index: '=',
52308                             name: '=',
52309                             remove: '&',
52310                             list: '='
52311                         };
52312                         this.templateUrl = 'templates/command.html';
52313                     }
52314                     Command.Factory = function () {
52315                         var directive = function () {
52316                             return new Command();
52317                         };
52318                         directive.$inject = [];
52319                         return directive;
52320                     };
52321                     return Command;
52322                 })();
52323                 directives.Command = Command;
52324                 var CommandController = (function () {
52325                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
52326                         this.APIEndPoint = APIEndPoint;
52327                         this.$scope = $scope;
52328                         this.MyModal = MyModal;
52329                         this.WebSocket = WebSocket;
52330                         this.$window = $window;
52331                         this.$rootScope = $rootScope;
52332                         this.Console = Console;
52333                         var controller = this;
52334                         this.APIEndPoint
52335                             .getOptionControlFile(this.name)
52336                             .$promise
52337                             .then(function (result) {
52338                             controller.options = result.info;
52339                         });
52340                         this.APIEndPoint
52341                             .getDirectories()
52342                             .$promise
52343                             .then(function (result) {
52344                             controller.dirs = result.info;
52345                         });
52346                         this.heading = "[" + this.index + "]: dcdFilePrint";
52347                         this.isOpen = true;
52348                         this.$scope.$on('close', function () {
52349                             controller.isOpen = false;
52350                         });
52351                         function guid() {
52352                             function s4() {
52353                                 return Math.floor((1 + Math.random()) * 0x10000)
52354                                     .toString(16)
52355                                     .substring(1);
52356                             }
52357                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
52358                                 s4() + '-' + s4() + s4() + s4();
52359                         }
52360                         this.uuid = guid();
52361                         this.Console.addDirective(this.uuid);
52362                         this.Console.showIDs();
52363                     }
52364                     CommandController.prototype.submit = function () {
52365                         var opt = [];
52366                         angular.forEach(this.options, function (option) {
52367                             var obj = {
52368                                 name: option.option,
52369                                 arguments: []
52370                             };
52371                             angular.forEach(option.arg, function (arg) {
52372                                 if (arg.input) {
52373                                     if (typeof arg.input === 'object') {
52374                                         obj.arguments.push(arg.input.name);
52375                                     }
52376                                     else {
52377                                         obj.arguments.push(arg.input);
52378                                     }
52379                                 }
52380                             });
52381                             if (obj.arguments.length > 0) {
52382                                 opt.push(obj);
52383                             }
52384                         });
52385                         var execObj = {
52386                             command: this.name,
52387                             workspace: this.workspace.fileId,
52388                             options: opt
52389                         };
52390                         this.APIEndPoint
52391                             .execute(JSON.stringify(execObj))
52392                             .then(function (result) {
52393                             console.log(result);
52394                         });
52395                     };
52396                     CommandController.prototype.removeMySelf = function (index) {
52397                         this.$scope.$destroy();
52398                         this.Console.removeDirective(this.uuid);
52399                         this.remove()(index, this.list);
52400                         this.Console.showIDs();
52401                     };
52402                     CommandController.prototype.reloadFiles = function () {
52403                         var _this = this;
52404                         var fileId = this.workspace.fileId;
52405                         this.APIEndPoint
52406                             .getFiles(fileId)
52407                             .$promise
52408                             .then(function (result) {
52409                             var status = result.status;
52410                             if (status === 'success') {
52411                                 _this.files = result.info;
52412                             }
52413                             else {
52414                                 console.log(result.message);
52415                             }
52416                         });
52417                     };
52418                     CommandController.prototype.debug = function () {
52419                         var div = angular.element(this.$window.document).find("div");
52420                         var consoleTag;
52421                         var parametersTag;
52422                         angular.forEach(div, function (v) {
52423                             if (v.className === "panel-body console") {
52424                                 consoleTag = v;
52425                             }
52426                             else if (v.className === "row parameters-console") {
52427                                 parametersTag = v;
52428                             }
52429                         });
52430                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
52431                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
52432                         consoleTag.style.height = consoleHeight;
52433                         consoleTag.style.width = consoleWidth;
52434                     };
52435                     CommandController.prototype.help = function () {
52436                         this.APIEndPoint
52437                             .help(this.name)
52438                             .then(function (result) {
52439                             console.log(result);
52440                         });
52441                     };
52442                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
52443                     return CommandController;
52444                 })();
52445                 directives.CommandController = CommandController;
52446             })(directives = app.directives || (app.directives = {}));
52447         })(app || (app = {}));
52448         var app;
52449         (function (app) {
52450             var directives;
52451             (function (directives) {
52452                 var HeaderMenu = (function () {
52453                     function HeaderMenu() {
52454                         this.restrict = 'E';
52455                         this.replace = true;
52456                         this.templateUrl = 'templates/header-menu.html';
52457                         this.controller = 'HeaderMenuController';
52458                         this.controllerAs = 'hmc';
52459                         this.scope = true;
52460                     }
52461                     HeaderMenu.Factory = function () {
52462                         var directive = function () {
52463                             return new HeaderMenu();
52464                         };
52465                         return directive;
52466                     };
52467                     return HeaderMenu;
52468                 })();
52469                 directives.HeaderMenu = HeaderMenu;
52470                 var HeaderMenuController = (function () {
52471                     function HeaderMenuController($state) {
52472                         this.$state = $state;
52473                         this.isExecution = this.$state.current.name === 'execution';
52474                         this.isWorkspace = this.$state.current.name === 'workspace';
52475                         this.isHistory = this.$state.current.name === 'history';
52476                     }
52477                     HeaderMenuController.prototype.transit = function (state) {
52478                         this.$state.go(state);
52479                     };
52480                     HeaderMenuController.$inject = ['$state'];
52481                     return HeaderMenuController;
52482                 })();
52483                 directives.HeaderMenuController = HeaderMenuController;
52484             })(directives = app.directives || (app.directives = {}));
52485         })(app || (app = {}));
52486         var app;
52487         (function (app) {
52488             var directives;
52489             (function (directives) {
52490                 var Option = (function () {
52491                     function Option() {
52492                         this.restrict = 'E';
52493                         this.replace = true;
52494                         this.controller = 'optionController';
52495                         this.bindToController = {
52496                             info: '=',
52497                             files: '='
52498                         };
52499                         this.scope = true;
52500                         this.templateUrl = 'templates/option.html';
52501                         this.controllerAs = 'ctrl';
52502                     }
52503                     Option.Factory = function () {
52504                         var directive = function () {
52505                             return new Option();
52506                         };
52507                         directive.$inject = [];
52508                         return directive;
52509                     };
52510                     return Option;
52511                 })();
52512                 directives.Option = Option;
52513                 var OptionController = (function () {
52514                     function OptionController() {
52515                         var controller = this;
52516                         angular.forEach(controller.info.arg, function (arg) {
52517                             if (arg.initialValue) {
52518                                 if (arg.formType === 'number') {
52519                                     arg.input = parseInt(arg.initialValue);
52520                                 }
52521                                 else {
52522                                     arg.input = arg.initialValue;
52523                                 }
52524                             }
52525                         });
52526                     }
52527                     OptionController.$inject = [];
52528                     return OptionController;
52529                 })();
52530                 directives.OptionController = OptionController;
52531             })(directives = app.directives || (app.directives = {}));
52532         })(app || (app = {}));
52533         var app;
52534         (function (app) {
52535             var directives;
52536             (function (directives) {
52537                 var Directory = (function () {
52538                     function Directory() {
52539                         this.restrict = 'E';
52540                         this.replace = true;
52541                         this.controller = 'directoryController';
52542                         this.controllerAs = 'ctrl';
52543                         this.bindToController = {
52544                             info: '=',
52545                             add: '&',
52546                             list: '=',
52547                             files: '='
52548                         };
52549                         this.templateUrl = 'templates/directory.html';
52550                     }
52551                     Directory.Factory = function () {
52552                         var directive = function () {
52553                             return new Directory();
52554                         };
52555                         return directive;
52556                     };
52557                     return Directory;
52558                 })();
52559                 directives.Directory = Directory;
52560                 var DirectoryController = (function () {
52561                     function DirectoryController(APIEndPoint, $scope) {
52562                         this.APIEndPoint = APIEndPoint;
52563                         this.$scope = $scope;
52564                         var controller = this;
52565                         this.APIEndPoint
52566                             .getFiles(this.info.fileId)
52567                             .$promise
52568                             .then(function (result) {
52569                             if (result.status === 'success') {
52570                                 controller.files = result.info;
52571                                 angular.forEach(result.info, function (file) {
52572                                     if (file.fileType === '0') {
52573                                         var o = file;
52574                                         if (controller.info.path === '/') {
52575                                             o.path = '/' + file.name;
52576                                         }
52577                                         else {
52578                                             o.path = controller.info.path + '/' + file.name;
52579                                         }
52580                                         controller.add()(o, controller.list);
52581                                     }
52582                                 });
52583                             }
52584                             ;
52585                         });
52586                     }
52587                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
52588                     return DirectoryController;
52589                 })();
52590                 directives.DirectoryController = DirectoryController;
52591             })(directives = app.directives || (app.directives = {}));
52592         })(app || (app = {}));
52593         var app;
52594         (function (app) {
52595             var directives;
52596             (function (directives) {
52597                 var Upload = (function () {
52598                     function Upload() {
52599                         this.restrict = 'E';
52600                         this.replace = true;
52601                         this.scope = true;
52602                         this.controller = 'UploadController';
52603                         this.controllerAs = 'ctrl';
52604                         this.bindToController = {
52605                             index: '=',
52606                             name: '=',
52607                             remove: '&',
52608                             list: '='
52609                         };
52610                         this.templateUrl = 'templates/upload.html';
52611                         console.log("templates/upload.html-constructor");
52612                     }
52613                     Upload.Factory = function () {
52614                         var directive = function () {
52615                             return new Upload();
52616                         };
52617                         directive.$inject = [];
52618                         return directive;
52619                     };
52620                     return Upload;
52621                 })();
52622                 directives.Upload = Upload;
52623                 var UploadController = (function () {
52624                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
52625                         this.APIEndPoint = APIEndPoint;
52626                         this.$scope = $scope;
52627                         this.MyModal = MyModal;
52628                         this.WebSocket = WebSocket;
52629                         this.$window = $window;
52630                         this.$rootScope = $rootScope;
52631                         this.Console = Console;
52632                         var controller = this;
52633                         console.log("directive.upload-constructor");
52634                     }
52635                     UploadController.prototype.submit = function () {
52636                         console.log("submit: function not supported¥n");
52637                     };
52638                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
52639                     return UploadController;
52640                 })();
52641                 directives.UploadController = UploadController;
52642             })(directives = app.directives || (app.directives = {}));
52643         })(app || (app = {}));
52644         var app;
52645         (function (app) {
52646             var controllers;
52647             (function (controllers) {
52648                 var Execution = (function () {
52649                     function Execution(MyModal, $scope) {
52650                         this.MyModal = MyModal;
52651                         this.$scope = $scope;
52652                         this.commandInfoList = [];
52653                     }
52654                     ;
52655                     Execution.prototype.add = function () {
52656                         this.$scope.$broadcast('close');
52657                         var commandInfoList = this.commandInfoList;
52658                         var commandInstance = this.MyModal.selectCommand();
52659                         commandInstance
52660                             .result
52661                             .then(function (command) {
52662                             commandInfoList.push(new app.declares.CommandInfo(command));
52663                         });
52664                     };
52665                     Execution.prototype.open = function () {
52666                         var result = this.MyModal.open('SelectCommand');
52667                         console.log(result);
52668                     };
52669                     Execution.prototype.remove = function (index, list) {
52670                         list.splice(index, 1);
52671                     };
52672                     Execution.prototype.close = function () {
52673                         console.log("close");
52674                     };
52675                     Execution.$inject = ['MyModal', '$scope'];
52676                     return Execution;
52677                 })();
52678                 controllers.Execution = Execution;
52679             })(controllers = app.controllers || (app.controllers = {}));
52680         })(app || (app = {}));
52681         var app;
52682         (function (app) {
52683             var controllers;
52684             (function (controllers) {
52685                 var Workspace = (function () {
52686                     function Workspace($scope, APIEndPoint, MyModal) {
52687                         this.$scope = $scope;
52688                         this.APIEndPoint = APIEndPoint;
52689                         this.MyModal = MyModal;
52690                         this.directoryList = [];
52691                         var controller = this;
52692                         var directoryList = this.directoryList;
52693                         var o = {
52694                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
52695                             name: '',
52696                             parentId: '',
52697                             fileType: '',
52698                             createdAt: '',
52699                             updatedAt: '',
52700                             path: '/'
52701                         };
52702                         directoryList.push(o);
52703                     }
52704                     Workspace.prototype.addDirectory = function (info, directoryList) {
52705                         directoryList.push(info);
52706                     };
52707                     Workspace.prototype.upload = function () {
52708                         this.MyModal.upload();
52709                     };
52710                     Workspace.prototype.debug = function () {
52711                         this.MyModal.preview();
52712                     };
52713                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
52714                     return Workspace;
52715                 })();
52716                 controllers.Workspace = Workspace;
52717             })(controllers = app.controllers || (app.controllers = {}));
52718         })(app || (app = {}));
52719         var app;
52720         (function (app) {
52721             var controllers;
52722             (function (controllers) {
52723                 var History = (function () {
52724                     function History($scope) {
52725                         this.page = "History";
52726                     }
52727                     History.$inject = ['$scope'];
52728                     return History;
52729                 })();
52730                 controllers.History = History;
52731             })(controllers = app.controllers || (app.controllers = {}));
52732         })(app || (app = {}));
52733         var app;
52734         (function (app) {
52735             var controllers;
52736             (function (controllers) {
52737                 var SelectCommand = (function () {
52738                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
52739                         this.APIEndPoint = APIEndPoint;
52740                         this.$modalInstance = $modalInstance;
52741                         var controller = this;
52742                         this.APIEndPoint
52743                             .getTags()
52744                             .$promise.then(function (result) {
52745                             controller.tags = result.info;
52746                         });
52747                         this.APIEndPoint
52748                             .getCommands()
52749                             .$promise.then(function (result) {
52750                             controller.commands = result.info;
52751                         });
52752                         this.currentTag = 'all';
52753                     }
52754                     SelectCommand.prototype.changeTag = function (tag) {
52755                         this.currentTag = tag;
52756                     };
52757                     SelectCommand.prototype.selectCommand = function (command) {
52758                         this.$modalInstance.close(command);
52759                     };
52760                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
52761                     return SelectCommand;
52762                 })();
52763                 controllers.SelectCommand = SelectCommand;
52764             })(controllers = app.controllers || (app.controllers = {}));
52765         })(app || (app = {}));
52766         var app;
52767         (function (app) {
52768             var controllers;
52769             (function (controllers) {
52770                 var Upload = (function () {
52771                     function Upload($scope, APIEndPoint, $modalInstance) {
52772                         this.APIEndPoint = APIEndPoint;
52773                         this.$modalInstance = $modalInstance;
52774                         var controller = this;
52775                         console.log('controller.upload-controllers');
52776                     }
52777                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
52778                     return Upload;
52779                 })();
52780                 controllers.Upload = Upload;
52781             })(controllers = app.controllers || (app.controllers = {}));
52782         })(app || (app = {}));
52783         var app;
52784         (function (app) {
52785             var controllers;
52786             (function (controllers) {
52787                 var Preview = (function () {
52788                     function Preview($scope, APIEndPoint, $modalInstance) {
52789                         this.APIEndPoint = APIEndPoint;
52790                         this.$modalInstance = $modalInstance;
52791                         var controller = this;
52792                         console.log('preview');
52793                     }
52794                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
52795                     return Preview;
52796                 })();
52797                 controllers.Preview = Preview;
52798             })(controllers = app.controllers || (app.controllers = {}));
52799         })(app || (app = {}));
52800         var filters;
52801         (function (filters) {
52802             function Tag() {
52803                 return function (commands, tag) {
52804                     var result = [];
52805                     angular.forEach(commands, function (command) {
52806                         var flag = false;
52807                         angular.forEach(command.tags, function (value) {
52808                             if (tag === value)
52809                                 flag = true;
52810                         });
52811                         if (flag)
52812                             result.push(command);
52813                     });
52814                     return result;
52815                 };
52816             }
52817             filters.Tag = Tag;
52818         })(filters || (filters = {}));
52819         var app;
52820         (function (app) {
52821             'use strict';
52822             var appName = 'zephyr';
52823             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
52824             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
52825                 $urlRouterProvider.otherwise('/execution');
52826                 $locationProvider.html5Mode({
52827                     enabled: true,
52828                     requireBase: false
52829                 });
52830                 $stateProvider
52831                     .state('execution', {
52832                     url: '/execution',
52833                     templateUrl: 'templates/execution.html',
52834                     controller: 'executionController',
52835                     controllerAs: 'c'
52836                 })
52837                     .state('workspace', {
52838                     url: '/workspace',
52839                     templateUrl: 'templates/workspace.html',
52840                     controller: 'workspaceController',
52841                     controllerAs: 'c'
52842                 })
52843                     .state('history', {
52844                     url: '/history',
52845                     templateUrl: 'templates/history.html',
52846                     controller: 'historyController',
52847                     controllerAs: 'c'
52848                 });
52849             });
52850             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
52851             app.zephyr.service('MyModal', app.services.MyModal);
52852             app.zephyr.service('WebSocket', app.services.WebSocket);
52853             app.zephyr.service('Console', app.services.Console);
52854             app.zephyr.filter('Tag', filters.Tag);
52855             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
52856             app.zephyr.controller('previewController', app.controllers.Preview);
52857             app.zephyr.controller('uploadController', app.controllers.Upload);
52858             app.zephyr.controller('executionController', app.controllers.Execution);
52859             app.zephyr.controller('workspaceController', app.controllers.Workspace);
52860             app.zephyr.controller('historyController', app.controllers.History);
52861             app.zephyr.controller('commandController', app.directives.CommandController);
52862             app.zephyr.controller('optionController', app.directives.OptionController);
52863             app.zephyr.controller('directoryController', app.directives.DirectoryController);
52864             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
52865             app.zephyr.controller('uploadController', app.directives.UploadController);
52866             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
52867             app.zephyr.directive('command', app.directives.Command.Factory());
52868             app.zephyr.directive('option', app.directives.Option.Factory());
52869             app.zephyr.directive('directory', app.directives.Directory.Factory());
52870         })(app || (app = {}));
52871
52872
52873 /***/ },
52874 /* 22 */
52875 /***/ function(module, exports) {
52876
52877         var app;
52878         (function (app) {
52879             var declares;
52880             (function (declares) {
52881                 var CommandInfo = (function () {
52882                     function CommandInfo(name) {
52883                         this.name = name;
52884                     }
52885                     return CommandInfo;
52886                 })();
52887                 declares.CommandInfo = CommandInfo;
52888             })(declares = app.declares || (app.declares = {}));
52889         })(app || (app = {}));
52890         var app;
52891         (function (app) {
52892             var services;
52893             (function (services) {
52894                 var APIEndPoint = (function () {
52895                     function APIEndPoint($resource, $http) {
52896                         this.$resource = $resource;
52897                         this.$http = $http;
52898                     }
52899                     APIEndPoint.prototype.resource = function (endPoint, data) {
52900                         var customAction = {
52901                             method: 'GET',
52902                             isArray: false
52903                         };
52904                         var execute = {
52905                             method: 'POST',
52906                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
52907                         };
52908                         return this.$resource(endPoint, {}, { execute: execute });
52909                     };
52910                     APIEndPoint.prototype.getOptionControlFile = function (command) {
52911                         var endPoint = '/api/v1/optionControlFile/' + command;
52912                         return this.resource(endPoint, {}).get();
52913                     };
52914                     APIEndPoint.prototype.getFiles = function (fileId) {
52915                         var endPoint = '/api/v1/workspace';
52916                         if (fileId) {
52917                             endPoint += '/' + fileId;
52918                         }
52919                         return this.resource(endPoint, {}).get();
52920                     };
52921                     APIEndPoint.prototype.getDirectories = function () {
52922                         var endPoint = '/api/v1/all/workspace/directory';
52923                         return this.resource(endPoint, {}).get();
52924                     };
52925                     APIEndPoint.prototype.getTags = function () {
52926                         var endPoint = '/api/v1/tagList';
52927                         return this.resource(endPoint, {}).get();
52928                     };
52929                     APIEndPoint.prototype.getCommands = function () {
52930                         var endPoint = '/api/v1/commandList';
52931                         return this.resource(endPoint, {}).get();
52932                     };
52933                     APIEndPoint.prototype.execute = function (data) {
52934                         var endPoint = '/api/v1/execution';
52935                         var fd = new FormData();
52936                         fd.append('data', data);
52937                         return this.$http.post(endPoint, fd, {
52938                             headers: { 'Content-Type': undefined },
52939                             transformRequest: angular.identity
52940                         });
52941                     };
52942                     APIEndPoint.prototype.debug = function () {
52943                         var endPoint = '/api/v1/debug';
52944                         return this.$http.get(endPoint);
52945                     };
52946                     APIEndPoint.prototype.upload = function () {
52947                         var endPoint = '/api/v1/upload';
52948                         return this.$http.get(endPoint);
52949                     };
52950                     APIEndPoint.prototype.help = function (command) {
52951                         var endPoint = '/api/v1/help/' + command;
52952                         return this.$http.get(endPoint);
52953                     };
52954                     return APIEndPoint;
52955                 })();
52956                 services.APIEndPoint = APIEndPoint;
52957             })(services = app.services || (app.services = {}));
52958         })(app || (app = {}));
52959         var app;
52960         (function (app) {
52961             var services;
52962             (function (services) {
52963                 var MyModal = (function () {
52964                     function MyModal($uibModal) {
52965                         this.$uibModal = $uibModal;
52966                         this.modalOption = {
52967                             backdrop: true,
52968                             controller: null,
52969                             templateUrl: null,
52970                             size: null
52971                         };
52972                     }
52973                     MyModal.prototype.open = function (modalName) {
52974                         if (modalName === 'SelectCommand') {
52975                             this.modalOption.templateUrl = 'templates/select-command.html';
52976                             this.modalOption.size = 'lg';
52977                         }
52978                         return this.$uibModal.open(this.modalOption);
52979                     };
52980                     MyModal.prototype.selectCommand = function () {
52981                         this.modalOption.templateUrl = 'templates/select-command.html';
52982                         this.modalOption.controller = 'selectCommandController';
52983                         this.modalOption.controllerAs = 'c';
52984                         this.modalOption.size = 'lg';
52985                         return this.$uibModal.open(this.modalOption);
52986                     };
52987                     MyModal.prototype.preview = function () {
52988                         this.modalOption.templateUrl = 'templates/preview.html';
52989                         this.modalOption.controller = 'previewController';
52990                         this.modalOption.controllerAs = 'c';
52991                         this.modalOption.size = 'lg';
52992                         return this.$uibModal.open(this.modalOption);
52993                     };
52994                     MyModal.prototype.upload = function () {
52995                         this.modalOption.templateUrl = 'templates/upload.html';
52996                         this.modalOption.controller = 'uploadController';
52997                         this.modalOption.controllerAs = 'c';
52998                         this.modalOption.size = 'lg';
52999                         return this.$uibModal.open(this.modalOption);
53000                     };
53001                     MyModal.$inject = ['$uibModal'];
53002                     return MyModal;
53003                 })();
53004                 services.MyModal = MyModal;
53005             })(services = app.services || (app.services = {}));
53006         })(app || (app = {}));
53007         var app;
53008         (function (app) {
53009             var services;
53010             (function (services) {
53011                 var WebSocket = (function () {
53012                     function WebSocket($rootScope) {
53013                         this.$rootScope = $rootScope;
53014                         this.socket = io.connect();
53015                     }
53016                     WebSocket.prototype.on = function (eventName, callback) {
53017                         var socket = this.socket;
53018                         var rootScope = this.$rootScope;
53019                         socket.on(eventName, function () {
53020                             var args = arguments;
53021                             rootScope.$apply(function () {
53022                                 callback.apply(socket, args);
53023                             });
53024                         });
53025                     };
53026                     WebSocket.prototype.emit = function (eventName, data, callback) {
53027                         var socket = this.socket;
53028                         var rootScope = this.$rootScope;
53029                         this.socket.emit(eventName, data, function () {
53030                             var args = arguments;
53031                             rootScope.$apply(function () {
53032                                 if (callback)
53033                                     callback.apply(socket, args);
53034                             });
53035                         });
53036                     };
53037                     return WebSocket;
53038                 })();
53039                 services.WebSocket = WebSocket;
53040             })(services = app.services || (app.services = {}));
53041         })(app || (app = {}));
53042         var app;
53043         (function (app) {
53044             var services;
53045             (function (services) {
53046                 var Console = (function () {
53047                     function Console(WebSocket, $rootScope) {
53048                         this.WebSocket = WebSocket;
53049                         this.$rootScope = $rootScope;
53050                         this.WebSocket = WebSocket;
53051                         this.$rootScope = $rootScope;
53052                         this.directiveIDs = [];
53053                         var directiveIDs = this.directiveIDs;
53054                         this.WebSocket.on('console', function (d) {
53055                             var id = d.id;
53056                             var message = d.message;
53057                             if (directiveIDs.indexOf(id) > -1) {
53058                                 $rootScope.$emit(id, message);
53059                             }
53060                         });
53061                     }
53062                     Console.prototype.addDirective = function (id) {
53063                         if (!(this.directiveIDs.indexOf(id) > -1)) {
53064                             this.directiveIDs.push(id);
53065                         }
53066                     };
53067                     Console.prototype.removeDirective = function (id) {
53068                         var i = this.directiveIDs.indexOf(id);
53069                         if (i > -1) {
53070                             this.directiveIDs.splice(i, 1);
53071                         }
53072                     };
53073                     Console.prototype.showIDs = function () {
53074                         console.log(this.directiveIDs);
53075                     };
53076                     return Console;
53077                 })();
53078                 services.Console = Console;
53079             })(services = app.services || (app.services = {}));
53080         })(app || (app = {}));
53081         var app;
53082         (function (app) {
53083             var directives;
53084             (function (directives) {
53085                 var Command = (function () {
53086                     function Command() {
53087                         this.restrict = 'E';
53088                         this.replace = true;
53089                         this.scope = true;
53090                         this.controller = 'commandController';
53091                         this.controllerAs = 'ctrl';
53092                         this.bindToController = {
53093                             index: '=',
53094                             name: '=',
53095                             remove: '&',
53096                             list: '='
53097                         };
53098                         this.templateUrl = 'templates/command.html';
53099                     }
53100                     Command.Factory = function () {
53101                         var directive = function () {
53102                             return new Command();
53103                         };
53104                         directive.$inject = [];
53105                         return directive;
53106                     };
53107                     return Command;
53108                 })();
53109                 directives.Command = Command;
53110                 var CommandController = (function () {
53111                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
53112                         this.APIEndPoint = APIEndPoint;
53113                         this.$scope = $scope;
53114                         this.MyModal = MyModal;
53115                         this.WebSocket = WebSocket;
53116                         this.$window = $window;
53117                         this.$rootScope = $rootScope;
53118                         this.Console = Console;
53119                         var controller = this;
53120                         this.APIEndPoint
53121                             .getOptionControlFile(this.name)
53122                             .$promise
53123                             .then(function (result) {
53124                             controller.options = result.info;
53125                         });
53126                         this.APIEndPoint
53127                             .getDirectories()
53128                             .$promise
53129                             .then(function (result) {
53130                             controller.dirs = result.info;
53131                         });
53132                         this.heading = "[" + this.index + "]: dcdFilePrint";
53133                         this.isOpen = true;
53134                         this.$scope.$on('close', function () {
53135                             controller.isOpen = false;
53136                         });
53137                         function guid() {
53138                             function s4() {
53139                                 return Math.floor((1 + Math.random()) * 0x10000)
53140                                     .toString(16)
53141                                     .substring(1);
53142                             }
53143                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
53144                                 s4() + '-' + s4() + s4() + s4();
53145                         }
53146                         this.uuid = guid();
53147                         this.Console.addDirective(this.uuid);
53148                         this.Console.showIDs();
53149                     }
53150                     CommandController.prototype.submit = function () {
53151                         var opt = [];
53152                         angular.forEach(this.options, function (option) {
53153                             var obj = {
53154                                 name: option.option,
53155                                 arguments: []
53156                             };
53157                             angular.forEach(option.arg, function (arg) {
53158                                 if (arg.input) {
53159                                     if (typeof arg.input === 'object') {
53160                                         obj.arguments.push(arg.input.name);
53161                                     }
53162                                     else {
53163                                         obj.arguments.push(arg.input);
53164                                     }
53165                                 }
53166                             });
53167                             if (obj.arguments.length > 0) {
53168                                 opt.push(obj);
53169                             }
53170                         });
53171                         var execObj = {
53172                             command: this.name,
53173                             workspace: this.workspace.fileId,
53174                             options: opt
53175                         };
53176                         this.APIEndPoint
53177                             .execute(JSON.stringify(execObj))
53178                             .then(function (result) {
53179                             console.log(result);
53180                         });
53181                     };
53182                     CommandController.prototype.removeMySelf = function (index) {
53183                         this.$scope.$destroy();
53184                         this.Console.removeDirective(this.uuid);
53185                         this.remove()(index, this.list);
53186                         this.Console.showIDs();
53187                     };
53188                     CommandController.prototype.reloadFiles = function () {
53189                         var _this = this;
53190                         var fileId = this.workspace.fileId;
53191                         this.APIEndPoint
53192                             .getFiles(fileId)
53193                             .$promise
53194                             .then(function (result) {
53195                             var status = result.status;
53196                             if (status === 'success') {
53197                                 _this.files = result.info;
53198                             }
53199                             else {
53200                                 console.log(result.message);
53201                             }
53202                         });
53203                     };
53204                     CommandController.prototype.debug = function () {
53205                         var div = angular.element(this.$window.document).find("div");
53206                         var consoleTag;
53207                         var parametersTag;
53208                         angular.forEach(div, function (v) {
53209                             if (v.className === "panel-body console") {
53210                                 consoleTag = v;
53211                             }
53212                             else if (v.className === "row parameters-console") {
53213                                 parametersTag = v;
53214                             }
53215                         });
53216                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
53217                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
53218                         consoleTag.style.height = consoleHeight;
53219                         consoleTag.style.width = consoleWidth;
53220                     };
53221                     CommandController.prototype.help = function () {
53222                         this.APIEndPoint
53223                             .help(this.name)
53224                             .then(function (result) {
53225                             console.log(result);
53226                         });
53227                     };
53228                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
53229                     return CommandController;
53230                 })();
53231                 directives.CommandController = CommandController;
53232             })(directives = app.directives || (app.directives = {}));
53233         })(app || (app = {}));
53234         var app;
53235         (function (app) {
53236             var directives;
53237             (function (directives) {
53238                 var HeaderMenu = (function () {
53239                     function HeaderMenu() {
53240                         this.restrict = 'E';
53241                         this.replace = true;
53242                         this.templateUrl = 'templates/header-menu.html';
53243                         this.controller = 'HeaderMenuController';
53244                         this.controllerAs = 'hmc';
53245                         this.scope = true;
53246                     }
53247                     HeaderMenu.Factory = function () {
53248                         var directive = function () {
53249                             return new HeaderMenu();
53250                         };
53251                         return directive;
53252                     };
53253                     return HeaderMenu;
53254                 })();
53255                 directives.HeaderMenu = HeaderMenu;
53256                 var HeaderMenuController = (function () {
53257                     function HeaderMenuController($state) {
53258                         this.$state = $state;
53259                         this.isExecution = this.$state.current.name === 'execution';
53260                         this.isWorkspace = this.$state.current.name === 'workspace';
53261                         this.isHistory = this.$state.current.name === 'history';
53262                     }
53263                     HeaderMenuController.prototype.transit = function (state) {
53264                         this.$state.go(state);
53265                     };
53266                     HeaderMenuController.$inject = ['$state'];
53267                     return HeaderMenuController;
53268                 })();
53269                 directives.HeaderMenuController = HeaderMenuController;
53270             })(directives = app.directives || (app.directives = {}));
53271         })(app || (app = {}));
53272         var app;
53273         (function (app) {
53274             var directives;
53275             (function (directives) {
53276                 var Option = (function () {
53277                     function Option() {
53278                         this.restrict = 'E';
53279                         this.replace = true;
53280                         this.controller = 'optionController';
53281                         this.bindToController = {
53282                             info: '=',
53283                             files: '='
53284                         };
53285                         this.scope = true;
53286                         this.templateUrl = 'templates/option.html';
53287                         this.controllerAs = 'ctrl';
53288                     }
53289                     Option.Factory = function () {
53290                         var directive = function () {
53291                             return new Option();
53292                         };
53293                         directive.$inject = [];
53294                         return directive;
53295                     };
53296                     return Option;
53297                 })();
53298                 directives.Option = Option;
53299                 var OptionController = (function () {
53300                     function OptionController() {
53301                         var controller = this;
53302                         angular.forEach(controller.info.arg, function (arg) {
53303                             if (arg.initialValue) {
53304                                 if (arg.formType === 'number') {
53305                                     arg.input = parseInt(arg.initialValue);
53306                                 }
53307                                 else {
53308                                     arg.input = arg.initialValue;
53309                                 }
53310                             }
53311                         });
53312                     }
53313                     OptionController.$inject = [];
53314                     return OptionController;
53315                 })();
53316                 directives.OptionController = OptionController;
53317             })(directives = app.directives || (app.directives = {}));
53318         })(app || (app = {}));
53319         var app;
53320         (function (app) {
53321             var directives;
53322             (function (directives) {
53323                 var Directory = (function () {
53324                     function Directory() {
53325                         this.restrict = 'E';
53326                         this.replace = true;
53327                         this.controller = 'directoryController';
53328                         this.controllerAs = 'ctrl';
53329                         this.bindToController = {
53330                             info: '=',
53331                             add: '&',
53332                             list: '=',
53333                             files: '='
53334                         };
53335                         this.templateUrl = 'templates/directory.html';
53336                     }
53337                     Directory.Factory = function () {
53338                         var directive = function () {
53339                             return new Directory();
53340                         };
53341                         return directive;
53342                     };
53343                     return Directory;
53344                 })();
53345                 directives.Directory = Directory;
53346                 var DirectoryController = (function () {
53347                     function DirectoryController(APIEndPoint, $scope) {
53348                         this.APIEndPoint = APIEndPoint;
53349                         this.$scope = $scope;
53350                         var controller = this;
53351                         this.APIEndPoint
53352                             .getFiles(this.info.fileId)
53353                             .$promise
53354                             .then(function (result) {
53355                             if (result.status === 'success') {
53356                                 controller.files = result.info;
53357                                 angular.forEach(result.info, function (file) {
53358                                     if (file.fileType === '0') {
53359                                         var o = file;
53360                                         if (controller.info.path === '/') {
53361                                             o.path = '/' + file.name;
53362                                         }
53363                                         else {
53364                                             o.path = controller.info.path + '/' + file.name;
53365                                         }
53366                                         controller.add()(o, controller.list);
53367                                     }
53368                                 });
53369                             }
53370                             ;
53371                         });
53372                     }
53373                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
53374                     return DirectoryController;
53375                 })();
53376                 directives.DirectoryController = DirectoryController;
53377             })(directives = app.directives || (app.directives = {}));
53378         })(app || (app = {}));
53379         var app;
53380         (function (app) {
53381             var directives;
53382             (function (directives) {
53383                 var Upload = (function () {
53384                     function Upload() {
53385                         this.restrict = 'E';
53386                         this.replace = true;
53387                         this.scope = true;
53388                         this.controller = 'UploadController';
53389                         this.controllerAs = 'ctrl';
53390                         this.bindToController = {
53391                             index: '=',
53392                             name: '=',
53393                             remove: '&',
53394                             list: '='
53395                         };
53396                         this.templateUrl = 'templates/upload.html';
53397                         console.log("templates/upload.html-constructor");
53398                     }
53399                     Upload.Factory = function () {
53400                         var directive = function () {
53401                             return new Upload();
53402                         };
53403                         directive.$inject = [];
53404                         return directive;
53405                     };
53406                     return Upload;
53407                 })();
53408                 directives.Upload = Upload;
53409                 var UploadController = (function () {
53410                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
53411                         this.APIEndPoint = APIEndPoint;
53412                         this.$scope = $scope;
53413                         this.MyModal = MyModal;
53414                         this.WebSocket = WebSocket;
53415                         this.$window = $window;
53416                         this.$rootScope = $rootScope;
53417                         this.Console = Console;
53418                         var controller = this;
53419                         console.log("directive.upload-constructor");
53420                     }
53421                     UploadController.prototype.submit = function () {
53422                         console.log("submit: function not supported¥n");
53423                     };
53424                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
53425                     return UploadController;
53426                 })();
53427                 directives.UploadController = UploadController;
53428             })(directives = app.directives || (app.directives = {}));
53429         })(app || (app = {}));
53430         var app;
53431         (function (app) {
53432             var controllers;
53433             (function (controllers) {
53434                 var Execution = (function () {
53435                     function Execution(MyModal, $scope) {
53436                         this.MyModal = MyModal;
53437                         this.$scope = $scope;
53438                         this.commandInfoList = [];
53439                     }
53440                     ;
53441                     Execution.prototype.add = function () {
53442                         this.$scope.$broadcast('close');
53443                         var commandInfoList = this.commandInfoList;
53444                         var commandInstance = this.MyModal.selectCommand();
53445                         commandInstance
53446                             .result
53447                             .then(function (command) {
53448                             commandInfoList.push(new app.declares.CommandInfo(command));
53449                         });
53450                     };
53451                     Execution.prototype.open = function () {
53452                         var result = this.MyModal.open('SelectCommand');
53453                         console.log(result);
53454                     };
53455                     Execution.prototype.remove = function (index, list) {
53456                         list.splice(index, 1);
53457                     };
53458                     Execution.prototype.close = function () {
53459                         console.log("close");
53460                     };
53461                     Execution.$inject = ['MyModal', '$scope'];
53462                     return Execution;
53463                 })();
53464                 controllers.Execution = Execution;
53465             })(controllers = app.controllers || (app.controllers = {}));
53466         })(app || (app = {}));
53467         var app;
53468         (function (app) {
53469             var controllers;
53470             (function (controllers) {
53471                 var Workspace = (function () {
53472                     function Workspace($scope, APIEndPoint, MyModal) {
53473                         this.$scope = $scope;
53474                         this.APIEndPoint = APIEndPoint;
53475                         this.MyModal = MyModal;
53476                         this.directoryList = [];
53477                         var controller = this;
53478                         var directoryList = this.directoryList;
53479                         var o = {
53480                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
53481                             name: '',
53482                             parentId: '',
53483                             fileType: '',
53484                             createdAt: '',
53485                             updatedAt: '',
53486                             path: '/'
53487                         };
53488                         directoryList.push(o);
53489                     }
53490                     Workspace.prototype.addDirectory = function (info, directoryList) {
53491                         directoryList.push(info);
53492                     };
53493                     Workspace.prototype.upload = function () {
53494                         this.MyModal.upload();
53495                     };
53496                     Workspace.prototype.debug = function () {
53497                         this.MyModal.preview();
53498                     };
53499                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
53500                     return Workspace;
53501                 })();
53502                 controllers.Workspace = Workspace;
53503             })(controllers = app.controllers || (app.controllers = {}));
53504         })(app || (app = {}));
53505         var app;
53506         (function (app) {
53507             var controllers;
53508             (function (controllers) {
53509                 var History = (function () {
53510                     function History($scope) {
53511                         this.page = "History";
53512                     }
53513                     History.$inject = ['$scope'];
53514                     return History;
53515                 })();
53516                 controllers.History = History;
53517             })(controllers = app.controllers || (app.controllers = {}));
53518         })(app || (app = {}));
53519         var app;
53520         (function (app) {
53521             var controllers;
53522             (function (controllers) {
53523                 var SelectCommand = (function () {
53524                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
53525                         this.APIEndPoint = APIEndPoint;
53526                         this.$modalInstance = $modalInstance;
53527                         var controller = this;
53528                         this.APIEndPoint
53529                             .getTags()
53530                             .$promise.then(function (result) {
53531                             controller.tags = result.info;
53532                         });
53533                         this.APIEndPoint
53534                             .getCommands()
53535                             .$promise.then(function (result) {
53536                             controller.commands = result.info;
53537                         });
53538                         this.currentTag = 'all';
53539                     }
53540                     SelectCommand.prototype.changeTag = function (tag) {
53541                         this.currentTag = tag;
53542                     };
53543                     SelectCommand.prototype.selectCommand = function (command) {
53544                         this.$modalInstance.close(command);
53545                     };
53546                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
53547                     return SelectCommand;
53548                 })();
53549                 controllers.SelectCommand = SelectCommand;
53550             })(controllers = app.controllers || (app.controllers = {}));
53551         })(app || (app = {}));
53552         var app;
53553         (function (app) {
53554             var controllers;
53555             (function (controllers) {
53556                 var Upload = (function () {
53557                     function Upload($scope, APIEndPoint, $modalInstance) {
53558                         this.APIEndPoint = APIEndPoint;
53559                         this.$modalInstance = $modalInstance;
53560                         var controller = this;
53561                         console.log('controller.upload-controllers');
53562                     }
53563                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
53564                     return Upload;
53565                 })();
53566                 controllers.Upload = Upload;
53567             })(controllers = app.controllers || (app.controllers = {}));
53568         })(app || (app = {}));
53569         var app;
53570         (function (app) {
53571             var controllers;
53572             (function (controllers) {
53573                 var Preview = (function () {
53574                     function Preview($scope, APIEndPoint, $modalInstance) {
53575                         this.APIEndPoint = APIEndPoint;
53576                         this.$modalInstance = $modalInstance;
53577                         var controller = this;
53578                         console.log('preview');
53579                     }
53580                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
53581                     return Preview;
53582                 })();
53583                 controllers.Preview = Preview;
53584             })(controllers = app.controllers || (app.controllers = {}));
53585         })(app || (app = {}));
53586         var filters;
53587         (function (filters) {
53588             function Tag() {
53589                 return function (commands, tag) {
53590                     var result = [];
53591                     angular.forEach(commands, function (command) {
53592                         var flag = false;
53593                         angular.forEach(command.tags, function (value) {
53594                             if (tag === value)
53595                                 flag = true;
53596                         });
53597                         if (flag)
53598                             result.push(command);
53599                     });
53600                     return result;
53601                 };
53602             }
53603             filters.Tag = Tag;
53604         })(filters || (filters = {}));
53605         var app;
53606         (function (app) {
53607             'use strict';
53608             var appName = 'zephyr';
53609             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
53610             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
53611                 $urlRouterProvider.otherwise('/execution');
53612                 $locationProvider.html5Mode({
53613                     enabled: true,
53614                     requireBase: false
53615                 });
53616                 $stateProvider
53617                     .state('execution', {
53618                     url: '/execution',
53619                     templateUrl: 'templates/execution.html',
53620                     controller: 'executionController',
53621                     controllerAs: 'c'
53622                 })
53623                     .state('workspace', {
53624                     url: '/workspace',
53625                     templateUrl: 'templates/workspace.html',
53626                     controller: 'workspaceController',
53627                     controllerAs: 'c'
53628                 })
53629                     .state('history', {
53630                     url: '/history',
53631                     templateUrl: 'templates/history.html',
53632                     controller: 'historyController',
53633                     controllerAs: 'c'
53634                 });
53635             });
53636             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
53637             app.zephyr.service('MyModal', app.services.MyModal);
53638             app.zephyr.service('WebSocket', app.services.WebSocket);
53639             app.zephyr.service('Console', app.services.Console);
53640             app.zephyr.filter('Tag', filters.Tag);
53641             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
53642             app.zephyr.controller('previewController', app.controllers.Preview);
53643             app.zephyr.controller('uploadController', app.controllers.Upload);
53644             app.zephyr.controller('executionController', app.controllers.Execution);
53645             app.zephyr.controller('workspaceController', app.controllers.Workspace);
53646             app.zephyr.controller('historyController', app.controllers.History);
53647             app.zephyr.controller('commandController', app.directives.CommandController);
53648             app.zephyr.controller('optionController', app.directives.OptionController);
53649             app.zephyr.controller('directoryController', app.directives.DirectoryController);
53650             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
53651             app.zephyr.controller('uploadController', app.directives.UploadController);
53652             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
53653             app.zephyr.directive('command', app.directives.Command.Factory());
53654             app.zephyr.directive('option', app.directives.Option.Factory());
53655             app.zephyr.directive('directory', app.directives.Directory.Factory());
53656         })(app || (app = {}));
53657
53658
53659 /***/ },
53660 /* 23 */
53661 /***/ function(module, exports) {
53662
53663         var app;
53664         (function (app) {
53665             var declares;
53666             (function (declares) {
53667                 var CommandInfo = (function () {
53668                     function CommandInfo(name) {
53669                         this.name = name;
53670                     }
53671                     return CommandInfo;
53672                 })();
53673                 declares.CommandInfo = CommandInfo;
53674             })(declares = app.declares || (app.declares = {}));
53675         })(app || (app = {}));
53676         var app;
53677         (function (app) {
53678             var services;
53679             (function (services) {
53680                 var APIEndPoint = (function () {
53681                     function APIEndPoint($resource, $http) {
53682                         this.$resource = $resource;
53683                         this.$http = $http;
53684                     }
53685                     APIEndPoint.prototype.resource = function (endPoint, data) {
53686                         var customAction = {
53687                             method: 'GET',
53688                             isArray: false
53689                         };
53690                         var execute = {
53691                             method: 'POST',
53692                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
53693                         };
53694                         return this.$resource(endPoint, {}, { execute: execute });
53695                     };
53696                     APIEndPoint.prototype.getOptionControlFile = function (command) {
53697                         var endPoint = '/api/v1/optionControlFile/' + command;
53698                         return this.resource(endPoint, {}).get();
53699                     };
53700                     APIEndPoint.prototype.getFiles = function (fileId) {
53701                         var endPoint = '/api/v1/workspace';
53702                         if (fileId) {
53703                             endPoint += '/' + fileId;
53704                         }
53705                         return this.resource(endPoint, {}).get();
53706                     };
53707                     APIEndPoint.prototype.getDirectories = function () {
53708                         var endPoint = '/api/v1/all/workspace/directory';
53709                         return this.resource(endPoint, {}).get();
53710                     };
53711                     APIEndPoint.prototype.getTags = function () {
53712                         var endPoint = '/api/v1/tagList';
53713                         return this.resource(endPoint, {}).get();
53714                     };
53715                     APIEndPoint.prototype.getCommands = function () {
53716                         var endPoint = '/api/v1/commandList';
53717                         return this.resource(endPoint, {}).get();
53718                     };
53719                     APIEndPoint.prototype.execute = function (data) {
53720                         var endPoint = '/api/v1/execution';
53721                         var fd = new FormData();
53722                         fd.append('data', data);
53723                         return this.$http.post(endPoint, fd, {
53724                             headers: { 'Content-Type': undefined },
53725                             transformRequest: angular.identity
53726                         });
53727                     };
53728                     APIEndPoint.prototype.debug = function () {
53729                         var endPoint = '/api/v1/debug';
53730                         return this.$http.get(endPoint);
53731                     };
53732                     APIEndPoint.prototype.upload = function () {
53733                         var endPoint = '/api/v1/upload';
53734                         return this.$http.get(endPoint);
53735                     };
53736                     APIEndPoint.prototype.help = function (command) {
53737                         var endPoint = '/api/v1/help/' + command;
53738                         return this.$http.get(endPoint);
53739                     };
53740                     return APIEndPoint;
53741                 })();
53742                 services.APIEndPoint = APIEndPoint;
53743             })(services = app.services || (app.services = {}));
53744         })(app || (app = {}));
53745         var app;
53746         (function (app) {
53747             var services;
53748             (function (services) {
53749                 var MyModal = (function () {
53750                     function MyModal($uibModal) {
53751                         this.$uibModal = $uibModal;
53752                         this.modalOption = {
53753                             backdrop: true,
53754                             controller: null,
53755                             templateUrl: null,
53756                             size: null
53757                         };
53758                     }
53759                     MyModal.prototype.open = function (modalName) {
53760                         if (modalName === 'SelectCommand') {
53761                             this.modalOption.templateUrl = 'templates/select-command.html';
53762                             this.modalOption.size = 'lg';
53763                         }
53764                         return this.$uibModal.open(this.modalOption);
53765                     };
53766                     MyModal.prototype.selectCommand = function () {
53767                         this.modalOption.templateUrl = 'templates/select-command.html';
53768                         this.modalOption.controller = 'selectCommandController';
53769                         this.modalOption.controllerAs = 'c';
53770                         this.modalOption.size = 'lg';
53771                         return this.$uibModal.open(this.modalOption);
53772                     };
53773                     MyModal.prototype.preview = function () {
53774                         this.modalOption.templateUrl = 'templates/preview.html';
53775                         this.modalOption.controller = 'previewController';
53776                         this.modalOption.controllerAs = 'c';
53777                         this.modalOption.size = 'lg';
53778                         return this.$uibModal.open(this.modalOption);
53779                     };
53780                     MyModal.prototype.upload = function () {
53781                         this.modalOption.templateUrl = 'templates/upload.html';
53782                         this.modalOption.controller = 'uploadController';
53783                         this.modalOption.controllerAs = 'c';
53784                         this.modalOption.size = 'lg';
53785                         return this.$uibModal.open(this.modalOption);
53786                     };
53787                     MyModal.$inject = ['$uibModal'];
53788                     return MyModal;
53789                 })();
53790                 services.MyModal = MyModal;
53791             })(services = app.services || (app.services = {}));
53792         })(app || (app = {}));
53793         var app;
53794         (function (app) {
53795             var services;
53796             (function (services) {
53797                 var WebSocket = (function () {
53798                     function WebSocket($rootScope) {
53799                         this.$rootScope = $rootScope;
53800                         this.socket = io.connect();
53801                     }
53802                     WebSocket.prototype.on = function (eventName, callback) {
53803                         var socket = this.socket;
53804                         var rootScope = this.$rootScope;
53805                         socket.on(eventName, function () {
53806                             var args = arguments;
53807                             rootScope.$apply(function () {
53808                                 callback.apply(socket, args);
53809                             });
53810                         });
53811                     };
53812                     WebSocket.prototype.emit = function (eventName, data, callback) {
53813                         var socket = this.socket;
53814                         var rootScope = this.$rootScope;
53815                         this.socket.emit(eventName, data, function () {
53816                             var args = arguments;
53817                             rootScope.$apply(function () {
53818                                 if (callback)
53819                                     callback.apply(socket, args);
53820                             });
53821                         });
53822                     };
53823                     return WebSocket;
53824                 })();
53825                 services.WebSocket = WebSocket;
53826             })(services = app.services || (app.services = {}));
53827         })(app || (app = {}));
53828         var app;
53829         (function (app) {
53830             var services;
53831             (function (services) {
53832                 var Console = (function () {
53833                     function Console(WebSocket, $rootScope) {
53834                         this.WebSocket = WebSocket;
53835                         this.$rootScope = $rootScope;
53836                         this.WebSocket = WebSocket;
53837                         this.$rootScope = $rootScope;
53838                         this.directiveIDs = [];
53839                         var directiveIDs = this.directiveIDs;
53840                         this.WebSocket.on('console', function (d) {
53841                             var id = d.id;
53842                             var message = d.message;
53843                             if (directiveIDs.indexOf(id) > -1) {
53844                                 $rootScope.$emit(id, message);
53845                             }
53846                         });
53847                     }
53848                     Console.prototype.addDirective = function (id) {
53849                         if (!(this.directiveIDs.indexOf(id) > -1)) {
53850                             this.directiveIDs.push(id);
53851                         }
53852                     };
53853                     Console.prototype.removeDirective = function (id) {
53854                         var i = this.directiveIDs.indexOf(id);
53855                         if (i > -1) {
53856                             this.directiveIDs.splice(i, 1);
53857                         }
53858                     };
53859                     Console.prototype.showIDs = function () {
53860                         console.log(this.directiveIDs);
53861                     };
53862                     return Console;
53863                 })();
53864                 services.Console = Console;
53865             })(services = app.services || (app.services = {}));
53866         })(app || (app = {}));
53867         var app;
53868         (function (app) {
53869             var directives;
53870             (function (directives) {
53871                 var Command = (function () {
53872                     function Command() {
53873                         this.restrict = 'E';
53874                         this.replace = true;
53875                         this.scope = true;
53876                         this.controller = 'commandController';
53877                         this.controllerAs = 'ctrl';
53878                         this.bindToController = {
53879                             index: '=',
53880                             name: '=',
53881                             remove: '&',
53882                             list: '='
53883                         };
53884                         this.templateUrl = 'templates/command.html';
53885                     }
53886                     Command.Factory = function () {
53887                         var directive = function () {
53888                             return new Command();
53889                         };
53890                         directive.$inject = [];
53891                         return directive;
53892                     };
53893                     return Command;
53894                 })();
53895                 directives.Command = Command;
53896                 var CommandController = (function () {
53897                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
53898                         this.APIEndPoint = APIEndPoint;
53899                         this.$scope = $scope;
53900                         this.MyModal = MyModal;
53901                         this.WebSocket = WebSocket;
53902                         this.$window = $window;
53903                         this.$rootScope = $rootScope;
53904                         this.Console = Console;
53905                         var controller = this;
53906                         this.APIEndPoint
53907                             .getOptionControlFile(this.name)
53908                             .$promise
53909                             .then(function (result) {
53910                             controller.options = result.info;
53911                         });
53912                         this.APIEndPoint
53913                             .getDirectories()
53914                             .$promise
53915                             .then(function (result) {
53916                             controller.dirs = result.info;
53917                         });
53918                         this.heading = "[" + this.index + "]: dcdFilePrint";
53919                         this.isOpen = true;
53920                         this.$scope.$on('close', function () {
53921                             controller.isOpen = false;
53922                         });
53923                         function guid() {
53924                             function s4() {
53925                                 return Math.floor((1 + Math.random()) * 0x10000)
53926                                     .toString(16)
53927                                     .substring(1);
53928                             }
53929                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
53930                                 s4() + '-' + s4() + s4() + s4();
53931                         }
53932                         this.uuid = guid();
53933                         this.Console.addDirective(this.uuid);
53934                         this.Console.showIDs();
53935                     }
53936                     CommandController.prototype.submit = function () {
53937                         var opt = [];
53938                         angular.forEach(this.options, function (option) {
53939                             var obj = {
53940                                 name: option.option,
53941                                 arguments: []
53942                             };
53943                             angular.forEach(option.arg, function (arg) {
53944                                 if (arg.input) {
53945                                     if (typeof arg.input === 'object') {
53946                                         obj.arguments.push(arg.input.name);
53947                                     }
53948                                     else {
53949                                         obj.arguments.push(arg.input);
53950                                     }
53951                                 }
53952                             });
53953                             if (obj.arguments.length > 0) {
53954                                 opt.push(obj);
53955                             }
53956                         });
53957                         var execObj = {
53958                             command: this.name,
53959                             workspace: this.workspace.fileId,
53960                             options: opt
53961                         };
53962                         this.APIEndPoint
53963                             .execute(JSON.stringify(execObj))
53964                             .then(function (result) {
53965                             console.log(result);
53966                         });
53967                     };
53968                     CommandController.prototype.removeMySelf = function (index) {
53969                         this.$scope.$destroy();
53970                         this.Console.removeDirective(this.uuid);
53971                         this.remove()(index, this.list);
53972                         this.Console.showIDs();
53973                     };
53974                     CommandController.prototype.reloadFiles = function () {
53975                         var _this = this;
53976                         var fileId = this.workspace.fileId;
53977                         this.APIEndPoint
53978                             .getFiles(fileId)
53979                             .$promise
53980                             .then(function (result) {
53981                             var status = result.status;
53982                             if (status === 'success') {
53983                                 _this.files = result.info;
53984                             }
53985                             else {
53986                                 console.log(result.message);
53987                             }
53988                         });
53989                     };
53990                     CommandController.prototype.debug = function () {
53991                         var div = angular.element(this.$window.document).find("div");
53992                         var consoleTag;
53993                         var parametersTag;
53994                         angular.forEach(div, function (v) {
53995                             if (v.className === "panel-body console") {
53996                                 consoleTag = v;
53997                             }
53998                             else if (v.className === "row parameters-console") {
53999                                 parametersTag = v;
54000                             }
54001                         });
54002                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
54003                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
54004                         consoleTag.style.height = consoleHeight;
54005                         consoleTag.style.width = consoleWidth;
54006                     };
54007                     CommandController.prototype.help = function () {
54008                         this.APIEndPoint
54009                             .help(this.name)
54010                             .then(function (result) {
54011                             console.log(result);
54012                         });
54013                     };
54014                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
54015                     return CommandController;
54016                 })();
54017                 directives.CommandController = CommandController;
54018             })(directives = app.directives || (app.directives = {}));
54019         })(app || (app = {}));
54020         var app;
54021         (function (app) {
54022             var directives;
54023             (function (directives) {
54024                 var HeaderMenu = (function () {
54025                     function HeaderMenu() {
54026                         this.restrict = 'E';
54027                         this.replace = true;
54028                         this.templateUrl = 'templates/header-menu.html';
54029                         this.controller = 'HeaderMenuController';
54030                         this.controllerAs = 'hmc';
54031                         this.scope = true;
54032                     }
54033                     HeaderMenu.Factory = function () {
54034                         var directive = function () {
54035                             return new HeaderMenu();
54036                         };
54037                         return directive;
54038                     };
54039                     return HeaderMenu;
54040                 })();
54041                 directives.HeaderMenu = HeaderMenu;
54042                 var HeaderMenuController = (function () {
54043                     function HeaderMenuController($state) {
54044                         this.$state = $state;
54045                         this.isExecution = this.$state.current.name === 'execution';
54046                         this.isWorkspace = this.$state.current.name === 'workspace';
54047                         this.isHistory = this.$state.current.name === 'history';
54048                     }
54049                     HeaderMenuController.prototype.transit = function (state) {
54050                         this.$state.go(state);
54051                     };
54052                     HeaderMenuController.$inject = ['$state'];
54053                     return HeaderMenuController;
54054                 })();
54055                 directives.HeaderMenuController = HeaderMenuController;
54056             })(directives = app.directives || (app.directives = {}));
54057         })(app || (app = {}));
54058         var app;
54059         (function (app) {
54060             var directives;
54061             (function (directives) {
54062                 var Option = (function () {
54063                     function Option() {
54064                         this.restrict = 'E';
54065                         this.replace = true;
54066                         this.controller = 'optionController';
54067                         this.bindToController = {
54068                             info: '=',
54069                             files: '='
54070                         };
54071                         this.scope = true;
54072                         this.templateUrl = 'templates/option.html';
54073                         this.controllerAs = 'ctrl';
54074                     }
54075                     Option.Factory = function () {
54076                         var directive = function () {
54077                             return new Option();
54078                         };
54079                         directive.$inject = [];
54080                         return directive;
54081                     };
54082                     return Option;
54083                 })();
54084                 directives.Option = Option;
54085                 var OptionController = (function () {
54086                     function OptionController() {
54087                         var controller = this;
54088                         angular.forEach(controller.info.arg, function (arg) {
54089                             if (arg.initialValue) {
54090                                 if (arg.formType === 'number') {
54091                                     arg.input = parseInt(arg.initialValue);
54092                                 }
54093                                 else {
54094                                     arg.input = arg.initialValue;
54095                                 }
54096                             }
54097                         });
54098                     }
54099                     OptionController.$inject = [];
54100                     return OptionController;
54101                 })();
54102                 directives.OptionController = OptionController;
54103             })(directives = app.directives || (app.directives = {}));
54104         })(app || (app = {}));
54105         var app;
54106         (function (app) {
54107             var directives;
54108             (function (directives) {
54109                 var Directory = (function () {
54110                     function Directory() {
54111                         this.restrict = 'E';
54112                         this.replace = true;
54113                         this.controller = 'directoryController';
54114                         this.controllerAs = 'ctrl';
54115                         this.bindToController = {
54116                             info: '=',
54117                             add: '&',
54118                             list: '=',
54119                             files: '='
54120                         };
54121                         this.templateUrl = 'templates/directory.html';
54122                     }
54123                     Directory.Factory = function () {
54124                         var directive = function () {
54125                             return new Directory();
54126                         };
54127                         return directive;
54128                     };
54129                     return Directory;
54130                 })();
54131                 directives.Directory = Directory;
54132                 var DirectoryController = (function () {
54133                     function DirectoryController(APIEndPoint, $scope) {
54134                         this.APIEndPoint = APIEndPoint;
54135                         this.$scope = $scope;
54136                         var controller = this;
54137                         this.APIEndPoint
54138                             .getFiles(this.info.fileId)
54139                             .$promise
54140                             .then(function (result) {
54141                             if (result.status === 'success') {
54142                                 controller.files = result.info;
54143                                 angular.forEach(result.info, function (file) {
54144                                     if (file.fileType === '0') {
54145                                         var o = file;
54146                                         if (controller.info.path === '/') {
54147                                             o.path = '/' + file.name;
54148                                         }
54149                                         else {
54150                                             o.path = controller.info.path + '/' + file.name;
54151                                         }
54152                                         controller.add()(o, controller.list);
54153                                     }
54154                                 });
54155                             }
54156                             ;
54157                         });
54158                     }
54159                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
54160                     return DirectoryController;
54161                 })();
54162                 directives.DirectoryController = DirectoryController;
54163             })(directives = app.directives || (app.directives = {}));
54164         })(app || (app = {}));
54165         var app;
54166         (function (app) {
54167             var directives;
54168             (function (directives) {
54169                 var Upload = (function () {
54170                     function Upload() {
54171                         this.restrict = 'E';
54172                         this.replace = true;
54173                         this.scope = true;
54174                         this.controller = 'UploadController';
54175                         this.controllerAs = 'ctrl';
54176                         this.bindToController = {
54177                             index: '=',
54178                             name: '=',
54179                             remove: '&',
54180                             list: '='
54181                         };
54182                         this.templateUrl = 'templates/upload.html';
54183                         console.log("templates/upload.html-constructor");
54184                     }
54185                     Upload.Factory = function () {
54186                         var directive = function () {
54187                             return new Upload();
54188                         };
54189                         directive.$inject = [];
54190                         return directive;
54191                     };
54192                     return Upload;
54193                 })();
54194                 directives.Upload = Upload;
54195                 var UploadController = (function () {
54196                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
54197                         this.APIEndPoint = APIEndPoint;
54198                         this.$scope = $scope;
54199                         this.MyModal = MyModal;
54200                         this.WebSocket = WebSocket;
54201                         this.$window = $window;
54202                         this.$rootScope = $rootScope;
54203                         this.Console = Console;
54204                         var controller = this;
54205                         console.log("directive.upload-constructor");
54206                     }
54207                     UploadController.prototype.submit = function () {
54208                         console.log("submit: function not supported¥n");
54209                     };
54210                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
54211                     return UploadController;
54212                 })();
54213                 directives.UploadController = UploadController;
54214             })(directives = app.directives || (app.directives = {}));
54215         })(app || (app = {}));
54216         var app;
54217         (function (app) {
54218             var controllers;
54219             (function (controllers) {
54220                 var Execution = (function () {
54221                     function Execution(MyModal, $scope) {
54222                         this.MyModal = MyModal;
54223                         this.$scope = $scope;
54224                         this.commandInfoList = [];
54225                     }
54226                     ;
54227                     Execution.prototype.add = function () {
54228                         this.$scope.$broadcast('close');
54229                         var commandInfoList = this.commandInfoList;
54230                         var commandInstance = this.MyModal.selectCommand();
54231                         commandInstance
54232                             .result
54233                             .then(function (command) {
54234                             commandInfoList.push(new app.declares.CommandInfo(command));
54235                         });
54236                     };
54237                     Execution.prototype.open = function () {
54238                         var result = this.MyModal.open('SelectCommand');
54239                         console.log(result);
54240                     };
54241                     Execution.prototype.remove = function (index, list) {
54242                         list.splice(index, 1);
54243                     };
54244                     Execution.prototype.close = function () {
54245                         console.log("close");
54246                     };
54247                     Execution.$inject = ['MyModal', '$scope'];
54248                     return Execution;
54249                 })();
54250                 controllers.Execution = Execution;
54251             })(controllers = app.controllers || (app.controllers = {}));
54252         })(app || (app = {}));
54253         var app;
54254         (function (app) {
54255             var controllers;
54256             (function (controllers) {
54257                 var Workspace = (function () {
54258                     function Workspace($scope, APIEndPoint, MyModal) {
54259                         this.$scope = $scope;
54260                         this.APIEndPoint = APIEndPoint;
54261                         this.MyModal = MyModal;
54262                         this.directoryList = [];
54263                         var controller = this;
54264                         var directoryList = this.directoryList;
54265                         var o = {
54266                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
54267                             name: '',
54268                             parentId: '',
54269                             fileType: '',
54270                             createdAt: '',
54271                             updatedAt: '',
54272                             path: '/'
54273                         };
54274                         directoryList.push(o);
54275                     }
54276                     Workspace.prototype.addDirectory = function (info, directoryList) {
54277                         directoryList.push(info);
54278                     };
54279                     Workspace.prototype.upload = function () {
54280                         this.MyModal.upload();
54281                     };
54282                     Workspace.prototype.debug = function () {
54283                         this.MyModal.preview();
54284                     };
54285                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
54286                     return Workspace;
54287                 })();
54288                 controllers.Workspace = Workspace;
54289             })(controllers = app.controllers || (app.controllers = {}));
54290         })(app || (app = {}));
54291         var app;
54292         (function (app) {
54293             var controllers;
54294             (function (controllers) {
54295                 var History = (function () {
54296                     function History($scope) {
54297                         this.page = "History";
54298                     }
54299                     History.$inject = ['$scope'];
54300                     return History;
54301                 })();
54302                 controllers.History = History;
54303             })(controllers = app.controllers || (app.controllers = {}));
54304         })(app || (app = {}));
54305         var app;
54306         (function (app) {
54307             var controllers;
54308             (function (controllers) {
54309                 var SelectCommand = (function () {
54310                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
54311                         this.APIEndPoint = APIEndPoint;
54312                         this.$modalInstance = $modalInstance;
54313                         var controller = this;
54314                         this.APIEndPoint
54315                             .getTags()
54316                             .$promise.then(function (result) {
54317                             controller.tags = result.info;
54318                         });
54319                         this.APIEndPoint
54320                             .getCommands()
54321                             .$promise.then(function (result) {
54322                             controller.commands = result.info;
54323                         });
54324                         this.currentTag = 'all';
54325                     }
54326                     SelectCommand.prototype.changeTag = function (tag) {
54327                         this.currentTag = tag;
54328                     };
54329                     SelectCommand.prototype.selectCommand = function (command) {
54330                         this.$modalInstance.close(command);
54331                     };
54332                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
54333                     return SelectCommand;
54334                 })();
54335                 controllers.SelectCommand = SelectCommand;
54336             })(controllers = app.controllers || (app.controllers = {}));
54337         })(app || (app = {}));
54338         var app;
54339         (function (app) {
54340             var controllers;
54341             (function (controllers) {
54342                 var Upload = (function () {
54343                     function Upload($scope, APIEndPoint, $modalInstance) {
54344                         this.APIEndPoint = APIEndPoint;
54345                         this.$modalInstance = $modalInstance;
54346                         var controller = this;
54347                         console.log('controller.upload-controllers');
54348                     }
54349                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
54350                     return Upload;
54351                 })();
54352                 controllers.Upload = Upload;
54353             })(controllers = app.controllers || (app.controllers = {}));
54354         })(app || (app = {}));
54355         var app;
54356         (function (app) {
54357             var controllers;
54358             (function (controllers) {
54359                 var Preview = (function () {
54360                     function Preview($scope, APIEndPoint, $modalInstance) {
54361                         this.APIEndPoint = APIEndPoint;
54362                         this.$modalInstance = $modalInstance;
54363                         var controller = this;
54364                         console.log('preview');
54365                     }
54366                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
54367                     return Preview;
54368                 })();
54369                 controllers.Preview = Preview;
54370             })(controllers = app.controllers || (app.controllers = {}));
54371         })(app || (app = {}));
54372         var filters;
54373         (function (filters) {
54374             function Tag() {
54375                 return function (commands, tag) {
54376                     var result = [];
54377                     angular.forEach(commands, function (command) {
54378                         var flag = false;
54379                         angular.forEach(command.tags, function (value) {
54380                             if (tag === value)
54381                                 flag = true;
54382                         });
54383                         if (flag)
54384                             result.push(command);
54385                     });
54386                     return result;
54387                 };
54388             }
54389             filters.Tag = Tag;
54390         })(filters || (filters = {}));
54391         var app;
54392         (function (app) {
54393             'use strict';
54394             var appName = 'zephyr';
54395             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
54396             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
54397                 $urlRouterProvider.otherwise('/execution');
54398                 $locationProvider.html5Mode({
54399                     enabled: true,
54400                     requireBase: false
54401                 });
54402                 $stateProvider
54403                     .state('execution', {
54404                     url: '/execution',
54405                     templateUrl: 'templates/execution.html',
54406                     controller: 'executionController',
54407                     controllerAs: 'c'
54408                 })
54409                     .state('workspace', {
54410                     url: '/workspace',
54411                     templateUrl: 'templates/workspace.html',
54412                     controller: 'workspaceController',
54413                     controllerAs: 'c'
54414                 })
54415                     .state('history', {
54416                     url: '/history',
54417                     templateUrl: 'templates/history.html',
54418                     controller: 'historyController',
54419                     controllerAs: 'c'
54420                 });
54421             });
54422             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
54423             app.zephyr.service('MyModal', app.services.MyModal);
54424             app.zephyr.service('WebSocket', app.services.WebSocket);
54425             app.zephyr.service('Console', app.services.Console);
54426             app.zephyr.filter('Tag', filters.Tag);
54427             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
54428             app.zephyr.controller('previewController', app.controllers.Preview);
54429             app.zephyr.controller('uploadController', app.controllers.Upload);
54430             app.zephyr.controller('executionController', app.controllers.Execution);
54431             app.zephyr.controller('workspaceController', app.controllers.Workspace);
54432             app.zephyr.controller('historyController', app.controllers.History);
54433             app.zephyr.controller('commandController', app.directives.CommandController);
54434             app.zephyr.controller('optionController', app.directives.OptionController);
54435             app.zephyr.controller('directoryController', app.directives.DirectoryController);
54436             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
54437             app.zephyr.controller('uploadController', app.directives.UploadController);
54438             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
54439             app.zephyr.directive('command', app.directives.Command.Factory());
54440             app.zephyr.directive('option', app.directives.Option.Factory());
54441             app.zephyr.directive('directory', app.directives.Directory.Factory());
54442         })(app || (app = {}));
54443
54444
54445 /***/ },
54446 /* 24 */
54447 /***/ function(module, exports) {
54448
54449         var app;
54450         (function (app) {
54451             var declares;
54452             (function (declares) {
54453                 var CommandInfo = (function () {
54454                     function CommandInfo(name) {
54455                         this.name = name;
54456                     }
54457                     return CommandInfo;
54458                 })();
54459                 declares.CommandInfo = CommandInfo;
54460             })(declares = app.declares || (app.declares = {}));
54461         })(app || (app = {}));
54462         var app;
54463         (function (app) {
54464             var services;
54465             (function (services) {
54466                 var APIEndPoint = (function () {
54467                     function APIEndPoint($resource, $http) {
54468                         this.$resource = $resource;
54469                         this.$http = $http;
54470                     }
54471                     APIEndPoint.prototype.resource = function (endPoint, data) {
54472                         var customAction = {
54473                             method: 'GET',
54474                             isArray: false
54475                         };
54476                         var execute = {
54477                             method: 'POST',
54478                             headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
54479                         };
54480                         return this.$resource(endPoint, {}, { execute: execute });
54481                     };
54482                     APIEndPoint.prototype.getOptionControlFile = function (command) {
54483                         var endPoint = '/api/v1/optionControlFile/' + command;
54484                         return this.resource(endPoint, {}).get();
54485                     };
54486                     APIEndPoint.prototype.getFiles = function (fileId) {
54487                         var endPoint = '/api/v1/workspace';
54488                         if (fileId) {
54489                             endPoint += '/' + fileId;
54490                         }
54491                         return this.resource(endPoint, {}).get();
54492                     };
54493                     APIEndPoint.prototype.getDirectories = function () {
54494                         var endPoint = '/api/v1/all/workspace/directory';
54495                         return this.resource(endPoint, {}).get();
54496                     };
54497                     APIEndPoint.prototype.getTags = function () {
54498                         var endPoint = '/api/v1/tagList';
54499                         return this.resource(endPoint, {}).get();
54500                     };
54501                     APIEndPoint.prototype.getCommands = function () {
54502                         var endPoint = '/api/v1/commandList';
54503                         return this.resource(endPoint, {}).get();
54504                     };
54505                     APIEndPoint.prototype.execute = function (data) {
54506                         var endPoint = '/api/v1/execution';
54507                         var fd = new FormData();
54508                         fd.append('data', data);
54509                         return this.$http.post(endPoint, fd, {
54510                             headers: { 'Content-Type': undefined },
54511                             transformRequest: angular.identity
54512                         });
54513                     };
54514                     APIEndPoint.prototype.debug = function () {
54515                         var endPoint = '/api/v1/debug';
54516                         return this.$http.get(endPoint);
54517                     };
54518                     APIEndPoint.prototype.upload = function () {
54519                         var endPoint = '/api/v1/upload';
54520                         return this.$http.get(endPoint);
54521                     };
54522                     APIEndPoint.prototype.help = function (command) {
54523                         var endPoint = '/api/v1/help/' + command;
54524                         return this.$http.get(endPoint);
54525                     };
54526                     return APIEndPoint;
54527                 })();
54528                 services.APIEndPoint = APIEndPoint;
54529             })(services = app.services || (app.services = {}));
54530         })(app || (app = {}));
54531         var app;
54532         (function (app) {
54533             var services;
54534             (function (services) {
54535                 var MyModal = (function () {
54536                     function MyModal($uibModal) {
54537                         this.$uibModal = $uibModal;
54538                         this.modalOption = {
54539                             backdrop: true,
54540                             controller: null,
54541                             templateUrl: null,
54542                             size: null
54543                         };
54544                     }
54545                     MyModal.prototype.open = function (modalName) {
54546                         if (modalName === 'SelectCommand') {
54547                             this.modalOption.templateUrl = 'templates/select-command.html';
54548                             this.modalOption.size = 'lg';
54549                         }
54550                         return this.$uibModal.open(this.modalOption);
54551                     };
54552                     MyModal.prototype.selectCommand = function () {
54553                         this.modalOption.templateUrl = 'templates/select-command.html';
54554                         this.modalOption.controller = 'selectCommandController';
54555                         this.modalOption.controllerAs = 'c';
54556                         this.modalOption.size = 'lg';
54557                         return this.$uibModal.open(this.modalOption);
54558                     };
54559                     MyModal.prototype.preview = function () {
54560                         this.modalOption.templateUrl = 'templates/preview.html';
54561                         this.modalOption.controller = 'previewController';
54562                         this.modalOption.controllerAs = 'c';
54563                         this.modalOption.size = 'lg';
54564                         return this.$uibModal.open(this.modalOption);
54565                     };
54566                     MyModal.prototype.upload = function () {
54567                         this.modalOption.templateUrl = 'templates/upload.html';
54568                         this.modalOption.controller = 'uploadController';
54569                         this.modalOption.controllerAs = 'c';
54570                         this.modalOption.size = 'lg';
54571                         return this.$uibModal.open(this.modalOption);
54572                     };
54573                     MyModal.$inject = ['$uibModal'];
54574                     return MyModal;
54575                 })();
54576                 services.MyModal = MyModal;
54577             })(services = app.services || (app.services = {}));
54578         })(app || (app = {}));
54579         var app;
54580         (function (app) {
54581             var services;
54582             (function (services) {
54583                 var WebSocket = (function () {
54584                     function WebSocket($rootScope) {
54585                         this.$rootScope = $rootScope;
54586                         this.socket = io.connect();
54587                     }
54588                     WebSocket.prototype.on = function (eventName, callback) {
54589                         var socket = this.socket;
54590                         var rootScope = this.$rootScope;
54591                         socket.on(eventName, function () {
54592                             var args = arguments;
54593                             rootScope.$apply(function () {
54594                                 callback.apply(socket, args);
54595                             });
54596                         });
54597                     };
54598                     WebSocket.prototype.emit = function (eventName, data, callback) {
54599                         var socket = this.socket;
54600                         var rootScope = this.$rootScope;
54601                         this.socket.emit(eventName, data, function () {
54602                             var args = arguments;
54603                             rootScope.$apply(function () {
54604                                 if (callback)
54605                                     callback.apply(socket, args);
54606                             });
54607                         });
54608                     };
54609                     return WebSocket;
54610                 })();
54611                 services.WebSocket = WebSocket;
54612             })(services = app.services || (app.services = {}));
54613         })(app || (app = {}));
54614         var app;
54615         (function (app) {
54616             var services;
54617             (function (services) {
54618                 var Console = (function () {
54619                     function Console(WebSocket, $rootScope) {
54620                         this.WebSocket = WebSocket;
54621                         this.$rootScope = $rootScope;
54622                         this.WebSocket = WebSocket;
54623                         this.$rootScope = $rootScope;
54624                         this.directiveIDs = [];
54625                         var directiveIDs = this.directiveIDs;
54626                         this.WebSocket.on('console', function (d) {
54627                             var id = d.id;
54628                             var message = d.message;
54629                             if (directiveIDs.indexOf(id) > -1) {
54630                                 $rootScope.$emit(id, message);
54631                             }
54632                         });
54633                     }
54634                     Console.prototype.addDirective = function (id) {
54635                         if (!(this.directiveIDs.indexOf(id) > -1)) {
54636                             this.directiveIDs.push(id);
54637                         }
54638                     };
54639                     Console.prototype.removeDirective = function (id) {
54640                         var i = this.directiveIDs.indexOf(id);
54641                         if (i > -1) {
54642                             this.directiveIDs.splice(i, 1);
54643                         }
54644                     };
54645                     Console.prototype.showIDs = function () {
54646                         console.log(this.directiveIDs);
54647                     };
54648                     return Console;
54649                 })();
54650                 services.Console = Console;
54651             })(services = app.services || (app.services = {}));
54652         })(app || (app = {}));
54653         var app;
54654         (function (app) {
54655             var directives;
54656             (function (directives) {
54657                 var Command = (function () {
54658                     function Command() {
54659                         this.restrict = 'E';
54660                         this.replace = true;
54661                         this.scope = true;
54662                         this.controller = 'commandController';
54663                         this.controllerAs = 'ctrl';
54664                         this.bindToController = {
54665                             index: '=',
54666                             name: '=',
54667                             remove: '&',
54668                             list: '='
54669                         };
54670                         this.templateUrl = 'templates/command.html';
54671                     }
54672                     Command.Factory = function () {
54673                         var directive = function () {
54674                             return new Command();
54675                         };
54676                         directive.$inject = [];
54677                         return directive;
54678                     };
54679                     return Command;
54680                 })();
54681                 directives.Command = Command;
54682                 var CommandController = (function () {
54683                     function CommandController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
54684                         this.APIEndPoint = APIEndPoint;
54685                         this.$scope = $scope;
54686                         this.MyModal = MyModal;
54687                         this.WebSocket = WebSocket;
54688                         this.$window = $window;
54689                         this.$rootScope = $rootScope;
54690                         this.Console = Console;
54691                         var controller = this;
54692                         this.APIEndPoint
54693                             .getOptionControlFile(this.name)
54694                             .$promise
54695                             .then(function (result) {
54696                             controller.options = result.info;
54697                         });
54698                         this.APIEndPoint
54699                             .getDirectories()
54700                             .$promise
54701                             .then(function (result) {
54702                             controller.dirs = result.info;
54703                         });
54704                         this.heading = "[" + this.index + "]: dcdFilePrint";
54705                         this.isOpen = true;
54706                         this.$scope.$on('close', function () {
54707                             controller.isOpen = false;
54708                         });
54709                         function guid() {
54710                             function s4() {
54711                                 return Math.floor((1 + Math.random()) * 0x10000)
54712                                     .toString(16)
54713                                     .substring(1);
54714                             }
54715                             return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
54716                                 s4() + '-' + s4() + s4() + s4();
54717                         }
54718                         this.uuid = guid();
54719                         this.Console.addDirective(this.uuid);
54720                         this.Console.showIDs();
54721                     }
54722                     CommandController.prototype.submit = function () {
54723                         var opt = [];
54724                         angular.forEach(this.options, function (option) {
54725                             var obj = {
54726                                 name: option.option,
54727                                 arguments: []
54728                             };
54729                             angular.forEach(option.arg, function (arg) {
54730                                 if (arg.input) {
54731                                     if (typeof arg.input === 'object') {
54732                                         obj.arguments.push(arg.input.name);
54733                                     }
54734                                     else {
54735                                         obj.arguments.push(arg.input);
54736                                     }
54737                                 }
54738                             });
54739                             if (obj.arguments.length > 0) {
54740                                 opt.push(obj);
54741                             }
54742                         });
54743                         var execObj = {
54744                             command: this.name,
54745                             workspace: this.workspace.fileId,
54746                             options: opt
54747                         };
54748                         this.APIEndPoint
54749                             .execute(JSON.stringify(execObj))
54750                             .then(function (result) {
54751                             console.log(result);
54752                         });
54753                     };
54754                     CommandController.prototype.removeMySelf = function (index) {
54755                         this.$scope.$destroy();
54756                         this.Console.removeDirective(this.uuid);
54757                         this.remove()(index, this.list);
54758                         this.Console.showIDs();
54759                     };
54760                     CommandController.prototype.reloadFiles = function () {
54761                         var _this = this;
54762                         var fileId = this.workspace.fileId;
54763                         this.APIEndPoint
54764                             .getFiles(fileId)
54765                             .$promise
54766                             .then(function (result) {
54767                             var status = result.status;
54768                             if (status === 'success') {
54769                                 _this.files = result.info;
54770                             }
54771                             else {
54772                                 console.log(result.message);
54773                             }
54774                         });
54775                     };
54776                     CommandController.prototype.debug = function () {
54777                         var div = angular.element(this.$window.document).find("div");
54778                         var consoleTag;
54779                         var parametersTag;
54780                         angular.forEach(div, function (v) {
54781                             if (v.className === "panel-body console") {
54782                                 consoleTag = v;
54783                             }
54784                             else if (v.className === "row parameters-console") {
54785                                 parametersTag = v;
54786                             }
54787                         });
54788                         var consoleHeight = parseInt(parametersTag.clientHeight.toString().replace('px', '')) - 150 + 'px';
54789                         var consoleWidth = parseInt(parametersTag.clientWidth.toString().replace('px', '')) / 3 * 2 - 150 + 'px';
54790                         consoleTag.style.height = consoleHeight;
54791                         consoleTag.style.width = consoleWidth;
54792                     };
54793                     CommandController.prototype.help = function () {
54794                         this.APIEndPoint
54795                             .help(this.name)
54796                             .then(function (result) {
54797                             console.log(result);
54798                         });
54799                     };
54800                     CommandController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
54801                     return CommandController;
54802                 })();
54803                 directives.CommandController = CommandController;
54804             })(directives = app.directives || (app.directives = {}));
54805         })(app || (app = {}));
54806         var app;
54807         (function (app) {
54808             var directives;
54809             (function (directives) {
54810                 var HeaderMenu = (function () {
54811                     function HeaderMenu() {
54812                         this.restrict = 'E';
54813                         this.replace = true;
54814                         this.templateUrl = 'templates/header-menu.html';
54815                         this.controller = 'HeaderMenuController';
54816                         this.controllerAs = 'hmc';
54817                         this.scope = true;
54818                     }
54819                     HeaderMenu.Factory = function () {
54820                         var directive = function () {
54821                             return new HeaderMenu();
54822                         };
54823                         return directive;
54824                     };
54825                     return HeaderMenu;
54826                 })();
54827                 directives.HeaderMenu = HeaderMenu;
54828                 var HeaderMenuController = (function () {
54829                     function HeaderMenuController($state) {
54830                         this.$state = $state;
54831                         this.isExecution = this.$state.current.name === 'execution';
54832                         this.isWorkspace = this.$state.current.name === 'workspace';
54833                         this.isHistory = this.$state.current.name === 'history';
54834                     }
54835                     HeaderMenuController.prototype.transit = function (state) {
54836                         this.$state.go(state);
54837                     };
54838                     HeaderMenuController.$inject = ['$state'];
54839                     return HeaderMenuController;
54840                 })();
54841                 directives.HeaderMenuController = HeaderMenuController;
54842             })(directives = app.directives || (app.directives = {}));
54843         })(app || (app = {}));
54844         var app;
54845         (function (app) {
54846             var directives;
54847             (function (directives) {
54848                 var Option = (function () {
54849                     function Option() {
54850                         this.restrict = 'E';
54851                         this.replace = true;
54852                         this.controller = 'optionController';
54853                         this.bindToController = {
54854                             info: '=',
54855                             files: '='
54856                         };
54857                         this.scope = true;
54858                         this.templateUrl = 'templates/option.html';
54859                         this.controllerAs = 'ctrl';
54860                     }
54861                     Option.Factory = function () {
54862                         var directive = function () {
54863                             return new Option();
54864                         };
54865                         directive.$inject = [];
54866                         return directive;
54867                     };
54868                     return Option;
54869                 })();
54870                 directives.Option = Option;
54871                 var OptionController = (function () {
54872                     function OptionController() {
54873                         var controller = this;
54874                         angular.forEach(controller.info.arg, function (arg) {
54875                             if (arg.initialValue) {
54876                                 if (arg.formType === 'number') {
54877                                     arg.input = parseInt(arg.initialValue);
54878                                 }
54879                                 else {
54880                                     arg.input = arg.initialValue;
54881                                 }
54882                             }
54883                         });
54884                     }
54885                     OptionController.$inject = [];
54886                     return OptionController;
54887                 })();
54888                 directives.OptionController = OptionController;
54889             })(directives = app.directives || (app.directives = {}));
54890         })(app || (app = {}));
54891         var app;
54892         (function (app) {
54893             var directives;
54894             (function (directives) {
54895                 var Directory = (function () {
54896                     function Directory() {
54897                         this.restrict = 'E';
54898                         this.replace = true;
54899                         this.controller = 'directoryController';
54900                         this.controllerAs = 'ctrl';
54901                         this.bindToController = {
54902                             info: '=',
54903                             add: '&',
54904                             list: '=',
54905                             files: '='
54906                         };
54907                         this.templateUrl = 'templates/directory.html';
54908                     }
54909                     Directory.Factory = function () {
54910                         var directive = function () {
54911                             return new Directory();
54912                         };
54913                         return directive;
54914                     };
54915                     return Directory;
54916                 })();
54917                 directives.Directory = Directory;
54918                 var DirectoryController = (function () {
54919                     function DirectoryController(APIEndPoint, $scope) {
54920                         this.APIEndPoint = APIEndPoint;
54921                         this.$scope = $scope;
54922                         var controller = this;
54923                         this.APIEndPoint
54924                             .getFiles(this.info.fileId)
54925                             .$promise
54926                             .then(function (result) {
54927                             if (result.status === 'success') {
54928                                 controller.files = result.info;
54929                                 angular.forEach(result.info, function (file) {
54930                                     if (file.fileType === '0') {
54931                                         var o = file;
54932                                         if (controller.info.path === '/') {
54933                                             o.path = '/' + file.name;
54934                                         }
54935                                         else {
54936                                             o.path = controller.info.path + '/' + file.name;
54937                                         }
54938                                         controller.add()(o, controller.list);
54939                                     }
54940                                 });
54941                             }
54942                             ;
54943                         });
54944                     }
54945                     DirectoryController.$inject = ['APIEndPoint', '$scope'];
54946                     return DirectoryController;
54947                 })();
54948                 directives.DirectoryController = DirectoryController;
54949             })(directives = app.directives || (app.directives = {}));
54950         })(app || (app = {}));
54951         var app;
54952         (function (app) {
54953             var directives;
54954             (function (directives) {
54955                 var Upload = (function () {
54956                     function Upload() {
54957                         this.restrict = 'E';
54958                         this.replace = true;
54959                         this.scope = true;
54960                         this.controller = 'UploadController';
54961                         this.controllerAs = 'ctrl';
54962                         this.bindToController = {
54963                             index: '=',
54964                             name: '=',
54965                             remove: '&',
54966                             list: '='
54967                         };
54968                         this.templateUrl = 'templates/upload.html';
54969                         console.log("templates/upload.html-constructor");
54970                     }
54971                     Upload.Factory = function () {
54972                         var directive = function () {
54973                             return new Upload();
54974                         };
54975                         directive.$inject = [];
54976                         return directive;
54977                     };
54978                     return Upload;
54979                 })();
54980                 directives.Upload = Upload;
54981                 var UploadController = (function () {
54982                     function UploadController(APIEndPoint, $scope, MyModal, WebSocket, $window, $rootScope, Console) {
54983                         this.APIEndPoint = APIEndPoint;
54984                         this.$scope = $scope;
54985                         this.MyModal = MyModal;
54986                         this.WebSocket = WebSocket;
54987                         this.$window = $window;
54988                         this.$rootScope = $rootScope;
54989                         this.Console = Console;
54990                         var controller = this;
54991                         console.log("directive.upload-constructor");
54992                     }
54993                     UploadController.prototype.submit = function () {
54994                         console.log("submit: function not supported¥n");
54995                     };
54996                     UploadController.$inject = ['APIEndPoint', '$scope', 'MyModal', 'WebSocket', '$window', '$rootScope', 'Console'];
54997                     return UploadController;
54998                 })();
54999                 directives.UploadController = UploadController;
55000             })(directives = app.directives || (app.directives = {}));
55001         })(app || (app = {}));
55002         var app;
55003         (function (app) {
55004             var controllers;
55005             (function (controllers) {
55006                 var Execution = (function () {
55007                     function Execution(MyModal, $scope) {
55008                         this.MyModal = MyModal;
55009                         this.$scope = $scope;
55010                         this.commandInfoList = [];
55011                     }
55012                     ;
55013                     Execution.prototype.add = function () {
55014                         this.$scope.$broadcast('close');
55015                         var commandInfoList = this.commandInfoList;
55016                         var commandInstance = this.MyModal.selectCommand();
55017                         commandInstance
55018                             .result
55019                             .then(function (command) {
55020                             commandInfoList.push(new app.declares.CommandInfo(command));
55021                         });
55022                     };
55023                     Execution.prototype.open = function () {
55024                         var result = this.MyModal.open('SelectCommand');
55025                         console.log(result);
55026                     };
55027                     Execution.prototype.remove = function (index, list) {
55028                         list.splice(index, 1);
55029                     };
55030                     Execution.prototype.close = function () {
55031                         console.log("close");
55032                     };
55033                     Execution.$inject = ['MyModal', '$scope'];
55034                     return Execution;
55035                 })();
55036                 controllers.Execution = Execution;
55037             })(controllers = app.controllers || (app.controllers = {}));
55038         })(app || (app = {}));
55039         var app;
55040         (function (app) {
55041             var controllers;
55042             (function (controllers) {
55043                 var Workspace = (function () {
55044                     function Workspace($scope, APIEndPoint, MyModal) {
55045                         this.$scope = $scope;
55046                         this.APIEndPoint = APIEndPoint;
55047                         this.MyModal = MyModal;
55048                         this.directoryList = [];
55049                         var controller = this;
55050                         var directoryList = this.directoryList;
55051                         var o = {
55052                             fileId: '1f83f620-c1ed-11e5-9657-7942989daa00',
55053                             name: '',
55054                             parentId: '',
55055                             fileType: '',
55056                             createdAt: '',
55057                             updatedAt: '',
55058                             path: '/'
55059                         };
55060                         directoryList.push(o);
55061                     }
55062                     Workspace.prototype.addDirectory = function (info, directoryList) {
55063                         directoryList.push(info);
55064                     };
55065                     Workspace.prototype.upload = function () {
55066                         this.MyModal.upload();
55067                     };
55068                     Workspace.prototype.debug = function () {
55069                         this.MyModal.preview();
55070                     };
55071                     Workspace.$inject = ['$scope', 'APIEndPoint', 'MyModal'];
55072                     return Workspace;
55073                 })();
55074                 controllers.Workspace = Workspace;
55075             })(controllers = app.controllers || (app.controllers = {}));
55076         })(app || (app = {}));
55077         var app;
55078         (function (app) {
55079             var controllers;
55080             (function (controllers) {
55081                 var History = (function () {
55082                     function History($scope) {
55083                         this.page = "History";
55084                     }
55085                     History.$inject = ['$scope'];
55086                     return History;
55087                 })();
55088                 controllers.History = History;
55089             })(controllers = app.controllers || (app.controllers = {}));
55090         })(app || (app = {}));
55091         var app;
55092         (function (app) {
55093             var controllers;
55094             (function (controllers) {
55095                 var SelectCommand = (function () {
55096                     function SelectCommand($scope, APIEndPoint, $modalInstance) {
55097                         this.APIEndPoint = APIEndPoint;
55098                         this.$modalInstance = $modalInstance;
55099                         var controller = this;
55100                         this.APIEndPoint
55101                             .getTags()
55102                             .$promise.then(function (result) {
55103                             controller.tags = result.info;
55104                         });
55105                         this.APIEndPoint
55106                             .getCommands()
55107                             .$promise.then(function (result) {
55108                             controller.commands = result.info;
55109                         });
55110                         this.currentTag = 'all';
55111                     }
55112                     SelectCommand.prototype.changeTag = function (tag) {
55113                         this.currentTag = tag;
55114                     };
55115                     SelectCommand.prototype.selectCommand = function (command) {
55116                         this.$modalInstance.close(command);
55117                     };
55118                     SelectCommand.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
55119                     return SelectCommand;
55120                 })();
55121                 controllers.SelectCommand = SelectCommand;
55122             })(controllers = app.controllers || (app.controllers = {}));
55123         })(app || (app = {}));
55124         var app;
55125         (function (app) {
55126             var controllers;
55127             (function (controllers) {
55128                 var Upload = (function () {
55129                     function Upload($scope, APIEndPoint, $modalInstance) {
55130                         this.APIEndPoint = APIEndPoint;
55131                         this.$modalInstance = $modalInstance;
55132                         var controller = this;
55133                         console.log('controller.upload-controllers');
55134                     }
55135                     Upload.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
55136                     return Upload;
55137                 })();
55138                 controllers.Upload = Upload;
55139             })(controllers = app.controllers || (app.controllers = {}));
55140         })(app || (app = {}));
55141         var app;
55142         (function (app) {
55143             var controllers;
55144             (function (controllers) {
55145                 var Preview = (function () {
55146                     function Preview($scope, APIEndPoint, $modalInstance) {
55147                         this.APIEndPoint = APIEndPoint;
55148                         this.$modalInstance = $modalInstance;
55149                         var controller = this;
55150                         console.log('preview');
55151                     }
55152                     Preview.$inject = ['$scope', 'APIEndPoint', '$uibModalInstance'];
55153                     return Preview;
55154                 })();
55155                 controllers.Preview = Preview;
55156             })(controllers = app.controllers || (app.controllers = {}));
55157         })(app || (app = {}));
55158         var filters;
55159         (function (filters) {
55160             function Tag() {
55161                 return function (commands, tag) {
55162                     var result = [];
55163                     angular.forEach(commands, function (command) {
55164                         var flag = false;
55165                         angular.forEach(command.tags, function (value) {
55166                             if (tag === value)
55167                                 flag = true;
55168                         });
55169                         if (flag)
55170                             result.push(command);
55171                     });
55172                     return result;
55173                 };
55174             }
55175             filters.Tag = Tag;
55176         })(filters || (filters = {}));
55177         var app;
55178         (function (app) {
55179             'use strict';
55180             var appName = 'zephyr';
55181             app.zephyr = angular.module(appName, ['ui.router', 'ngResource', 'ui.bootstrap']);
55182             app.zephyr.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
55183                 $urlRouterProvider.otherwise('/execution');
55184                 $locationProvider.html5Mode({
55185                     enabled: true,
55186                     requireBase: false
55187                 });
55188                 $stateProvider
55189                     .state('execution', {
55190                     url: '/execution',
55191                     templateUrl: 'templates/execution.html',
55192                     controller: 'executionController',
55193                     controllerAs: 'c'
55194                 })
55195                     .state('workspace', {
55196                     url: '/workspace',
55197                     templateUrl: 'templates/workspace.html',
55198                     controller: 'workspaceController',
55199                     controllerAs: 'c'
55200                 })
55201                     .state('history', {
55202                     url: '/history',
55203                     templateUrl: 'templates/history.html',
55204                     controller: 'historyController',
55205                     controllerAs: 'c'
55206                 });
55207             });
55208             app.zephyr.service('APIEndPoint', app.services.APIEndPoint);
55209             app.zephyr.service('MyModal', app.services.MyModal);
55210             app.zephyr.service('WebSocket', app.services.WebSocket);
55211             app.zephyr.service('Console', app.services.Console);
55212             app.zephyr.filter('Tag', filters.Tag);
55213             app.zephyr.controller('selectCommandController', app.controllers.SelectCommand);
55214             app.zephyr.controller('previewController', app.controllers.Preview);
55215             app.zephyr.controller('uploadController', app.controllers.Upload);
55216             app.zephyr.controller('executionController', app.controllers.Execution);
55217             app.zephyr.controller('workspaceController', app.controllers.Workspace);
55218             app.zephyr.controller('historyController', app.controllers.History);
55219             app.zephyr.controller('commandController', app.directives.CommandController);
55220             app.zephyr.controller('optionController', app.directives.OptionController);
55221             app.zephyr.controller('directoryController', app.directives.DirectoryController);
55222             app.zephyr.controller('HeaderMenuController', app.directives.HeaderMenuController);
55223             app.zephyr.controller('uploadController', app.directives.UploadController);
55224             app.zephyr.directive('headerMenu', app.directives.HeaderMenu.Factory());
55225             app.zephyr.directive('command', app.directives.Command.Factory());
55226             app.zephyr.directive('option', app.directives.Option.Factory());
55227             app.zephyr.directive('directory', app.directives.Directory.Factory());
55228         })(app || (app = {}));
55229
55230
55231 /***/ }
55232 /******/ ]);