PageSourceSearch

https://z-edit.github.io/vendor.js

js z-edit.github.io collected 2026-10-03 10:14:03 UTC 1,905,174 bytes, 50,953 lines download raw bytes

1(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2/*
3 * angular-marked
4 * (c) 2014 - 2016 J. Harshbarger
5 * Licensed MIT
6 */
7
8/* global angular, marked */
9
10'use strict';
11
12var unindent = require('./strip-indent');
13
14  /**
15   * @ngdoc overview
16   * @name index
17   *
18   * @description
19   * AngularJS Markdown using [marked](https://github.com/chjj/marked).
20   *
21   * ## Why?
22   *
23   * I wanted to use [marked](https://github.com/chjj/marked) instead of [showdown](https://github.com/coreyti/showdown) as used in [angular-markdown-directive](https://github.com/btford/angular-markdown-directive) as well as expose the option to globally set defaults.
24   *
25   * ## How?
26   *
27   * - {@link hc.marked.directive:marked As a directive}
28   * - {@link hc.marked.service:marked As a service}
29   * - {@link hc.marked.service:markedProvider Set default options}
30   *
31   * @example
32
33      Convert markdown to html at run time.  For example:
34
35      <example module="app">
36        <file name="example.html">
37          <form ng-controller="MainController">
38            Markdown:<br />
39            <textarea ng-model="my_markdown" cols="60" rows="5" class="span8"></textarea><br />
40            Output:<br />
41            <div marked="my_markdown" />
42          </form>
43        </file>
44        <file  name="example.js">
45          function MainController($scope) {
46            $scope.my_markdown = "*This* **is** [markdown](https://daringfireball.net/projects/markdown/)";
47          }
48          angular.module('app', ['hc.marked']).controller('MainController', MainController);
49        </file>
50      </example>
51
52    *
53    */
54
55    /**
56     * @ngdoc overview
57     * @name hc.marked
58     * @description # angular-marked (core module)
59       # Installation
60      First include angular-marked.js in your HTML:
61
62      ```js
63        <script src="angular-marked.js">
64      ```
65
66      Then load the module in your application by adding it as a dependency:
67
68      ```js
69      angular.module('yourApp', ['hc.marked']);
70      ```
71
72      With that you're ready to get started!
73     */
74
75    /**
76    * @ngdoc service
77    * @name hc.marked.service:marked
78    * @requires $window
79    * @description
80    * A reference to the [marked](https://github.com/chjj/marked) parser.
81    *
82    * @example
83    <example module="app">
84      <file name="example.html">
85        <div ng-controller="MainController">
86          html: {{html}}
87        </div>
88      </file>
89      <file  name="example.js">
90        function MainController($scope, marked) {
91          $scope.html = marked('#TEST');
92        }
93        angular.module('app', ['hc.marked']).controller('MainController', MainController);
94      </file>
95    </example>
96   **/
97
98   /**
99   * @ngdoc service
100   * @name hc.marked.service:markedProvider
101   * @description
102   * Use `markedProvider` to change the default behavior of the {@link hc.marked.service:marked marked} service.
103   *
104   * @example
105
106    ## Example using [google-code-prettify syntax highlighter](https://code.google.com/p/google-code-prettify/) (must include google-code-prettify.js script).  Also works with [highlight.js Javascript syntax highlighter](http://highlightjs.org/).
107
108    <example module="myAppA">
109      <file name="exampleA.js">
110      angular.module('myAppA', ['hc.marked'])
111        .config(['markedProvider', function(markedProvider) {
112          markedProvider.setOptions({
113            gfm: true,
114            tables: true,
115            highlight: function (code) {
116              return prettyPrintOne(code);
117            }
118          });
119        }]);
120      </file>
121      <file name="exampleA.html">
122        <marked>
123        ```js
124        angular.module('myAppA', ['hc.marked'])
125          .config(['markedProvider', function(markedProvider) {
126            markedProvider.setOptions({
127              gfm: true,
128              tables: true,
129              highlight: function (code) {
130                return prettyPrintOne(code);
131              }
132            });
133          }]);
134        ```
135        </marked>
136      </file>
137    </example>
138
139    ## Example overriding the way custom markdown links are displayed
140
141    <example module="myAppB">
142      <file name="exampleB.js">
143      angular.module('myAppB', ['hc.marked'])
144        .config(['markedProvider', function(markedProvider) {
145          markedProvider.setRenderer({
146            link: function(href, title, text) {
147              return "<a href='" + href + "'" + (title ? " title='" + title + "'" : '') + " target='_blank'>
147" + text + "</a>";
148            }
149          });
150        }]);
151      </file>
152      <file name="exampleB.html">
153        <marked>
154          This is [an example](http://example.com/ "Title") inline link.
155          [This link](http://example.net/) has no title attribute.
156        </marked>
157      </file>
158    </example>
159  **/
160
161function markedProvider() {
162  var self = this;
163
164  /**
165   * @ngdoc method
166   * @name markedProvider#setRenderer
167   * @methodOf hc.marked.service:markedProvider
168   *
169   * @param {object} opts Default renderer options for [marked](https://github.com/chjj/marked#overriding-renderer-methods).
170   */
171
172  self.setRenderer = function (opts) {
173    this.renderer = opts;
174  };
175
176  /**
177   * @ngdoc method
178   * @name markedProvider#setOptions
179   * @methodOf hc.marked.service:markedProvider
180   *
181   * @param {object} opts Default options for [marked](https://github.com/chjj/marked#options-1).
182   */
183
184  self.setOptions = function (opts) {  // Store options for later
185    this.defaults = opts;
186  };
187
188  self.$get = ['$log', '$window', function ($log, $window) {
189    var m;
190
191    try {
192      m = require('marked');
193    } catch (err) {
194      m = $window.marked || marked;
195    }
196
197    if (angular.isUndefined(m)) {
198      $log.error('angular-marked Error: marked not loaded.  See installation instructions.');
199      return;
200    }
201
202    var r = new m.Renderer();
203
204    // override rendered markdown html
205    // with custom definitions if defined
206    if (self.renderer) {
207      var o = Object.keys(self.renderer);
208      var l = o.length;
209
210      while (l--) {
211        r[o[l]] = self.renderer[o[l]];
212      }
213    }
214
215    // Customize code and codespan rendering to wrap default or overriden output in a ng-non-bindable span
216    function wrapNonBindable(string) {
217      return '<span ng-non-bindable>' + string + '</span>';
218    }
219
220    var renderCode = r.code.bind(r);
221    r.code = function (code, lang, escaped) {
222      return wrapNonBindable(renderCode(code, lang, escaped));
223    };
224    var renderCodespan = r.codespan.bind(r);
225    r.codespan = function (code) {
226      return wrapNonBindable(renderCodespan(code));
227    };
228
229    // add the new renderer to the options if need be
230    self.defaults = self.defaults || {};
231    self.defaults.renderer = r;
232
233    m.setOptions(self.defaults);
234
235    return m;
236  }];
237}
238
239  // xTODO: filter and tests */
240  // app.filter('marked', ['marked', function(marked) {
241  //   return marked;
242  // }]);
243
244  /**
245   * @ngdoc directive
246   * @name hc.marked.directive:marked
247   * @restrict AE
248   * @element any
249   *
250   * @description
251   * Compiles source test into HTML.
252   *
253   * @param {expression=} marked The source text to be compiled.  If blank uses content as the source.
254   * @param {expression=} opts Hash of options that override defaults.
255   * @param {boolean=} compile Set to true to to support AngularJS directives inside markdown.
256   * @param {string=} src Expression evaluating to URL. If the source is a string constant,
257   *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
258   *
259   * @example
260
261     ## A simple block of text
262
263      <example module="hc.marked">
264        <file name="exampleA.html">
265         * <marked>
266         *   ### Markdown directive
267         *
268         *   *It works!*
269         *
270         *   *This* **is** [markdown](https://daringfireball.net/projects/markdown/) in the view.
271         * </marked>
272        </file>
273      </example>
274
275     ## Bind to a scope variable
276
277      <example module="app">
278        <file name="exampleB.html">
279          <form ng-controller="MainController">
280            Markdown:<br />
281            <textarea ng-model="my_markdown" class="span8" cols="60" rows="5"></textarea><br />
282            Output:<br />
283            <blockquote marked="my_markdown"></blockquote>
284          </form>
285        </file>
286        <file  name="exampleB.js">
287          * function MainController($scope) {
288          *     $scope.my_markdown = '*This* **is** [markdown](https://daringfireball.net/projects/markdown/)';
289          *     $scope.my_markdown += ' in a scope variable';
290          * }
291          * angular.module('app', ['hc.marked']).controller('MainController', MainController);
292        </file>
293      </example>
294
295      ## Include a markdown file:
296
297       <example module="hc.marked">
298         <file name="exampleC.html">
299           <div marked src="'include.html'" />
300         </file>
301         * <file name="include.html">
302         * *This* **is** [markdown](https://daringfireball.net/projects/markdown/) in a include file.
303         * </file>
304       </example>
305   */
306markedDirective.$inject = ['marked', '$templateRequest', '$compile'];
307function markedDirective(marked, $templateRequest, $compile) {
308  return {
309    restrict: 'AE',
310    replace: true,
311    scope: {
312      opts: '=',
313      marked: '=',
314      compile: '@',
315      src: '='
316    },
317    link: function (scope, element, attrs) {
318      if (attrs.marked) {
319        set(scope.marked);
320        scope.$watch('marked', set);
321      } else if (attrs.src) {
322        scope.$watch('src', function (src) {
323          $templateRequest(src, true).then(function (response) {
324            set(response);
325          }, function () {
326            set('');
327            scope.$emit('$markedIncludeError', attrs.src);
328          });
329        });
330      } else {
331        set(element.text());
332      }
333
334      function set(text) {
335        text = unindent(String(text || ''));
336        element.html(marked(text, scope.opts || null));
337        if (scope.$eval(attrs.compile)) {
338          $compile(element.contents())(scope.$parent);
339        }
340      }
341    }
342  };
343}
344
345module.exports =
346  angular.module('hc.marked', [])
347    .directive('marked', markedDirective)
348    .provider('marked', markedProvider)
349    .name;
350
351},{"./strip-indent":2,"marked":11}],2:[function(require,module,exports){
352module.exports = function unindent(text) {
353  if (!text) {
354    return text;
355  }
356
357  var lines = text
358    .replace(/\t/g, '  ')
359    .split(/\r?\n/);
360
361  var min = null;
362  var len = lines.length;
363  var i;
364
365  for (i = 0; i < len; i++) {
366    var line = lines[i];
367    var l = line.match(/^(\s*)/)[0].length;
368    if (l === line.length) {
369      continue;
370    }
371    min = (l < min || min === null) ? l : min;
372  }
373
374  if (min !== null && min > 0) {
375    for (i = 0; i < len; i++) {
376      lines[i] = lines[i].substr(min);
377    }
378  }
379  return lines.join('\n');
380};
381
382},{}],3:[function(require,module,exports){
383/**
384 * State-based routing for AngularJS
385 * @version v0.4.3
386 * @link http://angular-ui.github.com/
387 * @license MIT License, http://www.opensource.org/licenses/MIT
388 */
389
390/* commonjs package manager support (eg componentjs) */
391if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
392  module.exports = 'ui.router';
393}
394
395(function (window, angular, undefined) {
396/*jshint globalstrict:true*/
397/*global angular:false*/
398'use strict';
399
400var isDefined = angular.isDefined,
401    isFunction = angular.isFunction,
402    isString = angular.isString,
403    isObject = angular.isObject,
404    isArray = angular.isArray,
405    forEach = angular.forEach,
406    extend = angular.extend,
407    copy = angular.copy,
408    toJson = angular.toJson;
409
410function inherit(parent, extra) {
411  return extend(new (extend(function() {}, { prototype: parent }))(), extra);
412}
413
414function merge(dst) {
415  forEach(arguments, function(obj) {
416    if (obj !== dst) {
417      forEach(obj, function(value, key) {
418        if (!dst.hasOwnProperty(key)) dst[key] = value;
419      });
420    }
421  });
422  return dst;
423}
424
425/**
426 * Finds the common ancestor path between two states.
427 *
428 * @param {Object} first The first state.
429 * @param {Object} second The second state.
430 * @return {Array} Returns an array of state names in descending order, not including the root.
431 */
432function ancestors(first, second) {
433  var path = [];
434
435  for (var n in first.path) {
436    if (first.path[n] !== second.path[n]) break;
437    path.push(first.path[n]);
438  }
439  return path;
440}
441
442/**
443 * IE8-safe wrapper for `Object.keys()`.
444 *
445 * @param {Object} object A JavaScript object.
446 * @return {Array} Returns the keys of the object as an array.
447 */
448function objectKeys(object) {
449  if (Object.keys) {
450    return Object.keys(object);
451  }
452  var result = [];
453
454  forEach(object, function(val, key) {
455    result.push(key);
456  });
457  return result;
458}
459
460/**
461 * IE8-safe wrapper for `Array.prototype.indexOf()`.
462 *
463 * @param {Array} array A JavaScript array.
464 * @param {*} value A value to search the array for.
465 * @return {Number} Returns the array index value of `value`, or `-1` if not present.
466 */
467function indexOf(array, value) {
468  if (Array.prototype.indexOf) {
469    return array.indexOf(value, Number(arguments[2]) || 0);
470  }
471  var len = array.length >>> 0, from = Number(arguments[2]) || 0;
472  from = (from < 0) ? Math.ceil(from) : Math.floor(from);
473
474  if (from < 0) from += len;
475
476  for (; from < len; from++) {
477    if (from in array && array[from] === value) return from;
478  }
479  return -1;
480}
481
482/**
483 * Merges a set of parameters with all parameters inherited between the common parents of the
484 * current state and a given destination state.
485 *
486 * @param {Object} currentParams The value of the current state parameters ($stateParams).
487 * @param {Object} newParams The set of parameters which will be composited with inherited params.
488 * @param {Object} $current Internal definition of object representing the current state.
489 * @param {Object} $to Internal definition of object representing state to transition to.
490 */
491function inheritParams(currentParams, newParams, $current, $to) {
492  var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
493
494  for (var i in parents) {
495    if (!parents[i] || !parents[i].params) continue;
496    parentParams = objectKeys(parents[i].params);
497    if (!parentParams.length) continue;
498
499    for (var j in parentParams) {
500      if (indexOf(inheritList, parentParams[j]) >= 0) continue;
501      inheritList.push(parentParams[j]);
502      inherited[parentParams[j]] = currentParams[parentParams[j]];
503    }
504  }
505  return extend({}, inherited, newParams);
506}
507
508/**
509 * Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
510 *
511 * @param {Object} a The first object.
512 * @param {Object} b The second object.
513 * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
514 *                     it defaults to the list of keys in `a`.
515 * @return {Boolean} Returns `true` if the keys match, otherwise `false`.
516 */
517function equalForKeys(a, b, keys) {
518  if (!keys) {
519    keys = [];
520    for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
521  }
522
523  for (var i=0; i<keys.length; i++) {
524    var k = keys[i];
525    if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
526  }
527  return true;
528}
529
530/**
531 * Returns the subset of an object, based on a list of keys.
532 *
533 * @param {Array} keys
534 * @param {Object} values
535 * @return {Boolean} Returns a subset of `values`.
536 */
537function filterByKeys(keys, values) {
538  var filtered = {};
539
540  forEach(keys, function (name) {
541    filtered[name] = values[name];
542  });
543  return filtered;
544}
545
546// like _.indexBy
547// when you know that your index values will be unique, or you want last-one-in to win
548function indexBy(array, propName) {
549  var result = {};
550  forEach(array, function(item) {
551    result[item[propName]] = item;
552  });
553  return result;
554}
555
556// extracted from underscore.js
557// Return a copy of the object only containing the whitelisted properties.
558function pick(obj) {
559  var copy = {};
560  var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
561  forEach(keys, function(key) {
562    if (key in obj) copy[key] = obj[key];
563  });
564  return copy;
565}
566
567// extracted from underscore.js
568// Return a copy of the object omitting the blacklisted properties.
569function omit(obj) {
570  var copy = {};
571  var keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
572  for (var key in obj) {
573    if (indexOf(keys, key) == -1) copy[key] = obj[key];
574  }
575  return copy;
576}
577
578function pluck(collection, key) {
579  var result = isArray(collection) ? [] : {};
580
581  forEach(collection, function(val, i) {
582    result[i] = isFunction(key) ? key(val) : val[key];
583  });
584  return result;
585}
586
587function filter(collection, callback) {
588  var array = isArray(collection);
589  var result = array ? [] : {};
590  forEach(collection, function(val, i) {
591    if (callback(val, i)) {
592      result[array ? result.length : i] = val;
593    }
594  });
595  return result;
596}
597
598function map(collection, callback) {
599  var result = isArray(collection) ? [] : {};
600
601  forEach(collection, function(val, i) {
602    result[i] = callback(val, i);
603  });
604  return result;
605}
606
607// issue #2676 #2889
608function silenceUncaughtInPromise (promise) {
609  return promise.then(undefined, function() {}) && promise;
610}
611
612/**
613 * @ngdoc overview
614 * @name ui.router.util
615 *
616 * @description
617 * # ui.router.util sub-module
618 *
619 * This module is a dependency of other sub-modules. Do not include this module as a dependency
620 * in your angular app (use {@link ui.router} module instead).
621 *
622 */
623angular.module('ui.router.util', ['ng']);
624
625/**
626 * @ngdoc overview
627 * @name ui.router.router
628 * 
629 * @requires ui.router.util
630 *
631 * @description
632 * # ui.router.router sub-module
633 *
634 * This module is a dependency of other sub-modules. Do not include this module as a dependency
635 * in your angular app (use {@link ui.router} module instead).
636 */
637angular.module('ui.router.router', ['ui.router.util']);
638
639/**
640 * @ngdoc overview
641 * @name ui.router.state
642 * 
643 * @requires ui.router.router
644 * @requires ui.router.util
645 *
646 * @description
647 * # ui.router.state sub-module
648 *
649 * This module is a dependency of the main ui.router module. Do not include this module as a dependency
650 * in your angular app (use {@link ui.router} module instead).
651 * 
652 */
653angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
654
655/**
656 * @ngdoc overview
657 * @name ui.router
658 *
659 * @requires ui.router.state
660 *
661 * @description
662 * # ui.router
663 * 
664 * ## The main module for ui.router 
665 * There are several sub-modules included with the ui.router module, however only this module is needed
666 * as a dependency within your angular app. The other modules are for organization purposes. 
667 *
668 * The modules are:
669 * * ui.router - the main "umbrella" module
670 * * ui.router.router - 
671 * 
672 * *You'll need to include **only** this module as the dependency within your angular app.*
673 * 
674 * <pre>
675 * <!doctype html>
676 * <html ng-app="myApp">
677 * <head>
678 *   <script src="js/angular.js"></script>
679 *   <!-- Include the ui-router script -->
680 *   <script src="js/angular-ui-router.min.js"></script>
681 *   <script>
682 *     // ...and add 'ui.router' as a dependency
683 *     var myApp = angular.module('myApp', ['ui.router']);
684 *   </script>
685 * </head>
686 * <body>
687 * </body>
688 * </html>
689 * </pre>
690 */
691angular.module('ui.router', ['ui.router.state']);
692
693angular.module('ui.router.compat', ['ui.router']);
694
695/**
696 * @ngdoc object
697 * @name ui.router.util.$resolve
698 *
699 * @requires $q
700 * @requires $injector
701 *
702 * @description
703 * Manages resolution of (acyclic) graphs of promises.
704 */
705$Resolve.$inject = ['$q', '$injector'];
706function $Resolve(  $q,    $injector) {
707  
708  var VISIT_IN_PROGRESS = 1,
709      VISIT_DONE = 2,
710      NOTHING = {},
711      NO_DEPENDENCIES = [],
712      NO_LOCALS = NOTHING,
713      NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
714  
715
716  /**
717   * @ngdoc function
718   * @name ui.router.util.$resolve#study
719   * @methodOf ui.router.util.$resolve
720   *
721   * @description
722   * Studies a set of invocables that are likely to be used multiple times.
723   * <pre>
724   * $resolve.study(invocables)(locals, parent, self)
725   * </pre>
726   * is equivalent to
727   * <pre>
728   * $resolve.resolve(invocables, locals, parent, self)
729   * </pre>
730   * but the former is more efficient (in fact `resolve` just calls `study` 
731   * internally).
732   *
733   * @param {object} invocables Invocable objects
734   * @return {function} a function to pass in locals, parent and self
735   */
736  this.study = function (invocables) {
737    if (!isObject(invocables)) throw new Error("'invocables' must be an object");
738    var invocableKeys = objectKeys(invocables || {});
739    
740    // Perform a topological sort of invocables to build an ordered plan
741    var plan = [], cycle = [], visited = {};
742    function visit(value, key) {
743      if (visited[key] === VISIT_DONE) return;
744      
745      cycle.push(key);
746      if (visited[key] === VISIT_IN_PROGRESS) {
747        cycle.splice(0, indexOf(cycle, key));
748        throw new Error("Cyclic dependency: " + cycle.join(" -> "));
749      }
750      visited[key] = VISIT_IN_PROGRESS;
751      
752      if (isString(value)) {
753        plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
754      } else {
755        var params = $injector.annotate(value);
756        forEach(params, function (param) {
757          if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
758        });
759        plan.push(key, value, params);
760      }
761      
762      cycle.pop();
763      visited[key] = VISIT_DONE;
764    }
765    forEach(invocables, visit);
766    invocables = cycle = visited = null; // plan is all that's required
767    
768    function isResolve(value) {
769      return isObject(value) && value.then && value.$$promises;
770    }
771    
772    return function (locals, parent, self) {
773      if (isResolve(locals) && self === undefined) {
774        self = parent; parent = locals; locals = null;
775      }
776      if (!locals) locals = NO_LOCALS;
777      else if (!isObject(locals)) {
778        throw new Error("'locals' must be an object");
779      }       
780      if (!parent) parent = NO_PARENT;
781      else if (!isResolve(parent)) {
782        throw new Error("'parent' must be a promise returned by $resolve.resolve()");
783      }
784      
785      // To complete the overall resolution, we have to wait for the parent
786      // promise and for the promise for each invokable in our plan.
787      var resolution = $q.defer(),
788          result = silenceUncaughtInPromise(resolution.promise),
789          promises = result.$$promises = {},
790          values = extend({}, locals),
791          wait = 1 + plan.length/3,
792          merged = false;
793
794      silenceUncaughtInPromise(result);
795          
796      function done() {
797        // Merge parent values we haven't got yet and publish our own $$values
798        if (!--wait) {
799          if (!merged) merge(values, parent.$$values); 
800          result.$$values = values;
801          result.$$promises = result.$$promises || true; // keep for isResolve()
802          delete result.$$inheritedValues;
803          resolution.resolve(values);
804        }
805      }
806      
807      function fail(reason) {
808        result.$$failure = reason;
809        resolution.reject(reason);
810      }
811
812      // Short-circuit if parent has already failed
813      if (isDefined(parent.$$failure)) {
814        fail(parent.$$failure);
815        return result;
816      }
817      
818      if (parent.$$inheritedValues) {
819        merge(values, omit(parent.$$inheritedValues, invocableKeys));
820      }
821
822      // Merge parent values if the parent has already resolved, or merge
823      // parent promises and wait if the parent resolve is still in progress.
824      extend(promises, parent.$$promises);
825      if (parent.$$values) {
826        merged = merge(values, omit(parent.$$values, invocableKeys));
827        result.$$inheritedValues = omit(parent.$$values, invocableKeys);
828        done();
829      } else {
830        if (parent.$$inheritedValues) {
831          result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys);
832        }        
833        parent.then(done, fail);
834      }
835      
836      // Process each invocable in the plan, but ignore any where a local of the same name exists.
837      for (var i=0, ii=plan.length; i<ii; i+=3) {
838        if (locals.hasOwnProperty(plan[i])) done();
839        else invoke(plan[i], plan[i+1], plan[i+2]);
840      }
841      
842      function invoke(key, invocable, params) {
843        // Create a deferred for this invocation. Failures will propagate to the resolution as well.
844        var invocation = $q.defer(), waitParams = 0;
845        function onfailure(reason) {
846          invocation.reject(reason);
847          fail(reason);
848        }
849        // Wait for any parameter that we have a promise for (either from parent or from this
850        // resolve; in that case study() will have made sure it's ordered before us in the plan).
851        forEach(params, function (dep) {
852          if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
853            waitParams++;
854            promises[dep].then(function (result) {
855              values[dep] = result;
856              if (!(--waitParams)) proceed();
857            }, onfailure);
858          }
859        });
860        if (!waitParams) proceed();
861        function proceed() {
862          if (isDefined(result.$$failure)) return;
863          try {
864            invocation.resolve($injector.invoke(invocable, self, values));
865            invocation.promise.then(function (result) {
866              values[key] = result;
867              done();
868            }, onfailure);
869          } catch (e) {
870            onfailure(e);
871          }
872        }
873        // Publish promise synchronously; invocations further down in the plan may depend on it.
874        promises[key] = silenceUncaughtInPromise(invocation.promise);
875      }
876      
877      return result;
878    };
879  };
880  
881  /**
882   * @ngdoc function
883   * @name ui.router.util.$resolve#resolve
884   * @methodOf ui.router.util.$resolve
885   *
886   * @description
887   * Resolves a set of invocables. An invocable is a function to be invoked via 
888   * `$injector.invoke()`, and can have an arbitrary number of dependencies. 
889   * An invocable can either return a value directly,
890   * or a `$q` promise. If a promise is returned it will be resolved and the 
891   * resulting value will be used instead. Dependencies of invocables are resolved 
892   * (in this order of precedence)
893   *
894   * - from the specified `locals`
895   * - from another invocable that is part of this `$resolve` call
896   * - from an invocable that is inherited from a `parent` call to `$resolve` 
897   *   (or recursively
898   * - from any ancestor `$resolve` of that parent).
899   *
900   * The return value of `$resolve` is a promise for an object that contains 
901   * (in this order of precedence)
902   *
903   * - any `locals` (if specified)
904   * - the resolved return values of all injectables
905   * - any values inherited from a `parent` call to `$resolve` (if specified)
906   *
907   * The promise will resolve after the `parent` promise (if any) and all promises 
908   * returned by injectables have been resolved. If any invocable 
909   * (or `$injector.invoke`) throws an exception, or if a promise returned by an 
910   * invocable is rejected, the `$resolve` promise is immediately rejected with the 
911   * same error. A rejection of a `parent` promise (if specified) will likewise be 
912   * propagated immediately. Once the `$resolve` promise has been rejected, no 
913   * further invocables will be called.
914   * 
915   * Cyclic dependencies between invocables are not permitted and will cause `$resolve`
916   * to throw an error. As a special case, an injectable can depend on a parameter 
917   * with the same name as the injectable, which will be fulfilled from the `parent` 
918   * injectable of the same name. This allows inherited values to be decorated. 
919   * Note that in this case any other injectable in the same `$resolve` with the same
920   * dependency would see the decorated value, not the inherited value.
921   *
922   * Note that missing dependencies -- unlike cyclic dependencies -- will cause an 
923   * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous) 
924   * exception.
925   *
926   * Invocables are invoked eagerly as soon as all dependencies are available. 
927   * This is true even for dependencies inherited from a `parent` call to `$resolve`.
928   *
929   * As a special case, an invocable can be a string, in which case it is taken to 
930   * be a service name to be passed to `$injector.get()`. This is supported primarily 
931   * for backwards-compatibility with the `resolve` property of `$routeProvider` 
932   * routes.
933   *
934   * @param {object} invocables functions to invoke or 
935   * `$injector` services to fetch.
936   * @param {object} locals  values to make available to the injectables
937   * @param {object} parent  a promise returned by another call to `$resolve`.
938   * @param {object} self  the `this` for the invoked methods
939   * @return {object} Promise for an object that contains the resolved return value
940   * of all invocables, as well as any inherited and local values.
941   */
942  this.resolve = function (invocables, locals, parent, self) {
943    return this.study(invocables)(locals, parent, self);
944  };
945}
946
947angular.module('ui.router.util').service('$resolve', $Resolve);
948
949
950
951/**
952 * @ngdoc object
953 * @name ui.router.util.$templateFactoryProvider
954 *
955 * @description
956 * Provider for $templateFactory. Manages which template-loading mechanism to
957 * use, and will default to the most recent one ($templateRequest on Angular
958 * versions starting from 1.3, $http otherwise).
959 */
960function TemplateFactoryProvider() {
961  var shouldUnsafelyUseHttp = angular.version.minor < 3;
962
963  /**
964   * @ngdoc function
965   * @name ui.router.util.$templateFactoryProvider#shouldUnsafelyUseHttp
966   * @methodOf ui.router.util.$templateFactoryProvider
967   *
968   * @description
969   * Forces $templateFactory to use $http instead of $templateRequest. This
970   * might cause XSS, as $http doesn't enforce the regular security checks for
971   * templates that have been introduced in Angular 1.3. Note that setting this
972   * to false on Angular older than 1.3.x will crash, as the $templateRequest
973   * service (and the security checks) are not implemented on these versions.
974   *
975   * See the $sce documentation, section
976   * <a href="https://docs.angularjs.org/api/ng/service/$sce#impact-on-loading-templates">
977   * Impact on loading templates</a> for more details about this mechanism.
978   *
979   * @param {boolean} value
980   */
981  this.shouldUnsafelyUseHttp = function(value) {
982    shouldUnsafelyUseHttp = !!value;
983  };
984
985  /**
986   * @ngdoc object
987   * @name ui.router.util.$templateFactory
988   *
989   * @requires $http
990   * @requires $templateCache
991   * @requires $injector
992   *
993   * @description
994   * Service. Manages loading of templates.
995   */
996  this.$get = ['$http', '$templateCache', '$injector', function($http, $templateCache, $injector){
997    return new TemplateFactory($http, $templateCache, $injector, shouldUnsafelyUseHttp);}];
998}
999
1000
1001/**
1002 * @ngdoc object
1003 * @name ui.router.util.$templateFactory
1004 *
1005 * @requires $http
1006 * @requires $templateCache
1007 * @requires $injector
1008 *
1009 * @description
1010 * Service. Manages loading of templates.
1011 */
1012function TemplateFactory($http, $templateCache, $injector, shouldUnsafelyUseHttp) {
1013
1014  /**
1015   * @ngdoc function
1016   * @name ui.router.util.$templateFactory#fromConfig
1017   * @methodOf ui.router.util.$templateFactory
1018   *
1019   * @description
1020   * Creates a template from a configuration object. 
1021   *
1022   * @param {object} config Configuration object for which to load a template. 
1023   * The following properties are search in the specified order, and the first one 
1024   * that is defined is used to create the template:
1025   *
1026   * @param {string|object} config.template html string template or function to 
1027   * load via {@link ui.router.util.$templateFactory#fromString fromString}.
1028   * @param {string|object} config.templateUrl url to load or a function returning 
1029   * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}.
1030   * @param {Function} config.templateProvider function to invoke via 
1031   * {@link ui.router.util.$templateFactory#fromProvider fromProvider}.
1032   * @param {object} params  Parameters to pass to the template function.
1033   * @param {object} locals Locals to pass to `invoke` if the template is loaded 
1034   * via a `templateProvider`. Defaults to `{ params: params }`.
1035   *
1036   * @return {string|object}  The template html as a string, or a promise for 
1037   * that string,or `null` if no template is configured.
1038   */
1039  this.fromConfig = function (config, params, locals) {
1040    return (
1041      isDefined(config.template) ? this.fromString(config.template, params) :
1042      isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
1043      isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
1044      null
1045    );
1046  };
1047
1048  /**
1049   * @ngdoc function
1050   * @name ui.router.util.$templateFactory#fromString
1051   * @methodOf ui.router.util.$templateFactory
1052   *
1053   * @description
1054   * Creates a template from a string or a function returning a string.
1055   *
1056   * @param {string|object} template html template as a string or function that 
1057   * returns an html template as a string.
1058   * @param {object} params Parameters to pass to the template function.
1059   *
1060   * @return {string|object} The template html as a string, or a promise for that 
1061   * string.
1062   */
1063  this.fromString = function (template, params) {
1064    return isFunction(template) ? template(params) : template;
1065  };
1066
1067  /**
1068   * @ngdoc function
1069   * @name ui.router.util.$templateFactory#fromUrl
1070   * @methodOf ui.router.util.$templateFactory
1071   * 
1072   * @description
1073   * Loads a template from the a URL via `$http` and `$templateCache`.
1074   *
1075   * @param {string|Function} url url of the template to load, or a function 
1076   * that returns a url.
1077   * @param {Object} params Parameters to pass to the url function.
1078   * @return {string|Promise.<string>} The template html as a string, or a promise 
1079   * for that string.
1080   */
1081  this.fromUrl = function (url, params) {
1082    if (isFunction(url)) url = url(params);
1083    if (url == null) return null;
1084    else {
1085      if(!shouldUnsafelyUseHttp) {
1086        return $injector.get('$templateRequest')(url);
1087      } else {
1088        return $http
1089          .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }})
1090          .then(function(response) { return response.data; });
1091      }
1092    }
1093  };
1094
1095  /**
1096   * @ngdoc function
1097   * @name ui.router.util.$templateFactory#fromProvider
1098   * @methodOf ui.router.util.$templateFactory
1099   *
1100   * @description
1101   * Creates a template by invoking an injectable provider function.
1102   *
1103   * @param {Function} provider Function to invoke via `$injector.invoke`
1104   * @param {Object} params Parameters for the template.
1105   * @param {Object} locals Locals to pass to `invoke`. Defaults to 
1106   * `{ params: params }`.
1107   * @return {string|Promise.<string>} The template html as a string, or a promise 
1108   * for that string.
1109   */
1110  this.fromProvider = function (provider, params, locals) {
1111    return $injector.invoke(provider, null, locals || { params: params });
1112  };
1113}
1114
1115angular.module('ui.router.util').provider('$templateFactory', TemplateFactoryProvi
1115der);
1116
1117var $$UMFP; // reference to $UrlMatcherFactoryProvider
1118
1119/**
1120 * @ngdoc object
1121 * @name ui.router.util.type:UrlMatcher
1122 *
1123 * @description
1124 * Matches URLs against patterns and extracts named parameters from the path or the search
1125 * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
1126 * of search parameters. Multiple search parameter names are separated by '&'. Search parameters
1127 * do not influence whether or not a URL is matched, but their values are passed through into
1128 * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.
1129 *
1130 * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
1131 * syntax, which optionally allows a regular expression for the parameter to be specified:
1132 *
1133 * * `':'` name - colon placeholder
1134 * * `'*'` name - catch-all placeholder
1135 * * `'{' name '}'` - curly placeholder
1136 * * `'{' name ':' regexp|type '}'` - curly placeholder with regexp or type name. Should the
1137 *   regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.
1138 *
1139 * Parameter names may contain only word characters (latin letters, digits, and underscore) and
1140 * must be unique within the pattern (across both path and search parameters). For colon
1141 * placeholders or curly placeholders without an explicit regexp, a path parameter matches any
1142 * number of characters other than '/'. For catch-all placeholders the path parameter matches
1143 * any number of characters.
1144 *
1145 * Examples:
1146 *
1147 * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
1148 *   trailing slashes, and patterns have to match the entire path, not just a prefix.
1149 * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
1150 *   '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
1151 * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
1152 * * `'/user/{id:[^/]*}'` - Same as the previous example.
1153 * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
1154 *   parameter consists of 1 to 8 hex digits.
1155 * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
1156 *   path into the parameter 'path'.
1157 * * `'/files/*path'` - ditto.
1158 * * `'/calendar/{start:date}'` - Matches "/calendar/2014-11-12" (because the pattern defined
1159 *   in the built-in  `date` Type matches `2014-11-12`) and provides a Date object in $stateParams.start
1160 *
1161 * @param {string} pattern  The pattern to compile into a matcher.
1162 * @param {Object} config  A configuration object hash:
1163 * @param {Object=} parentMatcher Used to concatenate the pattern/config onto
1164 *   an existing UrlMatcher
1165 *
1166 * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
1167 * * `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`.
1168 *
1169 * @property {string} prefix  A static prefix of this pattern. The matcher guarantees that any
1170 *   URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns
1171 *   non-null) will start with this prefix.
1172 *
1173 * @property {string} source  The pattern that was passed into the constructor
1174 *
1175 * @property {string} sourcePath  The path portion of the source property
1176 *
1177 * @property {string} sourceSearch  The search portion of the source property
1178 *
1179 * @property {string} regex  The constructed regex that will be used to match against the url when
1180 *   it is time to determine which url will match.
1181 *
1182 * @returns {Object}  New `UrlMatcher` object
1183 */
1184function UrlMatcher(pattern, config, parentMatcher) {
1185  config = extend({ params: {} }, isObject(config) ? config : {});
1186
1187  // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
1188  //   '*' name
1189  //   ':' name
1190  //   '{' name '}'
1191  //   '{' name ':' regexp '}'
1192  // The regular expression is somewhat complicated due to the need to allow curly braces
1193  // inside the regular expression. The placeholder regexp breaks down as follows:
1194  //    ([:*])([\w\[\]]+)              - classic placeholder ($1 / $2) (search version has - for snake-case)
1195  //    \{([\w\[\]]+)(?:\:\s*( ... ))?\}  - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case
1196  //    (?: ... | ... | ... )+         - the regexp consists of any number of atoms, an atom being either
1197  //    [^{}\\]+                       - anything other than curly braces or backslash
1198  //    \\.                            - a backslash escape
1199  //    \{(?:[^{}\\]+|\\.)*\}          - a matched set of curly braces containing other atoms
1200  var placeholder       = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:\s*((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
1201      searchPlaceholder = /([:]?)([\w\[\].-]+)|\{([\w\[\].-]+)(?:\:\s*((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
1202      compiled = '^', last = 0, m,
1203      segments = this.segments = [],
1204      parentParams = parentMatcher ? parentMatcher.params : {},
1205      params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(),
1206      paramNames = [];
1207
1208  function addParameter(id, type, config, location) {
1209    paramNames.push(id);
1210    if (parentParams[id]) return parentParams[id];
1211    if (!/^\w+([-.]+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
1212    if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
1213    params[id] = new $$UMFP.Param(id, type, config, location);
1214    return params[id];
1215  }
1216
1217  function quoteRegExp(string, pattern, squash, optional) {
1218    var surroundPattern = ['',''], result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
1219    if (!pattern) return result;
1220    switch(squash) {
1221      case false: surroundPattern = ['(', ')' + (optional ? "?" : "")]; break;
1222      case true:
1223        result = result.replace(/\/$/, '');
1224        surroundPattern = ['(?:\/(', ')|\/)?'];
1225      break;
1226      default:    surroundPattern = ['(' + squash + "|", ')?']; break;
1227    }
1228    return result + surroundPattern[0] + pattern + surroundPattern[1];
1229  }
1230
1231  this.source = pattern;
1232
1233  // Split into static segments separated by path parameter placeholders.
1234  // The number of segments is always 1 more than the number of parameters.
1235  function matchDetails(m, isSearch) {
1236    var id, regexp, segment, type, cfg, arrayMode;
1237    id          = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
1238    cfg         = config.params[id];
1239    segment     = pattern.substring(last, m.index);
1240    regexp      = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null);
1241
1242    if (regexp) {
1243      type      = $$UMFP.type(regexp) || inherit($$UMFP.type("string"), { pattern: new RegExp(regexp, config.caseInsensitive ? 'i' : undefined) });
1244    }
1245
1246    return {
1247      id: id, regexp: regexp, segment: segment, type: type, cfg: cfg
1248    };
1249  }
1250
1251  var p, param, segment;
1252  while ((m = placeholder.exec(pattern))) {
1253    p = matchDetails(m, false);
1254    if (p.segment.indexOf('?') >= 0) break; // we're into the search part
1255
1256    param = addParameter(p.id, p.type, p.cfg, "path");
1257    compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash, param.isOptional);
1258    segments.push(p.segment);
1259    last = placeholder.lastIndex;
1260  }
1261  segment = pattern.substring(last);
1262
1263  // Find any search parameter names and remove them from the last segment
1264  var i = segment.indexOf('?');
1265
1266  if (i >= 0) {
1267    var search = this.sourceSearch = segment.substring(i);
1268    segment = segment.substring(0, i);
1269    this.sourcePath = pattern.substring(0, last + i);
1270
1271    if (search.length > 0) {
1272      last = 0;
1273      while ((m = searchPlaceholder.exec(search))) {
1274        p = matchDetails(m, true);
1275        param = addParameter(p.id, p.type, p.cfg, "search");
1276        last = placeholder.lastIndex;
1277        // check if ?&
1278      }
1279    }
1280  } else {
1281    this.sourcePath = pattern;
1282    this.sourceSearch = '';
1283  }
1284
1285  compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$';
1286  segments.push(segment);
1287
1288  this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
1289  this.prefix = segments[0];
1290  this.$$paramNames = paramNames;
1291}
1292
1293/**
1294 * @ngdoc function
1295 * @name ui.router.util.type:UrlMatcher#concat
1296 * @methodOf ui.router.util.type:UrlMatcher
1297 *
1298 * @description
1299 * Returns a new matcher for a pattern constructed by appending the path part and adding the
1300 * search parameters of the specified pattern to this pattern. The current pattern is not
1301 * modified. This can be understood as creating a pattern for URLs that are relative to (or
1302 * suffixes of) the current pattern.
1303 *
1304 * @example
1305 * The following two matchers are equivalent:
1306 * <pre>
1307 * new UrlMatcher('/user/{id}?q').concat('/details?date');
1308 * new UrlMatcher('/user/{id}/details?q&date');
1309 * </pre>
1310 *
1311 * @param {string} pattern  The pattern to append.
1312 * @param {Object} config  An object hash of the configuration for the matcher.
1313 * @returns {UrlMatcher}  A matcher for the concatenated pattern.
1314 */
1315UrlMatcher.prototype.concat = function (pattern, config) {
1316  // Because order of search parameters is irrelevant, we can add our own search
1317  // parameters to the end of the new pattern. Parse the new pattern by itself
1318  // and then join the bits together, but it's much easier to do this on a string level.
1319  var defaultConfig = {
1320    caseInsensitive: $$UMFP.caseInsensitive(),
1321    strict: $$UMFP.strictMode(),
1322    squash: $$UMFP.defaultSquashPolicy()
1323  };
1324  return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this);
1325};
1326
1327UrlMatcher.prototype.toString = function () {
1328  return this.source;
1329};
1330
1331/**
1332 * @ngdoc function
1333 * @name ui.router.util.type:UrlMatcher#exec
1334 * @methodOf ui.router.util.type:UrlMatcher
1335 *
1336 * @description
1337 * Tests the specified path against this matcher, and returns an object c
1337ontaining the captured
1338 * parameter values, or null if the path does not match. The returned object contains the values
1339 * of any search parameters that are mentioned in the pattern, but their value may be null if
1340 * they are not present in `searchParams`. This means that search parameters are always treated
1341 * as optional.
1342 *
1343 * @example
1344 * <pre>
1345 * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
1346 *   x: '1', q: 'hello'
1347 * });
1348 * // returns { id: 'bob', q: 'hello', r: null }
1349 * </pre>
1350 *
1351 * @param {string} path  The URL path to match, e.g. `$location.path()`.
1352 * @param {Object} searchParams  URL search parameters, e.g. `$location.search()`.
1353 * @returns {Object}  The captured parameter values.
1354 */
1355UrlMatcher.prototype.exec = function (path, searchParams) {
1356  var m = this.regexp.exec(path);
1357  if (!m) return null;
1358  searchParams = searchParams || {};
1359
1360  var paramNames = this.parameters(), nTotal = paramNames.length,
1361    nPath = this.segments.length - 1,
1362    values = {}, i, j, cfg, paramName;
1363
1364  if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
1365
1366  function decodePathArray(string) {
1367    function reverseString(str) { return str.split("").reverse().join(""); }
1368    function unquoteDashes(str) { return str.replace(/\\-/g, "-"); }
1369
1370    var split = reverseString(string).split(/-(?!\\)/);
1371    var allReversed = map(split, reverseString);
1372    return map(allReversed, unquoteDashes).reverse();
1373  }
1374
1375  var param, paramVal;
1376  for (i = 0; i < nPath; i++) {
1377    paramName = paramNames[i];
1378    param = this.params[paramName];
1379    paramVal = m[i+1];
1380    // if the param value matches a pre-replace pair, replace the value before decoding.
1381    for (j = 0; j < param.replace.length; j++) {
1382      if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;
1383    }
1384    if (paramVal && param.array === true) paramVal = decodePathArray(paramVal);
1385    if (isDefined(paramVal)) paramVal = param.type.decode(paramVal);
1386    values[paramName] = param.value(paramVal);
1387  }
1388  for (/**/; i < nTotal; i++) {
1389    paramName = paramNames[i];
1390    values[paramName] = this.params[paramName].value(searchParams[paramName]);
1391    param = this.params[paramName];
1392    paramVal = searchParams[paramName];
1393    for (j = 0; j < param.replace.length; j++) {
1394      if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;
1395    }
1396    if (isDefined(paramVal)) paramVal = param.type.decode(paramVal);
1397    values[paramName] = param.value(paramVal);
1398  }
1399
1400  return values;
1401};
1402
1403/**
1404 * @ngdoc function
1405 * @name ui.router.util.type:UrlMatcher#parameters
1406 * @methodOf ui.router.util.type:UrlMatcher
1407 *
1408 * @description
1409 * Returns the names of all path and search parameters of this pattern in an unspecified order.
1410 *
1411 * @returns {Array.<string>}  An array of parameter names. Must be treated as read-only. If the
1412 *    pattern has no parameters, an empty array is returned.
1413 */
1414UrlMatcher.prototype.parameters = function (param) {
1415  if (!isDefined(param)) return this.$$paramNames;
1416  return this.params[param] || null;
1417};
1418
1419/**
1420 * @ngdoc function
1421 * @name ui.router.util.type:UrlMatcher#validates
1422 * @methodOf ui.router.util.type:UrlMatcher
1423 *
1424 * @description
1425 * Checks an object hash of parameters to validate their correctness according to the parameter
1426 * types of this `UrlMatcher`.
1427 *
1428 * @param {Object} params The object hash of parameters to validate.
1429 * @returns {boolean} Returns `true` if `params` validates, otherwise `false`.
1430 */
1431UrlMatcher.prototype.validates = function (params) {
1432  return this.params.$$validates(params);
1433};
1434
1435/**
1436 * @ngdoc function
1437 * @name ui.router.util.type:UrlMatcher#format
1438 * @methodOf ui.router.util.type:UrlMatcher
1439 *
1440 * @description
1441 * Creates a URL that matches this pattern by substituting the specified values
1442 * for the path and search parameters. Null values for path parameters are
1443 * treated as empty strings.
1444 *
1445 * @example
1446 * <pre>
1447 * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
1448 * // returns '/user/bob?q=yes'
1449 * </pre>
1450 *
1451 * @param {Object} values  the values to substitute for the parameters in this pattern.
1452 * @returns {string}  the formatted URL (path and optionally search part).
1453 */
1454UrlMatcher.prototype.format = function (values) {
1455  values = values || {};
1456  var segments = this.segments, params = this.parameters(), paramset = this.params;
1457  if (!this.validates(values)) return null;
1458
1459  var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0];
1460
1461  function encodeDashes(str) { // Replace dashes with encoded "\-"
1462    return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCo
1462deAt(0).toString(16).toUpperCase(); });
1463  }
1464
1465  for (i = 0; i < nTotal; i++) {
1466    var isPathParam = i < nPath;
1467    var name = params[i], param = paramset[name], value = param.value(values[name]);
1468    var isDefaultValue = param.isOptional && param.type.equals(param.value(), value);
1469    var squash = isDefaultValue ? param.squash : false;
1470    var encoded = param.type.encode(value);
1471
1472    if (isPathParam) {
1473      var nextSegment = segments[i + 1];
1474      var isFinalPathParam = i + 1 === nPath;
1475
1476      if (squash === false) {
1477        if (encoded != null) {
1478          if (isArray(encoded)) {
1479            result += map(encoded, encodeDashes).join("-");
1480          } else {
1481            result += encodeURIComponent(encoded);
1482          }
1483        }
1484        result += nextSegment;
1485      } else if (squash === true) {
1486        var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/;
1487        result += nextSegment.match(capture)[1];
1488      } else if (isString(squash)) {
1489        result += squash + nextSegment;
1490      }
1491
1492      if (isFinalPathParam && param.squash === true && result.slice(-1) === '/') result = result.slice(0, -1);
1493    } else {
1494      if (encoded == null || (isDefaultValue && squash !== false)) continue;
1495      if (!isArray(encoded)) encoded = [ encoded ];
1496      if (encoded.length === 0) continue;
1497      encoded = map(encoded, encodeURIComponent).join('&' + name + '=');
1498      result += (search ? '&' : '?') + (name + '=' + encoded);
1499      search = true;
1500    }
1501  }
1502
1503  return result;
1504};
1505
1506/**
1507 * @ngdoc object
1508 * @name ui.router.util.type:Type
1509 *
1510 * @description
1511 * Implements an interface to define custom parameter types that can be decoded from and encoded to
1512 * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`}
1513 * objects when matching or formatting URLs, or comparing or validating parameter values.
1514 *
1515 * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more
1516 * information on registering custom types.
1517 *
1518 * @param {Object} config  A configuration object which contains the custom type definition.  The object's
1519 *        properties will override the default methods and/or pattern in `Type`'s public interface.
1520 * @example
1521 * <pre>
1522 * {
1523 *   decode: function(val) { return parseInt(val, 10); },
1524 *   encode: function(val) { return val && val.toString(); },
1525 *   equals: function(a, b) { return this.is(a) && a === b; },
1526 *   is: function(val) { return angular.isNumber(val) isFinite(val) && val % 1 === 0; },
1527 *   pattern: /\d+/
1528 * }
1529 * </pre>
1530 *
1531 * @property {RegExp} pattern The regular expression pattern used to match values of this type when
1532 *           coming from a substring of a URL.
1533 *
1534 * @returns {Object}  Returns a new `Type` object.
1535 */
1536function Type(config) {
1537  extend(this, config);
1538}
1539
1540/**
1541 * @ngdoc function
1542 * @name ui.router.util.type:Type#is
1543 * @methodOf ui.router.util.type:Type
1544 *
1545 * @description
1546 * Detects whether a value is of a particular type. Accepts a native (decoded) value
1547 * and determines whether it matches the current `Type` object.
1548 *
1549 * @param {*} val  The value to check.
1550 * @param {string} key  Optional. If the type check is happening in the context of a specific
1551 *        {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the
1552 *        parameter in which `val` is stored. Can be used for meta-programming of `Type` objects.
1553 * @returns {Boolean}  Returns `true` if the value matches the type, otherwise `false`.
1554 */
1555Type.prototype.is = function(val, key) {
1556  return true;
1557};
1558
1559/**
1560 * @ngdoc function
1561 * @name ui.router.util.type:Type#encode
1562 * @methodOf ui.router.util.type:Type
1563 *
1564 * @description
1565 * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the
1566 * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it
1567 * only needs to be a representation of `val` that has been coerced to a string.
1568 *
1569 * @param {*} val  The value to encode.
1570 * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
1571 *        meta-programming of `Type` objects.
1572 * @returns {string}  Returns a string representation of `val` that can be encoded in a URL.
1573 */
1574Type.prototype.encode = function(val, key) {
1575  return val;
1576};
1577
1578/**
1579 * @ngdoc function
1580 * @name ui.router.util.type:Type#decode
1581 * @methodOf ui.router.util.type:Type
1582 *
1583 * @description
1584 * Converts a parameter value (from URL string or transition param) to a custom/native value.
1585 *
1586 * @param {string} val  The URL parameter value to decode.
1587 * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
1588 *        meta-programming of `Type` objects.
1589 * @returns {*}  Returns a custom representation of the URL parameter value.
1590 */
1591Type.prototype.decode = function(val, key) {
1592  return val;
1593};
1594
1595/**
1596 * @ngdoc function
1597 * @name ui.router.util.type:Type#equals
1598 * @methodOf ui.router.util.type:Type
1599 *
1600 * @description
1601 * Determines whether two decoded values are equivalent.
1602 *
1603 * @param {*} a  A value to compare against.
1604 * @param {*} b  A value to compare against.
1605 * @returns {Boolean}  Returns `true` if the values are equivalent/equal, otherwise `false`.
1606 */
1607Type.prototype.equals = function(a, b) {
1608  return a == b;
1609};
1610
1611Type.prototype.$subPattern = function() {
1612  var sub = this.pattern.toString();
1613  return sub.substr(1, sub.length - 2);
1614};
1615
1616Type.prototype.pattern = /.*/;
1617
1618Type.prototype.toString = function() { return "{Type:" + this.name + "}"; };
1619
1620/** Given an encoded string, or a decoded object, returns a decoded object */
1621Type.prototype.$normalize = function(val) {
1622  return this.is(val) ? val : this.decode(val);
1623};
1624
1625/*
1626 * Wraps an existing custom Type as an array of Type, depending on 'mode'.
1627 * e.g.:
1628 * - urlmatcher pattern "/path?{queryParam[]:int}"
1629 * - url: "/path?queryParam=1&queryParam=2
1630 * - $stateParams.queryParam will be [1, 2]
1631 * if `mode` is "auto", then
1632 * - url: "/path?queryParam=1 will create $stateParams.queryParam: 1
1633 * - url: "/path?queryParam=1&queryParam=2 will create $stateParams.queryParam: [1, 2]
1634 */
1635Type.prototype.$asArray = function(mode, isSearch) {
1636  if (!mode) return this;
1637  if (mode === "auto" && !isSearch) throw new Error("'auto' array mode is for query parameters only");
1638
1639  function ArrayType(type, mode) {
1640    function bindTo(type, callbackName) {
1641      return function() {
1642        return type[callbackName].apply(type, arguments);
1643      };
1644    }
1645
1646    // Wrap non-array value as array
1647    function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); }
1648    // Unwrap array value for "auto" mode. Return undefined for empty array.
1649    function arrayUnwrap(val) {
1650      switch(val.length) {
1651        case 0: return undefined;
1652        case 1: return mode === "auto" ? val[0] : val;
1653        default: return val;
1654      }
1655    }
1656    function falsey(val) { return !val; }
1657
1658    // Wraps type (.is/.encode/.decode) functions to operate on each value of an array
1659    function arrayHandler(callback, allTruthyMode) {
1660      return function handleArray(val) {
1661        if (isArray(val) && val.length === 0) return val;
1662        val = arrayWrap(val);
1663        var result = map(val, callback);
1664        if (allTruthyMode === true)
1665          return filter(result, falsey).length === 0;
1666        return arrayUnwrap(result);
1667      };
1668    }
1669
1670    // Wraps type (.equals) functions to operate on each value of an array
1671    function arrayEqualsHandler(callback) {
1672      return function handleArray(val1, val2) {
1673        var left = arrayWrap(val1), right = arrayWrap(val2);
1674        if (left.length !== right.length) return false;
1675        for (var i = 0; i < left.length; i++) {
1676          if (!callback(left[i], right[i])) return false;
1677        }
1678        return true;
1679      };
1680    }
1681
1682    this.encode = arrayHandler(bindTo(type, 'encode'));
1683    this.decode = arrayHandler(bindTo(type, 'decode'));
1684    this.is     = arrayHandler(bindTo(type, 'is'), true);
1685    this.equals = arrayEqualsHandler(bindTo(type, 'equals'));
1686    this.pattern = type.pattern;
1687    this.$normalize = arrayHandler(bindTo(type, '$normalize'));
1688    this.name = type.name;
1689    this.$arrayMode = mode;
1690  }
1691
1692  return new ArrayType(this, mode);
1693};
1694
1695
1696
1697/**
1698 * @ngdoc object
1699 * @name ui.router.util.$urlMatcherFactory
1700 *
1701 * @description
1702 * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory
1703 * is also available to providers under the name `$urlMatcherFactoryProvider`.
1704 */
1705function $UrlMatcherFactory() {
1706  $$UMFP = this;
1707
1708  var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false;
1709
1710  // Use tildes to pre-encode slashes.
1711  // If the slashes are simply URLEncoded, the browser can choose to pre-decode them,
1712  // and bidirectional encoding/decoding fails.
1713  // Tilde was chosen because it's not a RFC 3986 section 2.2 Reserved Character
1714  function valToString(val) { return val != null ? val.toString().replace(/(~|\/)/g, function (m) { return {'~':'~~', '/':'~2F'}[m]; }) : val; }
1715  function valFromString(val) { return val != null ? val.toString().replace(/(~~|~2F)/g, function (m) { return {'~~':'~', '~2F':'/'}[m]; }) : val; }
1716
1717  var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = {
1718    "string": {
1719      encode: valToString,
1720      decode: valFromString,
1721      // TODO: in 1.0, make string .is() return false if value is undefined/null by default.
1722      // In 0.2.x, string params are optional by default for backwards compat
1723      is: function(val) { return val == null || !isDefined(val) || typeof val === "string"; },
1724      pattern: /[^/]*/
1725    },
1726    "int": {
1727      encode: valToString,
1728      decode: function(val) { return parseInt(val, 10); },
1729      is: function(val) { return val !== undefined && val !== null && this.decode(val.toString()) === val; },
1730      pattern: /-?\d+/
1731    },
1732    "bool": {
1733      encode: function(val) { return val ? 1 : 0; },
1734      decode: function(val) { return parseInt(val, 10) !== 0; },
1735      is: function(val) { return val === true || val === false; },
1736      pattern: /0|1/
1737    },
1738    "date": {
1739      encode: function (val) {
1740        if (!this.is(val))
1741          return undefined;
1742        return [ val.getFullYear(),
1743          ('0' + (val.getMonth() + 1)).slice(-2),
1744          ('0' + val.getDate()).slice(-2)
1745        ].join("-");
1746      },
1747      decode: function (val) {
1748        if (this.is(val)) return val;
1749        var match = this.capture.exec(val);
1750        return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;
1751      },
1752      is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); },
1753      equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); },
1754      pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,
1755      capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
1756    },
1757    "json": {
1758      encode: angular.toJson,
1759      decode: angular.fromJson,
1760      is: angular.isObject,
1761      equals: angular.equals,
1762      pattern: /[^/]*/
1763    },
1764    "any": { // does not encode/decode
1765      encode: angular.identity,
1766      decode: angular.identity,
1767      equals: angular.equals,
1768      pattern: /.*/
1769    }
1770  };
1771
1772  function getDefaultConfig() {
1773    return {
1774      strict: isStrictMode,
1775      caseInsensitive: isCaseInsensitive
1776    };
1777  }
1778
1779  function isInjectable(value) {
1780    return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));
1781  }
1782
1783  /**
1784   * [Internal] Get the default value of a parameter, which may be an injectable function.
1785   */
1786  $UrlMatcherFactory.$$getDefaultValue = function(config) {
1787    if (!isInjectable(config.value)) return config.value;
1788    if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
1789    return injector.invoke(config.value);
1790  };
1791
1792  /**
1793   * @ngdoc function
1794   * @name ui.router.util.$urlMatcherFactory#caseInsensitive
1795   * @methodOf ui.router.util.$urlMatcherFactory
1796   *
1797   * @description
1798   * Defines whether URL matching should be case sensitive (the default behavior), or not.
1799   *
1800   * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`;
1801   * @returns {boolean} the current value of caseInsensitive
1802   */
1803  this.caseInsensitive = function(value) {
1804    if (isDefined(value))
1805      isCaseInsensitive = value;
1806    return isCaseInsensitive;
1807  };
1808
1809  /**
1810   * @ngdoc function
1811   * @name ui.router.util.$urlMatcherFactory#strictMode
1812   * @methodOf ui.router.util.$urlMatcherFactory
1813   *
1814   * @description
1815   * Defines whether URLs should match trailing slashes, or not (the default behavior).
1816   *
1817   * @param {boolean=} value `false` to match trailing slashes in URLs, otherwise `true`.
1818   * @returns {boolean} the current value of strictMode
1819   */
1820  this.strictMode = function(value) {
1821    if (isDefined(value))
1822      isStrictMode = value;
1823    return isStrictMode;
1824  };
1825
1826  /**
1827   * @ngdoc function
1828   * @name ui.router.util.$urlMatcherFactory#defaultSquashPolicy
1829   * @methodOf ui.router.util.$urlMatcherFactory
1830   *
1831   * @description
1832   * Sets the default behavior when generating or matching URLs with default parameter values.
1833   *
1834   * @param {string} value A string that defines the default parameter URL squashing behavior.
1835   *    `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL
1836   *    `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the
1837   *             parameter is surrounded by slashes, squash (remove) one slash from the URL
1838   *    any other string, e.g. "~": When generating an href with a default parameter value, squash (remove)
1839   *             the parameter value from the URL and replace it with this string.
1840   */
1841  this.defaultSquashPolicy = function(value) {
1842    if (!isDefined(value)) return defaultSquashPolicy;
1843    if (value !== true && value !== false && !isString(value))
1844      throw new Error("Invalid squash policy: " + value + ". Valid policies: false, true, arbitrary-string");
1845    defaultSquashPolicy = value;
1846    return value;
1847  };
1848
1849  /**
1850   * @ngdoc function
1851   * @name ui.router.util.$urlMatcherFactory#compile
1852   * @methodOf ui.router.util.$urlMatcherFactory
1853   *
1854   * @description
1855   * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern.
1856   *
1857   * @param {string} pattern  The URL pattern.
1858   * @param {Object} config  The config object hash.
1859   * @returns {UrlMatcher}  The UrlMatcher.
1860   */
1861  this.compile = function (pattern, config) {
1862    return new UrlMatcher(pattern, extend(getDefaultConfig(), config));
1863  };
1864
1865  /**
1866   * @ngdoc function
1867   * @name ui.router.util.$urlMatcherFactory#isMatcher
1868   * @methodOf ui.router.util.$urlMatcherFactory
1869   *
1870   * @description
1871   * Returns true if the specified object is a `UrlMatcher`, or false otherwise.
1872   *
1873   * @param {Object} object  The object to perform the type check against.
1874   * @returns {Boolean}  Returns `true` if the object matches the `UrlMatcher` interface, by
1875   *          implementing all the same methods.
1876   */
1877  this.isMatcher = function (o) {
1878    if (!isObject(o)) return false;
1879    var result = true;
1880
1881    forEach(UrlMatcher.prototype, function(val, name) {
1882      if (isFunction(val)) {
1883        result = result && (isDefined(o[name]) && isFunction(o[name]));
1884      }
1885    });
1886    return result;
1887  };
1888
1889  /**
1890   * @ngdoc function
1891   * @name ui.router.util.$urlMatcherFactory#type
1892   * @methodOf ui.router.util.$urlMatcherFactory
1893   *
1894   * @description
1895   * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to
1896   * generate URLs with typed parameters.
1897   *
1898   * @param {string} name  The type name.
1899   * @param {Object|Function} definition   The type definition. See
1900   *        {@link ui.router.util.type:Type `Type`} for information on the values accepted.
1901   * @param {Object|Function} definitionFn (optional) A function that is injected before the app
1902   *        runtime starts.  The result of this function is merged into the existing `definition`.
1903   *        See {@link ui.router.util.type:Type `Type`} for information on the values accepted.
1904   *
1905   * @returns {Object}  Returns `$urlMatcherFactoryProvider`.
1906   *
1907   * @example
1908   * This is a simple example of a custom type that encodes and decodes items from an
1909   * array, using the array index as the URL-encoded value:
1910   *
1911   * <pre>
1912   * var list = ['John', 'Paul', 'George', 'Ringo'];
1913   *
1914   * $urlMatcherFactoryProvider.type('listItem', {
1915   *   encode: function(item) {
1916   *     // Represent the list item in the URL using its corresponding index
1917   *     return list.indexOf(item);
1918   *   },
1919   *   decode: function(item) {
1920   *     // Look up the list item by index
1921   *     return list[parseInt(item, 10)];
1922   *   },
1923   *   is: function(item) {
1924   *     // Ensure the item is valid by checking to see that it appears
1925   *     // in the list
1926   *     return list.indexOf(item) > -1;
1927   *   }
1928   * });
1929   *
1930   * $stateProvider.state('list', {
1931   *   url: "/list/{item:listItem}",
1932   *   controller: function($scope, $stateParams) {
1933   *     console.log($stateParams.item);
1934   *   }
1935   * });
1936   *
1937   * // ...
1938   *
1939   * // Changes URL to '/list/3', logs "Ringo" to the console
1940   * $state.go('list', { item: "Ringo" });
1941   * </pre>
1942   *
1943   * This is a more complex example of a type that relies on dependency injection to
1944   * interact with services, and uses the parameter name from the URL to infer how to
1945   * handle encoding and decoding parameter values:
1946   *
1947   * <pre>
1948   * // Defines a custom type that gets a value from a service,
1949   * // where each service gets different types of values from
1950   * // a backend API:
1951   * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) {
1952   *
1953   *   // Matches up services to URL parameter names
1954   *   var services = {
1955   *     user: Users,
1956   *     post: Posts
1957   *   };
1958   *
1959   *   return {
1960   *     encode: function(object) {
1961   *       // Represent the object in the URL using its unique ID
1962   *       return object.id;
1963   *     },
1964   *     decode: function(value, key) {
1965   *       // Look up the object by ID, using the parameter
1966   *       // name (key) to call the correct service
1967   *       return services[key].findById(value);
1968   *     },
1969   *     is: function(object, key) {
1970   *       // Check that object is a valid dbObject
1971   *       return angular.isObject(object) && object.id && services[key];
1972   *     }
1973   *     equals: function(a, b) {
1974   *       // Check the equality of decoded objects by comparing
1975   *       // their unique IDs
1976   *       return a.id === b.id;
1977   *     }
1978   *   };
1979   * });
1980   *
1981   * // In a config() block, you can then attach URLs with
1982   * // type-annotated parameters:
1983   * $stateProvider.state('users', {
1984   *   url: "/users",
1985   *   // ...
1986   * }).state('users.item', {
1987   *   url: "/{user:dbObject}",
1988   *   controller: function($scope, $stateParams) {
1989   *     // $stateParams.user will now be an object returned from
1990   *     // the Users service
1991   *   },
1992   *   // ...
1993   * });
1994   * </pre>
1995   */
1996  this.type = function (name, definition, definitionFn) {
1997    if (!isDefined(definition)) return $types[name];
1998    if ($types.hasOwnProperty(name)) throw new Error("A type named '" + name + "' has already been defined.");
1999
2000    $types[name] = new Type(extend({ name: name }, definition));
2001    if (definitionFn) {
2002      typeQueue.push({ name: name, def: definitionFn });
2003      if (!enqueue) flushTypeQueue();
2004    }
2005    return this;
2006  };
2007
2008  // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s
2009  function flushTypeQueue() {
2010    while(typeQueue.length) {
2011      var type = typeQueue.shift();
2012      if (type.pattern) throw new Error("You cannot override a type's .pattern at runtime.");
2013      angular.extend($types[type.name], injector.invoke(type.def));
2014    }
2015  }
2016
2017  // Register default types. Store them in the prototype of $types.
2018  forEach(defaultTypes, function(type, name) { $types[name] = new Type(extend({name: name}, type)); });
2019  $types = inherit($types, {});
2020
2021  /* No need to document $get, since it returns this */
2022  this.$get = ['$injector', function ($injector) {
2023    injector = $injector;
2024    enqueue = false;
2025    flushTypeQueue();
2026
2027    forEach(defaultTypes, function(type, name) {
2028      if (!$types[name]) $types[name] = new Type(type);
2029    });
2030    return this;
2031  }];
2032
2033  this.Param = function Param(id, type, config, location) {
2034    var self = this;
2035    config = unwrapShorthand(config);
2036    type = getType(config, type, location);
2037    var arrayMode = getArrayMode();
2038    type = arrayMode ? type.$asArray(arrayMode, location === "search") : type;
2039    if (type.name === "string" && !arrayMode && location === "path" && config.value === undefined)
2040      config.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to ""
2041    var isOptional = config.value !== undefined;
2042    var squash = getSquashPolicy(config, isOptional);
2043    var replace = getReplace(config, arrayMode, isOptional, squash);
2044
2045    function unwrapShorthand(config) {
2046      var keys = isObject(config) ? objectKeys(config) : [];
2047      var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 &&
2048                        indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1;
2049      if (isShorthand) config = { value: config };
2050      config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; };
2051      return config;
2052    }
2053
2054    function getType(config, urlType, location) {
2055      if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations.");
2056      if (urlType) return urlType;
2057      if (!config.type) return (location === "config" ? $types.any : $types.string);
2058
2059      if (angular.isString(config.type))
2060        return $types[config.type];
2061      if (config.type instanceof Type)
2062        return config.type;
2063      return new Type(config.type);
2064    }
2065
2066    // array config: param name (param[]) overrides default settings.  explicit config overrides param name.
2067    function getArrayMode() {
2068      var arrayDefaults = { array: (location === "search" ? "auto" : false) };
2069      var arrayParamNomenclature = id.match(/\[\]$/) ? { array: true } : {};
2070      return extend(arrayDefaults, arrayParamNomenclature, config).array;
2071    }
2072
2073    /**
2074     * returns false, true, or the squash value to indicate the "default parameter url squash policy".
2075     */
2076    function getSquashPolicy(config, isOptional) {
2077      var squash = config.squash;
2078      if (!isOptional || squash === false) return false;
2079      if (!isDefined(squash) || squash == null) return defaultSquashPolicy;
2080      if (squash === true || isString(squash)) return squash;
2081      throw new Error("Invalid squash policy: '" + squash + "'. Valid policies: false, true, or arbitrary string");
2082    }
2083
2084    function getReplace(config, arrayMode, isOptional, squash) {
2085      var replace, configuredKeys, defaultPolicy = [
2086        { from: "",   to: (isOptional || arrayMode ? undefined : "") },
2087        { from: null, to: (isOptional || arrayMode ? undefined : "") }
2088      ];
2089      replace = isArray(config.replace) ? config.replace : [];
2090      if (isString(squash))
2091        replace.push({ from: squash, to: undefined });
2092      configuredKeys = map(replace, function(item) { return item.from; } );
2093      return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace);
2094    }
2095
2096    /**
2097     * [Internal] Get the default value of a parameter, which may be an injectable function.
2098     */
2099    function $$getDefaultValue() {
2100      if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
2101      var defaultValue = injector.invoke(config.$$fn);
2102      if (defaultValue !== null && defaultValue !== undefined && !self.type.is(defaultValue))
2103        throw new Error("Default value (" + defaultValue + ") for parameter '" + self.id + "' is not an instance of Type (" + self.type.name + ")");
2104      return defaultValue;
2105    }
2106
2107    /**
2108     * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the
2109     * default value, which may be the result of an injectable function.
2110     */
2111    function $value(value) {
2112      function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; }
2113      function $replace(value) {
2114        var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; });
2115        return replacement.length ? replacement[0] : value;
2116      }
2117      value = $replace(value);
2118      return !isDefined(value) ? $$getDefaultValue() : self.type.$normalize(value);
2119    }
2120
2121    function toString() { return "{Param:" + id + " " + type + " squash: '" + squash + "' optional: " + isOptional + "}"; }
2122
2123    extend(this, {
2124      id: id,
2125      type: type,
2126      location: location,
2127      array: arrayMode,
2128      squash: squash,
2129      replace: replace,
2130      isOptional: isOptional,
2131      value: $value,
2132      dynamic: undefined,
2133      config: config,
2134      toString: toString
2135    });
2136  };
2137
2138  function ParamSet(params) {
2139    extend(this, params || {});
2140  }
2141
2142  ParamSet.prototype = {
2143    $$new: function() {
2144      return inherit(this, extend(new ParamSet(), { $$parent: this}));
2145    },
2146    $$keys: function () {
2147      var keys = [], chain = [], parent = this,
2148        ignore = objectKeys(ParamSet.prototype);
2149      while (parent) { chain.push(parent); parent = parent.$$parent; }
2150      chain.reverse();
2151      forEach(chain, function(paramset) {
2152        forEach(objectKeys(paramset), function(key) {
2153            if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key);
2154        });
2155      });
2156      return keys;
2157    },
2158    $$values: function(paramValues) {
2159      var values = {}, self = this;
2160      forEach(self.$$keys(), function(key) {
2161        values[key] = self[key].value(paramValues && paramValues[key]);
2162      });
2163      return values;
2164    },
2165    $$equals: function(paramValues1, paramValues2) {
2166      var equal = true, self = this;
2167      forEach(self.$$keys(), function(key) {
2168        var left = paramValues1 && paramValues1[key], right = paramValues2 && paramValues2[key];
2169        if (!self[key].type.equals(left, right)) equal = false;
2170      });
2171      return equal;
2172    },
2173    $$validates: function $$validate(paramValues) {
2174      var keys = this.$$keys(), i, param, rawVal, normalized, encoded;
2175      for (i = 0; i < keys.length; i++) {
2176        param = this[keys[i]];
2177        rawVal = paramValues[keys[i]];
2178        if ((rawVal === undefined || rawVal === null) && param.isOptional)
2179          break; // There was no parameter value, but the param is optional
2180        normalized = param.type.$normalize(rawVal);
2181        if (!param.type.is(normalized))
2182          return false; // The value was not of the correct Type, and could not be decoded to the correct Type
2183        encoded = param.type.encode(normalized);
2184        if (angular.isString(encoded) && !param.type.pattern.exec(encoded))
2185          return false; // The value was of the correct type, but when encoded, did not match the Type's regexp
2186      }
2187      return true;
2188    },
2189    $$parent: undefined
2190  };
2191
2192  this.ParamSet = ParamSet;
2193}
2194
2195// Register as a provider so it's available to other providers
2196angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
2197angular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]);
2198
2199/**
2200 * @ngdoc object
2201 * @name ui.router.router.$urlRouterProvider
2202 *
2203 * @requires ui.router.util.$urlMatcherFactoryProvider
2204 * @requires $locationProvider
2205 *
2206 * @description
2207 * `$urlRouterProvider` has the responsibility of watching `$location`. 
2208 * When `$location` changes it runs through a list of rules one by one until a 
2209 * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify 
2210 * a url in a state configuration. All urls are compiled into a UrlMatcher object.
2211 *
2212 * There are several methods on `$urlRouterProvider` that make it useful to use directly
2213 * in your module config.
2214 */
2215$UrlRouterProvider.$inject = ['$locationProvider', '$urlMatcherFactoryProvider'];
2216function $UrlRouterProvider(   $locationProvider,   $urlMatcherFactory) {
2217  var rules = [], otherwise = null, interceptDeferred = false, listener;
2218
2219  // Returns a string that is a prefix of all strings matching the RegExp
2220  function regExpPrefix(re) {
2221    var prefix = /^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(re.source);
2222    return (prefix != null) ? prefix[1].replace(/\\(.)/g, "$1") : '';
2223  }
2224
2225  // Interpolates matched values into a String.replace()-style pattern
2226  function interpolate(pattern, match) {
2227    return pattern.replace(/\$(\$|\d{1,2})/, function (m, what) {
2228      return match[what === '$' ? 0 : Number(what)];
2229    });
2230  }
2231
2232  /**
2233   * @ngdoc function
2234   * @name ui.router.router.$urlRouterProvider#rule
2235   * @methodOf ui.router.router.$urlRouterProvider
2236   *
2237   * @description
2238   * Defines rules that are used by `$urlRouterProvider` to find matches for
2239   * specific URLs.
2240   *
2241   * @example
2242   * <pre>
2243   * var app = angular.module('app', ['ui.router.router']);
2244   *
2245   * app.config(function ($urlRouterProvider) {
2246   *   // Here's an example of how you might allow case insensitive urls
2247   *   $urlRouterProvider.rule(function ($injector, $location) {
2248   *     var path = $location.path(),
2249   *         normalized = path.toLowerCase();
2250   *
2251   *     if (path !== normalized) {
2252   *       return normalized;
2253   *     }
2254   *   });
2255   * });
2256   * </pre>
2257   *
2258   * @param {function} rule Handler function that takes `$injector` and `$location`
2259   * services as arguments. You can use them to return a valid path as a string.
2260   *
2261   * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
2262   */
2263  this.rule = function (rule) {
2264    if (!isFunction(rule)) throw new Error("'rule' must be a function");
2265    rules.push(rule);
2266    return this;
2267  };
2268
2269  /**
2270   * @ngdoc object
2271   * @name ui.router.router.$urlRouterProvider#otherwise
2272   * @methodOf ui.router.router.$urlRouterProvider
2273   *
2274   * @description
2275   * Defines a path that is used when an invalid route is requested.
2276   *
2277   * @example
2278   * <pre>
2279   * var app = angular.module('app', ['ui.router.router']);
2280   *
2281   * app.config(function ($urlRouterProvider) {
2282   *   // if the path doesn't match any of the urls you configured
2283   *   // otherwise will take care of routing the user to the
2284   *   // specified url
2285   *   $urlRouterProvider.otherwise('/index');
2286   *
2287   *   // Example of using function rule as param
2288   *   $urlRouterProvider.otherwise(function ($injector, $location) {
2289   *     return '/a/valid/url';
2290   *   });
2291   * });
2292   * </pre>
2293   *
2294   * @param {string|function} rule The url path you want to redirect to or a function 
2295   * rule that returns the url path. The function version is passed two params: 
2296   * `$injector` and `$location` services, and must return a url string.
2297   *
2298   * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance
2299   */
2300  this.otherwise = function (rule) {
2301    if (isString(rule)) {
2302      var redirect = rule;
2303      rule = function () { return redirect; };
2304    }
2305    else if (!isFunction(rule)) throw new Error("'rule' must be a function");
2306    otherwise = rule;
2307    return this;
2308  };
2309
2310
2311  function handleIfMatch($injector, handler, match) {
2312    if (!match) return false;
2313    var result = $injector.invoke(handler, handler, { $match: match });
2314    return isDefined(result) ? result : true;
2315  }
2316
2317  /**
2318   * @ngdoc function
2319   * @name ui.router.router.$urlRouterProvider#when
2320   * @methodOf ui.router.router.$urlRouterProvider
2321   *
2322   * @description
2323   * Registers a handler for a given url matching. 
2324   * 
2325   * If the handler is a string, it is
2326   * treated as a redirect, and is interpolated according to the syntax of match
2327   * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise).
2328   *
2329   * If the handler is a function, it is injectable. It gets invoked if `$location`
2330   * matches. You have the option of inject the match object as `$match`.
2331   *
2332   * The handler can return
2333   *
2334   * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter`
2335   *   will continue trying to find another one that matches.
2336   * - **string** which is treated as a redirect and passed to `$location.url()`
2337   * - **void** or any **truthy** value tells `$urlRouter` that the url was handled.
2338   *
2339   * @example
2340   * <pre>
2341   * var app = angular.module('app', ['ui.router.router']);
2342   *
2343   * app.config(function ($urlRouterProvider) {
2344   *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
2345   *     if ($state.$current.navigable !== state ||
2346   *         !equalForKeys($match, $stateParams) {
2347   *      $state.transitionTo(state, $match, false);
2348   *     }
2349   *   });
2350   * });
2351   * </pre>
2352   *
2353   * @param {string|object} what The incoming path that you want to redirect.
2354   * @param {string|function} handler The path you want to redirect your user to.
2355   */
2356  this.when = function (what, handler) {
2357    var redirect, handlerIsString = isString(handler);
2358    if (isString(what)) what = $urlMatcherFactory.compile(what);
2359
2360    if (!handlerIsString && !isFunction(handler) && !isArray(handler))
2361      throw new Error("invalid 'handler' in when()");
2362
2363    var strategies = {
2364      matcher: function (what, handler) {
2365        if (handlerIsString) {
2366          redirect = $urlMatcherFactory.compile(handler);
2367          handler = ['$match', function ($match) { return redirect.format($match); }];
2368        }
2369        return extend(function ($injector, $location) {
2370          return handleIfMatch($injector, handler, what.exec($location.path(), $location.search()));
2371        }, {
2372          prefix: isString(what.prefix) ? what.prefix : ''
2373        });
2374      },
2375      regex: function (what, handler) {
2376        if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky");
2377
2378        if (handlerIsString) {
2379          redirect = handler;
2380          handler = ['$match', function ($match) { return interpolate(redirect, $match); }];
2381        }
2382        return extend(function ($injector, $location) {
2383          return handleIfMatch($injector, handler, what.exec($location.path()));
2384        }, {
2385          prefix: regExpPrefix(what)
2386        });
2387      }
2388    };
2389
2390    var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp };
2391
2392    for (var n in check) {
2393      if (check[n]) return this.rule(strategies[n](what, handler));
2394    }
2395
2396    throw new Error("invalid 'what' in when()");
2397  };
2398
2399  /**
2400   * @ngdoc function
2401   * @name ui.router.router.$urlRouterProvider#deferIntercept
2402   * @methodOf ui.router.router.$urlRouterProvider
2403   *
2404   * @description
2405   * Disables (or enables) deferring location change interception.
2406   *
2407   * If you wish to customize the behavior of syncing the URL (for example, if you wish to
2408   * defer a transition but maintain the current URL), call this method at configuration time.
2409   * Then, at run time, call `$urlRouter.listen()` after you have configured your own
2410   * `$locationChangeSuccess` event handler.
2411   *
2412   * @example
2413   * <pre>
2414   * var app = angular.module('app', ['ui.router.router']);
2415   *
2416   * app.config(function ($urlRouterProvider) {
2417   *
2418   *   // Prevent $urlRouter from automatically intercepting URL changes;
2419   *   // this allows you to configure custom behavior in between
2420   *   // location changes and route synchronization:
2421   *   $urlRouterProvider.deferIntercept();
2422   *
2423   * }).run(function ($rootScope, $urlRouter, UserService) {
2424   *
2425   *   $rootScope.$on('$locationChangeSuccess', function(e) {
2426   *     // UserService is an example service for managing user state
2427   *     if (UserService.isLoggedIn()) return;
2428   *
2429   *     // Prevent $urlRouter's default handler from firing
2430   *     e.preventDefault();
2431   *
2432   *     UserService.handleLogin().then(function() {
2433   *       // Once the user has logged in, sync the current URL
2434   *       // to the router:
2435   *       $urlRouter.sync();
2436   *     });
2437   *   });
2438   *
2439   *   // Configures $urlRouter's listener *after* your custom listener
2440   *   $urlRouter.listen();
2441   * });
2442   * </pre>
2443   *
2444   * @param {boolean} defer Indicates whether to defer location change interception. Passing
2445            no parameter is equivalent to `true`.
2446   */
2447  this.deferIntercept = function (defer) {
2448    if (defer === undefined) defer = true;
2449    interceptDeferred = defer;
2450  };
2451
2452  /**
2453   * @ngdoc object
2454   * @name ui.router.router.$urlRouter
2455   *
2456   * @requires $location
2457   * @requires $rootScope
2458   * @requires $injector
2459   * @requires $browser
2460   *
2461   * @description
2462   *
2463   */
2464  this.$get = $get;
2465  $get.$inject = ['$location', '$rootScope', '$injector', '$browser', '$sniffer'];
2466  function $get(   $location,   $rootScope,   $injector,   $browser,   $sniffer) {
2467
2468    var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl;
2469
2470    function appendBasePath(url, isHtml5, absolute) {
2471      if (baseHref === '/') return url;
2472      if (isHtml5) return baseHref.slice(0, -1) + url;
2473      if (absolute) return baseHref.slice(1) + url;
2474      return url;
2475    }
2476
2477    // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree
2478    function update(evt) {
2479      if (evt && evt.defaultPrevented) return;
2480      var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl;
2481      lastPushedUrl = undefined;
2482      // TODO: Re-implement this in 1.0 for https://github.com/angular-ui/ui-router/issues/1573
2483      //if (ignoreUpdate) return true;
2484
2485      function check(rule) {
2486        var handled = rule($injector, $location);
2487
2488        if (!handled) return false;
2489        if (isString(handled)) $location.replace().url(handled);
2490        return true;
2491      }
2492      var n = rules.length, i;
2493
2494      for (i = 0; i < n; i++) {
2495        if (check(rules[i])) return;
2496      }
2497      // always check otherwise last to allow dynamic updates to the set of rules
2498      if (otherwise) check(otherwise);
2499    }
2500
2501    function listen() {
2502      listener = listener || $rootScope.$on('$locationChangeSuccess', update);
2503      return listener;
2504    }
2505
2506    if (!interceptDeferred) listen();
2507
2508    return {
2509      /**
2510       * @ngdoc function
2511       * @name ui.router.router.$urlRouter#sync
2512       * @methodOf ui.router.router.$urlRouter
2513       *
2514       * @description
2515       * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`.
2516       * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event,
2517       * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed
2518       * with the transition by calling `$urlRouter.sync()`.
2519       *
2520       * @example
2521       * <pre>
2522       * angular.module('app', ['ui.router'])
2523       *   .run(function($rootScope, $urlRouter) {
2524       *     $rootScope.$on('$locationChangeSuccess', function(evt) {
2525       *       // Halt state change from even starting
2526       *       evt.preventDefault();
2527       *       // Perform custom logic
2528       *       var meetsRequirement = ...
2529       *       // Continue with the update and state transition if logic allows
2530       *       if (meetsRequirement) $urlRouter.sync();
2531       *     });
2532       * });
2533       * </pre>
2534       */
2535      sync: function() {
2536        update();
2537      },
2538
2539      listen: function() {
2540        return listen();
2541      },
2542
2543      update: function(read) {
2544        if (read) {
2545          location = $location.url();
2546          return;
2547        }
2548        if ($location.url() === location) return;
2549
2550        $location.url(location);
2551        $location.replace();
2552      },
2553
2554      push: function(urlMatcher, params, options) {
2555         var url = urlMatcher.format(params || {});
2556
2557        // Handle the special hash param, if needed
2558        if (url !== null && params && params['#']) {
2559            url += '#' + params['#'];
2560        }
2561
2562        $location.url(url);
2563        lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined;
2564        if (options && options.replace) $location.replace();
2565      },
2566
2567      /**
2568       * @ngdoc function
2569       * @name ui.router.router.$urlRouter#href
2570       * @methodOf ui.router.router.$urlRouter
2571       *
2572       * @description
2573       * A URL generation method that returns the compiled URL for a given
2574       * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters.
2575       *
2576       * @example
2577       * <pre>
2578       * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), {
2579       *   person: "bob"
2580       * });
2581       * // $bob == "/about/bob";
2582       * </pre>
2583       *
2584       * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate.
2585       * @param {object=} params An object of parameter values to fill the matcher's required parameters.
2586       * @param {object=} options Options object. The options are:
2587       *
2588       * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
2589       *
2590       * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher`
2591       */
2592      href: function(urlMatcher, params, options) {
2593        if (!urlMatcher.validates(params)) return null;
2594
2595        var isHtml5 = $locationProvider.html5Mode();
2596        if (angular.isObject(isHtml5)) {
2597          isHtml5 = isHtml5.enabled;
2598        }
2599
2600        isHtml5 = isHtml5 && $sniffer.history;
2601        
2602        var url = urlMatcher.format(params);
2603        options = options || {};
2604
2605        if (!isHtml5 && url !== null) {
2606          url = "#" + $locationProvider.hashPrefix() + url;
2607        }
2608
2609        // Handle special hash param, if needed
2610        if (url !== null && params && params['#']) {
2611          url += '#' + params['#'];
2612        }
2613
2614        url = appendBasePath(url, isHtml5, options.absolute);
2615
2616        if (!options.absolute || !url) {
2617          return url;
2618        }
2619
2620        var slash = (!isHtml5 && url ? '/' : ''), port = $location.port();
2621        port = (port === 80 || port === 443 ? '' : ':' + port);
2622
2623        return [$location.protocol(), '://', $location.host(), port, slash, url].join('');
2624      }
2625    };
2626  }
2627}
2628
2629angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);
2630
2631/**
2632 * @ngdoc object
2633 * @name ui.router.state.$stateProvider
2634 *
2635 * @requires ui.router.router.$urlRouterProvider
2636 * @requires ui.router.util.$urlMatcherFactoryProvider
2637 *
2638 * @description
2639 * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely
2640 * on state.
2641 *
2642 * A state corresponds to a "place" in the application in terms of the overall UI and
2643 * navigation. A state describes (via the controller / template / view properties) what
2644 * the UI looks like and does at that place.
2645 *
2646 * States often have things in common, and the primary way of factoring out these
2647 * commonalities in this model is via the state hierarchy, i.e. parent/child states aka
2648 * nested states.
2649 *
2650 * The `$stateProvider` provides interfaces to declare these states for your app.
2651 */
2652$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
2653function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory) {
2654
2655  var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
2656
2657  // Builds state properties from definition passed to registerState()
2658  var stateBuilder = {
2659
2660    // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
2661    // state.children = [];
2662    // if (parent) parent.children.push(state);
2663    parent: function(state) {
2664      if (isDefined(state.parent) && state.parent) return findState(state.parent);
2665      // regex matches any valid composite state name
2666      // would match "contact.list" but not "contacts"
2667      var compositeName = /^(.+)\.[^.]+$/.exec(state.name);
2668      return compositeName ? findState(compositeName[1]) : root;
2669    },
2670
2671    // inherit 'data' from parent and override by own values (if any)
2672    data: function(state) {
2673      if (state.parent && state.parent.data) {
2674        state.data = state.self.data = inherit(state.parent.data, state.data);
2675      }
2676      return state.data;
2677    },
2678
2679    // Build a URLMatcher if necessary, either via a relative or absolute URL
2680    url: function(state) {
2681      var url = state.url, config = { params: state.params || {} };
2682
2683      if (isString(url)) {
2684        if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);
2685        return (state.parent.navigable || root).url.concat(url, config);
2686      }
2687
2688      if (!url || $urlMatcherFactory.isMatcher(url)) return url;
2689      throw new Error("Invalid url '" + url + "' in state '" + state + "'");
2690    },
2691
2692    // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
2693    navigable: function(state) {
2694      return state.url ? state : (state.parent ? state.parent.navigable : null);
2695    },
2696
2697    // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params
2698    ownParams: function(state) {
2699      var params = state.url && state.url.params || new $$UMFP.ParamSet();
2700      forEach(state.params || {}, function(config, id) {
2701        if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config");
2702      });
2703      return params;
2704    },
2705
2706    // Derive parameters for this state and ensure they're a super-set of parent's parameters
2707    params: function(state) {
2708      var ownParams = pick(state.ownParams, state.ownParams.$$keys());
2709      return state.parent && state.parent.params ? extend(state.parent.params.$$new(), ownParams) : new $$UMFP.ParamSet();
2710    },
2711
2712    // If there is no explicit multi-view configuration, make one up so we don't have
2713    // to handle both cases in the view directive later. Note that having an explicit
2714    // 'views' property will mean the default unnamed view properties are ignored. This
2715    // is also a good time to resolve view names to absolute names, so everything is a
2716    // straight lookup at link time.
2717    views: function(state) {
2718      var views = {};
2719
2720      forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {
2721        if (name.indexOf('@') < 0) name += '@' + state.parent.name;
2722        view.resolveAs = view.resolveAs || state.resolveAs || '$resolve';
2723        views[name] = view;
2724      });
2725      return views;
2726    },
2727
2728    // Keep a full path from the root down to this state as this is needed for state activation.
2729    path: function(state) {
2730      return state.parent ? state.parent.path.concat(state) : []; // exclude root from path
2731    },
2732
2733    // Speed up $state.contains() as it's used a lot
2734    includes: function(state) {
2735      var includes = state.parent ? extend({}, state.parent.includes) : {};
2736      includes[state.name] = true;
2737      return includes;
2738    },
2739
2740    $delegates: {}
2741  };
2742
2743  function isRelative(stateName) {
2744    return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
2745  }
2746
2747  function findState(stateOrName, base) {
2748    if (!stateOrName) return undefined;
2749
2750    var isStr = isString(stateOrName),
2751        name  = isStr ? stateOrName : stateOrName.name,
2752        path  = isRelative(name);
2753
2754    if (path) {
2755      if (!base) throw new Error("No reference point given for path '"  + name + "'");
2756      base = findState(base);
2757      
2758      var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
2759
2760      for (; i < pathLength; i++) {
2761        if (rel[i] === "" && i === 0) {
2762          current = base;
2763          continue;
2764        }
2765        if (rel[i] === "^") {
2766          if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
2767          current = current.parent;
2768          continue;
2769        }
2770        break;
2771      }
2772      rel = rel.slice(i).join(".");
2773      name = current.name + (current.name && rel ? "." : "") + rel;
2774    }
2775    var state = states[name];
2776
2777    if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {
2778      return state;
2779    }
2780    return undefined;
2781  }
2782
2783  function queueState(parentName, state) {
2784    if (!queue[parentName]) {
2785      queue[parentName] = [];
2786    }
2787    queue[parentName].push(state);
2788  }
2789
2790  function flushQueuedChildren(parentName) {
2791    var queued = queue[parentName] || [];
2792    while(queued.length) {
2793      registerState(queued.shift());
2794    }
2795  }
2796
2797  function registerState(state) {
2798    // Wrap a new object around the state so we can store our private details easily.
2799    state = inherit(state, {
2800      self: state,
2801      resolve: state.resolve || {},
2802      toString: function() { return this.name; }
2803    });
2804
2805    var name = state.name;
2806    if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name");
2807    if (states.hasOwnProperty(name)) throw new Error("State '" + n
2807ame + "' is already defined");
2808
2809    // Get parent name
2810    var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))
2811        : (isString(state.parent)) ? state.parent
2812        : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name
2813        : '';
2814
2815    // If parent is not registered yet, add state to queue and register later
2816    if (parentName && !states[parentName]) {
2817      return queueState(parentName, state.self);
2818    }
2819
2820    for (var key in stateBuilder) {
2821      if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);
2822    }
2823    states[name] = state;
2824
2825    // Register the state in the global state list and with $urlRouter if necessary.
2826    if (!state[abstractKey] && state.url) {
2827      $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
2828        if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
2829          $state.transitionTo(state, $match, { inherit: true, location: false });
2830        }
2831      }]);
2832    }
2833
2834    // Register any queued children
2835    flushQueuedChildren(name);
2836
2837    return state;
2838  }
2839
2840  // Checks text to see if it looks like a glob.
2841  function isGlob (text) {
2842    return text.indexOf('*') > -1;
2843  }
2844
2845  // Returns true if glob matches current $state name.
2846  function doesStateMatchGlob (glob) {
2847    var globSegments = glob.split('.'),
2848        segments = $state.$current.name.split('.');
2849
2850    //match single stars
2851    for (var i = 0, l = globSegments.length; i < l; i++) {
2852      if (globSegments[i] === '*') {
2853        segments[i] = '*';
2854      }
2855    }
2856
2857    //match greedy starts
2858    if (globSegments[0] === '**') {
2859       segments = segments.slice(indexOf(segments, globSegments[1]));
2860       segments.unshift('**');
2861    }
2862    //match greedy ends
2863    if (globSegments[globSegments.length - 1] === '**') {
2864       segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
2865       segments.push('**');
2866    }
2867
2868    if (globSegments.length != segments.length) {
2869      return false;
2870    }
2871
2872    return segments.join('') === globSegments.join('');
2873  }
2874
2875
2876  // Implicit root state that is always active
2877  root = registerState({
2878    name: '',
2879    url: '^',
2880    views: null,
2881    'abstract': true
2882  });
2883  root.navigable = null;
2884
2885
2886  /**
2887   * @ngdoc function
2888   * @name ui.router.state.$stateProvider#decorator
2889   * @methodOf ui.router.state.$stateProvider
2890   *
2891   * @description
2892   * Allows you to extend (carefully) or override (at your own peril) the 
2893   * `stateBuilder` object used internally by `$stateProvider`. This can be used 
2894   * to add custom functionality to ui-router, for example inferring templateUrl 
2895   * based on the state name.
2896   *
2897   * When passing only a name, it returns the current (original or decorated) builder
2898   * function that matches `name`.
2899   *
2900   * The builder functions that can be decorated are listed below. Though not all
2901   * necessarily have a good use case for decoration, that is up to you to decide.
2902   *
2903   * In addition, users can attach custom decorators, which will generate new 
2904   * properties within the state's internal definition. There is currently no clear 
2905   * use-case for this beyond accessing internal states (i.e. $state.$current), 
2906   * however, expect this to become increasingly relevant as we introduce additional 
2907   * meta-programming features.
2908   *
2909   * **Warning**: Decorators should not be interdependent because the order of 
2910   * execution of the builder functions in non-deterministic. Builder functions 
2911   * should only be dependent on the state definition object and super function.
2912   *
2913   *
2914   * Existing builder functions and current return values:
2915   *
2916   * - **parent** `{object}` - returns the parent state object.
2917   * - **data** `{object}` - returns state data, including any inherited data that is not
2918   *   overridden by own values (if any).
2919   * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}
2920   *   or `null`.
2921   * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is 
2922   *   navigable).
2923   * - **params** `{object}` - returns an array of state params that are ensured to 
2924   *   be a super-set of parent's params.
2925   * - **views** `{object}` - returns a views object where each key is an absolute view 
2926   *   name (i.e. "viewName@stateName") and each value is the config object 
2927   *   (template, controller) for the view. Even when you don't use the views object 
2928   *   explicitly on a state config, one is still created for you internally.
2929   *   So by decorating this builder function you have access to decorating template 
2930   *   and controller properties.
2931   * - **ownParams** `{object}` - returns an array of params that belong to the state, 
2932   *   not including any params defined by ancestor states.
2933   * - **path** `{string}` - returns the full path from the root down to this state. 
2934   *   Needed for state activation.
2935   * - **includes** `{object}` - returns an object that includes every state that 
2936   *   would pass a `$state.includes()` test.
2937   *
2938   * @example
2939   * <pre>
2940   * // Override the internal 'views' builder with a function that takes the state
2941   * // definition, and a reference to the internal function being overridden:
2942   * $stateProvider.decorator('views', function (state, parent) {
2943   *   var result = {},
2944   *       views = parent(state);
2945   *
2946   *   angular.forEach(views, function (config, name) {
2947   *     var autoName = (state.name + '.' + name).replace('.', '/');
2948   *     config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
2949   *     result[name] = config;
2950   *   });
2951   *   return result;
2952   * });
2953   *
2954   * $stateProvider.state('home', {
2955   *   views: {
2956   *     'contact.list': { controller: 'ListController' },
2957   *     'contact.item': { controller: 'ItemController' }
2958   *   }
2959   * });
2960   *
2961   * // ...
2962   *
2963   * $state.go('home');
2964   * // Auto-populates list and item views with /partials/home/contact/list.html,
2965   * // and /partials/home/contact/item.html, respectively.
2966   * </pre>
2967   *
2968   * @param {string} name The name of the builder function to decorate. 
2969   * @param {object} func A function that is responsible for decorating the original 
2970   * builder function. The function receives two parameters:
2971   *
2972   *   - `{object}` - state - The state config object.
2973   *   - `{object}` - super - The original builder function.
2974   *
2975   * @return {object} $stateProvider - $stateProvider instance
2976   */
2977  this.decorator = decorator;
2978  function decorator(name, func) {
2979    /*jshint validthis: true */
2980    if (isString(name) && !isDefined(func)) {
2981      return stateBuilder[name];
2982    }
2983    if (!isFunction(func) || !isString(name)) {
2984      return this;
2985    }
2986    if (stateBuilder[name] && !stateBuilder.$delegates[name]) {
2987      stateBuilder.$delegates[name] = stateBuilder[name];
2988    }
2989    stateBuilder[name] = func;
2990    return this;
2991  }
2992
2993  /**
2994   * @ngdoc function
2995   * @name ui.router.state.$stateProvider#state
2996   * @methodOf ui.router.state.$stateProvider
2997   *
2998   * @description
2999   * Registers a state configuration under a given state name. The stateConfig object
3000   * has the following acceptable properties.
3001   *
3002   * @param {string} name A unique state name, e.g. "home", "about", "contacts".
3003   * To create a parent/child state use a dot, e.g. "about.sales", "home.newest".
3004   * @param {object} stateConfig State configuration object.
3005   * @param {string|function=} stateConfig.template
3006   * <a id='template'></a>
3007   *   html template as a string or a function that returns
3008   *   an html template as a string which should be used by the uiView directives. This property 
3009   *   takes precedence over templateUrl.
3010   *   
3011   *   If `template` is a function, it will be called with the following parameters:
3012   *
3013   *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
3014   *     applying the current state
3015   *
3016   * <pre>template:
3017   *   "<h1>inline template definition</h1>" +
3018   *   "<div ui-view></div>"</pre>
3019   * <pre>template: function(params) {
3020   *       return "<h1>generated template</h1>"; }</pre>
3021   * </div>
3022   *
3023   * @param {string|function=} stateConfig.templateUrl
3024   * <a id='templateUrl'></a>
3025   *
3026   *   path or function that returns a path to an html
3027   *   template that should be used by uiView.
3028   *   
3029   *   If `templateUrl` is a function, it will be called with the following parameters:
3030   *
3031   *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by 
3032   *     applying the current state
3033   *
3034   * <pre>templateUrl: "home.html"</pre>
3035   * <pre>templateUrl: function(params) {
3036   *     return myTemplates[params.pageId]; }</pre>
3037   *
3038   * @param {function=} stateConfig.templateProvider
3039   * <a id='templateProvider'></a>
3040   *    Provider function that returns HTML content string.
3041   * <pre> templateProvider:
3042   *       function(MyTemplateService, params) {
3043   *         return MyTemplateService.getTemplate(params.pageId);
3044   *       }</pre>
3045   *
3046   * @param {string|function=} stateConfig.controller
3047   * <a id='controller'></a>
3048   *
3049   *  Controller fn that should be associated with newly
3050   *   related scope or the name of a registered controller if passed as a string.
3051   *   Optionally, the ControllerAs may be declared here.
3052   * <pre>controller: "MyRegisteredController"</pre>
3053   * <pre>controller:
3054   *     "MyRegisteredController as fooCtrl"}</pre>
3055   * <pre>controller: function($scope, MyService) {
3056   *     $scope.data = MyService.getData(); }</pre>
3057   *
3058   * @param {function=} stateConfig.controllerProvider
3059   * <a id='controllerProvider'></a>
3060   *
3061   * Injectable provider function that returns the actual controller or string.
3062   * <pre>controllerProvider:
3063   *   function(MyResolveData) {
3064   *     if (MyResolveData.foo)
3065   *       return "FooCtrl"
3066   *     else if (MyResolveData.bar)
3067   *       return "BarCtrl";
3068   *     else return function($scope) {
3069   *       $scope.baz = "Qux";
3070   *     }
3071   *   }</pre>
3072   *
3073   * @param {string=} stateConfig.controllerAs
3074   * <a id='controllerAs'></a>
3075   * 
3076   * A controller alias name. If present the controller will be
3077   *   published to scope under the controllerAs name.
3078   * <pre>controllerAs: "myCtrl"</pre>
3079   *
3080   * @param {string|object=} stateConfig.parent
3081   * <a id='parent'></a>
3082   * Optionally specifies the parent state of this state.
3083   *
3084   * <pre>parent: 'parentState'</pre>
3085   * <pre>parent: parentState // JS variable</pre>
3086   *
3087   * @param {object=} stateConfig.resolve
3088   * <a id='resolve'></a>
3089   *
3090   * An optional map&lt;string, function&gt; of dependencies which
3091   *   should be injected into the controller. If any of these dependencies are promises, 
3092   *   the router will wait for them all to be resolved before the controller is instantiated.
3093   *   If all the promises are resolved successfully, the $stateChangeSuccess event is fired
3094   *   and the values of the resolved promises are injected into any controllers that reference them.
3095   *   If any  of the promises are rejected the $stateChangeError event is fired.
3096   *
3097   *   The map object is:
3098   *   
3099   *   - key - {string}: name of dependency to be injected into controller
3100   *   - factory - {string|function}: If string then it is alias for service. Otherwise if function, 
3101   *     it is injected and return value it treated as dependency. If result is a promise, it is 
3102   *     resolved before its value is injected into controller.
3103   *
3104   * <pre>resolve: {
3105   *     myResolve1:
3106   *       function($http, $stateParams) {
3107   *         return $http.get("/api/foos/"+stateParams.fooID);
3108   *       }
3109   *     }</pre>
3110   *
3111   * @param {string=} stateConfig.url
3112   * <a id='url'></a>
3113   *
3114   *   A url fragment with optional parameters. When a state is navigated or
3115   *   transitioned to, the `$stateParams` service will be populated with any 
3116   *   parameters that were passed.
3117   *
3118   *   (See {@link ui.router.util.type:UrlMatcher UrlMatcher} `UrlMatcher`} for
3119   *   more details on acceptable patterns )
3120   *
3121   * examples:
3122   * <pre>url: "/home"
3123   * url: "/users/:userid"
3124   * url: "/books/{bookid:[a-zA-Z_-]}"
3125   * url: "/books/{categoryid:int}"
3126   * url: "/books/{publishername:string}/{categoryid:int}"
3127   * url: "/messages?before&after"
3128   * url: "/messages?{before:date}&{after:date}"
3129   * url: "/messages/:mailboxid?{before:date}&{after:date}"
3130   * </pre>
3131   *
3132   * @param {object=} stateConfig.views
3133   * <a id='views'></a>
3134   * an optional map&lt;string, object&gt; which defined multiple views, or targets views
3135   * manually/explicitly.
3136   *
3137   * Examples:
3138   *
3139   * Targets three named `ui-view`s in the parent state's template
3140   * <pre>views: {
3141   *     header: {
3142   *       controller: "headerCtrl",
3143   *       templateUrl: "header.html"
3144   *     }, body: {
3145   *       controller: "bodyCtrl",
3146   *       templateUrl: "body.html"
3147   *     }, footer: {
3148   *       controller: "footCtrl",
3149   *       templateUrl: "footer.html"
3150   *     }
3151   *   }</pre>
3152   *
3153   * Targets named `ui-view="header"` from grandparent state 'top''s template, and named `ui-view="body" from parent state's template.
3154   * <pre>views: {
3155   *     'header@top': {
3156   *       controller: "msgHeaderCtrl",
3157   *       templateUrl: "msgHeader.html"
3158   *     }, 'body': {
3159   *       controller: "messagesCtrl",
3160   *       templateUrl: "messages.html"
3161   *     }
3162   *   }</pre>
3163   *
3164   * @param {boolean=} [stateConfig.abstract=false]
3165   * <a id='abstract'></a>
3166   * An abstract state will never be directly activated,
3167   *   but can provide inherited properties to its common children states.
3168   * <pre>abstract: true</pre>
3169   *
3170   * @param {function=} stateConfig.onEnter
3171   * <a id='onEnter'></a>
3172   *
3173   * Callback function for when a state is entered. Good way
3174   *   to trigger an action or dispatch an event, such as opening a dialog.
3175   * If minifying your scripts, make sure to explicitly annotate this function,
3176   * because it won't be automatically annotated by your build tools.
3177   *
3178   * <pre>onEnter: function(MyService, $stateParams) {
3179   *     MyService.foo($stateParams.myParam);
3180   * }</pre>
3181   *
3182   * @param {function=} stateConfig.onExit
3183   * <a id='onExit'></a>
3184   *
3185   * Callback function for when a state is exited. Good way to
3186   *   trigger an action or dispatch an event, such as opening a dialog.
3187   * If minifying your scripts, make sure to explicitly annotate this function,
3188   * because it won't be automatically annotated by your build tools.
3189   *
3190   * <pre>onExit: function(MyService, $stateParams) {
3191   *     MyService.cleanup($stateParams.myParam);
3192   * }</pre>
3193   *
3194   * @param {boolean=} [stateConfig.reloadOnSearch=true]
3195   * <a id='reloadOnSearch'></a>
3196   *
3197   * If `false`, will not retrigger the same state
3198   *   just because a search/query parameter has changed (via $location.search() or $location.hash()). 
3199   *   Useful for when you'd like to modify $location.search() without triggering a reload.
3200   * <pre>reloadOnSearch: false</pre>
3201   *
3202   * @param {object=} stateConfig.data
3203   * <a id='data'></a>
3204   *
3205   * Arbitrary data object, useful for custom configuration.  The parent state's `data` is
3206   *   prototypally inherited.  In other words, adding a data property to a 
3206state adds it to
3207   *   the entire subtree via prototypal inheritance.
3208   *
3209   * <pre>data: {
3210   *     requiredRole: 'foo'
3211   * } </pre>
3212   *
3213   * @param {object=} stateConfig.params
3214   * <a id='params'></a>
3215   *
3216   * A map which optionally configures parameters declared in the `url`, or
3217   *   defines additional non-url parameters.  For each parameter being
3218   *   configured, add a configuration object keyed to the name of the parameter.
3219   *
3220   *   Each parameter configuration object may contain the following properties:
3221   *
3222   *   - ** value ** - {object|function=}: specifies the default value for this
3223   *     parameter.  This implicitly sets this parameter as optional.
3224   *
3225   *     When UI-Router routes to a state and no value is
3226   *     specified for this parameter in the URL or transition, the
3227   *     default value will be used instead.  If `value` is a function,
3228   *     it will be injected and invoked, and the return value used.
3229   *
3230   *     *Note*: `undefined` is treated as "no default value" while `null`
3231   *     is treated as "the default value is `null`".
3232   *
3233   *     *Shorthand*: If you only need to configure the default value of the
3234   *     parameter, you may use a shorthand syntax.   In the **`params`**
3235   *     map, instead mapping the param name to a full parameter configuration
3236   *     object, simply set map it to the default parameter value, e.g.:
3237   *
3238   * <pre>// define a parameter's default value
3239   * params: {
3240   *     param1: { value: "defaultValue" }
3241   * }
3242   * // shorthand default values
3243   * params: {
3244   *     param1: "defaultValue",
3245   *     param2: "param2Default"
3246   * }</pre>
3247   *
3248   *   - ** array ** - {boolean=}: *(default: false)* If true, the param value will be
3249   *     treated as an array of values.  If you specified a Type, the value will be
3250   *     treated as an array of the specified Type.  Note: query parameter values
3251   *     default to a special `"auto"` mode.
3252   *
3253   *     For query parameters in `"auto"` mode, if multiple  values for a single parameter
3254   *     are present in the URL (e.g.: `/foo?bar=1&bar=2&bar=3`) then the values
3255   *     are mapped to an array (e.g.: `{ foo: [ '1', '2', '3' ] }`).  However, if
3256   *     only one value is present (e.g.: `/foo?bar=1`) then the value is treated as single
3257   *     value (e.g.: `{ foo: '1' }`).
3258   *
3259   * <pre>params: {
3260   *     param1: { array: true }
3261   * }</pre>
3262   *
3263   *   - ** squash ** - {bool|string=}: `squash` configures how a default parameter value is represented in the URL when
3264   *     the current parameter value is the same as the default value. If `squash` is not set, it uses the
3265   *     configured default squash policy.
3266   *     (See {@link ui.router.util.$urlMatcherFactory#methods_defaultSquashPolicy `defaultSquashPolicy()`})
3267   *
3268   *   There are three squash settings:
3269   *
3270   *     - false: The parameter's default value is not squashed.  It is encoded and included in the URL
3271   *     - true: The parameter's default value is omitted from the URL.  If the parameter is preceeded and followed
3272   *       by slashes in the state's `url` declaration, then one of those slashes are omitted.
3273   *       This can allow for cleaner looking URLs.
3274   *     - `"<arbitrary string>"`: The parameter's default value is replaced with an arbitrary placeholder of  your choice.
3275   *
3276   * <pre>params: {
3277   *     param1: {
3278   *       value: "defaultId",
3279   *       squash: true
3280   * } }
3281   * // squash "defaultValue" to "~"
3282   * params: {
3283   *     param1: {
3284   *       value: "defaultValue",
3285   *       squash: "~"
3286   * } }
3287   * </pre>
3288   *
3289   *
3290   * @example
3291   * <pre>
3292   * // Some state name examples
3293   *
3294   * // stateName can be a single top-level name (must be unique).
3295   * $stateProvider.state("home", {});
3296   *
3297   * // Or it can be a nested state name. This state is a child of the
3298   * // above "home" state.
3299   * $stateProvider.state("home.newest", {});
3300   *
3301   * // Nest states as deeply as needed.
3302   * $stateProvider.state("home.newest.abc.xyz.inception", {});
3303   *
3304   * // state() returns $stateProvider, so you can chain state declarations.
3305   * $stateProvider
3306   *   .state("home", {})
3307   *   .state("about", {})
3308   *   .state("contacts", {});
3309   * </pre>
3310   *
3311   */
3312  this.state = state;
3313  function state(name, definition) {
3314    /*jshint validthis: true */
3315    if (isObject(name)) definition = name;
3316    else definition.name = name;
3317    registerState(definition);
3318    return this;
3319  }
3320
3321  /**
3322   * @ngdoc object
3323   * @name ui.router.state.$state
3324   *
3325   * @requires $rootScope
3326   * @requires $q
3327   * @requires ui.router.state.$view
3328   * @requires $injector
3329   * @requires ui.router.util.$resolve
3330   * @requires ui.router.state.$stateParams
3331   * @requires ui.router.router.$urlRouter
3332   *
3333   * @property {object} params A param object, e.g. {sectionId: section.id)}, that 
3334   * you'd like to test against the current active state.
3335   * @property {object} current A reference to the state's config object. However 
3336   * you passed it in. Useful for accessing custom data.
3337   * @property {object} transition Currently pending transition. A promise that'll 
3338   * resolve or reject.
3339   *
3340   * @description
3341   * `$state` service is responsible for representing states as well as transitioning
3342   * between them. It also provides interfaces to ask for current state or even states
3343   * you're coming from.
3344   */
3345  this.$get = $get;
3346  $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$urlRouter', '$location', '$urlMatcherFactory'];
3347  function $get(   $rootScope,   $q,   $view,   $injector,   $resolve,   $stateParams,   $urlRouter,   $location,   $urlMatcherFactory) {
3348
3349    var TransitionSupersededError = new Error('transition superseded');
3350
3351    var TransitionSuperseded = silenceUncaughtInPromise($q.reject(TransitionSupersededError));
3352    var TransitionPrevented = silenceUncaughtInPromise($q.reject(new Error('transition prevented')));
3353    var TransitionAborted = silenceUncaughtInPromise($q.reject(new Error('transition aborted')));
3354    var TransitionFailed = silenceUncaughtInPromise($q.reject(new Error('transition failed')));
3355
3356    // Handles the case where a state which is the target of a transition is not found, and the user
3357    // can optionally retry or defer the transition
3358    function handleRedirect(redirect, state, params, options) {
3359      /**
3360       * @ngdoc event
3361       * @name ui.router.state.$state#$stateNotFound
3362       * @eventOf ui.router.state.$state
3363       * @eventType broadcast on root scope
3364       * @description
3365       * Fired when a requested state **cannot be found** using the provided state name during transition.
3366       * The event is broadcast allowing any handlers a single chance to deal with the error (usually by
3367       * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler,
3368       * you can see its three properties in the example. You can use `event.preventDefault()` to abort the
3369       * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value.
3370       *
3371       * @param {Object} event Event object.
3372       * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties.
3373       * @param {State} fromState Current state object.
3374       * @param {Object} fromParams Current state params.
3375       *
3376       * @example
3377       *
3378       * <pre>
3379       * // somewhere, assume lazy.state has not been defined
3380       * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
3381       *
3382       * // somewhere else
3383       * $scope.$on('$stateNotFound',
3384       * function(event, unfoundState, fromState, fromParams){
3385       *     console.log(unfoundState.to); // "lazy.state"
3386       *     console.log(unfoundState.toParams); // {a:1, b:2}
3387       *     console.log(unfoundState.options); // {inherit:false} + default options
3388       * })
3389       * </pre>
3390       */
3391      var evt = $rootScope.$broadcast('$stateNotFound', redirect, state, params);
3392
3393      if (evt.defaultPrevented) {
3394        $urlRouter.update();
3395        return TransitionAborted;
3396      }
3397
3398      if (!evt.retry) {
3399        return null;
3400      }
3401
3402      // Allow the handler to return a promise to defer state lookup retry
3403      if (options.$retry) {
3404        $urlRouter.update();
3405        return TransitionFailed;
3406      }
3407      var retryTransition = $state.transition = $q.when(evt.retry);
3408
3409      retryTransition.then(function() {
3410        if (retryTransition !== $state.transition) {
3411          $rootScope.$broadcast('$stateChangeCancel', redirect.to, redirect.toParams, state, params);
3412          return TransitionSuperseded;
3413        }
3414        redirect.options.$retry = true;
3415        return $state.transitionTo(redirect.to, redirect.toParams, redirect.options);
3416      }, function() {
3417        return TransitionAborted;
3418      });
3419      $urlRouter.update();
3420
3421      return retryTransition;
3422    }
3423
3424    root.locals = { resolve: null, globals: { $stateParams: {} } };
3425
3426    $state = {
3427      params: {},
3428      current: root.self,
3429      $current: root,
3430      transition: null
3431    };
3432
3433    /**
3434     * @ngdoc function
3435     * @name ui.router.state.$state#reload
3436     * @methodOf ui.router.state.$state
3437     *
3438     * @description
3439     * A method that force reloads the current state. All resolves are re-resolved,
3440     * controllers reinstantiated, and events re-fired.
3441     *
3442     * @example
3443     * <pre>
3444     * var app angular.module('app', ['ui.router']);
3445     *
3446     * app.controller('ctrl', function ($scope, $state) {
3447     *   $scope.reload = function(){
3448     *     $state.reload();
3449     *   }
3450     * });
3451     * </pre>
3452     *
3453     * `reload()` is just an alias for:
3454     * <pre>
3455     * $state.transitionTo($state.current, $stateParams, { 
3456     *   reload: true, inherit: false, notify: true
3457     * });
3458     * </pre>
3459     *
3460     * @param {string=|object=} state - A state name or a state object, which is the root of the resolves to be re-resolved.
3461     * @example
3462     * <pre>
3463     * //assuming app application consists of 3 states: 'contacts', 'contacts.detail', 'contacts.detail.item' 
3464     * //and current state is 'contacts.detail.item'
3465     * var app angular.module('app', ['ui.router']);
3466     *
3467     * app.controller('ctrl', function ($scope, $state) {
3468     *   $scope.reload = function(){
3469     *     //will reload 'contact.detail' and 'contact.detail.item' states
3470     *     $state.reload('contact.detail');
3471     *   }
3472     * });
3473     * </pre>
3474     *
3475     * `reload()` is just an alias for:
3476     * <pre>
3477     * $state.transitionTo($state.current, $stateParams, { 
3478     *   reload: true, inherit: false, notify: true
3479     * });
3480     * </pre>
3481
3482     * @returns {promise} A promise representing the state of the new transition. See
3483     * {@link ui.router.state.$state#methods_go $state.go}.
3484     */
3485    $state.reload = function reload(state) {
3486      return $state.transitionTo($state.current, $stateParams, { reload: state || true, inherit: false, notify: true});
3487    };
3488
3489    /**
3490     * @ngdoc function
3491     * @name ui.router.state.$state#go
3492     * @methodOf ui.router.state.$state
3493     *
3494     * @description
3495     * Convenience method for transitioning to a new state. `$state.go` calls 
3496     * `$state.transitionTo` internally but automatically sets options to 
3497     * `{ location: true, inherit: true, relative: $state.$current, notify: true }`. 
3498     * This allows you to easily use an absolute or relative to path and specify 
3499     * only the parameters you'd like to update (while letting unspecified parameters 
3500     * inherit from the currently active ancestor states).
3501     *
3502     * @example
3503     * <pre>
3504     * var app = angular.module('app', ['ui.router']);
3505     *
3506     * app.controller('ctrl', function ($scope, $state) {
3507     *   $scope.changeState = function () {
3508     *     $state.go('contact.detail');
3509     *   };
3510     * });
3511     * </pre>
3512     * <img src='../ngdoc_assets/StateGoExamples.png'/>
3513     *
3514     * @param {string} to Absolute state name or relative state path. Some examples:
3515     *
3516     * - `$state.go('contact.detail')` - will go to the `contact.detail` state
3517     * - `$state.go('^')` - will go to a parent state
3518     * - `$state.go('^.sibling')` - will go to a sibling state
3519     * - `$state.go('.child.grandchild')` - will go to grandchild state
3520     *
3521     * @param {object=} params A map of the parameters that will be sent to the state, 
3522     * will populate $stateParams. Any parameters that are not specified will be inherited from currently 
3523     * defined parameters. Only parameters specified in the state definition can be overridden, new 
3524     * parameters will be ignored. This allows, for example, going to a sibling state that shares parameters
3525     * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e.
3526     * transitioning to a sibling will get you the parameters for all parents, transitioning to a child
3527     * will get you all current parameters, etc.
3528     * @param {object=} options Options object. The options are:
3529     *
3530     * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
3531     *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
3532     * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
3533     * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
3534     *    defines which state to be relative from.
3535     * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
3536     * - **`reload`** (v0.2.5) - {boolean=false|string|object}, If `true` will force transition even if no state or params
3537     *    have changed.  It will reload the resolves and views of the current state and parent states.
3538     *    If `reload` is a string (or state object), the state object is fetched (by name, or object reference); and \
3539     *    the transition reloads the resolves and views for that matched state, and all its children states.
3540     *
3541     * @returns {promise} A promise representing the state of the new transition.
3542     *
3543     * Possible success values:
3544     *
3545     * - $state.current
3546     *
3547     * <br/>Possible rejection values:
3548     *
3549     * - 'transition superseded' - when a newer transition has been started after this one
3550     * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener
3551     * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or
3552     *   when a `$stateNotFound` `event.retry` promise errors.
3553     * - 'transition failed' - when a state has been unsuccessfully found after 2 tries.
3554     * - *resolve error* - when an error has occurred with a `resolve`
3555     *
3556     */
3557    $state.go = function go(to, params, options) {
3558      return $state.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options));
3559    };
3560
3561    /**
3562     * @ngdoc function
3563     * @name ui.router.state.$state#transitionTo
3564     * @methodOf ui.router.state.$state
3565     *
3566     * @description
3567     * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go}
3568     * uses `transitionTo` internally. `$state.go` is recommended in most situations.
3569     *
3570     * @example
3571     * <pre>
3572     * var app = angular.module('app', ['ui.router']);
3573     *
3574     * app.controller('ctrl', function ($scope, $state) {
3575     *   $scope.changeState = function () {
3576     *     $state.transitionTo('contact.detail');
3577     *   };
3578     * });
3579     * </pre>
3580     *
3581     * @param {string} to State name.
3582     * @param {object=} toParams A map of the parameters that will be sent to the state,
3583     * will populate $stateParams.
3584     * @param {object=} options Options object. The options are:
3585     *
3586     * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
3587     *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
3588     * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
3589     * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), 
3590     *    defines which state to be relative from.
3591     * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
3592     * - **`reload`** (v0.2.5) - {boolean=false|string=|object=}, If `true` will force transition even if the state or params 
3593     *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
3594     *    use this when you want to force a reload when *everything* is the same, including search params.
3595     *    if String, then will reload the state with the name given in reload, and any children.
3596     *    if Object, then a stateObj is expected, will reload the state found in stateObj, and any children.
3597     *
3598     * @returns {promise} A promise representing the state of the new transition. See
3599     * {@link ui.router.state.$state#methods_go $state.go}.
3600     */
3601    $state.transitionTo = function transitionTo(to, toParams, options) {
3602      toParams = toParams || {};
3603      options = extend({
3604        location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false
3605      }, options || {});
3606
3607      var from = $state.$current, fromParams = $state.params, fromPath = from.path;
3608      var evt, toState = findState(to, options.relative);
3609
3610      // Store the hash param for later (since it will be stripped out by various methods)
3611      var hash = toParams['#'];
3612
3613      if (!isDefined(toState)) {
3614        var redirect = { to: to, toParams: toParams, options: options };
3615        var redirectResult = handleRedirect(redirect, from.self, fromParams, options);
3616
3617        if (redirectResult) {
3618          return redirectResult;
3619        }
3620
3621        // Always retry once if the $stateNotFound was not prevented
3622        // (handles either redirect changed or state lazy-definition)
3623        to = redirect.to;
3624        toParams = redirect.toParams;
3625        options = redirect.options;
3626        toState = findState(to, options.relative);
3627
3628        if (!isDefined(toState)) {
3629          if (!options.relative) throw new Error("No such state '" + to + "'");
3630          throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
3631        }
3632      }
3633      if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
3634      if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
3635      if (!toState.params.$$validates(toParams)) return TransitionFailed;
3636
3637      toParams = toState.params.$$values(toParams);
3638      to = toState;
3639
3640      var toPath = to.path;
3641
3642      // Starting from the root of the path, keep all levels that haven't changed
3643      var keep = 0, state = toPath[keep], locals = root.locals, toLocals = [];
3644
3645      if (!options.reload) {
3646        while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) {
3647          locals = toLocals[keep] = state.locals;
3648          keep++;
3649          state = toPath[keep];
3650        }
3651      } else if (isString(options.reload) || isObject(options.reload)) {
3652        if (isObject(options.reload) && !options.reload.name) {
3653          throw new Error('Invalid reload state object');
3654        }
3655        
3656        var reloadState = options.reload === true ? fromPath[0] : findState(options.reload);
3657        if (options.reload && !reloadState) {
3658          throw new Error("No such reload state '" + (isString(options.reload) ? options.reload : options.reload.name) + "'");
3659        }
3660
3661        while (state && state === fromPath[keep] && state !== reloadState) {
3662          locals = toLocals[keep] = state.locals;
3663          keep++;
3664          state = toPath[keep];
3665        }
3666      }
3667
3668      // If we're going to the same state and all locals are kept, we've got nothing to do.
3669      // But clear 'transition', as we still want to cancel any other pending transitions.
3670      // TODO: We may not want to bump 'transition' if we're called from a location change
3671      // that we've initiated ourselves, because we might accidentally abort a legitimate
3672      // transition initiated from code?
3673      if (shouldSkipReload(to, toParams, from, fromParams, locals, options)) {
3674        if (hash) toParams['#'] = hash;
3675        $state.params = toParams;
3676        copy($state.params, $stateParams);
3677        copy(filterByKeys(to.params.$$keys(), $stateParams), to.locals.globals.$stateParams);
3678        if (options.location && to.navigable && to.navigable.url) {
3679          $urlRouter.push(to.navigable.url, toParams, {
3680            $$avoidResync: true, replace: options.location === 'replace'
3681          });
3682          $urlRouter.update(true);
3683        }
3684        $state.transition = null;
3685        return $q.when($state.current);
3686      }
3687
3688      // Filter parameters before we pass them to event handlers etc.
3689      toParams = filterByKeys(to.params.$$keys(), toParams || {});
3690      
3691      // Re-add the saved hash before we start returning things or broadcasting $stateChangeStart
3692      if (hash) toParams['#'] = hash;
3693      
3694      // Broadcast start event and cancel the transition if requested
3695      if (options.notify) {
3696        /**
3697         * @ngdoc event
3698         * @name ui.router.state.$state#$stateChangeStart
3699         * @eventOf ui.router.state.$state
3700         * @eventType broadcast on root scope
3701         * @description
3702         * Fired when the state transition **begins**. You can use `event.preventDefault()`
3703         * to prevent the transition from happening and then the transition promise will be
3704         * rejected with a `'transition prevented'` value.
3705         *
3706         * @param {Object} event Event object.
3707         * @param {State} toState The state being transitioned to.
3708         * @param {Object} toParams The params supplied to the `toState`.
3709         * @param {State} fromState The current state, pre-transition.
3710         * @param {Object} fromParams The params supplied to the `fromState`.
3711         *
3712         * @example
3713         *
3714         * <pre>
3715         * $rootScope.$on('$stateChangeStart',
3716         * function(event, toState, toParams, fromState, fromParams){
3717         *     event.preventDefault();
3718         *     // transitionTo() promise will be rejected with
3719         *     // a 'transition prevented' error
3720         * })
3721         * </pre>
3722         */
3723        if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams, options).defaultPrevented) {
3724          $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
3725          //Don't update and resync url if there's been a new transition started. see issue #2238, #600
3726          if ($state.transition == null) $urlRouter.update();
3727          return TransitionPrevented;
3728        }
3729      }
3730
3731      // Resolve locals for the remaining states, but don't update any global state just
3732      // yet -- if anything fails to resolve the current state needs to remain untouched.
3733      // We also set up an inheritance chain for the locals here. This allows the view directive
3734      // to quickly look up the correct definition for each view in the current state. Even
3735      // though we create the locals object itself outside resolveState(), it is initially
3736      // empty and gets filled asynchronously. We need to keep track of the promise for the
3737      // (fully resolved) current locals, and pass this down the chain.
3738      var resolved = $q.when(locals);
3739
3740      for (var l = keep; l < toPath.length; l++, state = toPath[l]) {
3741        locals = toLocals[l] = inherit(locals);
3742        resolved = resolveState(state, toParams, state === to, resolved, locals, options);
3743      }
3744
3745      // Once everything is resolved, we are ready to perform the actual transition
3746      // and return a promise for the new state. We also keep track of what the
3747      // current promise is, so that we can detect overlapping transitions and
3748      // keep only the outcome of the last transition.
3749      var transition = $state.transition = resolved.then(function () {
3750        var l, entering, exiting;
3751
3752        if ($state.transition !== transition) {
3753          $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
3754          return TransitionSuperseded;
3755        }
3756
3757        // Exit 'from' states not kept
3758        for (l = fromPath.length - 1; l >= keep; l--) {
3759          exiting = fromPath[l];
3760          if (exiting.self.onExit) {
3761            $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
3762          }
3763          exiting.locals = null;
3764        }
3765
3766        // Enter 'to' states not kept
3767        for (l = keep; l < toPath.length; l++) {
3768          entering = toPath[l];
3769          entering.locals = toLocals[l];
3770          if (entering.self.onEnter) {
3771            $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
3772          }
3773        }
3774
3775        // Run it again, to catch any transitions in callbacks
3776        if ($state.transition !== transition) {
3777          $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
3778          return TransitionSuperseded;
3779        }
3780
3781        // Update globals in $state
3782        $state.$current = to;
3783        $state.current = to.self;
3784        $state.params = toParams;
3785        copy($state.params, $stateParams);
3786        $state.transition = null;
3787
3788        if (options.location && to.navigable) {
3789          $urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, {
3790            $$avoidResync: true, replace: options.location === 'replace'
3791          });
3792        }
3793
3794        if (options.notify) {
3795        /**
3796         * @ngdoc event
3797         * @name ui.router.state.$state#$stateChangeSuccess
3798         * @eventOf ui.router.state.$state
3799         * @eventType broadcast on root scope
3800         * @description
3801         * Fired once the state transition is **complete**.
3802         *
3803         * @param {Object} event Event object.
3804         * @param {State} toState The state being transitioned to.
3805         * @param {Object} toParams The params supplied to the `toState`.
3806         * @param {State} fromState The current state, pre-transition.
3807         * @param {Object} fromParams The params supplied to the `fromState`.
3808         */
3809          $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams);
3810        }
3811        $urlRouter.update(true);
3812
3813        return $state.current;
3814      }).then(null, function (error) {
3815        // propagate TransitionSuperseded error without emitting $stateChangeCancel
3816        // as it was already emitted in the success handler above
3817        if (error === TransitionSupersededError) return TransitionSuperseded;
3818
3819        if ($state.transition !== transition) {
3820          $rootScope.$broadcast('$stateChangeCancel', to.self, toParams, from.self, fromParams);
3821          return TransitionSuperseded;
3822        }
3823
3824        $state.transition = null;
3825        /**
3826         * @ngdoc event
3827         * @name ui.router.state.$state#$stateChangeError
3828         * @eventOf ui.router.state.$state
3829         * @eventType broadcast on root scope
3830         * @description
3831         * Fired when an **error occurs** during transition. It's important to note that if you
3832         * have any errors in your resolve functions (javascript errors, non-existent services, etc)
3833         * they will not throw traditionally. You must listen for this $stateChangeError event to
3834         * catch **ALL** errors.
3835         *
3836         * @param {Object} event Event object.
3837         * @param {State} toState The state being transitioned to.
3838         * @param {Object} toParams The params supplied to the `toState`.
3839         * @param {State} fromState The current state, pre-transition.
3840         * @param {Object} fromParams The params supplied to the `fromState`.
3841         * @param {Error} error The resolve error object.
3842         */
3843        evt = $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error);
3844
3845        if (!evt.defaultPrevented) {
3846          $urlRouter.update();
3847        }
3848
3849        return $q.reject(error);
3850      });
3851
3852      silenceUncaughtInPromise(transition);
3853      return transition;
3854    };
3855
3856    /**
3857     * @ngdoc function
3858     * @name ui.router.state.$state#is
3859     * @methodOf ui.router.state.$state
3860     *
3861     * @description
3862     * Similar to {@link ui.router.state.$state#methods_includes $state.includes},
3863     * but only checks for the full state name. If params is supplied then it will be
3864     * tested for strict equality against the current active params object, so all params
3865     * must match with none missing and no extras.
3866     *
3867     * @example
3868     * <pre>
3869     * $state.$current.name = 'contacts.details.item';
3870     *
3871     * // absolute name
3872     * $state.is('contact.details.item'); // returns true
3873     * $state.is(contactDetailItemStateObject); // returns true
3874     *
3875     * // relative name (. and ^), typically from a template
3876     * // E.g. from the 'contacts.details' template
3877     * <div ng-class="{highlighted: $state.is('.item')}">Item</div>
3878     * </pre>
3879     *
3880     * @param {string|object} stateOrName The state name (absolute or relative) or state object you'd like to check.
3881     * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like
3882     * to test against the current active state.
3883     * @param {object=} options An options object.  The options are:
3884     *
3885     * - **`relative`** - {string|object} -  If `stateOrName` is a relative state name and `options.relative` is set, .is will
3886     * test relative to `options.relative` state (or name).
3887     *
3888     * @returns {boolean} Returns true if it is the state.
3889     */
3890    $state.is = function is(stateOrName, params, options) {
3891      options = extend({ relative: $state.$current }, options || {});
3892      var state = findState(stateOrName, options.relative);
3893
3894      if (!isDefined(state)) { return undefined; }
3895      if ($state.$current !== state) { return false; }
3896
3897      return !params || objectKeys(params).reduce(function(acc, key) {
3898        var paramDef = state.params[key];
3899        return acc && (!paramDef || paramDef.type.equals($stateParams[key], params[key]));
3900      }, true);
3901    };
3902
3903    /**
3904     * @ngdoc function
3905     * @name ui.router.state.$state#includes
3906     * @methodOf ui.router.state.$state
3907     *
3908     * @description
3909     * A method to determine if the current active state is equal to or is the child of the
3910     * state stateName. If any params are passed then they will be tested for a match as well.
3911     * Not all the parameters need to be passed, just the ones you'd like to test for equality.
3912     *
3913     * @example
3914     * Partial and relative names
3915     * <pre>
3916     * $state.$current.name = 'contacts.details.item';
3917     *
3918     * // Using partial names
3919     * $state.includes("contacts"); // returns true
3920     * $state.includes("contacts.details"); // returns true
3921     * $state.includes("contacts.details.item"); // returns true
3922     * $state.includes("contacts.list"); // returns false
3923     * $state.includes("about"); // returns false
3924     *
3925     * // Using relative names (. and ^), typically from a template
3926     * // E.g. from the 'contacts.details' template
3927     * <div ng-class="{highlighted: $state.includes('.item')}">Item</div>
3928     * </pre>
3929     *
3930     * Basic globbing patterns
3931     * <pre>
3932     * $state.$current.name = 'contacts.details.item.url';
3933     *
3934     * $state.includes("*.details.*.*"); // returns true
3935     * $state.includes("*.details.**"); // returns true
3936     * $state.includes("**.item.**"); // returns true
3937     * $state.includes("*.details.item.url"); // returns true
3938     * $state.includes("*.details.*.url"); // returns true
3939     * $state.includes("*.details.*"); // returns false
3940     * $state.includes("item.**"); // returns false
3941     * </pre>
3942     *
3943     * @param {string} stateOrName A partial name, relative name, or glob pattern
3944     * to be searched for within the current state name.
3945     * @param {object=} params A param object, e.g. `{sectionId: section.id}`,
3946     * that you'd like to test against the current active state.
3947     * @param {object=} options An options object.  The options are:
3948     *
3949     * - **`relative`** - {string|object=} -  If `stateOrName` is a relative state reference and `options.relative` is set,
3950     * .includes will test relative to `options.relative` state (or name).
3951     *
3952     * @returns {boolean} Returns true if it does include the state
3953     */
3954    $state.includes = function includes(stateOrName, params, options) {
3955      options = extend({ relative: $state.$current }, options || {});
3956      if (isString(stateOrName) && isGlob(stateOrName)) {
3957        if (!doesStateMatchGlob(stateOrName)) {
3958          return false;
3959        }
3960        stateOrName = $state.$current.name;
3961      }
3962
3963      var state = findState(stateOrName, options.relative);
3964      if (!isDefined(state)) { return undefined; }
3965      if (!isDefined($state.$current.includes[state.name])) { return false; }
3966      if (!params) { return true; }
3967
3968      var keys = objectKeys(params);
3969      for (var i = 0; i < keys.length; i++) {
3970        var key = keys[i], paramDef = state.params[key];
3971        if (paramDef && !paramDef.type.equals($stateParams[key], params[key])) {
3972          return false;
3973        }
3974      }
3975
3976      return objectKeys(params).reduce(function(acc, key) {
3977        var paramDef = state.params[key];
3978        return acc && !paramDef || paramDef.type.equals($stateParams[key], params[key]);
3979      }, true);
3980    };
3981
3982
3983    /**
3984     * @ngdoc function
3985     * @name ui.router.state.$state#href
3986     * @methodOf ui.router.state.$state
3987     *
3988     * @description
3989     * A url generation method that returns the compiled url for the given state populated with the given params.
3990     *
3991     * @example
3992     * <pre>
3993     * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
3994     * </pre>
3995     *
3996     * @param {string|object} stateOrName The state name or state object you'd like to generate a url from.
3997     * @param {object=} params An object of parameter values to fill the state's required parameters.
3998     * @param {object=} options Options object. The options are:
3999     *
4000     * - **`lossy`** - {boolean=true} -  If true, and if there is no url associated with the state provided in the
4001     *    first parameter, then the constructed href url will be built from the first navigable ancestor (aka
4002     *    ancestor with a valid url).
4003     * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
4004     * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
4005     *    defines which state to be relative from.
4006     * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
4007     * 
4008     * @returns {string} compiled state url
4009     */
4010    $state.href = function href(stateOrName, params, options) {
4011      options = extend({
4012        lossy:    true,
4013        inherit:  true,
4014        absolute: false,
4015        relative: $state.$current
4016      }, options || {});
4017
4018      var state = findState(stateOrName, options.relative);
4019
4020      if (!isDefined(state)) return null;
4021      if (options.inherit) params = inheritParams($stateParams, params || {}, $state.$current, state);
4022      
4023      var nav = (state && options.lossy) ? state.navigable : state;
4024
4025      if (!nav || nav.url === undefined || nav.url === null) {
4026        return null;
4027      }
4028      return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys().concat('#'), params || {}), {
4029        absolute: options.absolute
4030      });
4031    };
4032
4033    /**
4034     * @ngdoc function
4035     * @name ui.router.state.$state#get
4036     * @methodOf ui.router.state.$state
4037     *
4038     * @description
4039     * Returns the state configuration object for any specific state or all states.
4040     *
4041     * @param {string|object=} stateOrName (absolute or relative) If provided, will only get the config for
4042     * the requested state. If not provided, returns an array of ALL state configs.
4043     * @param {string|object=} context When stateOrName is a relative state reference, the state will be retrieved relative to context.
4044     * @returns {Object|Array} State configuration object or array of all objects.
4045     */
4046    $state.get = function (stateOrName, context) {
4047      if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; });
4048      var state = findState(stateOrName, context || $state.$current);
4049      return (state && state.self) ? state.self : null;
4050    };
4051
4052    function resolveState(state, params, paramsAreFiltered, inherited, dst, options) {
4053      // Make a restricted $stateParams with only the parameters that apply to this state if
4054      // necessary. In addition to being available to the controller and onEnter/onExit callbacks,
4055      // we also need $stateParams to be available for any $injector calls we make during the
4056      // dependency resolution process.
4057      var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params.$$keys(), params);
4058      var locals = { $stateParams: $stateParams };
4059
4060      // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
4061      // We're also including $stateParams in this; that way the parameters are restricted
4062      // to the set that should be visible to the state, and are independent of when we update
4063      // the global $state and $stateParams values.
4064      dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state);
4065      var promises = [dst.resolve.then(function (globals) {
4066        dst.globals = globals;
4067      })];
4068      if (inherited) promises.push(inherited);
4069
4070      function resolveViews() {
4071        var viewsPromises = [];
4072
4073        // Resolve template and dependencies for all views.
4074        forEach(state.views, function (view, name) {
4075          var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {});
4076          injectables.$template = [ function () {
4077            return $view.load(name, { view: view, locals: dst.globals, params: $stateParams, notify: options.notify }) || '';
4078          }];
4079
4080          viewsPromises.push($resolve.resolve(injectables, dst.globals, dst.resolve, state).then(function (result) {
4081            // References to the controller (only instantiated at link time)
4082            if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) {
4083              var injectLocals = angular.extend({}, injectables, dst.globals);
4084              result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals);
4085            } else {
4086              result.$$controller = view.controller;
4087            }
4088            // Provide access to the state itself for internal use
4089            result.$$state = state;
4090            result.$$controllerAs = view.controllerAs;
4091            result.$$resolveAs = view.resolveAs;
4092            dst[name] = result;
4093          }));
4094        });
4095
4096        return $q.all(viewsPromises).then(function(){
4097          return dst.globals;
4098        });
4099      }
4100
4101      // Wait for all the promises and then return the activation object
4102      return $q.all(promises).then(resolveViews).then(function (values) {
4103        return dst;
4104      });
4105    }
4106
4107    return $state;
4108  }
4109
4110  function shouldSkipReload(to, toParams, from, fromParams, locals, options) {
4111    // Return true if there are no differences in non-search (path/object) params, false if there are differences
4112    function nonSearchParamsEqual(fromAndToState, fromParams, toParams) {
4113      // Identify whether all the parameters that differ between `fromParams` and `toParams` were search params.
4114      function notSearchParam(key) {
4115        return fromAndToState.params[key].location != "search";
4116      }
4117      var nonQueryParamKeys = fromAndToState.params.$$keys().filter(notSearchParam);
4118      var nonQueryParams = pick.apply({}
4118, [fromAndToState.params].concat(nonQueryParamKeys));
4119      var nonQueryParamSet = new $$UMFP.ParamSet(nonQueryParams);
4120      return nonQueryParamSet.$$equals(fromParams, toParams);
4121    }
4122
4123    // If reload was not explicitly requested
4124    // and we're transitioning to the same state we're already in
4125    // and    the locals didn't change
4126    //     or they changed in a way that doesn't merit reloading
4127    //        (reloadOnParams:false, or reloadOnSearch.false and only search params changed)
4128    // Then return true.
4129    if (!options.reload && to === from &&
4130      (locals === from.locals || (to.self.reloadOnSearch === false && nonSearchParamsEqual(from, fromParams, toParams)))) {
4131      return true;
4132    }
4133  }
4134}
4135
4136angular.module('ui.router.state')
4137  .factory('$stateParams', function () { return {}; })
4138  .constant("$state.runtime", { autoinject: true })
4139  .provider('$state', $StateProvider)
4140  // Inject $state to initialize when entering runtime. #2574
4141  .run(['$injector', function ($injector) {
4142    // Allow tests (stateSpec.js) to turn this off by defining this constant
4143    if ($injector.get("$state.runtime").autoinject) {
4144      $injector.get('$state');
4145    }
4146  }]);
4147
4148
4149$ViewProvider.$inject = [];
4150function $ViewProvider() {
4151
4152  this.$get = $get;
4153  /**
4154   * @ngdoc object
4155   * @name ui.router.state.$view
4156   *
4157   * @requires ui.router.util.$templateFactory
4158   * @requires $rootScope
4159   *
4160   * @description
4161   *
4162   */
4163  $get.$inject = ['$rootScope', '$templateFactory'];
4164  function $get(   $rootScope,   $templateFactory) {
4165    return {
4166      // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... })
4167      /**
4168       * @ngdoc function
4169       * @name ui.router.state.$view#load
4170       * @methodOf ui.router.state.$view
4171       *
4172       * @description
4173       *
4174       * @param {string} name name
4175       * @param {object} options option object.
4176       */
4177      load: function load(name, options) {
4178        var result, defaults = {
4179          template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {}
4180        };
4181        options = extend(defaults, options);
4182
4183        if (options.view) {
4184          result = $templateFactory.fromConfig(options.view, options.params, options.locals);
4185        }
4186        return result;
4187      }
4188    };
4189  }
4190}
4191
4192angular.module('ui.router.state').provider('$view', $ViewProvider);
4193
4194/**
4195 * @ngdoc object
4196 * @name ui.router.state.$uiViewScrollProvider
4197 *
4198 * @description
4199 * Provider that returns the {@link ui.router.state.$uiViewScroll} service function.
4200 */
4201function $ViewScrollProvider() {
4202
4203  var useAnchorScroll = false;
4204
4205  /**
4206   * @ngdoc function
4207   * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll
4208   * @methodOf ui.router.state.$uiViewScrollProvider
4209   *
4210   * @description
4211   * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for
4212   * scrolling based on the url anchor.
4213   */
4214  this.useAnchorScroll = function () {
4215    useAnchorScroll = true;
4216  };
4217
4218  /**
4219   * @ngdoc object
4220   * @name ui.router.state.$uiViewScroll
4221   *
4222   * @requires $anchorScroll
4223   * @requires $timeout
4224   *
4225   * @description
4226   * When called with a jqLite element, it scrolls the element into view (after a
4227   * `$timeout` so the DOM has time to refresh).
4228   *
4229   * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor,
4230   * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}.
4231   */
4232  this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) {
4233    if (useAnchorScroll) {
4234      return $anchorScroll;
4235    }
4236
4237    return function ($element) {
4238      return $timeout(function () {
4239        $element[0].scrollIntoView();
4240      }, 0, false);
4241    };
4242  }];
4243}
4244
4245angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider);
4246
4247/**
4248 * @ngdoc directive
4249 * @name ui.router.state.directive:ui-view
4250 *
4251 * @requires ui.router.state.$state
4252 * @requires $compile
4253 * @requires $controller
4254 * @requires $injector
4255 * @requires ui.router.state.$uiViewScroll
4256 * @requires $document
4257 *
4258 * @restrict ECA
4259 *
4260 * @description
4261 * The ui-view directive tells $state where to place your templates.
4262 *
4263 * @param {string=} name A view name. The name should be unique amongst the other views in the
4264 * same state. You can have views of the same name that live in different states.
4265 *
4266 * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window
4267 * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll
4268 * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you
4269 * scroll ui-view elements into view when they are populated during a state activation.
4270 *
4271 * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll)
4272 * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.*
4273 *
4274 * @param {string=} onload Expression to evaluate whenever the view updates.
4275 *
4276 * @example
4277 * A view can be unnamed or named.
4278 * <pre>
4279 * <!-- Unnamed -->
4280 * <div ui-view></div>
4281 *
4282 * <!-- Named -->
4283 * <div ui-view="viewName"></div>
4284 * </pre>
4285 *
4286 * You can only have one unnamed view within any template (or root html). If you are only using a
4287 * single view and it is unnamed then you can populate it like so:
4288 * <pre>
4289 * <div ui-view></div>
4290 * $stateProvider.state("home", {
4291 *   template: "<h1>HELLO!</h1>"
4292 * })
4293 * </pre>
4294 *
4295 * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#methods_state `views`}
4296 * config property, by name, in this case an empty name:
4297 * <pre>
4298 * $stateProvider.state("home", {
4299 *   views: {
4300 *     "": {
4301 *       template: "<h1>HELLO!</h1>"
4302 *     }
4303 *   }    
4304 * })
4305 * </pre>
4306 *
4307 * But typically you'll only use the views property if you name your view or have more than one view
4308 * in the same template. There's not really a compelling reason to name a view if its the only one,
4309 * but you could if you wanted, like so:
4310 * <pre>
4311 * <div ui-view="main"></div>
4312 * </pre>
4313 * <pre>
4314 * $stateProvider.state("home", {
4315 *   views: {
4316 *     "main": {
4317 *       template: "<h1>HELLO!</h1>"
4318 *     }
4319 *   }    
4320 * })
4321 * </pre>
4322 *
4323 * Really though, you'll use views to set up multiple views:
4324 * <pre>
4325 * <div ui-view></div>
4326 * <div ui-view="chart"></div>
4327 * <div ui-view="data"></div>
4328 * </pre>
4329 *
4330 * <pre>
4331 * $stateProvider.state("home", {
4332 *   views: {
4333 *     "": {
4334 *       template: "<h1>HELLO!</h1>"
4335 *     },
4336 *     "chart": {
4337 *       template: "<chart_thing/>"
4338 *     },
4339 *     "data": {
4340 *       template: "<data_thing/>"
4341 *     }
4342 *   }    
4343 * })
4344 * </pre>
4345 *
4346 * Examples for `autoscroll`:
4347 *
4348 * <pre>
4349 * <!-- If autoscroll present with no expression,
4350 *      then scroll ui-view into view -->
4351 * <ui-view autoscroll/>
4352 *
4353 * <!-- If autoscroll present with valid expression,
4354 *      then scroll ui-view into view if expression evaluates to true -->
4355 * <ui-view autoscroll='true'/>
4356 * <ui-view autoscroll='false'/>
4357 * <ui-view autoscroll='scopeVariable'/>
4358 * </pre>
4359 *
4360 * Resolve data:
4361 *
4362 * The resolved data from the state's `resolve` block is placed on the scope as `$resolve` (this
4363 * can be customized using [[ViewDeclaration.resolveAs]]).  This can be then accessed from the template.
4364 *
4365 * Note that when `controllerAs` is being used, `$resolve` is set on the controller instance *after* the
4366 * controller is instantiated.  The `$onInit()` hook can be used to perform initialization code which
4367 * depends on `$resolve` data.
4368 *
4369 * Example usage of $resolve in a view template
4370 * <pre>
4371 * $stateProvider.state('home', {
4372 *   template: '<my-component user="$resolve.user"></my-component>',
4373 *   resolve: {
4374 *     user: function(UserService) { return UserService.fetchUser(); }
4375 *   }
4376 * });
4377 * </pre>
4378 */
4379$ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll', '$interpolate', '$q'];
4380function $ViewDirective(   $state,   $injector,   $uiViewScroll,   $interpolate,   $q) {
4381
4382  function getService() {
4383    return ($injector.has) ? function(service) {
4384      return $injector.has(service) ? $injector.get(service) : null;
4385    } : function(service) {
4386      try {
4387        return $injector.get(service);
4388      } catch (e) {
4389        return null;
4390      }
4391    };
4392  }
4393
4394  var service = getService(),
4395      $animator = service('$animator'),
4396      $animate = service('$animate');
4397
4398  // Returns a set of DOM manipulation functions based on which Angular version
4399  // it should use
4400  function getRenderer(attrs, scope) {
4401    var statics = function() {
4402      return {
4403        enter: function (element, target, cb) { target.after(element); cb(); },
4404        leave: function (element, cb) { element.remove(); cb(); }
4405      };
4406    };
4407
4408    if ($animate) {
4409      return {
4410        enter: function(element, target, cb) {
4411          if (angular.version.minor > 2) {
4412            $animate.enter(element, null, target).then(cb);
4413          } else {
4414            $animate.enter(element, null, target, cb);
4415          }
4416        },
4417        leave: function(element, cb) {
4418          if (angular.version.minor > 2) {
4419            $animate.leave(element).then(cb);
4420          } else {
4421            $animate.leave(element, cb);
4422          }
4423        }
4424      };
4425    }
4426
4427    if ($animator) {
4428      var animate = $animator && $animator(scope, attrs);
4429
4430      return {
4431        enter: function(element, target, cb) {animate.enter(element, null, target); cb(); },
4432        leave: function(element, cb) { animate.leave(element); cb(); }
4433      };
4434    }
4435
4436    return statics();
4437  }
4438
4439  var directive = {
4440    restrict: 'ECA',
4441    terminal: true,
4442    priority: 400,
4443    transclude: 'element',
4444    compile: function (tElement, tAttrs, $transclude) {
4445      return function (scope, $element, attrs) {
4446        var previousEl, currentEl, currentScope, latestLocals,
4447            onloadExp     = attrs.onload || '',
4448            autoScrollExp = attrs.autoscroll,
4449            renderer      = getRenderer(attrs, scope),
4450            inherited     = $element.inheritedData('$uiView');
4451
4452        scope.$on('$stateChangeSuccess', function() {
4453          updateView(false);
4454        });
4455
4456        updateView(true);
4457
4458        function cleanupLastView() {
4459          if (previousEl) {
4460            previousEl.remove();
4461            previousEl = null;
4462          }
4463
4464          if (currentScope) {
4465            currentScope.$destroy();
4466            currentScope = null;
4467          }
4468
4469          if (currentEl) {
4470            var $uiViewData = currentEl.data('$uiViewAnim');
4471            renderer.leave(currentEl, function() {
4472              $uiViewData.$$animLeave.resolve();
4473              previousEl = null;
4474            });
4475
4476            previousEl = currentEl;
4477            currentEl = null;
4478          }
4479        }
4480
4481        function updateView(firstTime) {
4482          var newScope,
4483              name            = getUiViewName(scope, attrs, $element, $interpolate),
4484              previousLocals  = name && $state.$current && $state.$current.locals[name];
4485
4486          if (!firstTime && previousLocals === latestLocals) return; // nothing to do
4487          newScope = scope.$new();
4488          latestLocals = $state.$current.locals[name];
4489
4490          /**
4491           * @ngdoc event
4492           * @name ui.router.state.directive:ui-view#$viewContentLoading
4493           * @eventOf ui.router.state.directive:ui-view
4494           * @eventType emits on ui-view directive scope
4495           * @description
4496           *
4497           * Fired once the view **begins loading**, *before* the DOM is rendered.
4498           *
4499           * @param {Object} event Event object.
4500           * @param {string} viewName Name of the view.
4501           */
4502          newScope.$emit('$viewContentLoading', name);
4503
4504          var clone = $transclude(newScope, function(clone) {
4505            var animEnter = $q.defer(), animLeave = $q.defer();
4506            var viewAnimData = {
4507              $animEnter: animEnter.promise,
4508              $animLeave: animLeave.promise,
4509              $$animLeave: animLeave
4510            };
4511
4512            clone.data('$uiViewAnim', viewAnimData);
4513            renderer.enter(clone, $element, function onUiViewEnter() {
4514              animEnter.resolve();
4515              if(currentScope) {
4516                currentScope.$emit('$viewContentAnimationEnded');
4517              }
4518
4519              if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) {
4520                $uiViewScroll(clone);
4521              }
4522            });
4523            cleanupLastView();
4524          });
4525
4526          currentEl = clone;
4527          currentScope = newScope;
4528          /**
4529           * @ngdoc event
4530           * @name ui.router.state.directive:ui-view#$viewContentLoaded
4531           * @eventOf ui.router.state.directive:ui-view
4532           * @eventType emits on ui-view directive scope
4533           * @description
4534           * Fired once the view is **loaded**, *after* the DOM is rendered.
4535           *
4536           * @param {Object} event Event object.
4537           * @param {string} viewName Name of the view.
4538           */
4539          currentScope.$emit('$viewContentLoaded', name);
4540          currentScope.$eval(onloadExp);
4541        }
4542      };
4543    }
4544  };
4545
4546  return directive;
4547}
4548
4549$ViewDirectiveFill.$inject = ['$compile', '$controller', '$state', '$interpolate'];
4550function $ViewDirectiveFill (  $compile,   $controller,   $state,   $interpolate) {
4551  return {
4552    restrict: 'ECA',
4553    priority: -400,
4554    compile: function (tElement) {
4555      var initial = tElement.html();
4556      if (tElement.empty) {
4557        tElement.empty();
4558      } else {
4559        // ng 1.0.0 doesn't have empty(), which cleans up data and handlers
4560        tElement[0].innerHTML = null;
4561      }
4562
4563      return function (scope, $element, attrs) {
4564        var current = $state.$current,
4565            name = getUiViewName(scope, attrs, $element, $interpolate),
4566            locals  = current && current.locals[name];
4567
4568        if (! locals) {
4569          $element.html(initial);
4570          $compile($element.contents())(scope);
4571          return;
4572        }
4573
4574        $element.data('$uiView', { name: name, state: locals.$$state });
4575        $element.html(locals.$template ? locals.$template : initial);
4576
4577        var resolveData = angular.extend({}, locals);
4578        scope[locals.$$resolveAs] = resolveData;
4579
4580        var link = $compile($element.contents());
4581
4582        if (locals.$$controller) {
4583          locals.$scope = scope;
4584          locals.$element = $element;
4585          var controller = $controller(locals.$$controller, locals);
4586          if (locals.$$controllerAs) {
4587            scope[locals.$$controllerAs] = controller;
4588            scope[locals.$$controllerAs][locals.$$resolveAs] = resolveData;
4589          }
4590          if (isFunction(controller.$onInit)) controller.$onInit();
4591          $element.data('$ngControllerController', controller);
4592          $element.children().data('$ngControllerController', controller);
4593        }
4594
4595        link(scope);
4596      };
4597    }
4598  };
4599}
4600
4601/**
4602 * Shared ui-view code for both directives:
4603 * Given scope, element, and its attributes, return the view's name
4604 */
4605function getUiViewName(scope, attrs, element, $interpolate) {
4606  var name = $interpolate(attrs.uiView || attrs.name || '')(scope);
4607  var uiViewCreatedBy = element.inheritedData('$uiView');
4608  return name.indexOf('@') >= 0 ?  name :  (name + '@' + (uiViewCreatedBy ? uiViewCreatedBy.state.name : ''));
4609}
4610
4611angular.module('ui.router.state').directive('uiView', $ViewDirective);
4612angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);
4613
4614function parseStateRef(ref, current) {
4615  var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
4616  if (preparsed) ref = current + '(' + preparsed[1] + ')';
4617  parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
4618  if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
4619  return { state: parsed[1], paramExpr: parsed[3] || null };
4620}
4621
4622function stateContext(el) {
4623  var stateData = el.parent().inheritedData('$uiView');
4624
4625  if (stateData && stateData.state && stateData.state.name) {
4626    return stateData.state;
4627  }
4628}
4629
4630function getTypeInfo(el) {
4631  // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
4632  var isSvg = Object.prototype.toString.call(el.prop('href')) === '[object SVGAnimatedString]';
4633  var isForm = el[0].nodeName === "FORM";
4634
4635  return {
4636    attr: isForm ? "action" : (isSvg ? 'xlink:href' : 'href'),
4637    isAnchor: el.prop("tagName").toUpperCase() === "A",
4638    clickable: !isForm
4639  };
4640}
4641
4642function clickHook(el, $state, $timeout, type, current) {
4643  return function(e) {
4644    var button = e.which || e.button, target = current();
4645
4646    if (!(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || el.attr('target'))) {
4647      // HACK: This is to allow ng-clicks to be processed before the transition is initiated:
4648      var transition = $timeout(function() {
4649        $state.go(target.state, target.params, target.options);
4650      });
4651      e.preventDefault();
4652
4653      // if the state has no URL, ignore one preventDefault from the <a> directive.
4654      var ignorePreventDefaultCount = type.isAnchor && !target.href ? 1: 0;
4655
4656      e.preventDefault = function() {
4657        if (ignorePreventDefaultCount-- <= 0) $timeout.cancel(transition);
4658      };
4659    }
4660  };
4661}
4662
4663function defaultOpts(el, $state) {
4664  return { relative: stateContext(el) || $state.$current, inherit: true };
4665}
4666
4667/**
4668 * @ngdoc directive
4669 * @name ui.router.state.directive:ui-sref
4670 *
4671 * @requires ui.router.state.$state
4672 * @requires $timeout
4673 *
4674 * @restrict A
4675 *
4676 * @description
4677 * A directive that binds a link (`<a>` tag) to a state. If the state has an associated
4678 * URL, the directive will automatically generate & update the `href` attribute via
4679 * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking
4680 * the link will trigger a state transition with optional parameters.
4681 *
4682 * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be
4683 * handled natively by the browser.
4684 *
4685 * You can also use relative state paths within ui-sref, just like the relative
4686 * paths passed to `$state.go()`. You just need to be aware that the path is relative
4687 * to the state that the link lives in, in other words the state that loaded the
4688 * template containing the link.
4689 *
4690 * You can specify options to pass to {@link ui.router.state.$state#methods_go $state.go()}
4691 * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`,
4692 * and `reload`.
4693 *
4694 * @example
4695 * Here's an example of how you'd use ui-sref and how it would compile. If you have the
4696 * following template:
4697 * <pre>
4698 * <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> | <a ui-sref="{page: 2}">Next page</a>
4699 *
4700 * <ul>
4701 *     <li ng-repeat="contact in contacts">
4702 *         <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a>
4703 *     </li>
4704 * </ul>
4705 * </pre>
4706 *
4707 * Then the compiled html would be (assuming Html5Mode is off and current state is contacts):
4708 * <pre>
4709 * <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>
4710 *
4711 * <ul>
4712 *     <li ng-repeat="contact in contacts">
4713 *         <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a>
4714 *     </li>
4715 *     <li ng-repeat="contact in contacts">
4716 *         <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a>
4717 *     </li>
4718 *     <li ng-repeat="contact in contacts">
4719 *         <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a>
4720 *     </li>
4721 * </ul>
4722 *
4723 * <a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
4724 * </pre>
4725 *
4726 * @param {string} ui-sref 'stateName' can be any valid absolute or relative state
4727 * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#methods_go $state.go()}
4728 */
4729$StateRefDirective.$inject = ['$state', '$timeout'];
4730function $StateRefDirective($state, $timeout) {
4731  return {
4732    restrict: 'A',
4733    require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
4734    link: function(scope, element, attrs, uiSrefActive) {
4735      var ref    = parseStateRef(attrs.uiSref, $state.current.name);
4736      var def    = { state: ref.state, href: null, params: null };
4737      var type   = getTypeInfo(element);
4738      var active = uiSrefActive[1] || uiSrefActive[0];
4739      var unlinkInfoFn = null;
4740      var hookFn;
4741
4742      def.options = extend(defaultOpts(element, $state), attrs.uiSrefOpts ? scope.$eval(attrs.uiSrefOpts) : {});
4743
4744      var update = function(val) {
4745        if (val) def.params = angular.copy(val);
4746        def.href = $state.href(ref.state, def.params, def.options);
4747
4748        if (unlinkInfoFn) unlinkInfoFn();
4749        if (active) unlinkInfoFn = active.$$addStateInfo(ref.state, def.params);
4750        if (def.href !== null) attrs.$set(type.attr, def.href);
4751      };
4752
4753      if (ref.paramExpr) {
4754        scope.$watch(ref.paramExpr, function(val) { if (val !== def.params) update(val); }, true);
4755        def.params = angular.copy(scope.$eval(ref.paramExpr));
4756      }
4757      update();
4758
4759      if (!type.clickable) return;
4760      hookFn = clickHook(element, $state, $timeout, type, function() { return def; });
4761      element[element.on ? 'on' : 'bind']("click", hookFn);
4762      scope.$on('$destroy', function() {
4763        element[element.off ? 'off' : 'unbind']("click", hookFn);
4764      });
4765    }
4766  };
4767}
4768
4769/**
4770 * @ngdoc directive
4771 * @name ui.router.state.directive:ui-state
4772 *
4773 * @requires ui.router.state.uiSref
4774 *
4775 * @restrict A
4776 *
4777 * @description
4778 * Much like ui-sref, but will accept named $scope properties to evaluate for a state definition,
4779 * params and override options.
4780 *
4781 * @param {string} ui-state 'stateName' can be any valid absolute or relative state
4782 * @param {Object} ui-state-params params to pass to {@link ui.router.state.$state#methods_href $state.href()}
4783 * @param {Object} ui-state-opts options to pass to {@link ui.router.state.$state#methods_go $state.go()}
4784 */
4785$StateRefDynamicDirective.$inject = ['$state', '$timeout'];
4786function $StateRefDynamicDirective($state, $timeout) {
4787  return {
4788    restrict: 'A',
4789    require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
4790    link: function(scope, element, attrs, uiSrefActive) {
4791      var type   = getTypeInfo(element);
4792      var active = uiSrefActive[1] || uiSrefActive[0];
4793      var group  = [attrs.uiState, attrs.uiStateParams || null, attrs.uiStateOpts || null];
4794      var watch  = '[' + group.map(function(val) { return val || 'null'; }).join(', ') + ']';
4795      var def    = { state: null, params: null, options: null, href: null };
4796      var unlinkInfoFn = null;
4797      var hookFn;
4798
4799      function runStateRefLink (group) {
4800        def.state = group[0]; def.params = group[1]; def.options = group[2];
4801        def.href = $state.href(def.state, def.params, def.options);
4802
4803        if (unlinkInfoFn) unlinkInfoFn();
4804        if (active) unlinkInfoFn = active.$$addStateInfo(def.state, def.params);
4805        if (def.href) attrs.$set(type.attr, def.href);
4806      }
4807
4808      scope.$watch(watch, runStateRefLink, true);
4809      runStateRefLink(scope.$eval(watch));
4810
4811      if (!type.clickable) return;
4812      hookFn = clickHook(element, $state, $timeout, type, function() { return def; });
4813      element[element.on ? 'on' : 'bind']("click", hookFn);
4814      scope.$on('$destroy', function() {
4815        element[element.off ? 'off' : 'unbind']("click", hookFn);
4816      });
4817    }
4818  };
4819}
4820
4821
4822/**
4823 * @ngdoc directive
4824 * @name ui.router.state.directive:ui-sref-active
4825 *
4826 * @requires ui.router.state.$state
4827 * @requires ui.router.state.$stateParams
4828 * @requires $interpolate
4829 *
4830 * @restrict A
4831 *
4832 * @description
4833 * A directive working alongside ui-sref to add classes to an element when the
4834 * related ui-sref directive's state is active, and removing them when it is inactive.
4835 * The primary use-case is to simplify the special appearance of navigation menus
4836 * relying on `ui-sref`, by having the "active" state's menu button appear different,
4837 * distinguishing it from the inactive menu items.
4838 *
4839 * ui-sref-active can live on the same element as ui-sref or on a parent element. The first
4840 * ui-sref-active found at the same level or above the ui-sref will be used.
4841 *
4842 * Will activate when the ui-sref's target state or any child state is active. If you
4843 * need to activate only when the ui-sref target state is active and *not* any of
4844 * it's children, then you will use
4845 * {@link ui.router.state.directive:ui-sref-active-eq ui-sref-active-eq}
4846 *
4847 * @example
4848 * Given the following template:
4849 * <pre>
4850 * <ul>
4851 *   <li ui-sref-active="active" class="item">
4852 *     <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
4853 *   </li>
4854 * </ul>
4855 * </pre>
4856 *
4857 *
4858 * When the app state is "app.user" (or any children states), and contains the state parameter "user" with value "bilbobaggins",
4859 * the resulting HTML will appear as (note the 'active' class):
4860 * <pre>
4861 * <ul>
4862 *   <li ui-sref-active="active" class="item active">
4863 *     <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
4864 *   </li>
4865 * </ul>
4866 * </pre>
4867 *
4868 * The class name is interpolated **once** during the directives link time (any further changes to the
4869 * interpolated value are ignored).
4870 *
4871 * Multiple classes may be specified in a space-separated format:
4872 * <pre>
4873 * <ul>
4874 *   <li ui-sref-active='class1 class2 class3'>
4875 *     <a ui-sref="app.user">link</a>
4876 *   </li>
4877 * </ul>
4878 * </pre>
4879 *
4880 * It is also possible to pass ui-sref-active an expression that evaluates
4881 * to an object hash, whose keys represent active class names and whose
4882 * values represent the respective state names/globs.
4883 * ui-sref-active will match if the current active state **includes** any of
4884 * the specified state names/globs, even the abstract ones.
4885 *
4886 * @Example
4887 * Given the following template, with "admin" being an abstract state:
4888 * <pre>
4889 * <div ui-sref-active="{'active': 'admin.*'}">
4890 *   <a ui-sref-active="active" ui-sref="admin.roles">Roles</a>
4891 * </div>
4892 * </pre>
4893 *
4894 * When the current state is "admin.roles" the "active" class will be applied
4895 * to both the <div> and <a> elements. It is important to note that the state
4896 * names/globs passed to ui-sref-active shadow the state provided by ui-sref.
4897 */
4898
4899/**
4900 * @ngdoc directive
4901 * @name ui.router.state.directive:ui-sref-active-eq
4902 *
4903 * @requires ui.router.state.$state
4904 * @requires ui.router.state.$stateParams
4905 * @requires $interpolate
4906 *
4907 * @restrict A
4908 *
4909 * @description
4910 * The same as {@link ui.router.state.directive:ui-sref-active ui-sref-active} but will only activate
4911 * when the exact target state used in the `ui-sref` is active; no child states.
4912 *
4913 */
4914$StateRefActiveDirective.$inject = ['$state', '$stateParams', '$interpolate'];
4915function $StateRefActiveDirective($state, $stateParams, $interpolate) {
4916  return  {
4917    restrict: "A",
4918    controller: ['$scope', '$element', '$attrs', '$timeout', function ($scope, $element, $attrs, $timeout) {
4919      var states = [], activeClasses = {}, activeEqClass, uiSrefActive;
4920
4921      // There probably isn't much point in $observing this
4922      // uiSrefActive and uiSrefActiveEq share the same directive object with some
4923      // slight difference in logic routing
4924      activeEqClass = $interpolate($attrs.uiSrefActiveEq || '', false)($scope);
4925
4926      try {
4927        uiSrefActive = $scope.$eval($attrs.uiSrefActive);
4928      } catch (e) {
4929        // Do nothing. uiSrefActive is not a valid expression.
4930        // Fall back to using $interpolate below
4931      }
4932      uiSrefActive = uiSrefActive || $interpolate($attrs.uiSrefActive || '', false)($scope);
4933      if (isObject(uiSrefActive)) {
4934        forEach(uiSrefActive, function(stateOrName, activeClass) {
4935          if (isString(stateOrName)) {
4936            var ref = parseStateRef(stateOrName, $state.current.name);
4937            addState(ref.state, $scope.$eval(ref.paramExpr), activeClass);
4938          }
4939        });
4940      }
4941
4942      // Allow uiSref to communicate with uiSrefActive[Equals]
4943      this.$$addStateInfo = function (newState, newParams) {
4944        // we already got an explicit state provided by ui-sref-active, so we
4945        // shadow the one that comes from ui-sref
4946        if (isObject(uiSrefActive) && states.length > 0) {
4947          return;
4948        }
4949        var deregister = addState(newState, newParams, uiSrefActive);
4950        update();
4951        return deregister;
4952      };
4953
4954      $scope.$on('$stateChangeSuccess', update);
4955
4956      function addState(stateName, stateParams, activeClass) {
4957        var state = $state.get(stateName, stateContext($element));
4958        var stateHash = createStateHash(stateName, stateParams);
4959
4960        var stateInfo = {
4961          state: state || { name: stateName },
4962          params: stateParams,
4963          hash: stateHash
4964        };
4965
4966        states.push(stateInfo);
4967        activeClasses[stateHash] = activeClass;
4968
4969        return function removeState() {
4970          var idx = states.indexOf(stateInfo);
4971          if (idx !== -1) states.splice(idx, 1);
4972        };
4973      }
4974
4975      /**
4976       * @param {string} state
4977       * @param {Object|string} [params]
4978       * @return {string}
4979       */
4980      function createStateHash(state, params) {
4981        if (!isString(state)) {
4982          throw new Error('state should be a string');
4983        }
4984        if (isObject(params)) {
4985          return state + toJson(params);
4986        }
4987        params = $scope.$eval(params);
4988        if (isObject(params)) {
4989          return state + toJson(params);
4990        }
4991        return state;
4992      }
4993
4994      // Update route state
4995      function update() {
4996        for (var i = 0; i < states.length; i++) {
4997          if (anyMatch(states[i].state, states[i].params)) {
4998            addClass($element, activeClasses[states[i].hash]);
4999          } else {
5000            removeClass($element, activeClasses[states[i].hash]);
5001          }
5002
5003          if (exactMatch(states[i].state, states[i].params)) {
5004            addClass($element, activeEqClass);
5005          } else {
5006            removeClass($element, activeEqClass);
5007          }
5008        }
5009      }
5010
5011      function addClass(el, className) { $timeout(function () { el.addClass(className); }); }
5012      function removeClass(el, className) { el.removeClass(className); }
5013      function anyMatch(state, params) { return $state.includes(state.name, params); }
5014      function exactMatch(state, params) { return $state.is(state.name, params); }
5015
5016      update();
5017    }]
5018  };
5019}
5020
5021angular.module('ui.router.state')
5022  .directive('uiSref', $StateRefDirective)
5023  .directive('uiSrefActive', $StateRefActiveDirective)
5024  .directive('uiSrefActiveEq', $StateRefActiveDirective)
5025  .directive('uiState', $StateRefDynamicDirective);
5026
5027/**
5028 * @ngdoc filter
5029 * @name ui.router.state.filter:isState
5030 *
5031 * @requires ui.router.state.$state
5032 *
5033 * @description
5034 * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}.
5035 */
5036$IsStateFilter.$inject = ['$state'];
5037function $IsStateFilter($state) {
5038  var isFilter = function (state, params) {
5039    return $state.is(state, params);
5040  };
5041  isFilter.$stateful = true;
5042  return isFilter;
5043}
5044
5045/**
5046 * @ngdoc filter
5047 * @name ui.router.state.filter:includedByState
5048 *
5049 * @requires ui.router.state.$state
5050 *
5051 * @description
5052 * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}.
5053 */
5054$IncludedByStateFilter.$inject = ['$state'];
5055function $IncludedByStateFilter($state) {
5056  var includesFilter = function (state, params, options) {
5057    return $state.includes(state, params, options);
5058  };
5059  includesFilter.$stateful = true;
5060  return  includesFilter;
5061}
5062
5063angular.module('ui.router.state')
5064  .filter('isState', $IsStateFilter)
5065  .filter('includedByState', $IncludedByStateFilter);
5066})(window, window.angular);
5067},{}],4:[function(require,module,exports){
5068/**
5069 * @license AngularJS v1.5.1
5070 * (c) 2010-2016 Google, Inc. http://angularjs.org
5071 * License: MIT
5072 */
5073(function(window, document, undefined) {'use strict';
5074
5075/**
5076 * @description
5077 *
5078 * This object provides a utility for producing rich Error messages within
5079 * Angular. It can be called as follows:
5080 *
5081 * var exampleMinErr = minErr('example');
5082 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
5083 *
5084 * The above creates an instance of minErr in the example namespace. The
5085 * resulting error will have a namespaced error code of example.one.  The
5086 * resulting error will replace {0} with the value of foo, and {1} with the
5087 * value of bar. The object is not restricted in the number of arguments it can
5088 * take.
5089 *
5090 * If fewer arguments are specified than necessary for interpolation, the extra
5091 * interpolation markers will be preserved in the final string.
5092 *
5093 * Since data will be parsed statically during a build step, some restrictions
5094 * are applied with respect to how minErr instances are created and called.
5095 * Instances should have names of the form namespaceMinErr for a minErr created
5096 * using minErr('namespace') . Error codes, namespaces and template strings
5097 * should all be static strings, not variables or general expressions.
5098 *
5099 * @param {string} module The namespace to use for the new minErr instance.
5100 * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
5101 *   error from returned function, for cases when a particular type of error is useful.
5102 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
5103 */
5104
5105function minErr(module, ErrorConstructor) {
5106  ErrorConstructor = ErrorConstructor || Error;
5107  return function() {
5108    var SKIP_INDEXES = 2;
5109
5110    var templateArgs = arguments,
5111      code = templateArgs[0],
5112      message = '[' + (module ? module + ':' : '') + code + '] ',
5113      template = templateArgs[1],
5114      paramPrefix, i;
5115
5116    message += template.replace(/\{\d+\}/g, function(match) {
5117      var index = +match.slice(1, -1),
5118        shiftedIndex = index + SKIP_INDEXES;
5119
5120      if (shiftedIndex < templateArgs.length) {
5121        return toDebugString(templateArgs[shiftedIndex]);
5122      }
5123
5124      return match;
5125    });
5126
5127    message += '\nhttp://errors.angularjs.org/1.5.1/' +
5128      (module ? module + '/' : '') + code;
5129
5130    for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
5131      message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
5132        encodeURIComponent(toDebugString(templateArgs[i]));
5133    }
5134
5135    return new ErrorConstructor(message);
5136  };
5137}
5138
5139/* We need to tell jshint what variables are being exported */
5140/* global angular: true,
5141  msie: true,
5142  jqLite: true,
5143  jQuery: true,
5144  slice: true,
5145  splice: true,
5146  push: true,
5147  toString: true,
5148  ngMinErr: true,
5149  angularModule: true,
5150  uid: true,
5151  REGEX_STRING_REGEXP: true,
5152  VALIDITY_STATE_PROPERTY: true,
5153
5154  lowercase: true,
5155  uppercase: true,
5156  manualLowercase: true,
5157  manualUppercase: true,
5158  nodeName_: true,
5159  isArrayLike: true,
5160  forEach: true,
5161  forEachSorted: true,
5162  reverseParams: true,
5163  nextUid: true,
5164  setHashKey: true,
5165  extend: true,
5166  toInt: true,
5167  inherit: true,
5168  merge: true,
5169  noop: true,
5170  identity: true,
5171  valueFn: true,
5172  isUndefined: true,
5173  isDefined: true,
5174  isObject: true,
5175  isBlankObject: true,
5176  isString: true,
5177  isNumber: true,
5178  isDate: true,
5179  isArray: true,
5180  isFunction: true,
5181  isRegExp: true,
5182  isWindow: true,
5183  isScope: true,
5184  isFile: true,
5185  isFormData: true,
5186  isBlob: true,
5187  isBoolean: true,
5188  isPromiseLike: true,
5189  trim: true,
5190  escapeForRegexp: true,
5191  isElement: true,
5192  makeMap: true,
5193  includes: true,
5194  arrayRemove: true,
5195  copy: true,
5196  shallowCopy: true,
5197  equals: true,
5198  csp: true,
5199  jq: true,
5200  concat: true,
5201  sliceArgs: true,
5202  bind: true,
5203  toJsonReplacer: true,
5204  toJson: true,
5205  fromJson: true,
5206  convertTimezoneToLocal: true,
5207  timezoneToOffset: true,
5208  startingTag: true,
5209  tryDecodeURIComponent: true,
5210  parseKeyValue: true,
5211  toKeyValue: true,
5212  encodeUriSegment: true,
5213  encodeUriQuery: true,
5214  angularInit: true,
5215  bootstrap: true,
5216  getTestability: true,
5217  snake_case: true,
5218  bindJQuery: true,
5219  assertArg: true,
5220  assertArgFn: true,
5221  assertNotHasOwnProperty: true,
5222  getter: true,
5223  getBlockNodes: true,
5224  hasOwnProperty: true,
5225  createMap: true,
5226
5227  NODE_TYPE_ELEMENT: true,
5228  NODE_TYPE_ATTRIBUTE: true,
5229  NODE_TYPE_TEXT: true,
5230  NODE_TYPE_COMMENT: true,
5231  NODE_TYPE_DOCUMENT: true,
5232  NODE_TYPE_DOCUMENT_FRAGMENT: true,
5233*/
5234
5235////////////////////////////////////
5236
5237/**
5238 * @ngdoc module
5239 * @name ng
5240 * @module ng
5241 * @description
5242 *
5243 * # ng (core module)
5244 * The ng module is loaded by default when an AngularJS application is started. The module itself
5245 * contains the essential components for an AngularJS application to function. The table below
5246 * lists a high level breakdown of each of the services/factories, filters, directives and testing
5247 * components available within this core module.
5248 *
5249 * <div doc-module-components="ng"></div>
5250 */
5251
5252var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
5253
5254// The name of a form control's ValidityState property.
5255// This is used so that it's possible for internal tests to create mock ValidityStates.
5256var VALIDITY_STATE_PROPERTY = 'validity';
5257
5258var hasOwnProperty = Object.prototype.hasOwnProperty;
5259
5260var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
5261var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
5262
5263
5264var manualLowercase = function(s) {
5265  /* jshint bitwise: false */
5266  return isString(s)
5267      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
5268      : s;
5269};
5270var manualUppercase = function(s) {
5271  /* jshint bitwise: false */
5272  return isString(s)
5273      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
5274      : s;
5275};
5276
5277
5278// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
5279// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
5280// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
5281if ('i' !== 'I'.toLowerCase()) {
5282  lowercase = manualLowercase;
5283  uppercase = manualUppercase;
5284}
5285
5286
5287var
5288    msie,             // holds major version number for IE, or NaN if UA is not IE.
5289    jqLite,           // delay binding since jQuery could be loaded after us.
5290    jQuery,           // delay binding
5291    slice             = [].slice,
5292    splice            = [].splice,
5293    push              = [].push,
5294    toString          = Object.prototype.toString,
5295    getPrototypeOf    = Object.getPrototypeOf,
5296    ngMinErr          = minErr('ng'),
5297
5298    /** @name angular */
5299    angular           = window.angular || (window.angular = {}),
5300    angularModule,
5301    uid               = 0;
5302
5303/**
5304 * documentMode is an IE-only property
5305 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
5306 */
5307msie = document.documentMode;
5308
5309
5310/**
5311 * @private
5312 * @param {*} obj
5313 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
5314 *                   String ...)
5315 */
5316function isArrayLike(obj) {
5317
5318  // `null`, `undefined` and `window` are not array-like
5319  if (obj == null || isWindow(obj)) return false;
5320
5321  // arrays, strings and jQuery/jqLite objects are array like
5322  // * jqLite is either the jQuery or jqLite constructor function
5323  // * we have to check the existence of jqLite first as this method is called
5324  //   via the forEach method when constructing the jqLite object in the first place
5325  if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
5326
5327  // Support: iOS 8.2 (not reproducible in simulator)
5328  // "length" in obj used to prevent JIT error (gh-11508)
5329  var length = "length" in Object(obj) && obj.length;
5330
5331  // NodeList objects (with `item` method) and
5332  // other objects with suitable length characteristics are array-like
5333  return isNumber(length) &&
5334    (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
5335
5336}
5337
5338/**
5339 * @ngdoc function
5340 * @name angular.forEach
5341 * @module ng
5342 * @kind function
5343 *
5344 * @description
5345 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
5346 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
5347 * is the value of an object property or an array element, `key` is the object property key or
5348 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
5349 *
5350 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
5351 * using the `hasOwnProperty` method.
5352 *
5353 * Unlike ES262's
5354 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
5355 * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
5356 * return the value provided.
5357 *
5358   ```js
5359     var values = {name: 'misko', gender: 'male'};
5360     var log = [];
5361     angular.forEach(values, function(value, key) {
5362       this.push(key + ': ' + value);
5363     }, log);
5364     expect(log).toEqual(['name: misko', 'gender: male']);
5365   ```
5366 *
5367 * @param {Object|Array} obj Object to iterate over.
5368 * @param {Function} iterator Iterator function.
5369 * @param {Object=} context Object to become context (`this`) for the iterator function.
5370 * @returns {Object|Array} Reference to `obj`.
5371 */
5372
5373function forEach(obj, iterator, context) {
5374  var key, length;
5375  if (obj) {
5376    if (isFunction(obj)) {
5377      for (key in obj) {
5378        // Need to check if hasOwnProperty exists,
5379        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
5380        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
5381          iterator.call(context, obj[key], key, obj);
5382        }
5383      }
5384    } else if (isArray(obj) || isArrayLike(obj)) {
5385      var isPrimitive = typeof obj !== 'object';
5386      for (key = 0, length = obj.length; key < length; key++) {
5387        if (isPrimitive || key in obj) {
5388          iterator.call(context, obj[key], key, obj);
5389        }
5390      }
5391    } else if (obj.forEach && obj.forEach !== forEach) {
5392        obj.forEach(iterator, context, obj);
5393    } else if (isBlankObject(obj)) {
5394      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
5395      for (key in obj) {
5396        iterator.call(context, obj[key], key, obj);
5397      }
5398    } else if (typeof obj.hasOwnProperty === 'function') {
5399      // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
5400      for (key in obj) {
5401        if (obj.hasOwnProperty(key)) {
5402          iterator.call(context, obj[key], key, obj);
5403        }
5404      }
5405    } else {
5406      // Slow path for objects which do not have a method `hasOwnProperty`
5407      for (key in obj) {
5408        if (hasOwnProperty.call(obj, key)) {
5409          iterator.call(context, obj[key], key, obj);
5410        }
5411      }
5412    }
5413  }
5414  return obj;
5415}
5416
5417function forEachSorted(obj, iterator, context) {
5418  var keys = Object.keys(obj).sort();
5419  for (var i = 0; i < keys.length; i++) {
5420    iterator.call(context, obj[keys[i]], keys[i]);
5421  }
5422  return keys;
5423}
5424
5425
5426/**
vendor: 10,542 bytes, lines 5427-5875
5427 * when using forEach the params are value, key, but it is often useful to have key, value.
5428 * @param {function(string, *)} iteratorFn
5429 * @returns {function(*, string)}
5430 */
5431function reverseParams(iteratorFn) {
5432  return function(value, key) {iteratorFn(key, value);};
5433}
5434
5435/**
5436 * A consistent way of creating unique IDs in angular.
5437 *
5438 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
5439 * we hit number precision issues in JavaScript.
5440 *
5441 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
5442 *
5443 * @returns {number} an unique alpha-numeric string
5444 */
5445function nextUid() {
5446  return ++uid;
5447}
5448
5449
5450/**
5451 * Set or clear the hashkey for an object.
5452 * @param obj object
5453 * @param h the hashkey (!truthy to delete the hashkey)
5454 */
5455function setHashKey(obj, h) {
5456  if (h) {
5457    obj.$$hashKey = h;
5458  } else {
5459    delete obj.$$hashKey;
5460  }
5461}
5462
5463
5464function baseExtend(dst, objs, deep) {
5465  var h = dst.$$hashKey;
5466
5467  for (var i = 0, ii = objs.length; i < ii; ++i) {
5468    var obj = objs[i];
5469    if (!isObject(obj) && !isFunction(obj)) continue;
5470    var keys = Object.keys(obj);
5471    for (var j = 0, jj = keys.length; j < jj; j++) {
5472      var key = keys[j];
5473      var src = obj[key];
5474
5475      if (deep && isObject(src)) {
5476        if (isDate(src)) {
5477          dst[key] = new Date(src.valueOf());
5478        } else if (isRegExp(src)) {
5479          dst[key] = new RegExp(src);
5480        } else if (src.nodeName) {
5481          dst[key] = src.cloneNode(true);
5482        } else if (isElement(src)) {
5483          dst[key] = src.clone();
5484        } else {
5485          if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
5486          baseExtend(dst[key], [src], true);
5487        }
5488      } else {
5489        dst[key] = src;
5490      }
5491    }
5492  }
5493
5494  setHashKey(dst, h);
5495  return dst;
5496}
5497
5498/**
5499 * @ngdoc function
5500 * @name angular.extend
5501 * @module ng
5502 * @kind function
5503 *
5504 * @description
5505 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
5506 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
5507 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
5508 *
5509 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
5510 * {@link angular.merge} for this.
5511 *
5512 * @param {Object} dst Destination object.
5513 * @param {...Object} src Source object(s).
5514 * @returns {Object} Reference to `dst`.
5515 */
5516function extend(dst) {
5517  return baseExtend(dst, slice.call(arguments, 1), false);
5518}
5519
5520
5521/**
5522* @ngdoc function
5523* @name angular.merge
5524* @module ng
5525* @kind function
5526*
5527* @description
5528* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
5529* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
5530* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
5531*
5532* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
5533* objects, performing a deep copy.
5534*
5535* @param {Object} dst Destination object.
5536* @param {...Object} src Source object(s).
5537* @returns {Object} Reference to `dst`.
5538*/
5539function merge(dst) {
5540  return baseExtend(dst, slice.call(arguments, 1), true);
5541}
5542
5543
5544
5545function toInt(str) {
5546  return parseInt(str, 10);
5547}
5548
5549
5550function inherit(parent, extra) {
5551  return extend(Object.create(parent), extra);
5552}
5553
5554/**
5555 * @ngdoc function
5556 * @name angular.noop
5557 * @module ng
5558 * @kind function
5559 *
5560 * @description
5561 * A function that performs no operations. This function can be useful when writing code in the
5562 * functional style.
5563   ```js
5564     function foo(callback) {
5565       var result = calculateResult();
5566       (callback || angular.noop)(result);
5567     }
5568   ```
5569 */
5570function noop() {}
5571noop.$inject = [];
5572
5573
5574/**
5575 * @ngdoc function
5576 * @name angular.identity
5577 * @module ng
5578 * @kind function
5579 *
5580 * @description
5581 * A function that returns its first argument. This function is useful when writing code in the
5582 * functional style.
5583 *
5584   ```js
5585     function transformer(transformationFn, value) {
5586       return (transformationFn || angular.identity)(value);
5587     };
5588   ```
5589  * @param {*} value to be returned.
5590  * @returns {*} the value passed in.
5591 */
5592function identity($) {return $;}
5593identity.$inject = [];
5594
5595
5596function valueFn(value) {return function() {return value;};}
5597
5598function hasCustomToString(obj) {
5599  return isFunction(obj.toString) && obj.toString !== toString;
5600}
5601
5602
5603/**
5604 * @ngdoc function
5605 * @name angular.isUndefined
5606 * @module ng
5607 * @kind function
5608 *
5609 * @description
5610 * Determines if a reference is undefined.
5611 *
5612 * @param {*} value Reference to check.
5613 * @returns {boolean} True if `value` is undefined.
5614 */
5615function isUndefined(value) {return typeof value === 'undefined';}
5616
5617
5618/**
5619 * @ngdoc function
5620 * @name angular.isDefined
5621 * @module ng
5622 * @kind function
5623 *
5624 * @description
5625 * Determines if a reference is defined.
5626 *
5627 * @param {*} value Reference to check.
5628 * @returns {boolean} True if `value` is defined.
5629 */
5630function isDefined(value) {return typeof value !== 'undefined';}
5631
5632
5633/**
5634 * @ngdoc function
5635 * @name angular.isObject
5636 * @module ng
5637 * @kind function
5638 *
5639 * @description
5640 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
5641 * considered to be objects. Note that JavaScript arrays are objects.
5642 *
5643 * @param {*} value Reference to check.
5644 * @returns {boolean} True if `value` is an `Object` but not `null`.
5645 */
5646function isObject(value) {
5647  // http://jsperf.com/isobject4
5648  return value !== null && typeof value === 'object';
5649}
5650
5651
5652/**
5653 * Determine if a value is an object with a null prototype
5654 *
5655 * @returns {boolean} True if `value` is an `Object` with a null prototype
5656 */
5657function isBlankObject(value) {
5658  return value !== null && typeof value === 'object' && !getPrototypeOf(value);
5659}
5660
5661
5662/**
5663 * @ngdoc function
5664 * @name angular.isString
5665 * @module ng
5666 * @kind function
5667 *
5668 * @description
5669 * Determines if a reference is a `String`.
5670 *
5671 * @param {*} value Reference to check.
5672 * @returns {boolean} True if `value` is a `String`.
5673 */
5674function isString(value) {return typeof value === 'string';}
5675
5676
5677/**
5678 * @ngdoc function
5679 * @name angular.isNumber
5680 * @module ng
5681 * @kind function
5682 *
5683 * @description
5684 * Determines if a reference is a `Number`.
5685 *
5686 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
5687 *
5688 * If you wish to exclude these then you can use the native
5689 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
5690 * method.
5691 *
5692 * @param {*} value Reference to check.
5693 * @returns {boolean} True if `value` is a `Number`.
5694 */
5695function isNumber(value) {return typeof value === 'number';}
5696
5697
5698/**
5699 * @ngdoc function
5700 * @name angular.isDate
5701 * @module ng
5702 * @kind function
5703 *
5704 * @description
5705 * Determines if a value is a date.
5706 *
5707 * @param {*} value Reference to check.
5708 * @returns {boolean} True if `value` is a `Date`.
5709 */
5710function isDate(value) {
5711  return toString.call(value) === '[object Date]';
5712}
5713
5714
5715/**
5716 * @ngdoc function
5717 * @name angular.isArray
5718 * @module ng
5719 * @kind function
5720 *
5721 * @description
5722 * Determines if a reference is an `Array`.
5723 *
5724 * @param {*} value Reference to check.
5725 * @returns {boolean} True if `value` is an `Array`.
5726 */
5727var isArray = Array.isArray;
5728
5729/**
5730 * @ngdoc function
5731 * @name angular.isFunction
5732 * @module ng
5733 * @kind function
5734 *
5735 * @description
5736 * Determines if a reference is a `Function`.
5737 *
5738 * @param {*} value Reference to check.
5739 * @returns {boolean} True if `value` is a `Function`.
5740 */
5741function isFunction(value) {return typeof value === 'function';}
5742
5743
5744/**
5745 * Determines if a value is a regular expression object.
5746 *
5747 * @private
5748 * @param {*} value Reference to check.
5749 * @returns {boolean} True if `value` is a `RegExp`.
5750 */
5751function isRegExp(value) {
5752  return toString.call(value) === '[object RegExp]';
5753}
5754
5755
5756/**
5757 * Checks if `obj` is a window object.
5758 *
5759 * @private
5760 * @param {*} obj Object to check
5761 * @returns {boolean} True if `obj` is a window obj.
5762 */
5763function isWindow(obj) {
5764  return obj && obj.window === obj;
5765}
5766
5767
5768function isScope(obj) {
5769  return obj && obj.$evalAsync && obj.$watch;
5770}
5771
5772
5773function isFile(obj) {
5774  return toString.call(obj) === '[object File]';
5775}
5776
5777
5778function isFormData(obj) {
5779  return toString.call(obj) === '[object FormData]';
5780}
5781
5782
5783function isBlob(obj) {
5784  return toString.call(obj) === '[object Blob]';
5785}
5786
5787
5788function isBoolean(value) {
5789  return typeof value === 'boolean';
5790}
5791
5792
5793function isPromiseLike(obj) {
5794  return obj && isFunction(obj.then);
5795}
5796
5797
5798var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
5799function isTypedArray(value) {
5800  return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
5801}
5802
5803function isArrayBuffer(obj) {
5804  return toString.call(obj) === '[object ArrayBuffer]';
5805}
5806
5807
5808var trim = function(value) {
5809  return isString(value) ? value.trim() : value;
5810};
5811
5812// Copied from:
5813// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
5814// Prereq: s is a string.
5815var escapeForRegexp = function(s) {
5816  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
5817           replace(/\x08/g, '\\x08');
5818};
5819
5820
5821/**
5822 * @ngdoc function
5823 * @name angular.isElement
5824 * @module ng
5825 * @kind function
5826 *
5827 * @description
5828 * Determines if a reference is a DOM element (or wrapped jQuery element).
5829 *
5830 * @param {*} value Reference to check.
5831 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
5832 */
5833function isElement(node) {
5834  return !!(node &&
5835    (node.nodeName  // we are a direct element
5836    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
5837}
5838
5839/**
5840 * @param str 'key1,key2,...'
5841 * @returns {object} in the form of {key1:true, key2:true, ...}
5842 */
5843function makeMap(str) {
5844  var obj = {}, items = str.split(','), i;
5845  for (i = 0; i < items.length; i++) {
5846    obj[items[i]] = true;
5847  }
5848  return obj;
5849}
5850
5851
5852function nodeName_(element) {
5853  return lowercase(element.nodeName || (element[0] && element[0].nodeName));
5854}
5855
5856function includes(array, obj) {
5857  return Array.prototype.indexOf.call(array, obj) != -1;
5858}
5859
5860function arrayRemove(array, value) {
5861  var index = array.indexOf(value);
5862  if (index >= 0) {
5863    array.splice(index, 1);
5864  }
5865  return index;
5866}
5867
5868/**
5869 * @ngdoc function
5870 * @name angular.copy
5871 * @module ng
5872 * @kind function
5873 *
5874 * @description
5875 * Creates a deep copy of `source`, which should be an object or an array.
5876 *
5877 * * If no destination is supplied, a copy of the object or array is created.
5878 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
5879 *   are deleted and then all elements/properties from the source are copied to it.
5880 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
5881 * * If `source` is identical to 'destination' an exception will be thrown.
5882 *
5883 * @param {*} source The source that will be used to make a copy.
5884 *                   Can be any type, including primitives, `null`, and `undefined`.
5885 * @param {(Object|Array)=} destination Destination into which the source is copied. If
5886 *     provided, must be of the same type as `source`.
5887 * @returns {*} The copy or updated `destination`, if `destination` was specified.
5888 *
5889 * @example
5890 <example module="copyExample">
5891 <file name="index.html">
5892 <div ng-controller="ExampleController">
5893 <form novalidate class="simple-form">
5894 Name: <input type="text" ng-model="user.name" /><br />
5895 E-mail: <input type="email" ng-model="user.email" /><br />
5896 Gender: <input type="radio" ng-model="user.gender" value="male" />male
5897 <input type="radio" ng-model="user.gender" value="female" />female<br />
5898 <button ng-click="reset()">RESET</button>
5899 <button ng-click="update(user)">SAVE</button>
5900 </form>
5901 <pre>form = {{user | json}}</pre>
5902 <pre>master = {{master | json}}</pre>
5903 </div>
5904
5905 <script>
5906  angular.module('copyExample', [])
5907    .controller('ExampleController', ['$scope', function($scope) {
5908      $scope.master= {};
5909
5910      $scope.update = function(user) {
5911        // Example with 1 argument
5912        $scope.master= angular.copy(user);
5913      };
5914
5915      $scope.reset = function() {
5916        // Example with 2 arguments
5917        angular.copy($scope.master, $scope.user);
5918      };
5919
5920      $scope.reset();
5921    }]);
5922 </script>
5923 </file>
5924 </example>
5925 */
5926function copy(source, destination) {
5927  var stackSource = [];
5928  var stackDest = [];
5929
5930  if (destination) {
5931    if (isTypedArray(destination) || isArrayBuffer(destination)) {
5932      throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
5933    }
5934    if (source === destination) {
5935      throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
5936    }
5937
5938    // Empty the destination object
5939    if (isArray(destination)) {
5940      destination.length = 0;
5941    } else {
5942      forEach(destination, function(value, key) {
5943        if (key !== '$$hashKey') {
5944          delete destination[key];
5945        }
5946      });
5947    }
5948
5949    stackSource.push(source);
5950    stackDest.push(destination);
5951    return copyRecurse(source, destination);
5952  }
5953
5954  return copyElement(source);
5955
5956  function copyRecurse(source, destination) {
5957    var h = destination.$$hashKey;
5958    var result, key;
5959    if (isArray(source)) {
5960      for (var i = 0, ii = source.length; i < ii; i++) {
5961        destination.push(copyElement(source[i]));
5962      }
5963    } else if (isBlankObject(source)) {
5964      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
5965      for (key in source) {
5966        destination[key] = copyElement(source[key]);
5967      }
5968    } else if (source && typeof source.hasOwnProperty === 'function') {
5969      // Slow path, which must rely on hasOwnProperty
5970      for (key in source) {
5971        if (source.hasOwnProperty(key)) {
5972          destination[key] = copyElement(source[key]);
5973        }
5974      }
5975    } else {
5976      // Slowest path --- hasOwnProperty can't be called as a method
5977      for (key in source) {
5978        if (hasOwnProperty.call(source, key)) {
5979          destination[key] = copyElement(source[key]);
5980        }
5981      }
5982    }
5983    setHashKey(destination, h);
5984    return destination;
5985  }
5986
5987  function copyElement(source) {
5988    // Simple values
5989    if (!isObject(source)) {
5990      return source;
5991    }
5992
5993    // Already copied values
5994    var index = stackSource.indexOf(source);
5995    if (index !== -1) {
5996      return stackDest[index];
5997    }
5998
5999    if (isWindow(source) || isScope(source)) {
6000      throw ngMinErr('cpws',
6001        "Can't copy! Making copies of Window or Scope instances is not supported.");
6002    }
6003
6004    var needsRecurse = false;
vendor: 15,778 bytes, lines 6005-6534
6005    var destination = copyType(source);
6006
6007    if (destination === undefined) {
6008      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
6009      needsRecurse = true;
6010    }
6011
6012    stackSource.push(source);
6013    stackDest.push(destination);
6014
6015    return needsRecurse
6016      ? copyRecurse(source, destination)
6017      : destination;
6018  }
6019
6020  function copyType(source) {
6021    switch (toString.call(source)) {
6022      case '[object Int8Array]':
6023      case '[object Int16Array]':
6024      case '[object Int32Array]':
6025      case '[object Float32Array]':
6026      case '[object Float64Array]':
6027      case '[object Uint8Array]':
6028      case '[object Uint8ClampedArray]':
6029      case '[object Uint16Array]':
6030      case '[object Uint32Array]':
6031        return new source.constructor(copyElement(source.buffer));
6032
6033      case '[object ArrayBuffer]':
6034        //Support: IE10
6035        if (!source.slice) {
6036          var copied = new ArrayBuffer(source.byteLength);
6037          new Uint8Array(copied).set(new Uint8Array(source));
6038          return copied;
6039        }
6040        return source.slice(0);
6041
6042      case '[object Boolean]':
6043      case '[object Number]':
6044      case '[object String]':
6045      case '[object Date]':
6046        return new source.constructor(source.valueOf());
6047
6048      case '[object RegExp]':
6049        var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
6050        re.lastIndex = source.lastIndex;
6051        return re;
6052
6053      case '[object Blob]':
6054        return new source.constructor([source], {type: source.type});
6055    }
6056
6057    if (isFunction(source.cloneNode)) {
6058      return source.cloneNode(true);
6059    }
6060  }
6061}
6062
6063/**
6064 * Creates a shallow copy of an object, an array or a primitive.
6065 *
6066 * Assumes that there are no proto properties for objects.
6067 */
6068function shallowCopy(src, dst) {
6069  if (isArray(src)) {
6070    dst = dst || [];
6071
6072    for (var i = 0, ii = src.length; i < ii; i++) {
6073      dst[i] = src[i];
6074    }
6075  } else if (isObject(src)) {
6076    dst = dst || {};
6077
6078    for (var key in src) {
6079      if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
6080        dst[key] = src[key];
6081      }
6082    }
6083  }
6084
6085  return dst || src;
6086}
6087
6088
6089/**
6090 * @ngdoc function
6091 * @name angular.equals
6092 * @module ng
6093 * @kind function
6094 *
6095 * @description
6096 * Determines if two objects or two values are equivalent. Supports value types, regular
6097 * expressions, arrays and objects.
6098 *
6099 * Two objects or values are considered equivalent if at least one of the following is true:
6100 *
6101 * * Both objects or values pass `===` comparison.
6102 * * Both objects or values are of the same type and all of their properties are equal by
6103 *   comparing them with `angular.equals`.
6104 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
6105 * * Both values represent the same regular expression (In JavaScript,
6106 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
6107 *   representation matches).
6108 *
6109 * During a property comparison, properties of `function` type and properties with names
6110 * that begin with `$` are ignored.
6111 *
6112 * Scope and DOMWindow objects are being compared only by identify (`===`).
6113 *
6114 * @param {*} o1 Object or value to compare.
6115 * @param {*} o2 Object or value to compare.
6116 * @returns {boolean} True if arguments are equal.
6117 */
6118function equals(o1, o2) {
6119  if (o1 === o2) return true;
6120  if (o1 === null || o2 === null) return false;
6121  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
6122  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
6123  if (t1 == t2 && t1 == 'object') {
6124    if (isArray(o1)) {
6125      if (!isArray(o2)) return false;
6126      if ((length = o1.length) == o2.length) {
6127        for (key = 0; key < length; key++) {
6128          if (!equals(o1[key], o2[key])) return false;
6129        }
6130        return true;
6131      }
6132    } else if (isDate(o1)) {
6133      if (!isDate(o2)) return false;
6134      return equals(o1.getTime(), o2.getTime());
6135    } else if (isRegExp(o1)) {
6136      if (!isRegExp(o2)) return false;
6137      return o1.toString() == o2.toString();
6138    } else {
6139      if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
6140        isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
6141      keySet = createMap();
6142      for (key in o1) {
6143        if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
6144        if (!equals(o1[key], o2[key])) return false;
6145        keySet[key] = true;
6146      }
6147      for (key in o2) {
6148        if (!(key in keySet) &&
6149            key.charAt(0) !== '$' &&
6150            isDefined(o2[key]) &&
6151            !isFunction(o2[key])) return false;
6152      }
6153      return true;
6154    }
6155  }
6156  return false;
6157}
6158
6159var csp = function() {
6160  if (!isDefined(csp.rules)) {
6161
6162
6163    var ngCspElement = (document.querySelector('[ng-csp]') ||
6164                    document.querySelector('[data-ng-csp]'));
6165
6166    if (ngCspElement) {
6167      var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
6168                    ngCspElement.getAttribute('data-ng-csp');
6169      csp.rules = {
6170        noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
6171        noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
6172      };
6173    } else {
6174      csp.rules = {
6175        noUnsafeEval: noUnsafeEval(),
6176        noInlineStyle: false
6177      };
6178    }
6179  }
6180
6181  return csp.rules;
6182
6183  function noUnsafeEval() {
6184    try {
6185      /* jshint -W031, -W054 */
6186      new Function('');
6187      /* jshint +W031, +W054 */
6188      return false;
6189    } catch (e) {
6190      return true;
6191    }
6192  }
6193};
6194
6195/**
6196 * @ngdoc directive
6197 * @module ng
6198 * @name ngJq
6199 *
6200 * @element ANY
6201 * @param {string=} ngJq the name of the library available under `window`
6202 * to be used for angular.element
6203 * @description
6204 * Use this directive to force the angular.element library.  This should be
6205 * used to force either jqLite by leaving ng-jq blank or setting the name of
6206 * the jquery variable under window (eg. jQuery).
6207 *
6208 * Since angular looks for this directive when it is loaded (doesn't wait for the
6209 * DOMContentLoaded event), it must be placed on an element that comes before the script
6210 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
6211 * others ignored.
6212 *
6213 * @example
6214 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
6215 ```html
6216 <!doctype html>
6217 <html ng-app ng-jq>
6218 ...
6219 ...
6220 </html>
6221 ```
6222 * @example
6223 * This example shows how to use a jQuery based library of a different name.
6224 * The library name must be available at the top most 'window'.
6225 ```html
6226 <!doctype html>
6227 <html ng-app ng-jq="jQueryLib">
6228 ...
6229 ...
6230 </html>
6231 ```
6232 */
6233var jq = function() {
6234  if (isDefined(jq.name_)) return jq.name_;
6235  var el;
6236  var i, ii = ngAttrPrefixes.length, prefix, name;
6237  for (i = 0; i < ii; ++i) {
6238    prefix = ngAttrPrefixes[i];
6239    if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
6240      name = el.getAttribute(prefix + 'jq');
6241      break;
6242    }
6243  }
6244
6245  return (jq.name_ = name);
6246};
6247
6248function concat(array1, array2, index) {
6249  return array1.concat(slice.call(array2, index));
6250}
6251
6252function sliceArgs(args, startIndex) {
6253  return slice.call(args, startIndex || 0);
6254}
6255
6256
6257/* jshint -W101 */
6258/**
6259 * @ngdoc function
6260 * @name angular.bind
6261 * @module ng
6262 * @kind function
6263 *
6264 * @description
6265 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
6266 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
6267 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
6268 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
6269 *
6270 * @param {Object} self Context which `fn` should be evaluated in.
6271 * @param {function()} fn Function to be bound.
6272 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
6273 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
6274 */
6275/* jshint +W101 */
6276function bind(self, fn) {
6277  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
6278  if (isFunction(fn) && !(fn instanceof RegExp)) {
6279    return curryArgs.length
6280      ? function() {
6281          return arguments.length
6282            ? fn.apply(self, concat(curryArgs, arguments, 0))
6283            : fn.apply(self, curryArgs);
6284        }
6285      : function() {
6286          return arguments.length
6287            ? fn.apply(self, arguments)
6288            : fn.call(self);
6289        };
6290  } else {
6291    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
6292    return fn;
6293  }
6294}
6295
6296
6297function toJsonReplacer(key, value) {
6298  var val = value;
6299
6300  if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
6301    val = undefined;
6302  } else if (isWindow(value)) {
6303    val = '$WINDOW';
6304  } else if (value &&  document === value) {
6305    val = '$DOCUMENT';
6306  } else if (isScope(value)) {
6307    val = '$SCOPE';
6308  }
6309
6310  return val;
6311}
6312
6313
6314/**
6315 * @ngdoc function
6316 * @name angular.toJson
6317 * @module ng
6318 * @kind function
6319 *
6320 * @description
6321 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
6322 * stripped since angular uses this notation internally.
6323 *
6324 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
6325 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
6326 *    If set to an integer, the JSON output will contain that many spaces per indentation.
6327 * @returns {string|undefined} JSON-ified string representing `obj`.
6328 */
6329function toJson(obj, pretty) {
6330  if (isUndefined(obj)) return undefined;
6331  if (!isNumber(pretty)) {
6332    pretty = pretty ? 2 : null;
6333  }
6334  return JSON.stringify(obj, toJsonReplacer, pretty);
6335}
6336
6337
6338/**
6339 * @ngdoc function
6340 * @name angular.fromJson
6341 * @module ng
6342 * @kind function
6343 *
6344 * @description
6345 * Deserializes a JSON string.
6346 *
6347 * @param {string} json JSON string to deserialize.
6348 * @returns {Object|Array|string|number} Deserialized JSON string.
6349 */
6350function fromJson(json) {
6351  return isString(json)
6352      ? JSON.parse(json)
6353      : json;
6354}
6355
6356
6357var ALL_COLONS = /:/g;
6358function timezoneToOffset(timezone, fallback) {
6359  // IE/Edge do not "understand" colon (`:`) in timezone
6360  timezone = timezone.replace(ALL_COLONS, '');
6361  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
6362  return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
6363}
6364
6365
6366function addDateMinutes(date, minutes) {
6367  date = new Date(date.getTime());
6368  date.setMinutes(date.getMinutes() + minutes);
6369  return date;
6370}
6371
6372
6373function convertTimezoneToLocal(date, timezone, reverse) {
6374  reverse = reverse ? -1 : 1;
6375  var dateTimezoneOffset = date.getTimezoneOffset();
6376  var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
6377  return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
6378}
6379
6380
6381/**
6382 * @returns {string} Returns the string representation of the element.
6383 */
6384function startingTag(element) {
6385  element = jqLite(element).clone();
6386  try {
6387    // turns out IE does not let you set .html() on elements which
6388    // are not allowed to have children. So we just ignore it.
6389    element.empty();
6390  } catch (e) {}
6391  var elemHtml = jqLite('<div>').append(element).html();
6392  try {
6393    return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
6394        elemHtml.
6395          match(/^(<[^>]+>)/)[1].
6396          replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
6397  } catch (e) {
6398    return lowercase(elemHtml);
6399  }
6400
6401}
6402
6403
6404/////////////////////////////////////////////////
6405
6406/**
6407 * Tries to decode the URI component without throwing an exception.
6408 *
6409 * @private
6410 * @param str value potential URI component to check.
6411 * @returns {boolean} True if `value` can be decoded
6412 * with the decodeURIComponent function.
6413 */
6414function tryDecodeURIComponent(value) {
6415  try {
6416    return decodeURIComponent(value);
6417  } catch (e) {
6418    // Ignore any invalid uri component
6419  }
6420}
6421
6422
6423/**
6424 * Parses an escaped url query string into key-value pairs.
6425 * @returns {Object.<string,boolean|Array>}
6426 */
6427function parseKeyValue(/**string*/keyValue) {
6428  var obj = {};
6429  forEach((keyValue || "").split('&'), function(keyValue) {
6430    var splitPoint, key, val;
6431    if (keyValue) {
6432      key = keyValue = keyValue.replace(/\+/g,'%20');
6433      splitPoint = keyValue.indexOf('=');
6434      if (splitPoint !== -1) {
6435        key = keyValue.substring(0, splitPoint);
6436        val = keyValue.substring(splitPoint + 1);
6437      }
6438      key = tryDecodeURIComponent(key);
6439      if (isDefined(key)) {
6440        val = isDefined(val) ? tryDecodeURIComponent(val) : true;
6441        if (!hasOwnProperty.call(obj, key)) {
6442          obj[key] = val;
6443        } else if (isArray(obj[key])) {
6444          obj[key].push(val);
6445        } else {
6446          obj[key] = [obj[key],val];
6447        }
6448      }
6449    }
6450  });
6451  return obj;
6452}
6453
6454function toKeyValue(obj) {
6455  var parts = [];
6456  forEach(obj, function(value, key) {
6457    if (isArray(value)) {
6458      forEach(value, function(arrayValue) {
6459        parts.push(encodeUriQuery(key, true) +
6460                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
6461      });
6462    } else {
6463    parts.push(encodeUriQuery(key, true) +
6464               (value === true ? '' : '=' + encodeUriQuery(value, true)));
6465    }
6466  });
6467  return parts.length ? parts.join('&') : '';
6468}
6469
6470
6471/**
6472 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
6473 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
6474 * segments:
6475 *    segment       = *pchar
6476 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
6477 *    pct-encoded   = "%" HEXDIG HEXDIG
6478 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
6479 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
6480 *                     / "*" / "+" / "," / ";" / "="
6481 */
6482function encodeUriSegment(val) {
6483  return encodeUriQuery(val, true).
6484             replace(/%26/gi, '&').
6485             replace(/%3D/gi, '=').
6486             replace(/%2B/gi, '+');
6487}
6488
6489
6490/**
6491 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
6492 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
6493 * encoded per http://tools.ietf.org/html/rfc3986:
6494 *    query       = *( pchar / "/" / "?" )
6495 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
6496 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
6497 *    pct-encoded   = "%" HEXDIG HEXDIG
6498 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
6499 *                     / "*" / "+" / "," / ";" / "="
6500 */
6501function encodeUriQuery(val, pctEncodeSpaces) {
6502  return encodeURIComponent(val).
6503             replace(/%40/gi, '@').
6504             replace(/%3A/gi, ':').
6505             replace(/%24/g, '$').
6506             replace(/%2C/gi, ',').
6507             replace(/%3B/gi, ';').
6508             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
6509}
6510
6511var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
6512
6513function getNgAttribute(element, ngAttr) {
6514  var attr, i, ii = ngAttrPrefixes.length;
6515  for (i = 0; i < ii; ++i) {
6516    attr = ngAttrPrefixes[i] + ngAttr;
6517    if (isString(attr = element.getAttribute(attr))) {
6518      return attr;
6519    }
6520  }
6521  return null;
6522}
6523
6524/**
6525 * @ngdoc directive
6526 * @name ngApp
6527 * @module ng
6528 *
6529 * @element ANY
6530 * @param {angular.Module} ngApp an optional application
6531 *   {@link angular.module module} name to load.
6532 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
6533 *   created in "strict-di" mode. This means that the application will fail to invoke functions which
6534 *   do not use explicit function annotation (and are thus unsuitable for minification), as de
6534scribed
6535 *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
6536 *   tracking down the root of these bugs.
6537 *
6538 * @description
6539 *
6540 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
6541 * designates the **root element** of the application and is typically placed near the root element
6542 * of the page - e.g. on the `<body>` or `<html>` tags.
6543 *
6544 * There are a few things to keep in mind when using `ngApp`:
6545 * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
6546 *   found in the document will be used to define the root element to auto-bootstrap as an
6547 *   application. To run multiple applications in an HTML document you must manually bootstrap them using
6548 *   {@link angular.bootstrap} instead.
6549 * - AngularJS applications cannot be nested within each other.
6550 * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
6551 *   This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
6552 *   {@link ngRoute.ngView `ngView`}.
6553 *   Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
6554 *   causing animations to stop working and making the injector inaccessible from outside the app.
6555 *
6556 * You can specify an **AngularJS module** to be used as the root module for the application.  This
6557 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
6558 * should contain the application code needed or have dependencies on other modules that will
6559 * contain the code. See {@link angular.module} for more information.
6560 *
6561 * In the example below if the `ngApp` directive were not placed on the `html` element then the
6562 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
6563 * would not be resolved to `3`.
6564 *
6565 * `ngApp` is the easiest, and most common way to bootstrap an application.
6566 *
6567 <example module="ngAppDemo">
6568   <file name="index.html">
6569   <div ng-controller="ngAppDemoController">
6570     I can add: {{a}} + {{b}} =  {{ a+b }}
6571   </div>
6572   </file>
6573   <file name="script.js">
6574   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
6575     $scope.a = 1;
6576     $scope.b = 2;
6577   });
6578   </file>
6579 </example>
6580 *
6581 * Using `ngStrictDi`, you would see something like this:
6582 *
6583 <example ng-app-included="true">
6584   <file name="index.html">
6585   <div ng-app="ngAppStrictDemo" ng-strict-di>
6586       <div ng-controller="GoodController1">
6587           I can add: {{a}} + {{b}} =  {{ a+b }}
6588
6589           <p>This renders because the controller does not fail to
6590              instantiate, by using explicit annotation style (see
6591              script.js for details)
6592           </p>
6593       </div>
6594
6595       <div ng-controller="GoodController2">
6596           Name: <input ng-model="name"><br />
6597           Hello, {{name}}!
6598
6599           <p>This renders because the controller does not fail to
6600              instantiate, by using explicit annotation style
6601              (see script.js for details)
6602           </p>
6603       </div>
6604
6605       <div ng-controller="BadController">
6606           I can add: {{a}} + {{b}} =  {{ a+b }}
6607
6608           <p>The controller could not be instantiated, due to relying
6609              on automatic function annotations (which are disabled in
6610              strict mode). As such, the content of this section is not
6611              interpolated, and there should be an error in your web console.
6612           </p>
6613       </div>
6614   </div>
6615   </file>
6616   <file name="script.js">
6617   angular.module('ngAppStrictDemo', [])
6618     // BadController will fail to instantiate, due to relying on automatic function annotation,
6619     // rather than an explicit annotation
6620     .controller('BadController', function($scope) {
6621       $scope.a = 1;
6622       $scope.b = 2;
6623     })
6624     // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
6625     // due to using explicit annotations using the array style and $inject property, respectively.
6626     .controller('GoodController1', ['$scope', function($scope) {
6627       $scope.a = 1;
6628       $scope.b = 2;
6629     }])
6630     .controller('GoodController2', GoodController2);
6631     function GoodController2($scope) {
6632       $scope.name = "World";
6633     }
6634     GoodController2.$inject = ['$scope'];
6635   </file>
6636   <file name="style.css">
6637   div[ng-controller] {
6638       margin-bottom: 1em;
6639       -webkit-border-radius: 4px;
6640       border-radius: 4px;
6641       border: 1px solid;
6642       padding: .5em;
6643   }
6644   div[ng-controller^=Good] {
6645       border-color: #d6e9c6;
6646       background-color: #dff0d8;
6647       color: #3c763d;
6648   }
6649   div[ng-controller^=Bad] {
6650       border-color: #ebccd1;
6651       background-color: #f2dede;
6652       color: #a94442;
6653       margin-bottom: 0;
6654   }
6655   </file>
6656 </example>
6657 */
6658function angularInit(element, bootstrap) {
6659  var appElement,
6660      module,
6661      config = {};
6662
6663  // The element `element` has priority over any other element
6664  forEach(ngAttrPrefixes, function(prefix) {
6665    var name = prefix + 'app';
6666
6667    if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
6668      appElement = element;
6669      module = element.getAttribute(name);
6670    }
6671  });
6672  forEach(ngAttrPrefixes, function(prefix) {
6673    var name = prefix + 'app';
6674    var candidate;
6675
6676    if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
6677      appElement = candidate;
6678      module = candidate.getAttribute(name);
6679    }
6680  });
6681  if (appElement) {
6682    config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
6683    bootstrap(appElement, module ? [module] : [], config);
6684  }
6685}
6686
6687/**
6688 * @ngdoc function
6689 * @name angular.bootstrap
6690 * @module ng
6691 * @description
6692 * Use this function to manually start up angular application.
6693 *
6694 * For more information, see the {@link guide/bootstrap Bootstrap guide}.
6695 *
6696 * Angular will detect if it has been loaded into the browser more than once and only allow the
6697 * first loaded script to be bootstrapped and will report a warning to the browser console for
6698 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
6699 * multiple instances of Angular try to work on the DOM.
6700 *
6701 * <div class="alert alert-warning">
6702 * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
6703 * They must use {@link ng.directive:ngApp ngApp}.
6704 * </div>
6705 *
6706 * <div class="alert alert-warning">
6707 * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
6708 * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
6709 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
6710 * causing animations to stop working and making the injector inaccessible from outside the app.
6711 * </div>
6712 *
6713 * ```html
6714 * <!doctype html>
6715 * <html>
6716 * <body>
6717 * <div ng-controller="WelcomeController">
6718 *   {{greeting}}
6719 * </div>
6720 *
6721 * <script src="angular.js"></script>
6722 * <script>
6723 *   var app = angular.module('demo', [])
6724 *   .controller('WelcomeController', function($scope) {
6725 *       $scope.greeting = 'Welcome!';
6726 *   });
6727 *   angular.bootstrap(document, ['demo']);
6728 * </script>
6729 * </body>
6730 * </html>
6731 * ```
6732 *
6733 * @param {DOMElement} element DOM element which is the root of angular application.
6734 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
6735 *     Each item in the array should be the name of a predefined module or a (DI annotated)
6736 *     function that will be invoked by the injector as a `config` block.
6737 *     See: {@link angular.module modules}
6738 * @param {Object=} config an object for defining configuration options for the application. The
6739 *     following keys are supported:
6740 *
6741 * * `strictDi` - disable automatic function annotation for the application. This is meant to
6742 *   assist in finding bugs which break minified code. Defaults to `false`.
6743 *
6744 * @returns {auto.$injector} Returns the newly created injector for this app.
6745 */
6746function bootstrap(element, modules, config) {
6747  if (!isObject(config)) config = {};
6748  var defaultConfig = {
6749    strictDi: false
6750  };
6751  config = extend(defaultConfig, config);
6752  var doBootstrap = function() {
6753    element = jqLite(element);
6754
6755    if (element.injector()) {
6756      var tag = (element[0] === document) ? 'document' : startingTag(element);
6757      //Encode angle brackets to prevent input from being sanitized to empty string #8683
6758      throw ngMinErr(
6759          'btstrpd',
6760          "App Already Bootstrapped with this Element '{0}'",
6761          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
6762    }
6763
6764    modules = modules || [];
6765    modules.unshift(['$provide', function($provide) {
6766      $provide.value('$rootElement', element);
6767    }]);
6768
6769    if (config.debugInfoEnabled) {
6770      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
6771      modules.push(['$compileProvider', function($compileProvider) {
6772        $compileProvider.debugInfoEnabled(true);
6773      }]);
6774    }
6775
6776    modules.unshift('ng');
6777    var injector = createInjector(modules, config.strictDi);
6778    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
6779       function bootstrapApply(scope, element, compile, injector) {
6780        scope.$apply(function() {
6781          element.data('$injector', injector);
6782          compile(element)(scope);
6783        });
6784      }]
6785    );
6786    return injector;
6787  };
6788
6789  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
6790  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
6791
6792  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
6793    config.debugInfoEnabled = true;
6794    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
6795  }
6796
6797  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
6798    return doBootstrap();
6799  }
6800
6801  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
6802  angular.resumeBootstrap = function(extraModules) {
6803    forEach(extraModules, function(module) {
6804      modules.push(module);
6805    });
6806    return doBootstrap();
6807  };
6808
6809  if (isFunction(angular.resumeDeferredBootstrap)) {
6810    angular.resumeDeferredBootstrap();
6811  }
6812}
6813
6814/**
6815 * @ngdoc function
6816 * @name angular.reloadWithDebugInfo
6817 * @module ng
6818 * @description
6819 * Use this function to reload the current application with debug information turned on.
6820 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
6821 *
6822 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
6823 */
6824function reloadWithDebugInfo() {
6825  window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
6826  window.location.reload();
6827}
6828
6829/**
6830 * @name angular.getTestability
6831 * @module ng
6832 * @description
6833 * Get the testability service for the instance of Angular on the given
6834 * element.
6835 * @param {DOMElement} element DOM element which is the root of angular application.
6836 */
6837function getTestability(rootElement) {
6838  var injector = angular.element(rootElement).injector();
6839  if (!injector) {
6840    throw ngMinErr('test',
6841      'no injector found for element argument to getTestability');
6842  }
6843  return injector.get('$$testability');
6844}
6845
6846var SNAKE_CASE_REGEXP = /[A-Z]/g;
6847function snake_case(name, separator) {
6848  separator = separator || '_';
6849  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
6850    return (pos ? separator : '') + letter.toLowerCase();
6851  });
6852}
6853
6854var bindJQueryFired = false;
vendor: 8,937 bytes, lines 6855-7139
6855function bindJQuery() {
6856  var originalCleanData;
6857
6858  if (bindJQueryFired) {
6859    return;
6860  }
6861
6862  // bind to jQuery if present;
6863  var jqName = jq();
6864  jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
6865           !jqName             ? undefined     :   // use jqLite
6866                                 window[jqName];   // use jQuery specified by `ngJq`
6867
6868  // Use jQuery if it exists with proper functionality, otherwise default to us.
6869  // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
6870  // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
6871  // versions. It will not work for sure with jQuery <1.7, though.
6872  if (jQuery && jQuery.fn.on) {
6873    jqLite = jQuery;
6874    extend(jQuery.fn, {
6875      scope: JQLitePrototype.scope,
6876      isolateScope: JQLitePrototype.isolateScope,
6877      controller: JQLitePrototype.controller,
6878      injector: JQLitePrototype.injector,
6879      inheritedData: JQLitePrototype.inheritedData
6880    });
6881
6882    // All nodes removed from the DOM via various jQuery APIs like .remove()
6883    // are passed through jQuery.cleanData. Monkey-patch this method to fire
6884    // the $destroy event on all removed nodes.
6885    originalCleanData = jQuery.cleanData;
6886    jQuery.cleanData = function(elems) {
6887      var events;
6888      for (var i = 0, elem; (elem = elems[i]) != null; i++) {
6889        events = jQuery._data(elem, "events");
6890        if (events && events.$destroy) {
6891          jQuery(elem).triggerHandler('$destroy');
6892        }
6893      }
6894      originalCleanData(elems);
6895    };
6896  } else {
6897    jqLite = JQLite;
6898  }
6899
6900  angular.element = jqLite;
6901
6902  // Prevent double-proxying.
6903  bindJQueryFired = true;
6904}
6905
6906/**
6907 * throw error if the argument is falsy.
6908 */
6909function assertArg(arg, name, reason) {
6910  if (!arg) {
6911    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
6912  }
6913  return arg;
6914}
6915
6916function assertArgFn(arg, name, acceptArrayAnnotation) {
6917  if (acceptArrayAnnotation && isArray(arg)) {
6918      arg = arg[arg.length - 1];
6919  }
6920
6921  assertArg(isFunction(arg), name, 'not a function, got ' +
6922      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
6923  return arg;
6924}
6925
6926/**
6927 * throw error if the name given is hasOwnProperty
6928 * @param  {String} name    the name to test
6929 * @param  {String} context the context in which the name is used, such as module or directive
6930 */
6931function assertNotHasOwnProperty(name, context) {
6932  if (name === 'hasOwnProperty') {
6933    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
6934  }
6935}
6936
6937/**
6938 * Return the value accessible from the object by path. Any undefined traversals are ignored
6939 * @param {Object} obj starting object
6940 * @param {String} path path to traverse
6941 * @param {boolean} [bindFnToScope=true]
6942 * @returns {Object} value as accessible by path
6943 */
6944//TODO(misko): this function needs to be removed
6945function getter(obj, path, bindFnToScope) {
6946  if (!path) return obj;
6947  var keys = path.split('.');
6948  var key;
6949  var lastInstance = obj;
6950  var len = keys.length;
6951
6952  for (var i = 0; i < len; i++) {
6953    key = keys[i];
6954    if (obj) {
6955      obj = (lastInstance = obj)[key];
6956    }
6957  }
6958  if (!bindFnToScope && isFunction(obj)) {
6959    return bind(lastInstance, obj);
6960  }
6961  return obj;
6962}
6963
6964/**
6965 * Return the DOM siblings between the first and last node in the given array.
6966 * @param {Array} array like object
6967 * @returns {Array} the inputted object or a jqLite collection containing the nodes
6968 */
6969function getBlockNodes(nodes) {
6970  // TODO(perf): update `nodes` instead of creating a new object?
6971  var node = nodes[0];
6972  var endNode = nodes[nodes.length - 1];
6973  var blockNodes;
6974
6975  for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
6976    if (blockNodes || nodes[i] !== node) {
6977      if (!blockNodes) {
6978        blockNodes = jqLite(slice.call(nodes, 0, i));
6979      }
6980      blockNodes.push(node);
6981    }
6982  }
6983
6984  return blockNodes || nodes;
6985}
6986
6987
6988/**
6989 * Creates a new object without a prototype. This object is useful for lookup without having to
6990 * guard against prototypically inherited properties via hasOwnProperty.
6991 *
6992 * Related micro-benchmarks:
6993 * - http://jsperf.com/object-create2
6994 * - http://jsperf.com/proto-map-lookup/2
6995 * - http://jsperf.com/for-in-vs-object-keys2
6996 *
6997 * @returns {Object}
6998 */
6999function createMap() {
7000  return Object.create(null);
7001}
7002
7003var NODE_TYPE_ELEMENT = 1;
7004var NODE_TYPE_ATTRIBUTE = 2;
7005var NODE_TYPE_TEXT = 3;
7006var NODE_TYPE_COMMENT = 8;
7007var NODE_TYPE_DOCUMENT = 9;
7008var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
7009
7010/**
7011 * @ngdoc type
7012 * @name angular.Module
7013 * @module ng
7014 * @description
7015 *
7016 * Interface for configuring angular {@link angular.module modules}.
7017 */
7018
7019function setupModuleLoader(window) {
7020
7021  var $injectorMinErr = minErr('$injector');
7022  var ngMinErr = minErr('ng');
7023
7024  function ensure(obj, name, factory) {
7025    return obj[name] || (obj[name] = factory());
7026  }
7027
7028  var angular = ensure(window, 'angular', Object);
7029
7030  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
7031  angular.$$minErr = angular.$$minErr || minErr;
7032
7033  return ensure(angular, 'module', function() {
7034    /** @type {Object.<string, angular.Module>} */
7035    var modules = {};
7036
7037    /**
7038     * @ngdoc function
7039     * @name angular.module
7040     * @module ng
7041     * @description
7042     *
7043     * The `angular.module` is a global place for creating, registering and retrieving Angular
7044     * modules.
7045     * All modules (angular core or 3rd party) that should be available to an application must be
7046     * registered using this mechanism.
7047     *
7048     * Passing one argument retrieves an existing {@link angular.Module},
7049     * whereas passing more than one argument creates a new {@link angular.Module}
7050     *
7051     *
7052     * # Module
7053     *
7054     * A module is a collection of services, directives, controllers, filters, and configuration information.
7055     * `angular.module` is used to configure the {@link auto.$injector $injector}.
7056     *
7057     * ```js
7058     * // Create a new module
7059     * var myModule = angular.module('myModule', []);
7060     *
7061     * // register a new service
7062     * myModule.value('appName', 'MyCoolApp');
7063     *
7064     * // configure existing services inside initialization blocks.
7065     * myModule.config(['$locationProvider', function($locationProvider) {
7066     *   // Configure existing providers
7067     *   $locationProvider.hashPrefix('!');
7068     * }]);
7069     * ```
7070     *
7071     * Then you can create an injector and load your modules like this:
7072     *
7073     * ```js
7074     * var injector = angular.injector(['ng', 'myModule'])
7075     * ```
7076     *
7077     * However it's more likely that you'll just use
7078     * {@link ng.directive:ngApp ngApp} or
7079     * {@link angular.bootstrap} to simplify this process for you.
7080     *
7081     * @param {!string} name The name of the module to create or retrieve.
7082     * @param {!Array.<string>=} requires If specified then new module is being created. If
7083     *        unspecified then the module is being retrieved for further configuration.
7084     * @param {Function=} configFn Optional configuration function for the module. Same as
7085     *        {@link angular.Module#config Module#config()}.
7086     * @returns {angular.Module} new module with the {@link angular.Module} api.
7087     */
7088    return function module(name, requires, configFn) {
7089      var assertNotHasOwnProperty = function(name, context) {
7090        if (name === 'hasOwnProperty') {
7091          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
7092        }
7093      };
7094
7095      assertNotHasOwnProperty(name, 'module');
7096      if (requires && modules.hasOwnProperty(name)) {
7097        modules[name] = null;
7098      }
7099      return ensure(modules, name, function() {
7100        if (!requires) {
7101          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
7102             "the module name or forgot to load it. If registering a module ensure that you " +
7103             "specify the dependencies as the second argument.", name);
7104        }
7105
7106        /** @type {!Array.<Array.<*>>} */
7107        var invokeQueue = [];
7108
7109        /** @type {!Array.<Function>} */
7110        var configBlocks = [];
7111
7112        /** @type {!Array.<Function>} */
7113        var runBlocks = [];
7114
7115        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
7116
7117        /** @type {angular.Module} */
7118        var moduleInstance = {
7119          // Private state
7120          _invokeQueue: invokeQueue,
7121          _configBlocks: configBlocks,
7122          _runBlocks: runBlocks,
7123
7124          /**
7125           * @ngdoc property
7126           * @name angular.Module#requires
7127           * @module ng
7128           *
7129           * @description
7130           * Holds the list of modules which the injector will load before the current module is
7131           * loaded.
7132           */
7133          requires: requires,
7134
7135          /**
7136           * @ngdoc property
7137           * @name angular.Module#name
7138           * @module ng
7139           *
7140           * @description
7141           * Name of the module.
7142           */
7143          name: name,
7144
7145
7146          /**
7147           * @ngdoc method
7148           * @name angular.Module#provider
7149           * @module ng
7150           * @param {string} name service name
7151           * @param {Function} providerType Construction function for creating new instance of the
7152           *                                service.
7153           * @description
7154           * See {@link auto.$provide#provider $provide.provider()}.
7155           */
7156          provider: invokeLaterAndSetModuleName('$provide', 'provider'),
7157
7158          /**
7159           * @ngdoc method
7160           * @name angular.Module#factory
7161           * @module ng
7162           * @param {string} name service name
7163           * @param {Function} providerFunction Function for creating new instance of the service.
7164           * @description
7165           * See {@link auto.$provide#factory $provide.factory()}.
7166           */
7167          factory: invokeLaterAndSetModuleName('$provide', 'factory'),
7168
7169          /**
7170           * @ngdoc method
7171           * @name angular.Module#service
7172           * @module ng
7173           * @param {string} name service name
7174           * @param {Function} constructor A constructor function that will be instantiated.
7175           * @description
7176           * See {@link auto.$provide#service $provide.service()}.
7177           */
7178          service: invokeLaterAndSetModuleName('$provide', 'service'),
7179
7180          /**
7181           * @ngdoc method
7182           * @name angular.Module#value
7183           * @module ng
7184           * @param {string} name service name
7185           * @param {*} object Service instance object.
7186           * @description
7187           * See {@link auto.$provide#value $provide.value()}.
7188           */
7189          value: invokeLater('$provide', 'value'),
7190
7191          /**
7192           * @ngdoc method
7193           * @name angular.Module#constant
7194           * @module ng
7195           * @param {string} name constant name
7196           * @param {*} object Constant value.
7197           * @description
7198           * Because the constants are fixed, they get applied before other provide methods.
7199           * See {@link auto.$provide#constant $provide.constant()}.
7200           */
7201          constant: invokeLater('$provide', 'constant', 'unshift'),
7202
7203           /**
7204           * @ngdoc method
7205           * @name angular.Module#decorator
7206           * @module ng
7207           * @param {string} The name of the service to decorate.
7208           * @param {Function} This function will be invoked when the service needs to be
7209           *                                    instantiated and should return the decorated service instance.
7210           * @description
7211           * See {@link auto.$provide#decorator $provide.decorator()}.
7212           */
7213          decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
7214
7215          /**
7216           * @ngdoc method
7217           * @name angular.Module#animation
7218           * @module ng
7219           * @param {string} name animation name
7220           * @param {Function} animationFactory Factory function for creating new instance of an
7221           *                                    animation.
7222           * @description
7223           *
7224           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
7225           *
7226           *
7227           * Defines an animation hook that can be later used with
7228           * {@link $animate $animate} service and directives that use this service.
7229           *
7230           * ```js
7231           * module.animation('.animation-name', function($inject1, $inject2) {
7232           *   return {
7233           *     eventName : function(element, done) {
7234           *       //code to run the animation
7235           *       //once complete, then run done()
7236           *       return function cancellationFunction(element) {
7237           *         //code to cancel the animation
7238           *       }
7239           *     }
7240           *   }
7241           * })
7242           * ```
7243           *
7244           * See {@link ng.$animateProvider#register $animateProvider.register()} and
7245           * {@link ngAnimate ngAnimate module} for more information.
7246           */
7247          animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
7248
7249          /**
7250           * @ngdoc method
7251           * @name angular.Module#filter
7252           * @module ng
7253           * @param {string} name Filter name - this must be a valid angular expression identifier
7254           * @param {Function} filterFactory Factory function for creating new instance of filter.
7255           * @description
7256           * See {@link ng.$filterProvider#register $filterProvider.register()}.
7257           *
7258           * <div class="alert alert-warning">
7259           * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
7260           * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
7261           * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
7262           * (`myapp_subsection_filterx`).
7263           * </div>
7264           */
7265          filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
7266
7267          /**
7268           * @ngdoc method
7269           * @name angular.Module#controller
7270           * @module ng
7271           * @param {string|Object} name Controller name, or an object map of controllers where the
7272           *    keys are the names and the values are the constructors.
7273           * @param {Function} constructor Controller constructor function.
7274           * @description
7275           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
7276           */
7277          controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
7278
7279          /**
7280           * @ngdoc method
7281           * @name angular.Module#directive
7282           * @module ng
7283           * @param {string|Object} name Directive name, or an object map of directives where the
7284           *    keys are the names and the values are the factories.
7285           * @param {Function} directiveFactory Factory function for creating new instance of
7286           * directives.
7287           * @description
7288           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
7289           */
7290          directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
7291
7292          /**
7293           * @ngdoc method
7294           * @name angular.Module#component
7295           * @module ng
7296           * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
7297           * @param {Object} options Component definition object (a simplified
7298           *    {@link ng.$compile#directive-definition-object directive definition object})
7299           *
7300           * @description
7301           * See {@link ng.$compileProvider#component $compileProvider.component()}.
7302           */
7303          component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
7304
7305          /**
7306           * @ngdoc method
7307           * @name angular.Module#config
7308           * @module ng
7309           * @param {Function} configFn Execute this function on module load. Useful for service
7310           *    configuration.
7311           * @description
7312           * Use this method to register work which needs to be performed on module loading.
7313           * For more about how to configure services, see
7314           * {@link providers#provider-recipe Provider Recipe}.
7315           */
7316          config: config,
7317
7318          /**
7319           * @ngdoc method
7320           * @name angular.Module#run
7321           * @module ng
7322           * @param {Function} initializationFn Execute this function after injector creation.
7323           *    Useful for application initialization.
7324           * @description
7325           * Use this method to register work which should be performed when the injector is done
7326           * loading all modules.
7327           */
7328          run: function(block) {
7329            runBlocks.push(block);
7330            return this;
7331          }
7332        };
7333
7334        if (configFn) {
7335          config(configFn);
7336        }
7337
7338        return moduleInstance;
7339
7340        /**
7341         * @param {string} provider
7342         * @param {string} method
7343         * @param {String=} insertMethod
7344         * @returns {angular.Module}
7345         */
7346        function invokeLater(provider, method, insertMethod, queue) {
7347          if (!queue) queue = invokeQueue;
7348          return function() {
7349            queue[insertMethod || 'push']([provider, method, arguments]);
7350            return moduleInstance;
7351          };
7352        }
7353
7354        /**
7355         * @param {string} provider
7356         * @param {string} method
7357         * @returns {angular.Module}
7358         */
vendor: 4,717 bytes, lines 7359-7558
7359        function invokeLaterAndSetModuleName(provider, method) {
7360          return function(recipeName, factoryFunction) {
7361            if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
7362            invokeQueue.push([provider, method, arguments]);
7363            return moduleInstance;
7364          };
7365        }
7366      });
7367    };
7368  });
7369
7370}
7371
7372/* global: toDebugString: true */
7373
7374function serializeObject(obj) {
7375  var seen = [];
7376
7377  return JSON.stringify(obj, function(key, val) {
7378    val = toJsonReplacer(key, val);
7379    if (isObject(val)) {
7380
7381      if (seen.indexOf(val) >= 0) return '...';
7382
7383      seen.push(val);
7384    }
7385    return val;
7386  });
7387}
7388
7389function toDebugString(obj) {
7390  if (typeof obj === 'function') {
7391    return obj.toString().replace(/ \{[\s\S]*$/, '');
7392  } else if (isUndefined(obj)) {
7393    return 'undefined';
7394  } else if (typeof obj !== 'string') {
7395    return serializeObject(obj);
7396  }
7397  return obj;
7398}
7399
7400/* global angularModule: true,
7401  version: true,
7402
7403  $CompileProvider,
7404
7405  htmlAnchorDirective,
7406  inputDirective,
7407  inputDirective,
7408  formDirective,
7409  scriptDirective,
7410  selectDirective,
7411  styleDirective,
7412  optionDirective,
7413  ngBindDirective,
7414  ngBindHtmlDirective,
7415  ngBindTemplateDirective,
7416  ngClassDirective,
7417  ngClassEvenDirective,
7418  ngClassOddDirective,
7419  ngCloakDirective,
7420  ngControllerDirective,
7421  ngFormDirective,
7422  ngHideDirective,
7423  ngIfDirective,
7424  ngIncludeDirective,
7425  ngIncludeFillContentDirective,
7426  ngInitDirective,
7427  ngNonBindableDirective,
7428  ngPluralizeDirective,
7429  ngRepeatDirective,
7430  ngShowDirective,
7431  ngStyleDirective,
7432  ngSwitchDirective,
7433  ngSwitchWhenDirective,
7434  ngSwitchDefaultDirective,
7435  ngOptionsDirective,
7436  ngTranscludeDirective,
7437  ngModelDirective,
7438  ngListDirective,
7439  ngChangeDirective,
7440  patternDirective,
7441  patternDirective,
7442  requiredDirective,
7443  requiredDirective,
7444  minlengthDirective,
7445  minlengthDirective,
7446  maxlengthDirective,
7447  maxlengthDirective,
7448  ngValueDirective,
7449  ngModelOptionsDirective,
7450  ngAttributeAliasDirectives,
7451  ngEventDirectives,
7452
7453  $AnchorScrollProvider,
7454  $AnimateProvider,
7455  $CoreAnimateCssProvider,
7456  $$CoreAnimateJsProvider,
7457  $$CoreAnimateQueueProvider,
7458  $$AnimateRunnerFactoryProvider,
7459  $$AnimateAsyncRunFactoryProvider,
7460  $BrowserProvider,
7461  $CacheFactoryProvider,
7462  $ControllerProvider,
7463  $DateProvider,
7464  $DocumentProvider,
7465  $ExceptionHandlerProvider,
7466  $FilterProvider,
7467  $$ForceReflowProvider,
7468  $InterpolateProvider,
7469  $IntervalProvider,
7470  $$HashMapProvider,
7471  $HttpProvider,
7472  $HttpParamSerializerProvider,
7473  $HttpParamSerializerJQLikeProvider,
7474  $HttpBackendProvider,
7475  $xhrFactoryProvider,
7476  $LocationProvider,
7477  $LogProvider,
7478  $ParseProvider,
7479  $RootScopeProvider,
7480  $QProvider,
7481  $$QProvider,
7482  $$SanitizeUriProvider,
7483  $SceProvider,
7484  $SceDelegateProvider,
7485  $SnifferProvider,
7486  $TemplateCacheProvider,
7487  $TemplateRequestProvider,
7488  $$TestabilityProvider,
7489  $TimeoutProvider,
7490  $$RAFProvider,
7491  $WindowProvider,
7492  $$jqLiteProvider,
7493  $$CookieReaderProvider
7494*/
7495
7496
7497/**
7498 * @ngdoc object
7499 * @name angular.version
7500 * @module ng
7501 * @description
7502 * An object that contains information about the current AngularJS version.
7503 *
7504 * This object has the following properties:
7505 *
7506 * - `full` – `{string}` – Full version string, such as "0.9.18".
7507 * - `major` – `{number}` – Major version number, such as "0".
7508 * - `minor` – `{number}` – Minor version number, such as "9".
7509 * - `dot` – `{number}` – Dot version number, such as "18".
7510 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
7511 */
7512var version = {
7513  full: '1.5.1',    // all of these placeholder strings will be replaced by grunt's
7514  major: 1,    // package task
7515  minor: 5,
7516  dot: 1,
7517  codeName: 'equivocal-sophistication'
7518};
7519
7520
7521function publishExternalAPI(angular) {
7522  extend(angular, {
7523    'bootstrap': bootstrap,
7524    'copy': copy,
7525    'extend': extend,
7526    'merge': merge,
7527    'equals': equals,
7528    'element': jqLite,
7529    'forEach': forEach,
7530    'injector': createInjector,
7531    'noop': noop,
7532    'bind': bind,
7533    'toJson': toJson,
7534    'fromJson': fromJson,
7535    'identity': identity,
7536    'isUndefined': isUndefined,
7537    'isDefined': isDefined,
7538    'isString': isString,
7539    'isFunction': isFunction,
7540    'isObject': isObject,
7541    'isNumber': isNumber,
7542    'isElement': isElement,
7543    'isArray': isArray,
7544    'version': version,
7545    'isDate': isDate,
7546    'lowercase': lowercase,
7547    'uppercase': uppercase,
7548    'callbacks': {counter: 0},
7549    'getTestability': getTestability,
7550    '$$minErr': minErr,
7551    '$$csp': csp,
7552    'reloadWithDebugInfo': reloadWithDebugInfo
7553  });
7554
7555  angularModule = setupModuleLoader(window);
7556
7557  angularModule('ng', ['ngLocale'], ['$provide',
7558    function ngModule($provide) {
7559      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
7560      $provide.provider({
7561        $$sanitizeUri: $$SanitizeUriProvider
7562      });
7563      $provide.provider('$compile', $CompileProvider).
7564        directive({
7565            a: htmlAnchorDirective,
7566            input: inputDirective,
7567            textarea: inputDirective,
7568            form: formDirective,
7569            script: scriptDirective,
7570            select: selectDirective,
7571            style: styleDirective,
7572            option: optionDirective,
7573            ngBind: ngBindDirective,
7574            ngBindHtml: ngBindHtmlDirective,
7575            ngBindTemplate: ngBindTemplateDirective,
7576            ngClass: ngClassDirective,
7577            ngClassEven: ngClassEvenDirective,
7578            ngClassOdd: ngClassOddDirective,
7579            ngCloak: ngCloakDirective,
7580            ngController: ngControllerDirective,
7581            ngForm: ngFormDirective,
7582            ngHide: ngHideDirective,
7583            ngIf: ngIfDirective,
7584            ngInclude: ngIncludeDirective,
7585            ngInit: ngInitDirective,
7586            ngNonBindable: ngNonBindableDirective,
7587            ngPluralize: ngPluralizeDirective,
7588            ngRepeat: ngRepeatDirective,
7589            ngShow: ngShowDirective,
7590            ngStyle: ngStyleDirective,
7591            ngSwitch: ngSwitchDirective,
7592            ngSwitchWhen: ngSwitchWhenDirective,
7593            ngSwitchDefault: ngSwitchDefaultDirective,
7594            ngOptions: ngOptionsDirective,
7595            ngTransclude: ngTranscludeDirective,
7596            ngModel: ngModelDirective,
7597            ngList: ngListDirective,
7598            ngChange: ngChangeDirective,
7599            pattern: patternDirective,
7600            ngPattern: patternDirective,
7601            required: requiredDirective,
7602            ngRequired: requiredDirective,
7603            minlength: minlengthDirective,
7604            ngMinlength: minlengthDirective,
7605            maxlength: maxlengthDirective,
7606            ngMaxlength: maxlengthDirective,
7607            ngValue: ngValueDirective,
7608            ngModelOptions: ngModelOptionsDirective
7609        }).
7610        directive({
7611          ngInclude: ngIncludeFillContentDirective
7612        }).
7613        directive(ngAttributeAliasDirectives).
7614        directive(ngEventDirectives);
7615      $provide.provider({
7616        $anchorScroll: $AnchorScrollProvider,
7617        $animate: $AnimateProvider,
7618        $animateCss: $CoreAnimateCssProvider,
7619        $$animateJs: $$CoreAnimateJsProvider,
7620        $$animateQueue: $$CoreAnimateQueueProvider,
7621        $$AnimateRunner: $$AnimateRunnerFactoryProvider,
7622        $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
7623        $browser: $BrowserProvider,
7624        $cacheFactory: $CacheFactoryProvider,
7625        $controller: $ControllerProvider,
7626        $document: $DocumentProvider,
7627        $exceptionHandler: $ExceptionHandlerProvider,
7628        $filter: $FilterProvider,
7629        $$forceReflow: $$ForceReflowProvider,
7630        $interpolate: $InterpolateProvider,
7631        $interval: $IntervalProvider,
7632        $http: $HttpProvider,
7633        $httpParamSerializer: $HttpParamSerializerProvider,
7634        $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
7635        $httpBackend: $HttpBackendProvider,
7636        $xhrFactory: $xhrFactoryProvider,
7637        $location: $LocationProvider,
7638        $log: $LogProvider,
7639        $parse: $ParseProvider,
7640        $rootScope: $RootScopeProvider,
7641        $q: $QProvider,
7642        $$q: $$QProvider,
7643        $sce: $SceProvider,
7644        $sceDelegate: $SceDelegateProvider,
7645        $sniffer: $SnifferProvider,
7646        $templateCache: $TemplateCacheProvider,
7647        $templateRequest: $TemplateRequestProvider,
7648        $$testability: $$TestabilityProvider,
7649        $timeout: $TimeoutProvider,
7650        $window: $WindowProvider,
7651        $$rAF: $$RAFProvider,
7652        $$jqLite: $$jqLiteProvider,
7653        $$HashMap: $$HashMapProvider,
7654        $$cookieReader: $$CookieReaderProvider
7655      });
7656    }
7657  ]);
7658}
7659
7660/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7661 *     Any commits to this file should be reviewed with security in mind.  *
7662 *   Changes to this file can potentially create security vulnerabilities. *
7663 *          An approval from 2 Core members with history of modifying      *
7664 *                         this file is required.                          *
7665 *                                                                         *
7666 *  Does the change somehow allow for arbitrary javascript to be executed? *
7667 *    Or allows for someone to change the prototype of built-in objects?   *
7668 *     Or gives undesired access to variables likes document or window?    *
7669 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7670
7671/* global JQLitePrototype: true,
7672  addEventListenerFn: true,
7673  removeEventListenerFn: true,
7674  BOOLEAN_ATTR: true,
7675  ALIASED_ATTR: true,
7676*/
7677
7678//////////////////////////////////
7679//JQLite
7680//////////////////////////////////
7681
7682/**
7683 * @ngdoc function
7684 * @name angular.element
7685 * @module ng
7686 * @kind function
7687 *
7688 * @description
7689 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
7690 *
7691 * If jQuery is available, `angular.element` is an alias for the
7692 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
7693 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
7694 *
7695 * jqLite is a tiny, API-compatible subset of jQuery that allows
7696 * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
7697 * commonly needed functionality with the goal of having a very small footprint.
7698 *
7699 * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
7700 * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
7701 * specific version of jQuery if multiple versions exist on the page.
7702 *
7703 * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
7704 * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
7705 *
7706 * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
7707 * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
7708 * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
7709 *
7710 * ## Angular's jqLite
7711 * jqLite provides only the following jQuery methods:
7712 *
7713 * - [`addClass()`](http://api.jquery.com/addClass/)
7714 * - [`after()`](http://api.jquery.com/after/)
7715 * - [`append()`](http://api.jquery.com/append/)
7716 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
7717 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
7718 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
7719 * - [`clone()`](http://api.jquery.com/clone/)
7720 * - [`contents()`](http://api.jquery.com/contents/)
7721 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
7722 *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
7723 * - [`data()`](http://api.jquery.com/data/)
7724 * - [`detach()`](http://api.jquery.com/detach/)
7725 * - [`empty()`](http://api.jquery.com/empty/)
7726 * - [`eq()`](http://api.jquery.com/eq/)
7727 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
7728 * - [`hasClass()`](http://api.jquery.com/hasClass/)
7729 * - [`html()`](http://api.jquery.com/html/)
7730 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
7731 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
7732 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
7733 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
7734 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
7735 * - [`prepend()`](http://api.jquery.com/prepend/)
7736 * - [`prop()`](http://api.jquery.com/prop/)
7737 * - [`ready()`](http://api.jquery.com/ready/)
7738 * - [`remove()`](http://api.jquery.com/remove/)
7739 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
7740 * - [`removeClass()`](http://api.jquery.com/removeClass/)
7741 * - [`removeData()`](http://api.jquery.com/removeData/)
7742 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
7743 * - [`text()`](http://api.jquery.com/text/)
7744 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
7745 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
7746 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
7747 * - [`val()`](http://api.jquery.com/val/)
7748 * - [`wrap()`](http://api.jquery.com/wrap/)
7749 *
7750 * ## jQuery/jqLite Extras
7751 * Angular also provides the following additional methods and events to both jQuery and jqLite:
7752 *
7753 * ### Events
7754 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
7754pis and fires this event
7755 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
7756 *    element before it is removed.
7757 *
7758 * ### Methods
7759 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
7760 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
7761 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
7762 *   `'ngModel'`).
7763 * - `injector()` - retrieves the injector of the current element or its parent.
7764 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
7765 *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
7766 *   be enabled.
7767 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
7768 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
7769 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
7770 *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
7771 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
7772 *   parent element is reached.
7773 *
7774 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
7775 * @returns {Object} jQuery object.
7776 */
7777
7778JQLite.expando = 'ng339';
7779
7780var jqCache = JQLite.cache = {},
7781    jqId = 1,
7782    addEventListenerFn = function(element, type, fn) {
7783      element.addEventListener(type, fn, false);
7784    },
7785    removeEventListenerFn = function(element, type, fn) {
7786      element.removeEventListener(type, fn, false);
7787    };
7788
7789/*
7790 * !!! This is an undocumented "private" function !!!
7791 */
7792JQLite._data = function(node) {
7793  //jQuery always returns an object on cache miss
7794  return this.cache[node[this.expando]] || {};
7795};
7796
7797function jqNextId() { return ++jqId; }
7798
7799
7800var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
7801var MOZ_HACK_REGEXP = /^moz([A-Z])/;
7802var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
7803var jqLiteMinErr = minErr('jqLite');
7804
7805/**
7806 * Converts snake_case to camelCase.
7807 * Also there is special case for Moz prefix starting with upper case letter.
7808 * @param name Name to normalize
7809 */
7810function camelCase(name) {
7811  return name.
7812    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
7813      return offset ? letter.toUpperCase() : letter;
7814    }).
7815    replace(MOZ_HACK_REGEXP, 'Moz$1');
7816}
7817
7818var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
7819var HTML_REGEXP = /<|&#?\w+;/;
7820var TAG_NAME_REGEXP = /<([\w:-]+)/;
7821var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
7822
7823var wrapMap = {
7824  'option': [1, '<select multiple="multiple">', '</select>'],
7825
7826  'thead': [1, '<table>', '</table>'],
7827  'col': [2, '<table><colgroup>', '</colgroup></table>'],
7828  'tr': [2, '<table><tbody>', '</tbody></table>'],
7829  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
7830  '_default': [0, "", ""]
7831};
7832
7833wrapMap.optgroup = wrapMap.option;
7834wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
7835wrapMap.th = wrapMap.td;
7836
7837
7838function jqLiteIsTextNode(html) {
7839  return !HTML_REGEXP.test(html);
7840}
7841
7842function jqLiteAcceptsData(node) {
7843  // The window object can accept data but has no nodeType
7844  // Otherwise we are only interested in elements (1) and documents (9)
7845  var nodeType = node.nodeType;
7846  return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
7847}
7848
7849function jqLiteHasData(node) {
7850  for (var key in jqCache[node.ng339]) {
7851    return true;
7852  }
7853  return false;
7854}
7855
7856function jqLiteCleanData(nodes) {
7857  for (var i = 0, ii = nodes.length; i < ii; i++) {
7858    jqLiteRemoveData(nodes[i]);
7859  }
7860}
7861
7862function jqLiteBuildFragment(html, context) {
7863  var tmp, tag, wrap,
7864      fragment = context.createDocumentFragment(),
7865      nodes = [], i;
7866
7867  if (jqLiteIsTextNode(html)) {
7868    // Convert non-html into a text node
7869    nodes.push(context.createTextNode(html));
7870  } else {
7871    // Convert html into DOM nodes
7872    tmp = tmp || fragment.appendChild(context.createElement("div"));
7873    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
7874    wrap = wrapMap[tag] || wrapMap._default;
7875    tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
7876
7877    // Descend through wrappers to the right content
7878    i = wrap[0];
7879    while (i--) {
7880      tmp = tmp.lastChild;
7881    }
7882
7883    nodes = concat(nodes, tmp.childNodes);
7884
7885    tmp = fragment.firstChild;
7886    tmp.textContent = "";
7887  }
7888
7889  // Remove wrapper from fragment
7890  fragment.textContent = "";
7891  fragment.innerHTML = ""; // Clear inner HTML
7892  forEach(nodes, function(node) {
7893    fragment.appendChild(node);
7894  });
7895
7896  return fragment;
7897}
7898
7899function jqLiteParseHTML(html, context) {
7900  context = context || document;
7901  var parsed;
7902
7903  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
7904    return [context.createElement(parsed[1])];
7905  }
7906
7907  if ((parsed = jqLiteBuildFragment(html, context))) {
7908    return parsed.childNodes;
7909  }
7910
7911  return [];
7912}
7913
7914function jqLiteWrapNode(node, wrapper) {
7915  var parent = node.parentNode;
7916
7917  if (parent) {
7918    parent.replaceChild(wrapper, node);
7919  }
7920
7921  wrapper.appendChild(node);
7922}
7923
7924
7925// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
7926var jqLiteContains = Node.prototype.contains || function(arg) {
7927  // jshint bitwise: false
7928  return !!(this.compareDocumentPosition(arg) & 16);
7929  // jshint bitwise: true
7930};
7931
7932/////////////////////////////////////////////
7933function JQLite(element) {
7934  if (element instanceof JQLite) {
7935    return element;
7936  }
7937
7938  var argIsString;
7939
7940  if (isString(element)) {
7941    element = trim(element);
7942    argIsString = true;
7943  }
7944  if (!(this instanceof JQLite)) {
7945    if (argIsString && element.charAt(0) != '<') {
7946      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
7947    }
7948    return new JQLite(element);
7949  }
7950
7951  if (argIsString) {
7952    jqLiteAddNodes(this, jqLiteParseHTML(element));
7953  } else {
7954    jqLiteAddNodes(this, element);
7955  }
7956}
7957
7958function jqLiteClone(element) {
7959  return element.cloneNode(true);
7960}
7961
7962function jqLiteDealoc(element, onlyDescendants) {
7963  if (!onlyDescendants) jqLiteRemoveData(element);
7964
7965  if (element.querySelectorAll) {
7966    var descendants = element.querySelectorAll('*');
7967    for (var i = 0, l = descendants.length; i < l; i++) {
7968      jqLiteRemoveData(descendants[i]);
7969    }
7970  }
7971}
7972
7973function jqLiteOff(element, type, fn, unsupported) {
7974  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
7975
7976  var expandoStore = jqLiteExpandoStore(element);
7977  var events = expandoStore && expandoStore.events;
7978  var handle = expandoStore && expandoStore.handle;
7979
7980  if (!handle) return; //no listeners registered
7981
7982  if (!type) {
7983    for (type in events) {
7984      if (type !== '$destroy') {
7985        removeEventListenerFn(element, type, handle);
7986      }
7987      delete events[type];
7988    }
7989  } else {
7990
7991    var removeHandler = function(type) {
7992      var listenerFns = events[type];
7993      if (isDefined(fn)) {
7994        arrayRemove(listenerFns || [], fn);
7995      }
7996      if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
7997        removeEventListenerFn(element, type, handle);
7998        delete events[type];
7999      }
8000    };
8001
8002    forEach(type.split(' '), function(type) {
8003      removeHandler(type);
8004      if (MOUSE_EVENT_MAP[type]) {
8005        removeHandler(MOUSE_EVENT_MAP[type]);
8006      }
8007    });
8008  }
8009}
8010
8011function jqLiteRemoveData(element, name) {
8012  var expandoId = element.ng339;
8013  var expandoStore = expandoId && jqCache[expandoId];
8014
8015  if (expandoStore) {
8016    if (name) {
8017      delete expandoStore.data[name];
8018      return;
8019    }
8020
8021    if (expandoStore.handle) {
8022      if (expandoStore.events.$destroy) {
8023        expandoStore.handle({}, '$destroy');
8024      }
8025      jqLiteOff(element);
8026    }
8027    delete jqCache[expandoId];
8028    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
8029  }
8030}
8031
8032
8033function jqLiteExpandoStore(element, createIfNecessary) {
8034  var expandoId = element.ng339,
8035      expandoStore = expandoId && jqCache[expandoId];
8036
8037  if (createIfNecessary && !expandoStore) {
8038    element.ng339 = expandoId = jqNextId();
8039    expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
8040  }
8041
8042  return expandoStore;
8043}
8044
8045
8046function jqLiteData(element, key, value) {
8047  if (jqLiteAcceptsData(element)) {
8048
8049    var isSimpleSetter = isDefined(value);
8050    var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
8051    var massGetter = !key;
8052    var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
8053    var data = expandoStore && expandoStore.data;
8054
8055    if (isSimpleSetter) { // data('key', value)
8056      data[key] = value;
8057    } else {
8058      if (massGetter) {  // data()
8059        return data;
8060      } else {
8061        if (isSimpleGetter) { // data('key')
8062          // don't force creation of expandoStore if it doesn't exist yet
8063          return data && data[key];
8064        } else { // mass-setter: data({key1: val1, key2: val2})
8065          extend(data, key);
8066        }
8067      }
8068    }
8069  }
8070}
8071
8072function jqLiteHasClass(element, selector) {
8073  if (!element.getAttribute) return false;
8074  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
8075      indexOf(" " + selector + " ") > -1);
8076}
8077
8078function jqLiteRemoveClass(element, cssClasses) {
8079  if (cssClasses && element.setAttribute) {
8080    forEach(cssClasses.split(' '), function(cssClass) {
8081      element.setAttribute('class', trim(
8082          (" " + (element.getAttribute('class') || '') + " ")
8083          .replace(/[\n\t]/g, " ")
8084          .replace(" " + trim(cssClass) + " ", " "))
8085      );
8086    });
8087  }
8088}
8089
8090function jqLiteAddClass(element, cssClasses) {
8091  if (cssClasses && element.setAttribute) {
8092    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
8093                            .replace(/[\n\t]/g, " ");
8094
8095    forEach(cssClasses.split(' '), function(cssClass) {
8096      cssClass = trim(cssClass);
8097      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
8098        existingClasses += cssClass + ' ';
8099      }
8100    });
8101
8102    element.setAttribute('class', trim(existingClasses));
8103  }
8104}
8105
8106
8107function jqLiteAddNodes(root, elements) {
8108  // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
8109
8110  if (elements) {
8111
8112    // if a Node (the most common case)
8113    if (elements.nodeType) {
8114      root[root.length++] = elements;
8115    } else {
8116      var length = elements.length;
8117
8118      // if an Array or NodeList and not a Window
8119      if (typeof length === 'number' && elements.window !== elements) {
8120        if (length) {
8121          for (var i = 0; i < length; i++) {
8122            root[root.length++] = elements[i];
8123          }
8124        }
8125      } else {
8126        root[root.length++] = elements;
8127      }
8128    }
8129  }
8130}
8131
8132
8133function jqLiteController(element, name) {
8134  return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
8135}
8136
8137function jqLiteInheritedData(element, name, value) {
8138  // if element is the document object work with the html element instead
8139  // this makes $(document).scope() possible
8140  if (element.nodeType == NODE_TYPE_DOCUMENT) {
8141    element = element.documentElement;
8142  }
8143  var names = isArray(name) ? name : [name];
8144
8145  while (element) {
8146    for (var i = 0, ii = names.length; i < ii; i++) {
8147      if (isDefined(value = jqLite.data(element, names[i]))) return value;
8148    }
8149
8150    // If dealing with a document fragment node with a host element, and no parent, use the host
8151    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
8152    // to lookup parent controllers.
8153    element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
8154  }
8155}
8156
8157function jqLiteEmpty(element) {
8158  jqLiteDealoc(element, true);
8159  while (element.firstChild) {
8160    element.removeChild(element.firstChild);
8161  }
8162}
8163
8164function jqLiteRemove(element, keepData) {
8165  if (!keepData) jqLiteDealoc(element);
8166  var parent = element.parentNode;
8167  if (parent) parent.removeChild(element);
8168}
8169
8170
8171function jqLiteDocumentLoaded(action, win) {
8172  win = win || window;
8173  if (win.document.readyState === 'complete') {
8174    // Force the action to be run async for consistent behavior
8175    // from the action's point of view
8176    // i.e. it will definitely not be in a $apply
8177    win.setTimeout(action);
8178  } else {
8179    // No need to unbind this handler as load is only ever called once
8180    jqLite(win).on('load', action);
8181  }
8182}
8183
8184//////////////////////////////////////////
8185// Functions which are declared directly.
8186//////////////////////////////////////////
8187var JQLitePrototype = JQLite.prototype = {
8188  ready: function(fn) {
8189    var fired = false;
8190
8191    function trigger() {
8192      if (fired) return;
8193      fired = true;
8194      fn();
8195    }
8196
8197    // check if document is already loaded
8198    if (document.readyState === 'complete') {
8199      setTimeout(trigger);
8200    } else {
8201      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
8202      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
8203      // jshint -W064
8204      JQLite(window).on('load', trigger); // fallback to window.onload for others
8205      // jshint +W064
8206    }
8207  },
8208  toString: function() {
8209    var value = [];
8210    forEach(this, function(e) { value.push('' + e);});
8211    return '[' + value.join(', ') + ']';
8212  },
8213
8214  eq: function(index) {
8215      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
8216  },
8217
8218  length: 0,
8219  push: push,
8220  sort: [].sort,
8221  splice: [].splice
8222};
8223
8224//////////////////////////////////////////
8225// Functions iterating getter/setters.
8226// these functions return self on setter and
8227// value on get.
8228//////////////////////////////////////////
8229var BOOLEAN_ATTR = {};
8230forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
8231  BOOLEAN_ATTR[lowercase(value)] = value;
8232});
8233var BOOLEAN_ELEMENTS = {};
8234forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
8235  BOOLEAN_ELEMENTS[value] = true;
8236});
8237var ALIASED_ATTR = {
8238  'ngMinlength': 'minlength',
8239  'ngMaxlength': 'maxlength',
8240  'ngMin': 'min',
8241  'ngMax': 'max',
8242  'ngPattern': 'pattern'
8243};
8244
8245function getBooleanAttrName(element, name) {
8246  // check dom last since we will most likely fail on name
8247  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
8248
8249  // booleanAttr is here twice to minimize DOM access
8250  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
8251}
8252
8253function getAliasedAttrName(name) {
8254  return ALIASED_ATTR[name];
8255}
8256
8257forEach({
8258  data: jqLiteData,
8259  removeData: jqLiteRemoveData,
8260  hasData: jqLiteHasData,
8261  cleanData: jqLiteCleanData
8262}, function(fn, name) {
8263  JQLite[name] = fn;
8264});
8265
8266forEach({
8267  data: jqLiteData,
8268  inheritedData: jqLiteInheritedData,
8269
8270  scope: function(element) {
8271    // Can't use jqLiteData here directly so we stay compatible with jQuery!
8272    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
8273  },
8274
8275  isolateScope: function(element) {
8276    // Can't use jqLiteData here directly so we stay compatible with jQuery!
8277    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
8278  },
8279
8280  controller: jqLiteController,
8281
8282  injector: function(element) {
8283    return jqLiteInheritedData(element, '$injector');
8284  },
8285
8286  removeAttr: function(element, name) {
8287    element.removeAttribute(name);
8288  },
8289
8290  hasClass: jqLiteHasClass,
8291
8292  css: function(element, name, value) {
8293    name = camelCase(name);
8294
8295    if (isDefined(value)) {
8296      element.style[name] = value;
8297    } else {
8298      return element.style[name];
8299    }
8300  },
8301
8302  attr: function(element, name, value) {
8303    var nodeType = element.nodeType;
8304    if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
8305      return;
8306    }
8307    var lowercasedName = lowercase(name);
8308    if (BOOLEAN_ATTR[lowercasedName]) {
8309      if (isDefined(value)) {
8310        if (!!value) {
8311          element[name] = true;
8312          element.setAttribute(name, lowercasedName);
8313        } else {
8314          element[name] = false;
8315          element.removeAttribute(lowercasedName);
8316        }
8317      } else {
8318        return (element[name] ||
8319                 (element.attributes.getNamedItem(name) || noop).specified)
8320               ? lowercasedName
8321               : undefined;
8322      }
8323    } else if (isDefined(value)) {
8324      element.setAttribute(name, value);
8325    } else if (element.getAttribute) {
8326      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
8327      // some elements (e.g. Document) don't have get attribute, so return undefined
8328      var ret = element.getAttribute(name, 2);
8329      // normalize non-existing attributes to undefined (as jQuery)
8330      return ret === null ? undefined : ret;
8331    }
8332  },
8333
8334  prop: function(element, name, value) {
8335    if (isDefined(value)) {
8336      element[name] = value;
8337    } else {
8338      return element[name];
8339    }
8340  },
8341
8342  text: (function() {
8343    getText.$dv = '';
8344    return getText;
8345
8346    function getText(element, value) {
8347      if (isUndefined(value)) {
8348        var nodeType = element.nodeType;
8349        return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
8350      }
8351      element.textContent = value;
8352    }
8353  })(),
8354
8355  val: function(element, value) {
8356    if (isUndefined(value)) {
8357      if (element.multiple && nodeName_(element) === 'select') {
8358        var result = [];
vendor: 10,249 bytes, lines 8359-8698
8359        forEach(element.options, function(option) {
8360          if (option.selected) {
8361            result.push(option.value || option.text);
8362          }
8363        });
8364        return result.length === 0 ? null : result;
8365      }
8366      return element.value;
8367    }
8368    element.value = value;
8369  },
8370
8371  html: function(element, value) {
8372    if (isUndefined(value)) {
8373      return element.innerHTML;
8374    }
8375    jqLiteDealoc(element, true);
8376    element.innerHTML = value;
8377  },
8378
8379  empty: jqLiteEmpty
8380}, function(fn, name) {
8381  /**
8382   * Properties: writes return selection, reads return first value
8383   */
8384  JQLite.prototype[name] = function(arg1, arg2) {
8385    var i, key;
8386    var nodeCount = this.length;
8387
8388    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
8389    // in a way that survives minification.
8390    // jqLiteEmpty takes no arguments but is a setter.
8391    if (fn !== jqLiteEmpty &&
8392        (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
8393      if (isObject(arg1)) {
8394
8395        // we are a write, but the object properties are the key/values
8396        for (i = 0; i < nodeCount; i++) {
8397          if (fn === jqLiteData) {
8398            // data() takes the whole object in jQuery
8399            fn(this[i], arg1);
8400          } else {
8401            for (key in arg1) {
8402              fn(this[i], key, arg1[key]);
8403            }
8404          }
8405        }
8406        // return self for chaining
8407        return this;
8408      } else {
8409        // we are a read, so read the first child.
8410        // TODO: do we still need this?
8411        var value = fn.$dv;
8412        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
8413        var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
8414        for (var j = 0; j < jj; j++) {
8415          var nodeValue = fn(this[j], arg1, arg2);
8416          value = value ? value + nodeValue : nodeValue;
8417        }
8418        return value;
8419      }
8420    } else {
8421      // we are a write, so apply to all children
8422      for (i = 0; i < nodeCount; i++) {
8423        fn(this[i], arg1, arg2);
8424      }
8425      // return self for chaining
8426      return this;
8427    }
8428  };
8429});
8430
8431function createEventHandler(element, events) {
8432  var eventHandler = function(event, type) {
8433    // jQuery specific api
8434    event.isDefaultPrevented = function() {
8435      return event.defaultPrevented;
8436    };
8437
8438    var eventFns = events[type || event.type];
8439    var eventFnsLength = eventFns ? eventFns.length : 0;
8440
8441    if (!eventFnsLength) return;
8442
8443    if (isUndefined(event.immediatePropagationStopped)) {
8444      var originalStopImmediatePropagation = event.stopImmediatePropagation;
8445      event.stopImmediatePropagation = function() {
8446        event.immediatePropagationStopped = true;
8447
8448        if (event.stopPropagation) {
8449          event.stopPropagation();
8450        }
8451
8452        if (originalStopImmediatePropagation) {
8453          originalStopImmediatePropagation.call(event);
8454        }
8455      };
8456    }
8457
8458    event.isImmediatePropagationStopped = function() {
8459      return event.immediatePropagationStopped === true;
8460    };
8461
8462    // Some events have special handlers that wrap the real handler
8463    var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
8464
8465    // Copy event handlers in case event handlers array is modified during execution.
8466    if ((eventFnsLength > 1)) {
8467      eventFns = shallowCopy(eventFns);
8468    }
8469
8470    for (var i = 0; i < eventFnsLength; i++) {
8471      if (!event.isImmediatePropagationStopped()) {
8472        handlerWrapper(element, event, eventFns[i]);
8473      }
8474    }
8475  };
8476
8477  // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
8478  //       events on `element`
8479  eventHandler.elem = element;
8480  return eventHandler;
8481}
8482
8483function defaultHandlerWrapper(element, event, handler) {
8484  handler.call(element, event);
8485}
8486
8487function specialMouseHandlerWrapper(target, event, handler) {
8488  // Refer to jQuery's implementation of mouseenter & mouseleave
8489  // Read about mouseenter and mouseleave:
8490  // http://www.quirksmode.org/js/events_mouse.html#link8
8491  var related = event.relatedTarget;
8492  // For mousenter/leave call the handler if related is outside the target.
8493  // NB: No relatedTarget if the mouse left/entered the browser window
8494  if (!related || (related !== target && !jqLiteContains.call(target, related))) {
8495    handler.call(target, event);
8496  }
8497}
8498
8499//////////////////////////////////////////
8500// Functions iterating traversal.
8501// These functions chain results into a single
8502// selector.
8503//////////////////////////////////////////
8504forEach({
8505  removeData: jqLiteRemoveData,
8506
8507  on: function jqLiteOn(element, type, fn, unsupported) {
8508    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
8509
8510    // Do not add event handlers to non-elements because they will not be cleaned up.
8511    if (!jqLiteAcceptsData(element)) {
8512      return;
8513    }
8514
8515    var expandoStore = jqLiteExpandoStore(element, true);
8516    var events = expandoStore.events;
8517    var handle = expandoStore.handle;
8518
8519    if (!handle) {
8520      handle = expandoStore.handle = createEventHandler(element, events);
8521    }
8522
8523    // http://jsperf.com/string-indexof-vs-split
8524    var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
8525    var i = types.length;
8526
8527    var addHandler = function(type, specialHandlerWrapper, noEventListener) {
8528      var eventFns = events[type];
8529
8530      if (!eventFns) {
8531        eventFns = events[type] = [];
8532        eventFns.specialHandlerWrapper = specialHandlerWrapper;
8533        if (type !== '$destroy' && !noEventListener) {
8534          addEventListenerFn(element, type, handle);
8535        }
8536      }
8537
8538      eventFns.push(fn);
8539    };
8540
8541    while (i--) {
8542      type = types[i];
8543      if (MOUSE_EVENT_MAP[type]) {
8544        addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
8545        addHandler(type, undefined, true);
8546      } else {
8547        addHandler(type);
8548      }
8549    }
8550  },
8551
8552  off: jqLiteOff,
8553
8554  one: function(element, type, fn) {
8555    element = jqLite(element);
8556
8557    //add the listener twice so that when it is called
8558    //you can remove the original function and still be
8559    //able to call element.off(ev, fn) normally
8560    element.on(type, function onFn() {
8561      element.off(type, fn);
8562      element.off(type, onFn);
8563    });
8564    element.on(type, fn);
8565  },
8566
8567  replaceWith: function(element, replaceNode) {
8568    var index, parent = element.parentNode;
8569    jqLiteDealoc(element);
8570    forEach(new JQLite(replaceNode), function(node) {
8571      if (index) {
8572        parent.insertBefore(node, index.nextSibling);
8573      } else {
8574        parent.replaceChild(node, element);
8575      }
8576      index = node;
8577    });
8578  },
8579
8580  children: function(element) {
8581    var children = [];
8582    forEach(element.childNodes, function(element) {
8583      if (element.nodeType === NODE_TYPE_ELEMENT) {
8584        children.push(element);
8585      }
8586    });
8587    return children;
8588  },
8589
8590  contents: function(element) {
8591    return element.contentDocument || element.childNodes || [];
8592  },
8593
8594  append: function(element, node) {
8595    var nodeType = element.nodeType;
8596    if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
8597
8598    node = new JQLite(node);
8599
8600    for (var i = 0, ii = node.length; i < ii; i++) {
8601      var child = node[i];
8602      element.appendChild(child);
8603    }
8604  },
8605
8606  prepend: function(element, node) {
8607    if (element.nodeType === NODE_TYPE_ELEMENT) {
8608      var index = element.firstChild;
8609      forEach(new JQLite(node), function(child) {
8610        element.insertBefore(child, index);
8611      });
8612    }
8613  },
8614
8615  wrap: function(element, wrapNode) {
8616    jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
8617  },
8618
8619  remove: jqLiteRemove,
8620
8621  detach: function(element) {
8622    jqLiteRemove(element, true);
8623  },
8624
8625  after: function(element, newElement) {
8626    var index = element, parent = element.parentNode;
8627    newElement = new JQLite(newElement);
8628
8629    for (var i = 0, ii = newElement.length; i < ii; i++) {
8630      var node = newElement[i];
8631      parent.insertBefore(node, index.nextSibling);
8632      index = node;
8633    }
8634  },
8635
8636  addClass: jqLiteAddClass,
8637  removeClass: jqLiteRemoveClass,
8638
8639  toggleClass: function(element, selector, condition) {
8640    if (selector) {
8641      forEach(selector.split(' '), function(className) {
8642        var classCondition = condition;
8643        if (isUndefined(classCondition)) {
8644          classCondition = !jqLiteHasClass(element, className);
8645        }
8646        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
8647      });
8648    }
8649  },
8650
8651  parent: function(element) {
8652    var parent = element.parentNode;
8653    return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
8654  },
8655
8656  next: function(element) {
8657    return element.nextElementSibling;
8658  },
8659
8660  find: function(element, selector) {
8661    if (element.getElementsByTagName) {
8662      return element.getElementsByTagName(selector);
8663    } else {
8664      return [];
8665    }
8666  },
8667
8668  clone: jqLiteClone,
8669
8670  triggerHandler: function(element, event, extraParameters) {
8671
8672    var dummyEvent, eventFnsCopy, handlerArgs;
8673    var eventName = event.type || event;
8674    var expandoStore = jqLiteExpandoStore(element);
8675    var events = expandoStore && expandoStore.events;
8676    var eventFns = events && events[eventName];
8677
8678    if (eventFns) {
8679      // Create a dummy event to pass to the handlers
8680      dummyEvent = {
8681        preventDefault: function() { this.defaultPrevented = true; },
8682        isDefaultPrevented: function() { return this.defaultPrevented === true; },
8683        stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
8684        isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
8685        stopPropagation: noop,
8686        type: eventName,
8687        target: element
8688      };
8689
8690      // If a custom event was provided then extend our dummy event with it
8691      if (event.type) {
8692        dummyEvent = extend(dummyEvent, event);
8693      }
8694
8695      // Copy event handlers in case event handlers array is modified during execution.
8696      eventFnsCopy = shallowCopy(eventFns);
8697      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
8698
8699      forEach(eventFnsCopy, function(fn) {
8700        if (!dummyEvent.isImmediatePropagationStopped()) {
8701          fn.apply(element, handlerArgs);
8702        }
8703      });
8704    }
8705  }
8706}, function(fn, name) {
8707  /**
8708   * chaining functions
8709   */
8710  JQLite.prototype[name] = function(arg1, arg2, arg3) {
8711    var value;
8712
8713    for (var i = 0, ii = this.length; i < ii; i++) {
8714      if (isUndefined(value)) {
8715        value = fn(this[i], arg1, arg2, arg3);
8716        if (isDefined(value)) {
8717          // any function which returns a value needs to be wrapped
8718          value = jqLite(value);
8719        }
8720      } else {
8721        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
8722      }
8723    }
8724    return isDefined(value) ? value : this;
8725  };
8726
8727  // bind legacy bind/unbind to on/off
8728  JQLite.prototype.bind = JQLite.prototype.on;
8729  JQLite.prototype.unbind = JQLite.prototype.off;
8730});
8731
8732
8733// Provider for private $$jqLite service
8734function $$jqLiteProvider() {
8735  this.$get = function $$jqLite() {
8736    return extend(JQLite, {
8737      hasClass: function(node, classes) {
8738        if (node.attr) node = node[0];
8739        return jqLiteHasClass(node, classes);
8740      },
8741      addClass: function(node, classes) {
8742        if (node.attr) node = node[0];
8743        return jqLiteAddClass(node, classes);
8744      },
8745      removeClass: function(node, classes) {
8746        if (node.attr) node = node[0];
8747        return jqLiteRemoveClass(node, classes);
8748      }
8749    });
8750  };
8751}
8752
8753/**
8754 * Computes a hash of an 'obj'.
8755 * Hash of a:
8756 *  string is string
8757 *  number is number as string
8758 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
8759 *         that is also assigned to the $$hashKey property of the object.
8760 *
8761 * @param obj
8762 * @returns {string} hash string such that the same input will have the same hash string.
8763 *         The resulting string key is in 'type:hashKey' format.
8764 */
8765function hashKey(obj, nextUidFn) {
8766  var key = obj && obj.$$hashKey;
8767
8768  if (key) {
8769    if (typeof key === 'function') {
8770      key = obj.$$hashKey();
8771    }
8772    return key;
8773  }
8774
8775  var objType = typeof obj;
8776  if (objType == 'function' || (objType == 'object' && obj !== null)) {
8777    key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
8778  } else {
8779    key = objType + ':' + obj;
8780  }
8781
8782  return key;
8783}
8784
8785/**
8786 * HashMap which can use objects as keys
8787 */
8788function HashMap(array, isolatedUid) {
8789  if (isolatedUid) {
8790    var uid = 0;
8791    this.nextUid = function() {
8792      return ++uid;
8793    };
8794  }
8795  forEach(array, this.put, this);
8796}
8797HashMap.prototype = {
8798  /**
8799   * Store key value pair
8800   * @param key key to store can be any type
8801   * @param value value to store can be any type
8802   */
8803  put: function(key, value) {
8804    this[hashKey(key, this.nextUid)] = value;
8805  },
8806
8807  /**
8808   * @param key
8809   * @returns {Object} the value for the key
8810   */
8811  get: function(key) {
8812    return this[hashKey(key, this.nextUid)];
8813  },
8814
8815  /**
8816   * Remove the key/value pair
8817   * @param key
8818   */
8819  remove: function(key) {
8820    var value = this[key = hashKey(key, this.nextUid)];
8821    delete this[key];
8822    return value;
8823  }
8824};
8825
8826var $$HashMapProvider = [function() {
8827  this.$get = [function() {
8828    return HashMap;
8829  }];
8830}];
8831
8832/**
8833 * @ngdoc function
8834 * @module ng
8835 * @name angular.injector
8836 * @kind function
8837 *
8838 * @description
8839 * Creates an injector object that can be used for retrieving services as well as for
8840 * dependency injection (see {@link guide/di dependency injection}).
8841 *
8842 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
8843 *     {@link angular.module}. The `ng` module must be explicitly added.
8844 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
8845 *     disallows argument name annotation inference.
8846 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
8847 *
8848 * @example
8849 * Typical usage
8850 * ```js
8851 *   // create an injector
8852 *   var $injector = angular.injector(['ng']);
8853 *
8854 *   // use the injector to kick off your application
8855 *   // use the type inference to auto inject arguments, or use impl
8855icit injection
8856 *   $injector.invoke(function($rootScope, $compile, $document) {
8857 *     $compile($document)($rootScope);
8858 *     $rootScope.$digest();
8859 *   });
8860 * ```
8861 *
8862 * Sometimes you want to get access to the injector of a currently running Angular app
8863 * from outside Angular. Perhaps, you want to inject and compile some markup after the
8864 * application has been bootstrapped. You can do this using the extra `injector()` added
8865 * to JQuery/jqLite elements. See {@link angular.element}.
8866 *
8867 * *This is fairly rare but could be the case if a third party library is injecting the
8868 * markup.*
8869 *
8870 * In the following example a new block of HTML containing a `ng-controller`
8871 * directive is added to the end of the document body by JQuery. We then compile and link
8872 * it into the current AngularJS scope.
8873 *
8874 * ```js
8875 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
8876 * $(document.body).append($div);
8877 *
8878 * angular.element(document).injector().invoke(function($compile) {
8879 *   var scope = angular.element($div).scope();
8880 *   $compile($div)(scope);
8881 * });
8882 * ```
8883 */
8884
8885
8886/**
8887 * @ngdoc module
8888 * @name auto
8889 * @description
8890 *
8891 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
8892 */
8893
8894var ARROW_ARG = /^([^\(]+?)=>/;
8895var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
8896var FN_ARG_SPLIT = /,/;
8897var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
8898var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
8899var $injectorMinErr = minErr('$injector');
8900
8901function extractArgs(fn) {
8902  var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
8903      args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
8904  return args;
8905}
8906
8907function anonFn(fn) {
8908  // For anonymous functions, showing at the very least the function signature can help in
8909  // debugging.
8910  var args = extractArgs(fn);
8911  if (args) {
8912    return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
8913  }
8914  return 'fn';
8915}
8916
8917function annotate(fn, strictDi, name) {
8918  var $inject,
8919      argDecl,
8920      last;
8921
8922  if (typeof fn === 'function') {
8923    if (!($inject = fn.$inject)) {
8924      $inject = [];
8925      if (fn.length) {
8926        if (strictDi) {
8927          if (!isString(name) || !name) {
8928            name = fn.name || anonFn(fn);
8929          }
8930          throw $injectorMinErr('strictdi',
8931            '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
8932        }
8933        argDecl = extractArgs(fn);
8934        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
8935          arg.replace(FN_ARG, function(all, underscore, name) {
8936            $inject.push(name);
8937          });
8938        });
8939      }
8940      fn.$inject = $inject;
8941    }
8942  } else if (isArray(fn)) {
8943    last = fn.length - 1;
8944    assertArgFn(fn[last], 'fn');
8945    $inject = fn.slice(0, last);
8946  } else {
8947    assertArgFn(fn, 'fn', true);
8948  }
8949  return $inject;
8950}
8951
8952///////////////////////////////////////
8953
8954/**
8955 * @ngdoc service
8956 * @name $injector
8957 *
8958 * @description
8959 *
8960 * `$injector` is used to retrieve object instances as defined by
8961 * {@link auto.$provide provider}, instantiate types, invoke methods,
8962 * and load modules.
8963 *
8964 * The following always holds true:
8965 *
8966 * ```js
8967 *   var $injector = angular.injector();
8968 *   expect($injector.get('$injector')).toBe($injector);
8969 *   expect($injector.invoke(function($injector) {
8970 *     return $injector;
8971 *   })).toBe($injector);
8972 * ```
8973 *
8974 * # Injection Function Annotation
8975 *
8976 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
8977 * following are all valid ways of annotating function with injection arguments and are equivalent.
8978 *
8979 * ```js
8980 *   // inferred (only works if code not minified/obfuscated)
8981 *   $injector.invoke(function(serviceA){});
8982 *
8983 *   // annotated
8984 *   function explicit(serviceA) {};
8985 *   explicit.$inject = ['serviceA'];
8986 *   $injector.invoke(explicit);
8987 *
8988 *   // inline
8989 *   $injector.invoke(['serviceA', function(serviceA){}]);
8990 * ```
8991 *
8992 * ## Inference
8993 *
8994 * In JavaScript calling `toString()` on a function returns the function definition. The definition
8995 * can then be parsed and the function arguments can be extracted. This method of discovering
8996 * annotations is disallowed when the injector is in strict mode.
8997 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
8998 * argument names.
8999 *
9000 * ## `$inject` Annotation
9001 * By adding an `$inject` property onto a function the injection parameters can be specified.
9002 *
9003 * ## Inline
9004 * As an array of injection names, where the last item in the array is the function to call.
9005 */
9006
9007/**
9008 * @ngdoc method
9009 * @name $injector#get
9010 *
9011 * @description
9012 * Return an instance of the service.
9013 *
9014 * @param {string} name The name of the instance to retrieve.
9015 * @param {string=} caller An optional string to provide the origin of the function call for error messages.
9016 * @return {*} The instance.
9017 */
9018
9019/**
9020 * @ngdoc method
9021 * @name $injector#invoke
9022 *
9023 * @description
9024 * Invoke the method and supply the method arguments from the `$injector`.
9025 *
9026 * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
9027 *   injected according to the {@link guide/di $inject Annotation} rules.
9028 * @param {Object=} self The `this` for the invoked method.
9029 * @param {Object=} locals Optional object. If preset then any argument names are read from this
9030 *                         object first, before the `$injector` is consulted.
9031 * @returns {*} the value returned by the invoked `fn` function.
9032 */
9033
9034/**
9035 * @ngdoc method
9036 * @name $injector#has
9037 *
9038 * @description
9039 * Allows the user to query if the particular service exists.
9040 *
9041 * @param {string} name Name of the service to query.
9042 * @returns {boolean} `true` if injector has given service.
9043 */
9044
9045/**
9046 * @ngdoc method
9047 * @name $injector#instantiate
9048 * @description
9049 * Create a new instance of JS type. The method takes a constructor function, invokes the new
9050 * operator, and supplies all of the arguments to the constructor function as specified by the
9051 * constructor annotation.
9052 *
9053 * @param {Function} Type Annotated constructor function.
9054 * @param {Object=} locals Optional object. If preset then any argument names are read from this
9055 * object first, before the `$injector` is consulted.
9056 * @returns {Object} new instance of `Type`.
9057 */
9058
9059/**
9060 * @ngdoc method
9061 * @name $injector#annotate
9062 *
9063 * @description
9064 * Returns an array of service names which the function is requesting for injection. This API is
9065 * used by the injector to determine which services need to be injected into the function when the
9066 * function is invoked. There are three ways in which the function can be annotated with the needed
9067 * dependencies.
9068 *
9069 * # Argument names
9070 *
9071 * The simplest form is to extract the dependencies from the arguments of the function. This is done
9072 * by converting the function into a string using `toString()` method and extracting the argument
9073 * names.
9074 * ```js
9075 *   // Given
9076 *   function MyController($scope, $route) {
9077 *     // ...
9078 *   }
9079 *
9080 *   // Then
9081 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
9082 * ```
9083 *
9084 * You can disallow this method by using strict injection mode.
9085 *
9086 * This method does not work with code minification / obfuscation. For this reason the following
9087 * annotation strategies are supported.
9088 *
9089 * # The `$inject` property
9090 *
9091 * If a function has an `$inject` property and its value is an array of strings, then the strings
9092 * represent names of services to be injected into the function.
9093 * ```js
9094 *   // Given
9095 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
9096 *     // ...
9097 *   }
9098 *   // Define function dependencies
9099 *   MyController['$inject'] = ['$scope', '$route'];
9100 *
9101 *   // Then
9102 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
9103 * ```
9104 *
9105 * # The array notation
9106 *
9107 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
9108 * is very inconvenient. In these situations using the array notation to specify the dependencies in
9109 * a way that survives minification is a better choice:
9110 *
9111 * ```js
9112 *   // We wish to write this (not minification / obfuscation safe)
9113 *   injector.invoke(function($compile, $rootScope) {
9114 *     // ...
9115 *   });
9116 *
9117 *   // We are forced to write break inlining
9118 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
9119 *     // ...
9120 *   };
9121 *   tmpFn.$inject = ['$compile', '$rootScope'];
9122 *   injector.invoke(tmpFn);
9123 *
9124 *   // To better support inline function the inline annotation is supported
9125 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
9126 *     // ...
9127 *   }]);
9128 *
9129 *   // Therefore
9130 *   expect(injector.annotate(
9131 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
9132 *    ).toEqual(['$compile', '$rootScope']);
9133 * ```
9134 *
9135 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
9136 * be retrieved as described above.
9137 *
9138 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
9139 *
9140 * @returns {Array.<string>} The names of the services which the function requires.
9141 */
9142
9143
9144
9145
9146/**
9147 * @ngdoc service
9148 * @name $provide
9149 *
9150 * @description
9151 *
9152 * The {@link auto.$provide $provide} service has a number of methods for registering components
9153 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
9154 * {@link angular.Module}.
9155 *
9156 * An Angular **service** is a singleton object created by a **service factory**.  These **service
9157 * factories** are functions which, in turn, are created by a **service provider**.
9158 * The **service providers** are constructor functions. When instantiated they must contain a
9159 * property called `$get`, which holds the **service factory** function.
9160 *
9161 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
9162 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
9163 * function to get the instance of the **service**.
9164 *
9165 * Often services have no configuration options and there is no need to add methods to the service
9166 * provider.  The provider will be no more than a constructor function with a `$get` property. For
9167 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
9168 * services without specifying a provider.
9169 *
9170 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
9171 *     {@link auto.$injector $injector}
9172 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
9173 *     providers and services.
9174 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
9175 *     services, not providers.
9176 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
9177 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
9178 *     given factory function.
9179 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
9180 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
9181 *      a new object using the given constructor function.
9182 *
9183 * See the individual methods for more information and examples.
9184 */
9185
9186/**
9187 * @ngdoc method
9188 * @name $provide#provider
9189 * @description
9190 *
9191 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
9192 * are constructor functions, whose instances are responsible for "providing" a factory for a
9193 * service.
9194 *
9195 * Service provider names start with the name of the service they provide followed by `Provider`.
9196 * For example, the {@link ng.$log $log} service has a provider called
9197 * {@link ng.$logProvider $logProvider}.
9198 *
9199 * Service provider objects can have additional methods which allow configuration of the provider
9200 * and its service. Importantly, you can configure what kind of service is created by the `$get`
9201 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
9202 * method {@link ng.$logProvider#debugEnabled debugEnabled}
9203 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
9204 * console or not.
9205 *
9206 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
9207                        'Provider'` key.
9208 * @param {(Object|function())} provider If the provider is:
9209 *
9210 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
9211 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
9212 *   - `Constructor`: a new instance of the provider will be created using
9213 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
9214 *
9215 * @returns {Object} registered provider instance
9216
9217 * @example
9218 *
9219 * The following example shows how to create a simple event tracking service and register it using
9220 * {@link auto.$provide#provider $provide.provider()}.
9221 *
9222 * ```js
9223 *  // Define the eventTracker provider
9224 *  function EventTrackerProvider() {
9225 *    var trackingUrl = '/track';
9226 *
9227 *    // A provider method for configuring where the tracked events should been saved
9228 *    this.setTrackingUrl = function(url) {
9229 *      trackingUrl = url;
9230 *    };
9231 *
9232 *    // The service factory function
9233 *    this.$get = ['$http', function($http) {
9234 *      var trackedEvents = {};
9235 *      return {
9236 *        // Call this to track an event
9237 *        event: function(event) {
9238 *          var count = trackedEvents[event] || 0;
9239 *          count += 1;
9240 *          trackedEvents[event] = count;
9241 *          return count;
9242 *        },
9243 *        // Call this to save the tracked events to the trackingUrl
9244 *        save: function() {
9245 *          $http.post(trackingUrl, trackedEvents);
9246 *        }
9247 *      };
9248 *    }];
9249 *  }
9250 *
9251 *  describe('eventTracker', function() {
9252 *    var postSpy;
9253 *
9254 *    beforeEach(module(function($provide) {
9255 *      // Register the eventTracker provider
9256 *      $provide.provider('eventTracker', EventTrackerProvider);
9257 *    }));
9258 *
9259 *    beforeEach(module(function(eventTrackerProvider) {
9260 *      // Configure eventTracker provider
9261 *      eventTrackerProvider.setTrackingUrl('/custom-track');
9262 *    }));
9263 *
9264 *    it('tracks events', inject(function(eventTracker) {
9265 *      expect(eventTracker.event('login')).toEqual(1);
9266 *      expect(eventTracker.event('login')).toEqual(2);
9267 *    }));
9268 *
9269 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
9270 *      postSpy = spyOn($http, 'post');
9271 *      eventTracker.event('login');
9272 *      eventTracker.save();
9273 *      expect(postSpy).toHaveBeenCalled();
9274 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
9275 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
9276 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
9277 *    }));
9278 *  });
9279 * ```
9280 */
9281
9282/**
9283 * @ngdoc method
9284 * @name $provide#factory
9285 * @description
9286 *
9287 * Register a **service factory**, which will be called to return the service instance.
9288 * This is short for registering a service where its provider consists of only a `$get` property,
9289 * which is the given service factory function.
9290 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
9291 * configure your service in a provider.
9292 *
9293 * @param {string} name The name of the instance.
9294 * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
9295 *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
9296 * @returns {Object} registered provider instance
9297 *
9298 * @example
9299 * Here is an example of registering a service
9300 * ```js
9301 *   $provide.factory('ping', ['$http', function($http) {
9302 *     return function ping() {
9303 *       return $http.send('/ping');
9304 *     };
9305 *   }]);
9306 * ```
9307 * You would then inject and use this service like this:
9308 * ```js
9309 *   someModule.controller('Ctrl', ['ping', function(ping) {
9310 *     ping();
9311 *   }]);
9312 * ```
9313 */
9314
9315
9316/**
9317 * @ngdoc method
9318 * @name $provide#service
9319 * @description
9320 *
9321 * Register a **service constructor**, which will be invoked with `new` to create the service
9322 * instance.
9323 * This is short for registering a service where its provider's `$get` property is a factory
9324 * function that returns an instance instantiated by the injector from the service constructor
9325 * function.
9326 *
9327 * Internally it looks a bit like this:
9328 *
9329 * ```
9330 * {
9331 *   $get: function() {
9332 *     return $injector.instantiate(constructor);
9333 *   }
9334 * }
9335 * ```
9336 *
9337 *
9338 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
9339 * as a type/class.
9340 *
9341 * @param {string} name The name of the instance.
9342 * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
9343 *     that will be instantiated.
9344 * @returns {Object} registered provider instance
9345 *
9346 * @example
9347 * Here is an example of registering a service using
9348 * {@link auto.$provide#service $provide.service(class)}.
9349 * ```js
9350 *   var Ping = function($http) {
9351 *     this.$http = $http;
9352 *   };
9353 *
9354 *   Ping.$inject = ['$http'];
9355 *
9356 *   Ping.prototype.send = function() {
9357 *     return this.$http.get('/ping');
9358 *   };
9359 *   $provide.service('ping', Ping);
9360 * ```
9361 * You would then inject and use this service like this:
9362 * ```js
9363 *   someModule.controller('Ctrl', ['ping', function(ping) {
9364 *     ping.send();
9365 *   }]);
9366 * ```
9367 */
9368
9369
9370/**
9371 * @ngdoc method
9372 * @name $provide#value
9373 * @description
9374 *
9375 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
9376 * number, an array, an object or a function. This is short for registering a service where its
9377 * provider's `$get` property is a factory function that takes no arguments and returns the **value
9378 * service**. That also means it is not possible to inject other services into a value service.
9379 *
9380 * Value services are similar to constant services, except that they cannot be injected into a
9381 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
9382 * an Angular {@link auto.$provide#decorator decorator}.
9383 *
9384 * @param {string} name The name of the instance.
9385 * @param {*} value The value.
9386 * @returns {Object} registered provider instance
9387 *
9388 * @example
9389 * Here are some examples of creating value services.
9390 * ```js
9391 *   $provide.value('ADMIN_USER', 'admin');
9392 *
9393 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
9394 *
9395 *   $provide.value('halfOf', function(value) {
9396 *     return value / 2;
9397 *   });
9398 * ```
9399 */
9400
9401
9402/**
9403 * @ngdoc method
9404 * @name $provide#constant
9405 * @description
9406 *
9407 * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
9408 * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
9409 * possible to inject other services into a constant.
9410 *
9411 * But unlike {@link auto.$provide#value value}, a constant can be
9412 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
9413 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
9414 *
9415 * @param {string} name The name of the constant.
9416 * @param {*} value The constant value.
9417 * @returns {Object} registered instance
9418 *
9419 * @example
9420 * Here a some examples of creating constants:
9421 * ```js
9422 *   $provide.constant('SHARD_HEIGHT', 306);
9423 *
9424 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
9425 *
9426 *   $provide.constant('double', function(value) {
9427 *     return value * 2;
9428 *   });
9429 * ```
9430 */
9431
9432
9433/**
9434 * @ngdoc method
9435 * @name $provide#decorator
9436 * @description
9437 *
9438 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
9439 * intercepts the creation of a service, allowing it to override or modify the behavior of the
9440 * service. The object returned by the decorator may be the original service, or a new service
9441 * object which replaces or wraps and delegates to the original service.
9442 *
9443 * @param {string} name The name of the service to decorate.
9444 * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
9445 *    instantiated and should return the decorated service instance. The function is called using
9446 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
9447 *    Local injection arguments:
9448 *
9449 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
9450 *      decorated or delegated to.
9451 *
9452 * @example
9453 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
9454 * calls to {@link ng.$log#error $log.warn()}.
9455 * ```js
9456 *   $provide.decorator('$log', ['$delegate', function($delegate) {
9457 *     $delegate.warn = $delegate.error;
9458 *     return $delegate;
9459 *   }]);
9460 * ```
9461 */
9462
9463
9464function createInjector(modulesToLoad, strictDi) {
9465  strictDi = (strictDi === true);
9466  var INSTANTIATING = {},
9467      providerSuffix = 'Provider',
9468      path = [],
9469      loadedModules = new HashMap([], true),
9470      providerCache = {
9471        $provide: {
9472            provider: supportObject(provider),
9473            factory: supportObject(factory),
9474            service: supportObject(service),
9475            value: supportObject(value),
9476            constant: supportObject(constant),
9477            decorator: decorator
9478          }
9479      },
9480      providerInjector = (providerCache.$injector =
9481          createInternalInjector(providerCache, function(serviceName, caller) {
9482            if (angular.isString(caller)) {
9483              path.push(caller);
9484            }
9485            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
9486          })),
9487      instanceCache = {},
9488      protoInstanceInjector =
9489          createInternalInjector(instanceCache, function(serviceName, caller) {
9490            var provider = providerInjector.get(serviceName + providerSuffix, caller);
9491            return instanceInjector.invoke(
9492                provider.$get, provider, undefined, serviceName);
9493          }),
9494      instanceInjector = protoInstanceInjector;
9495
9496  providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
9497  var runBlocks = loadModules(modulesToLoad);
9498  instanceInjector = protoInstanceInjector.get('$injector');
9499  instanceInjector.strictDi = strictDi;
9500  forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
9501
9502  return instanceInjector;
9503
9504  ////////////////////////////////////
9505  // $provider
9506  ////////////////////////////////////
9507
9508  function supportObject(delegate) {
9509    return function(key, value) {
9510      if (isObject(key)) {
vendor: 10,003 bytes, lines 9511-9789
9511        forEach(key, reverseParams(delegate));
9512      } else {
9513        return delegate(key, value);
9514      }
9515    };
9516  }
9517
9518  function provider(name, provider_) {
9519    assertNotHasOwnProperty(name, 'service');
9520    if (isFunction(provider_) || isArray(provider_)) {
9521      provider_ = providerInjector.instantiate(provider_);
9522    }
9523    if (!provider_.$get) {
9524      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
9525    }
9526    return providerCache[name + providerSuffix] = provider_;
9527  }
9528
9529  function enforceReturnValue(name, factory) {
9530    return function enforcedReturnValue() {
9531      var result = instanceInjector.invoke(factory, this);
9532      if (isUndefined(result)) {
9533        throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
9534      }
9535      return result;
9536    };
9537  }
9538
9539  function factory(name, factoryFn, enforce) {
9540    return provider(name, {
9541      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
9542    });
9543  }
9544
9545  function service(name, constructor) {
9546    return factory(name, ['$injector', function($injector) {
9547      return $injector.instantiate(constructor);
9548    }]);
9549  }
9550
9551  function value(name, val) { return factory(name, valueFn(val), false); }
9552
9553  function constant(name, value) {
9554    assertNotHasOwnProperty(name, 'constant');
9555    providerCache[name] = value;
9556    instanceCache[name] = value;
9557  }
9558
9559  function decorator(serviceName, decorFn) {
9560    var origProvider = providerInjector.get(serviceName + providerSuffix),
9561        orig$get = origProvider.$get;
9562
9563    origProvider.$get = function() {
9564      var origInstance = instanceInjector.invoke(orig$get, origProvider);
9565      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
9566    };
9567  }
9568
9569  ////////////////////////////////////
9570  // Module Loading
9571  ////////////////////////////////////
9572  function loadModules(modulesToLoad) {
9573    assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
9574    var runBlocks = [], moduleFn;
9575    forEach(modulesToLoad, function(module) {
9576      if (loadedModules.get(module)) return;
9577      loadedModules.put(module, true);
9578
9579      function runInvokeQueue(queue) {
9580        var i, ii;
9581        for (i = 0, ii = queue.length; i < ii; i++) {
9582          var invokeArgs = queue[i],
9583              provider = providerInjector.get(invokeArgs[0]);
9584
9585          provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
9586        }
9587      }
9588
9589      try {
9590        if (isString(module)) {
9591          moduleFn = angularModule(module);
9592          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
9593          runInvokeQueue(moduleFn._invokeQueue);
9594          runInvokeQueue(moduleFn._configBlocks);
9595        } else if (isFunction(module)) {
9596            runBlocks.push(providerInjector.invoke(module));
9597        } else if (isArray(module)) {
9598            runBlocks.push(providerInjector.invoke(module));
9599        } else {
9600          assertArgFn(module, 'module');
9601        }
9602      } catch (e) {
9603        if (isArray(module)) {
9604          module = module[module.length - 1];
9605        }
9606        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
9607          // Safari & FF's stack traces don't contain error.message content
9608          // unlike those of Chrome and IE
9609          // So if stack doesn't contain message, we create a new string that contains both.
9610          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
9611          /* jshint -W022 */
9612          e = e.message + '\n' + e.stack;
9613        }
9614        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
9615                  module, e.stack || e.message || e);
9616      }
9617    });
9618    return runBlocks;
9619  }
9620
9621  ////////////////////////////////////
9622  // internal Injector
9623  ////////////////////////////////////
9624
9625  function createInternalInjector(cache, factory) {
9626
9627    function getService(serviceName, caller) {
9628      if (cache.hasOwnProperty(serviceName)) {
9629        if (cache[serviceName] === INSTANTIATING) {
9630          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
9631                    serviceName + ' <- ' + path.join(' <- '));
9632        }
9633        return cache[serviceName];
9634      } else {
9635        try {
9636          path.unshift(serviceName);
9637          cache[serviceName] = INSTANTIATING;
9638          return cache[serviceName] = factory(serviceName, caller);
9639        } catch (err) {
9640          if (cache[serviceName] === INSTANTIATING) {
9641            delete cache[serviceName];
9642          }
9643          throw err;
9644        } finally {
9645          path.shift();
9646        }
9647      }
9648    }
9649
9650
9651    function injectionArgs(fn, locals, serviceName) {
9652      var args = [],
9653          $inject = createInjector.$$annotate(fn, strictDi, serviceName);
9654
9655      for (var i = 0, length = $inject.length; i < length; i++) {
9656        var key = $inject[i];
9657        if (typeof key !== 'string') {
9658          throw $injectorMinErr('itkn',
9659                  'Incorrect injection token! Expected service name as string, got {0}', key);
9660        }
9661        args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
9662                                                         getService(key, serviceName));
9663      }
9664      return args;
9665    }
9666
9667    function isClass(func) {
9668      // IE 9-11 do not support classes and IE9 leaks with the code below.
9669      if (msie <= 11) {
9670        return false;
9671      }
9672      // Workaround for MS Edge.
9673      // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
9674      return typeof func === 'function'
9675        && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
9676    }
9677
9678    function invoke(fn, self, locals, serviceName) {
9679      if (typeof locals === 'string') {
9680        serviceName = locals;
9681        locals = null;
9682      }
9683
9684      var args = injectionArgs(fn, locals, serviceName);
9685      if (isArray(fn)) {
9686        fn = fn[fn.length - 1];
9687      }
9688
9689      if (!isClass(fn)) {
9690        // http://jsperf.com/angularjs-invoke-apply-vs-switch
9691        // #5388
9692        return fn.apply(self, args);
9693      } else {
9694        args.unshift(null);
9695        return new (Function.prototype.bind.apply(fn, args))();
9696      }
9697    }
9698
9699
9700    function instantiate(Type, locals, serviceName) {
9701      // Check if Type is annotated and use just the given function at n-1 as parameter
9702      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
9703      var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
9704      var args = injectionArgs(Type, locals, serviceName);
9705      // Empty object at position 0 is ignored for invocation with `new`, but required.
9706      args.unshift(null);
9707      return new (Function.prototype.bind.apply(ctor, args))();
9708    }
9709
9710
9711    return {
9712      invoke: invoke,
9713      instantiate: instantiate,
9714      get: getService,
9715      annotate: createInjector.$$annotate,
9716      has: function(name) {
9717        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
9718      }
9719    };
9720  }
9721}
9722
9723createInjector.$$annotate = annotate;
9724
9725/**
9726 * @ngdoc provider
9727 * @name $anchorScrollProvider
9728 *
9729 * @description
9730 * Use `$anchorScrollProvider` to disable automatic scrolling whenever
9731 * {@link ng.$location#hash $location.hash()} changes.
9732 */
9733function $AnchorScrollProvider() {
9734
9735  var autoScrollingEnabled = true;
9736
9737  /**
9738   * @ngdoc method
9739   * @name $anchorScrollProvider#disableAutoScrolling
9740   *
9741   * @description
9742   * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
9743   * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
9744   * Use this method to disable automatic scrolling.
9745   *
9746   * If automatic scrolling is disabled, one must explicitly call
9747   * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
9748   * current hash.
9749   */
9750  this.disableAutoScrolling = function() {
9751    autoScrollingEnabled = false;
9752  };
9753
9754  /**
9755   * @ngdoc service
9756   * @name $anchorScroll
9757   * @kind function
9758   * @requires $window
9759   * @requires $location
9760   * @requires $rootScope
9761   *
9762   * @description
9763   * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
9764   * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
9765   * in the
9766   * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
9767   *
9768   * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
9769   * match any anchor whenever it changes. This can be disabled by calling
9770   * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
9771   *
9772   * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
9773   * vertical scroll-offset (either fixed or dynamic).
9774   *
9775   * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
9776   *                       {@link ng.$location#hash $location.hash()} will be used.
9777   *
9778   * @property {(number|function|jqLite)} yOffset
9779   * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
9780   * positioned elements at the top of the page, such as navbars, headers etc.
9781   *
9782   * `yOffset` can be specified in various ways:
9783   * - **number**: A fixed number of pixels to be used as offset.<br /><br />
9784   * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
9785   *   a number representing the offset (in pixels).<br /><br />
9786   * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
9787   *   the top of the page to the element's bottom will be used as offset.<br />
9788   *   **Note**: The element will be taken into account only as long as its `position` is set to
9789   *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adju
9789st
9790   *   their height and/or positioning according to the viewport's size.
9791   *
9792   * <br />
9793   * <div class="alert alert-warning">
9794   * In order for `yOffset` to work properly, scrolling should take place on the document's root and
9795   * not some child element.
9796   * </div>
9797   *
9798   * @example
9799     <example module="anchorScrollExample">
9800       <file name="index.html">
9801         <div id="scrollArea" ng-controller="ScrollController">
9802           <a ng-click="gotoBottom()">Go to bottom</a>
9803           <a id="bottom"></a> You're at the bottom!
9804         </div>
9805       </file>
9806       <file name="script.js">
9807         angular.module('anchorScrollExample', [])
9808           .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
9809             function ($scope, $location, $anchorScroll) {
9810               $scope.gotoBottom = function() {
9811                 // set the location.hash to the id of
9812                 // the element you wish to scroll to.
9813                 $location.hash('bottom');
9814
9815                 // call $anchorScroll()
9816                 $anchorScroll();
9817               };
9818             }]);
9819       </file>
9820       <file name="style.css">
9821         #scrollArea {
9822           height: 280px;
9823           overflow: auto;
9824         }
9825
9826         #bottom {
9827           display: block;
9828           margin-top: 2000px;
9829         }
9830       </file>
9831     </example>
9832   *
9833   * <hr />
9834   * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
9835   * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
9836   *
9837   * @example
9838     <example module="anchorScrollOffsetExample">
9839       <file name="index.html">
9840         <div class="fixed-header" ng-controller="headerCtrl">
9841           <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
9842             Go to anchor {{x}}
9843           </a>
9844         </div>
9845         <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
9846           Anchor {{x}} of 5
9847         </div>
9848       </file>
9849       <file name="script.js">
9850         angular.module('anchorScrollOffsetExample', [])
9851           .run(['$anchorScroll', function($anchorScroll) {
9852             $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
9853           }])
9854           .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
9855             function ($anchorScroll, $location, $scope) {
vendor: 10,126 bytes, lines 9856-10181
9856               $scope.gotoAnchor = function(x) {
9857                 var newHash = 'anchor' + x;
9858                 if ($location.hash() !== newHash) {
9859                   // set the $location.hash to `newHash` and
9860                   // $anchorScroll will automatically scroll to it
9861                   $location.hash('anchor' + x);
9862                 } else {
9863                   // call $anchorScroll() explicitly,
9864                   // since $location.hash hasn't changed
9865                   $anchorScroll();
9866                 }
9867               };
9868             }
9869           ]);
9870       </file>
9871       <file name="style.css">
9872         body {
9873           padding-top: 50px;
9874         }
9875
9876         .anchor {
9877           border: 2px dashed DarkOrchid;
9878           padding: 10px 10px 200px 10px;
9879         }
9880
9881         .fixed-header {
9882           background-color: rgba(0, 0, 0, 0.2);
9883           height: 50px;
9884           position: fixed;
9885           top: 0; left: 0; right: 0;
9886         }
9887
9888         .fixed-header > a {
9889           display: inline-block;
9890           margin: 5px 15px;
9891         }
9892       </file>
9893     </example>
9894   */
9895  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
9896    var document = $window.document;
9897
9898    // Helper function to get first anchor from a NodeList
9899    // (using `Array#some()` instead of `angular#forEach()` since it's more performant
9900    //  and working in all supported browsers.)
9901    function getFirstAnchor(list) {
9902      var result = null;
9903      Array.prototype.some.call(list, function(element) {
9904        if (nodeName_(element) === 'a') {
9905          result = element;
9906          return true;
9907        }
9908      });
9909      return result;
9910    }
9911
9912    function getYOffset() {
9913
9914      var offset = scroll.yOffset;
9915
9916      if (isFunction(offset)) {
9917        offset = offset();
9918      } else if (isElement(offset)) {
9919        var elem = offset[0];
9920        var style = $window.getComputedStyle(elem);
9921        if (style.position !== 'fixed') {
9922          offset = 0;
9923        } else {
9924          offset = elem.getBoundingClientRect().bottom;
9925        }
9926      } else if (!isNumber(offset)) {
9927        offset = 0;
9928      }
9929
9930      return offset;
9931    }
9932
9933    function scrollTo(elem) {
9934      if (elem) {
9935        elem.scrollIntoView();
9936
9937        var offset = getYOffset();
9938
9939        if (offset) {
9940          // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
9941          // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
9942          // top of the viewport.
9943          //
9944          // IF the number of pixels from the top of `elem` to the end of the page's content is less
9945          // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
9946          // way down the page.
9947          //
9948          // This is often the case for elements near the bottom of the page.
9949          //
9950          // In such cases we do not need to scroll the whole `offset` up, just the difference between
9951          // the top of the element and the offset, which is enough to align the top of `elem` at the
9952          // desired position.
9953          var elemTop = elem.getBoundingClientRect().top;
9954          $window.scrollBy(0, elemTop - offset);
9955        }
9956      } else {
9957        $window.scrollTo(0, 0);
9958      }
9959    }
9960
9961    function scroll(hash) {
9962      hash = isString(hash) ? hash : $location.hash();
9963      var elm;
9964
9965      // empty hash, scroll to the top of the page
9966      if (!hash) scrollTo(null);
9967
9968      // element with given id
9969      else if ((elm = document.getElementById(hash))) scrollTo(elm);
9970
9971      // first anchor with given name :-D
9972      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
9973
9974      // no element and hash == 'top', scroll to the top of the page
9975      else if (hash === 'top') scrollTo(null);
9976    }
9977
9978    // does not scroll when user clicks on anchor link that is currently on
9979    // (no url change, no $location.hash() change), browser native does scroll
9980    if (autoScrollingEnabled) {
9981      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
9982        function autoScrollWatchAction(newVal, oldVal) {
9983          // skip the initial scroll if $location.hash is empty
9984          if (newVal === oldVal && newVal === '') return;
9985
9986          jqLiteDocumentLoaded(function() {
9987            $rootScope.$evalAsync(scroll);
9988          });
9989        });
9990    }
9991
9992    return scroll;
9993  }];
9994}
9995
9996var $animateMinErr = minErr('$animate');
9997var ELEMENT_NODE = 1;
9998var NG_ANIMATE_CLASSNAME = 'ng-animate';
9999
10000function mergeClasses(a,b) {
10001  if (!a && !b) return '';
10002  if (!a) return b;
10003  if (!b) return a;
10004  if (isArray(a)) a = a.join(' ');
10005  if (isArray(b)) b = b.join(' ');
10006  return a + ' ' + b;
10007}
10008
10009function extractElementNode(element) {
10010  for (var i = 0; i < element.length; i++) {
10011    var elm = element[i];
10012    if (elm.nodeType === ELEMENT_NODE) {
10013      return elm;
10014    }
10015  }
10016}
10017
10018function splitClasses(classes) {
10019  if (isString(classes)) {
10020    classes = classes.split(' ');
10021  }
10022
10023  // Use createMap() to prevent class assumptions involving property names in
10024  // Object.prototype
10025  var obj = createMap();
10026  forEach(classes, function(klass) {
10027    // sometimes the split leaves empty string values
10028    // incase extra spaces were applied to the options
10029    if (klass.length) {
10030      obj[klass] = true;
10031    }
10032  });
10033  return obj;
10034}
10035
10036// if any other type of options value besides an Object value is
10037// passed into the $animate.method() animation then this helper code
10038// will be run which will ignore it. While this patch is not the
10039// greatest solution to this, a lot of existing plugins depend on
10040// $animate to either call the callback (< 1.2) or return a promise
10041// that can be changed. This helper function ensures that the options
10042// are wiped clean incase a callback function is provided.
10043function prepareAnimateOptions(options) {
10044  return isObject(options)
10045      ? options
10046      : {};
10047}
10048
10049var $$CoreAnimateJsProvider = function() {
10050  this.$get = noop;
10051};
10052
10053// this is prefixed with Core since it conflicts with
10054// the animateQueueProvider defined in ngAnimate/animateQueue.js
10055var $$CoreAnimateQueueProvider = function() {
10056  var postDigestQueue = new HashMap();
10057  var postDigestElements = [];
10058
10059  this.$get = ['$$AnimateRunner', '$rootScope',
10060       function($$AnimateRunner,   $rootScope) {
10061    return {
10062      enabled: noop,
10063      on: noop,
10064      off: noop,
10065      pin: noop,
10066
10067      push: function(element, event, options, domOperation) {
10068        domOperation        && domOperation();
10069
10070        options = options || {};
10071        options.from        && element.css(options.from);
10072        options.to          && element.css(options.to);
10073
10074        if (options.addClass || options.removeClass) {
10075          addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
10076        }
10077
10078        var runner = new $$AnimateRunner(); // jshint ignore:line
10079
10080        // since there are no animations to run the runner needs to be
10081        // notified that the animation call is complete.
10082        runner.complete();
10083        return runner;
10084      }
10085    };
10086
10087
10088    function updateData(data, classes, value) {
10089      var changed = false;
10090      if (classes) {
10091        classes = isString(classes) ? classes.split(' ') :
10092                  isArray(classes) ? classes : [];
10093        forEach(classes, function(className) {
10094          if (className) {
10095            changed = true;
10096            data[className] = value;
10097          }
10098        });
10099      }
10100      return changed;
10101    }
10102
10103    function handleCSSClassChanges() {
10104      forEach(postDigestElements, function(element) {
10105        var data = postDigestQueue.get(element);
10106        if (data) {
10107          var existing = splitClasses(element.attr('class'));
10108          var toAdd = '';
10109          var toRemove = '';
10110          forEach(data, function(status, className) {
10111            var hasClass = !!existing[className];
10112            if (status !== hasClass) {
10113              if (status) {
10114                toAdd += (toAdd.length ? ' ' : '') + className;
10115              } else {
10116                toRemove += (toRemove.length ? ' ' : '') + className;
10117              }
10118            }
10119          });
10120
10121          forEach(element, function(elm) {
10122            toAdd    && jqLiteAddClass(elm, toAdd);
10123            toRemove && jqLiteRemoveClass(elm, toRemove);
10124          });
10125          postDigestQueue.remove(element);
10126        }
10127      });
10128      postDigestElements.length = 0;
10129    }
10130
10131
10132    function addRemoveClassesPostDigest(element, add, remove) {
10133      var data = postDigestQueue.get(element) || {};
10134
10135      var classesAdded = updateData(data, add, true);
10136      var classesRemoved = updateData(data, remove, false);
10137
10138      if (classesAdded || classesRemoved) {
10139
10140        postDigestQueue.put(element, data);
10141        postDigestElements.push(element);
10142
10143        if (postDigestElements.length === 1) {
10144          $rootScope.$$postDigest(handleCSSClassChanges);
10145        }
10146      }
10147    }
10148  }];
10149};
10150
10151/**
10152 * @ngdoc provider
10153 * @name $animateProvider
10154 *
10155 * @description
10156 * Default implementation of $animate that doesn't perform any animations, instead just
10157 * synchronously performs DOM updates and resolves the returned runner promise.
10158 *
10159 * In order to enable animations the `ngAnimate` module has to be loaded.
10160 *
10161 * To see the functional implementation check out `src/ngAnimate/animate.js`.
10162 */
10163var $AnimateProvider = ['$provide', function($provide) {
10164  var provider = this;
10165
10166  this.$$registeredAnimations = Object.create(null);
10167
10168   /**
10169   * @ngdoc method
10170   * @name $animateProvider#register
10171   *
10172   * @description
10173   * Registers a new injectable animation factory function. The factory function produces the
10174   * animation object which contains callback functions for each event that is expected to be
10175   * animated.
10176   *
10177   *   * `eventFn`: `function(element, ... , doneFunction, options)`
10178   *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
10179   *   on the type of animation additional arguments will be injected into the animation function. The
10180   *   list below explains the function signatures for the different animation methods:
10181   *
10182   *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
10183   *   - addClass: function(element, addedClasses, doneFunction, options)
10184   *   - removeClass: function(element, removedClasses, doneFunction, options)
10185   *   - enter, leave, move: function(element, doneFunction, options)
10186   *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
10187   *
10188   *   Make sure to trigger the `doneFunction` once the animation is fully complete.
10189   *
10190   * ```js
10191   *   return {
10192   *     //enter, leave, move signature
10193   *     eventFn : function(element, done, options) {
10194   *       //code to run the animation
10195   *       //once complete, then run done()
10196   *       return function endFunction(wasCancelled) {
10197   *         //code to cancel the animation
10198   *       }
10199   *     }
10200   *   }
10201   * ```
10202   *
10203   * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
10204   * @param {Function} factory The factory function that will be executed to return the animation
10205   *                           object.
10206   */
10207  this.register = function(name, factory) {
10208    if (name && name.charAt(0) !== '.') {
10209      throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
10210    }
10211
10212    var key = name + '-animation';
10213    provider.$$registeredAnimations[name.substr(1)] = key;
10214    $provide.factory(key, factory);
10215  };
10216
10217  /**
10218   * @ngdoc method
10219   * @name $animateProvider#classNameFilter
10220   *
10221   * @description
10222   * Sets and/or returns the CSS class regular expression that is checked when performing
10223   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
10224   * therefore enable $animate to attempt to perform an animation on any element that is triggered.
10225   * When setting the `classNameFilter` value, animations will only be performed on elements
10226   * that successfully match the filter expression. This in turn can boost performance
10227   * for low-powered devices as well as applications containing a lot of structural operations.
10228   * @param {RegExp=} expression The className expression which will be checked against all animations
10229   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
10230   */
10231  this.classNameFilter = function(expression) {
10232    if (arguments.length === 1) {
10233      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
10234      if (this.$$classNameFilter) {
10235        var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
10236        if (reservedRegex.test(this.$$classNameFilter.toString())) {
10237          throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
10238
10239        }
10240      }
10241    }
10242    return this.$$classNameFilter;
10243  };
10244
10245  this.$get = ['$$animateQueue', function($$animateQueue) {
10246    function domInsert(element, parentElement, afterElement) {
10247      // if for some reason the previous element was removed
10248      // from the dom sometime before this code runs then let's
10249      // just stick to using the parent element as the anchor
10250      if (afterElement) {
10251        var afterNode = extractElementNode(afterElement);
10252        if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
10253          afterElement = null;
10254        }
10255      }
10256      afterElement ? afterElement.after(element) : parentElement.prepend(element);
10257    }
10258
10259    /**
10260     * @ngdoc service
10261     * @name $animate
10262     * @description The $animate service exposes a series of DOM utility methods that provide support
10263     * for animation hooks. The default behavior is the application of DOM operations, however,
10264     * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
10265     * to ensure that animation runs with the triggered DOM operation.
10266     *
10267     * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
10268     * included and only when it is active then the animation hooks that `$animate` triggers will be
10269     * functional. Once active then all structural `ng-` directives will trigger animations as they perform
10270     * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
10271     * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
10272     *
10273     * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
10274     *
10275     * To learn more about enabling animation support, click here to visit the
10276     * {@link ngAnimate ngAnimate module page}.
10277     */
10278    return {
10279      // we don't call it directly since non-existant arguments may
10280      // be interpreted as null within the sub enabled function
10281
10282      /**
10283       *
10284       * @ngdoc method
10285       * @name $animate#on
10286       * @kind function
10287       * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
10288       *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
10289       *    is fired with the following params:
10290       *
10291       * ```js
10292       * $animate.on('enter', container,
10293       *    function callback(element, phase) {
10294       *      // cool we detected an enter animation within the container
10295       *    }
10296       * );
10297       * ```
10298       *
10299       * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
10300       * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
10301       *     as well as among its children
10302       * @param {Function} callback the callback function that will be fired when the listener is triggered
10303       *
10304       * The arguments present in the callback function are:
10305       * * `element` - The captured DOM element that the animation was fired on.
10306       * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
10307       */
10308      on: $$animateQueue.on,
10309
10310      /**
10311       *
10312       * @ngdoc method
10313       * @name $animate#off
10314       * @kind function
10315       * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
10316       * can be used in three different ways depending on the arguments:
10317       *
10318       * ```js
10319       * // remove all the animation event listeners listening for `enter`
10320       * $animate.off('enter');
10321       *
10322       * // remove all the animation event listeners listening for `enter` on the given element and its children
10323       * $animate.off('enter', container);
10324       *
10325       * // remove the event listener function provided by `callback` that is set
10326       * // to listen for `enter` on the given `container` as well as its children
10327       * $animate.off('enter', container, callback);
10328       * ```
10329       *
10330       * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
10331       * @param {DOMElement=} container the container element the event listener was placed on
10332       * @param {Function=} callback the callback function that was registered as the listener
10333       */
10334      off: $$animateQueue.off,
10335
10336      /**
10337       * @ngdoc method
10338       * @name $animate#pin
10339       * @kind function
10340       * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
10341       *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
10342       *    element despite being outside the realm of the application or within another application. Say for example if the application
10343       *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
10344       *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
10345       *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
10346       *
10347       *    Note that this feature is only active when the `ngAnimate` module is used.
10348       *
10349       * @param {DOMElement} element the external element that will be pinned
10350       * @param {DOMElement} parentElement the host parent element that will be associated with the external element
10351       */
10352      pin: $$animateQueue.pin,
10353
10354      /**
10355       *
10356       * @ngdoc method
10357       * @name $animate#enabled
10358       * @kind function
10359       * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
10360       * function can be called in four ways:
10361       *
10362       * ```js
10363       * // returns true or false
10364       * $animate.enabled();
10365       *
10366       * // changes the enabled state for all animations
10367       * $animate.enabled(false);
10368       * $animate.enabled(true);
10369       *
10370       * // returns true or false if animations are enabled for an element
10371       * $animate.enabled(element);
10372       *
10373       * // changes the enabled state for an element and its children
10374       * $animate.enabled(element, true);
10375       * $animate.enabled(element, false);
10376       * ```
10377       *
10378       * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
10379       * @param {boolean=} enabled whether or not the animations will be enabled for the element
10380       *
10381       * @return {boolean} whether or not animations are enabled
10382       */
10383      enabled: $$animateQueue.enabled,
10384
10385      /**
10386       * @ngdoc method
10387       * @name $animate#cancel
10388       * @kind function
10389       * @description Cancels the provided animation.
10390       *
10391       * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
10392       */
10393      cancel: function(runner) {
10394        runner.end && runner.end();
10395      },
10396
10397      /**
10398       *
10399       * @ngdoc method
10400       * @name $animate#enter
10401       * @kind function
10402       * @description Inserts the element into the DOM either after the `after` element (if provided) or
10403       *   as the first child within the `parent` element and then triggers an animation.
10404       *   A promise is returned that will be resolved during the next digest once the animation
10405       *   has completed.
10406       *
10407       * @param {DOMElement} element the element which will be inserted into the DOM
10408       * @param {DOMElement} parent the parent element which will append the element as
10409       *   a child (so long as the after element is not present)
10410       * @param {DOMElement=} after the sibling element after which the element will be appended
10411       * @param {object=} options an optional collection of options/styles that will be applied to the element
10412       *
10413       * @return {Promise} the animation callback promise
10414       */
10415      enter: function(element, parent, after, options) {
10416        parent = parent && jqLite(parent);
10417        after = after && jqLite(after);
10418        parent = parent || after.parent();
10419        domInsert(element, parent, after);
10420        return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
10421      },
10422
10423      /**
10424       *
10425       * @ngdoc method
10426       * @name $animate#move
10427       * @kind function
10428       * @description Inserts (moves) the element into its new position in the DOM either after
10429       *   the `after` element (if provided) or as the first child within the `parent` element
10430       *   and then triggers an animation. A promise is returned that will be resolved
10431       *   during the next digest once the animation has completed.
10432       *
10433       * @param {DOMElement} element the element which will be moved into the new DOM position
10434       * @param {DOMElement} parent the parent element which will append the element as
10435       *   a child (so long as the after element is not present)
10436       * @param {DOMElement=} after the sibling element after which the element will be appended
10437       * @param {object=} options an optional collection of options/styles that will be applied to the element
10438       *
10439       * @return {Promise} the animation callback promise
10440       */
10441      move: function(element, parent, after, options) {
10442        parent = parent && jqLite(parent);
10443        after = after && jqLite(after);
10444        parent = parent || after.parent();
10445        domInsert(element, parent, after);
10446        return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
10447      },
10448
10449      /**
10450       * @ngdoc method
10451       * @name $animate#leave
10452       * @kind function
10453       * @description Triggers an animation and then removes the element from the DOM.
10454       * When the function is called a promise is returned that will be resolved during the next
10455       * digest once the animation has completed.
10456       *
10457       * @param {DOMElement} element the element which will be removed from the DOM
10458       * @param {object=} options an optional collection of options/styles that will be applied to the element
10459       *
10460       * @return {Promise} the animation callback promise
10461       */
10462      leave: function(element, options) {
10463        return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
10464          element.remove();
10465        });
10466      },
10467
10468      /**
10469       * @ngdoc method
10470       * @name $animate#addClass
10471       * @kind function
10472       *
10473       * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
10474       *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
10475       *   animation if element already contains the CSS class or if the class is removed at a later step.
10476       *   Note that class-based animations are treated differently compared to structural animations
10477       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
10478       *   depending if CSS or JavaScript animations are used.
10479       *
10480       * @param {DOMElement} element the element which the CSS classes will be applied to
10481       * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
10482       * @param {object=} options an optional collection of options/styles that will be applied to the element
10483       *
10484       * @return {Promise} the animation callback promise
10485       */
10486      addClass: function(element, className, options) {
10487        options = prepareAnimateOptions(options);
10488        options.addClass = mergeClasses(options.addclass, className);
10489        return $$animateQueue.push(element, 'addClass', options);
10490      },
10491
10492      /**
10493       * @ngdoc method
10494       * @name $animate#removeClass
10495       * @kind function
10496       *
10497       * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
10498       *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
10499       *   animation if element does not contain the CSS class or if the class is added at a later step.
10500       *   Note that class-based animations are treated differently compared to structural animations
10501       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
10502       *   depending if CSS or JavaScript animations are used.
10503       *
10504       * @param {DOMElement} element the element which the CSS classes will be applied to
10505       * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
10506       * @param {object=} options an optional collection of options/styles that will be applied to the element
10507       *
10508       * @return {Promise} the animation callback promise
10509       */
10510      removeClass: function(element, className, options) {
10511        options = prepareAnimateOptions(options);
10512        options.removeClass = mergeClasses(options.removeClass, className);
10513        return $$animateQueue.push(element, 'removeClass', options);
10514      },
10515
10516      /**
10517       * @ngdoc method
10518       * @name $animate#setClass
10519       * @kind function
10520       *
10521       * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
10522       *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
10523       *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
10524       *    passed. Note that class-based animations are treated differently compared to structural animations
10525       *    (like enter, move and leave) since the CSS classes may be added/removed at different points
10526       *    depending if CSS or JavaScript animations are used.
10527       *
10528       * @param {DOMElement} element the element which the CSS classes will be applied to
10529       * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
10530       * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
10531       * @param {object=} options an optional collection of options/styles that will be applied to the element
10532       *
10533       * @return {Promise} the animation callback promise
10534       */
10535      setClass: function(element, add, remove, options) {
10536        options = prepareAnimateOptions(options);
10537        options.addClass = mergeClasses(options.addClass, add);
10538        options.removeClass = mergeClasses(options.removeClass, remove);
10539        return $$animateQueue.push(element, 'setClass', options);
10540      },
10541
10542      /**
10543       * @ngdoc method
10544       * @name $animate#animate
10545       * @kind function
10546       *
10547       * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
10548       * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
10549       * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
10550       * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
10551       * style in `to`, the style in `from` is applied immediately, and no animation is run.
10552       * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
10553       * method (or as part of the `options` parameter):
10554       *
10555       * ```js
10556       * ngModule.animation('.my-inline-animation', function() {
10557       *   return {
10558       *     animate : function(element, from, to, done, options) {
10559       *       //animation
10560       *       done();
10561       *     }
10562       *   }
10563       * });
10564       * ```
10565       *
10566       * @param {DOMElement} element the element which the CSS styles will be applied to
10567       * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
10568       * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
10569       * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
10570       *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
10571       *    (Note that if no animation is detected then this value will not be applied to the element.)
10572       * @param {object=} options an optional collection of options/styles that will be applied to the element
10573       *
10574       * @return {Promise} the animation callback promise
10575       */
10576      animate: function(element, from, to, className, options) {
10577        options = prepareAnimateOptions(options);
10578        options.from = options.from ? extend(options.from, from) : from;
10579        options.to   = options.to   ? extend(options.to, to)     : to;
10580
10581        className = className || 'ng-inline-animate';
vendor: 4,147 bytes, lines 10582-10759
10582        options.tempClasses = mergeClasses(options.tempClasses, className);
10583        return $$animateQueue.push(element, 'animate', options);
10584      }
10585    };
10586  }];
10587}];
10588
10589var $$AnimateAsyncRunFactoryProvider = function() {
10590  this.$get = ['$$rAF', function($$rAF) {
10591    var waitQueue = [];
10592
10593    function waitForTick(fn) {
10594      waitQueue.push(fn);
10595      if (waitQueue.length > 1) return;
10596      $$rAF(function() {
10597        for (var i = 0; i < waitQueue.length; i++) {
10598          waitQueue[i]();
10599        }
10600        waitQueue = [];
10601      });
10602    }
10603
10604    return function() {
10605      var passed = false;
10606      waitForTick(function() {
10607        passed = true;
10608      });
10609      return function(callback) {
10610        passed ? callback() : waitForTick(callback);
10611      };
10612    };
10613  }];
10614};
10615
10616var $$AnimateRunnerFactoryProvider = function() {
10617  this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
10618       function($q,   $sniffer,   $$animateAsyncRun,   $document,   $timeout) {
10619
10620    var INITIAL_STATE = 0;
10621    var DONE_PENDING_STATE = 1;
10622    var DONE_COMPLETE_STATE = 2;
10623
10624    AnimateRunner.chain = function(chain, callback) {
10625      var index = 0;
10626
10627      next();
10628      function next() {
10629        if (index === chain.length) {
10630          callback(true);
10631          return;
10632        }
10633
10634        chain[index](function(response) {
10635          if (response === false) {
10636            callback(false);
10637            return;
10638          }
10639          index++;
10640          next();
10641        });
10642      }
10643    };
10644
10645    AnimateRunner.all = function(runners, callback) {
10646      var count = 0;
10647      var status = true;
10648      forEach(runners, function(runner) {
10649        runner.done(onProgress);
10650      });
10651
10652      function onProgress(response) {
10653        status = status && response;
10654        if (++count === runners.length) {
10655          callback(status);
10656        }
10657      }
10658    };
10659
10660    function AnimateRunner(host) {
10661      this.setHost(host);
10662
10663      var rafTick = $$animateAsyncRun();
10664      var timeoutTick = function(fn) {
10665        $timeout(fn, 0, false);
10666      };
10667
10668      this._doneCallbacks = [];
10669      this._tick = function(fn) {
10670        var doc = $document[0];
10671
10672        // the document may not be ready or attached
10673        // to the module for some internal tests
10674        if (doc && doc.hidden) {
10675          timeoutTick(fn);
10676        } else {
10677          rafTick(fn);
10678        }
10679      };
10680      this._state = 0;
10681    }
10682
10683    AnimateRunner.prototype = {
10684      setHost: function(host) {
10685        this.host = host || {};
10686      },
10687
10688      done: function(fn) {
10689        if (this._state === DONE_COMPLETE_STATE) {
10690          fn();
10691        } else {
10692          this._doneCallbacks.push(fn);
10693        }
10694      },
10695
10696      progress: noop,
10697
10698      getPromise: function() {
10699        if (!this.promise) {
10700          var self = this;
10701          this.promise = $q(function(resolve, reject) {
10702            self.done(function(status) {
10703              status === false ? reject() : resolve();
10704            });
10705          });
10706        }
10707        return this.promise;
10708      },
10709
10710      then: function(resolveHandler, rejectHandler) {
10711        return this.getPromise().then(resolveHandler, rejectHandler);
10712      },
10713
10714      'catch': function(handler) {
10715        return this.getPromise()['catch'](handler);
10716      },
10717
10718      'finally': function(handler) {
10719        return this.getPromise()['finally'](handler);
10720      },
10721
10722      pause: function() {
10723        if (this.host.pause) {
10724          this.host.pause();
10725        }
10726      },
10727
10728      resume: function() {
10729        if (this.host.resume) {
10730          this.host.resume();
10731        }
10732      },
10733
10734      end: function() {
10735        if (this.host.end) {
10736          this.host.end();
10737        }
10738        this._resolve(true);
10739      },
10740
10741      cancel: function() {
10742        if (this.host.cancel) {
10743          this.host.cancel();
10744        }
10745        this._resolve(false);
10746      },
10747
10748      complete: function(response) {
10749        var self = this;
10750        if (self._state === INITIAL_STATE) {
10751          self._state = DONE_PENDING_STATE;
10752          self._tick(function() {
10753            self._resolve(response);
10754          });
10755        }
10756      },
10757
10758      _resolve: function(response) {
10759        if (this._state !== DONE_COMPLETE_STATE) {
10760          forEach(this._doneCallbacks, function(fn) {
10761            fn(response);
10762          });
10763          this._doneCallbacks.length = 0;
10764          this._state = DONE_COMPLETE_STATE;
10765        }
10766      }
10767    };
10768
10769    return AnimateRunner;
10770  }];
10771};
10772
10773/**
10774 * @ngdoc service
10775 * @name $animateCss
10776 * @kind object
10777 *
10778 * @description
10779 * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
10780 * then the `$animateCss` service will actually perform animations.
10781 *
10782 * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
10783 */
10784var $CoreAnimateCssProvider = function() {
10785  this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
10786
10787    return function(element, initialOptions) {
10788      // all of the animation functions should create
10789      // a copy of the options data, however, if a
10790      // parent service has already created a copy then
10791      // we should stick to using that
10792      var options = initialOptions || {};
10793      if (!options.$$prepared) {
10794        options = copy(options);
10795      }
10796
10797      // there is no point in applying the styles since
10798      // there is no animation that goes on at all in
10799      // this version of $animateCss.
10800      if (options.cleanupStyles) {
10801        options.from = options.to = null;
10802      }
10803
10804      if (options.from) {
10805        element.css(options.from);
10806        options.from = null;
10807      }
10808
10809      /* jshint newcap: false */
10810      var closed, runner = new $$AnimateRunner();
10811      return {
10812        start: run,
10813        end: run
10814      };
10815
10816      function run() {
10817        $$rAF(function() {
10818          applyAnimationContents();
10819          if (!closed) {
10820            runner.complete();
10821          }
10822          closed = true;
10823        });
10824        return runner;
10825      }
10826
10827      function applyAnimationContents() {
10828        if (options.addClass) {
10829          element.addClass(options.addClass);
10830          options.addClass = null;
10831        }
10832        if (options.removeClass) {
10833          element.removeClass(options.removeClass);
10834          options.removeClass = null;
10835        }
10836        if (options.to) {
10837          element.css(options.to);
10838          options.to = null;
10839        }
10840      }
10841    };
10842  }];
10843};
10844
10845/* global stripHash: true */
10846
10847/**
10848 * ! This is a private undocumented service !
10849 *
10850 * @name $browser
10851 * @requires $log
10852 * @description
10853 * This object has two goals:
10854 *
10855 * - hide all the global state in the browser caused by the window object
10856 * - abstract away all the browser specific features and inconsistencies
10857 *
10858 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
10859 * service, which can be used for convenient testing of the application without the interaction with
10860 * the real browser apis.
10861 */
10862/**
10863 * @param {object} window The global window object.
10864 * @param {object} document jQuery wrapped document.
10865 * @param {object} $log window.console or an object with the same interface.
10866 * @param {object} $sniffer $sniffer service
10867 */
10868function Browser(window, document, $log, $sniffer) {
10869  var self = this,
10870      rawDocument = document[0],
10871      location = window.location,
10872      history = window.history,
10873      setTimeout = window.setTimeout,
10874      clearTimeout = window.clearTimeout,
10875      pendingDeferIds = {};
10876
10877  self.isMock = false;
10878
10879  var outstandingRequestCount = 0;
10880  var outstandingRequestCallbacks = [];
10881
10882  // TODO(vojta): remove this temporary api
10883  self.$$completeOutstandingRequest = completeOutstandingRequest;
10884  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
10885
10886  /**
10887   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
10888   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
10889   */
10890  function completeOutstandingRequest(fn) {
10891    try {
10892      fn.apply(null, sliceArgs(arguments, 1));
10893    } finally {
10894      outstandingRequestCount--;
10895      if (outstandingRequestCount === 0) {
10896        while (outstandingRequestCallbacks.length) {
10897          try {
10898            outstandingRequestCallbacks.pop()();
10899          } catch (e) {
10900            $log.error(e);
10901          }
10902        }
10903      }
10904    }
10905  }
10906
10907  function getHash(url) {
10908    var index = url.indexOf('#');
10909    return index === -1 ? '' : url.substr(index);
10910  }
10911
10912  /**
10913   * @private
10914   * Note: this method is used only by scenario runner
10915   * TODO(vojta): prefix this method with $$ ?
10916   * @param {function()} callback Function that will be called when no outstanding request
10917   */
10918  self.notifyWhenNoOutstandingRequests = function(callback) {
10919    if (outstandingRequestCount === 0) {
10920      callback();
10921    } else {
10922      outstandingRequestCallbacks.push(callback);
10923    }
10924  };
10925
10926  //////////////////////////////////////////////////////////////
10927  // URL API
10928  //////////////////////////////////////////////////////////////
10929
10930  var cachedState, lastHistoryState,
10931      lastBrowserUrl = location.href,
10932      baseElement = document.find('base'),
10933      pendingLocation = null;
10934
10935  cacheState();
10936  lastHistoryState = cachedState;
10937
10938  /**
10939   * @name $browser#url
10940   *
10941   * @description
10942   * GETTER:
10943   * Without any argument, this method just returns current value of location.href.
10944   *
10945   * SETTER:
10946   * With at least one argument, this method sets url to new value.
10947   * If html5 history api supported, pushState/replaceState is used, otherwise
10948   * location.href/location.replace is used.
10949   * Returns its own instance to allow chaining
10950   *
10951   * NOTE: this api is intended for use only by the $location service. Please use the
10952   * {@link ng.$location $location service} to change url.
10953   *
10954   * @param {string} url New url (when used as setter)
10955   * @param {boolean=} replace Should new url replace current history record?
10956   * @param {object=} state object to use with pushState/replaceState
10957   */
10958  self.url = function(url, replace, state) {
10959    // In modern browsers `history.state` is `null` by default; treating it separately
10960    // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
10961    // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
10962    if (isUndefined(state)) {
10963      state = null;
10964    }
10965
10966    // Android Browser BFCache causes location, history reference to become stale.
10967    if (location !== window.location) location = window.location;
10968    if (history !== window.history) history = window.history;
10969
10970    // setter
10971    if (url) {
10972      var sameState = lastHistoryState === state;
10973
10974      // Don't change anything if previous and current URLs and states match. This also prevents
10975      // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
10976      // See https://github.com/angular/angular.js/commit/ffb2701
10977      if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
10978        return self;
10979      }
10980      var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
10981      lastBrowserUrl = url;
10982      lastHistoryState = state;
10983      // Don't use history API if only the hash changed
10984      // due to a bug in IE10/IE11 which leads
10985      // to not firing a `hashchange` nor `popstate` event
10986      // in some cases (see #9143).
10987      if ($sniffer.history && (!sameBase || !sameState)) {
10988        history[replace ? 'replaceState' : 'pushState'](state, '', url);
10989        cacheState();
10990        // Do the assignment again so that those two variables are referentially identical.
10991        lastHistoryState = cachedState;
10992      } else {
10993        if (!sameBase || pendingLocation) {
10994          pendingLocation = url;
10995        }
10996        if (replace) {
10997          location.replace(url);
10998        } else if (!sameBase) {
10999          location.href = url;
11000        } else {
11001          location.hash = getHash(url);
11002        }
11003        if (location.href !== url) {
11004          pendingLocation = url;
11005        }
11006      }
11007      return self;
11008    // getter
11009    } else {
11010      // - pendingLocation is needed as browsers don't allow to read out
11011      //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
11012      //   https://openradar.appspot.com/22186109).
11013      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
11014      return pendingLocation || location.href.replace(/%27/g,"'");
11015    }
11016  };
11017
11018  /**
11019   * @name $browser#state
11020   *
11021   * @description
11022   * This method is a getter.
11023   *
11024   * Return history.state or null if history.state is undefined.
11025   *
11026   * @returns {object} state
11027   */
11028  self.state = function() {
11029    return cachedState;
11030  };
11031
11032  var urlChangeListeners = [],
11033      urlChangeInit = false;
11034
11035  function cacheStateAndFireUrlChange() {
11036    pendingLocation = null;
11037    cacheState();
11038    fireUrlChange();
11039  }
11040
11041  function getCurrentState() {
11042    try {
11043      return history.state;
11044    } catch (e) {
11045      // MSIE can reportedly throw when there is no state (UNCONFIRMED).
11046    }
11047  }
11048
11049  // This variable should be used *only* inside the cacheState function.
11050  var lastCachedState = null;
11051  function cacheState() {
11052    // This should be the only place in $browser where `history.state` is read.
11053    cachedState = getCurrentState();
11054    cachedState = isUndefined(cachedState) ? null : cachedState;
11055
11056    // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
11057    if (equals(cachedState, lastCachedState)) {
11058      cachedState = lastCachedState;
11059    }
11060    lastCachedState = cachedState;
11061  }
11062
11063  function fireUrlChange() {
11064    if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
11065      return;
11066    }
11067
11068    lastBrowserUrl = self.url();
11069    lastHistoryState = cachedState;
11070    forEach(urlChangeListeners, function(listener) {
11071      listener(self.url(), cachedState);
11072    });
11073  }
11074
11075  /**
11076   * @name $browser#onUrlChange
11077   *
11078   * @description
11079   * Register callback function that will be called, when url changes.
11080   *
11081   * It's only called when the url is changed from outside of angular:
11082   * - user types different url into address bar
11083   * - user clicks on history (forward/back) button
11084   * - user clicks on a link
11085   *
11086   * It's not called when url is changed by $browser.url() method
11087   *
11088   * The listener gets called with new url as parameter.
11089   *
11090   * NOTE: this api is intended for use only by the $location service. Please use the
11091   * {@link ng.$location $location service} to monitor url changes in angular apps.
11092   *
11093   * @param {function(string)} listener Listener function to be called when url changes.
11094   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
11095   */
11096  self.onUrlChange = function(callback) {
11097    // TODO(vojta): refactor to use node's syntax for events
11098    if (!urlChangeInit) {
11099      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
11100      // don't fire popstate when user change the address bar and don't fire hashchange when url
11101      // changed by push/replaceState
11102
11103      // html5 history api - popstate event
11104      if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
11105      // hashchange event
11106      jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
11107
11108      urlChangeInit = true;
11109    }
11110
11111    urlChangeListeners.push(callback);
11112    return callback;
11113  };
11114
11115  /**
11116   * @private
11117   * Remove popstate and hashchange handler from window.
11118   *
11119   * NOTE: this api is intended for use only by $rootScope.
11120   */
11121  self.$$applicationDestroyed = function() {
11122    jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
11123  };
11124
11125  /**
11126   * Checks whether the url has changed outside of Angular.
11127   * Needs to be exported to be able to check for changes that have been done in sync,
11128   * as hashchange/popstate events fire in async.
11129   */
11130  self.$$checkUrlChange = fireUrlChange;
11131
11132  //////////////////////////////////////////////////////////////
11133  // Misc API
11134  //////////////////////////////////////////////////////////////
11135
11136  /**
11137   * @name $browser#baseHref
11138   *
11139   * @description
11140   * Returns current <base href>
11141   * (always relative - without domain)
11142   *
11143   * @returns {string} The current base href
11144   */
11145  self.baseHref = function() {
11146    var href = baseElement.attr('href');
11147    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
11148  };
11149
11150  /**
11151   * @name $browser#defer
11152   * @param {function()} fn A function, who's execution should be deferred.
11153   * @param {number=} [delay=0] of milliseconds to defer the function execution.
11154   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
11155   *
11156   * @description
11157   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
11158   *
11159   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
11160   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
11161   * via `$browser.defer.flush()`.
11162   *
11163   */
11164  self.defer = function(fn, delay) {
11165    var timeoutId;
11166    outstandingRequestCount++;
11167    timeoutId = setTimeout(function() {
11168      delete pendingDeferIds[timeoutId];
11169      completeOutstandingRequest(fn);
11170    }, delay || 0);
11171    pendingDeferIds[timeoutId] = true;
11172    return timeoutId;
11173  };
11174
11175
11176  /**
11177   * @name $browser#defer.cancel
11178   *
11179   * @description
11180   * Cancels a deferred task identified with `deferId`.
11181   *
11182   * @param {*} deferId Token returned by the `$browser.defer` function.
11183   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
11184   *                    canceled.
11185   */
11186  self.defer.cancel = function(deferId) {
11187    if (pendingDeferIds[deferId]) {
11188      delete pendingDeferIds[deferId];
11189      clearTimeout(deferId);
11190      completeOutstandingRequest(noop);
11191      return true;
11192    }
11193    return false;
11194  };
11195
11196}
11197
11198function $BrowserProvider() {
11199  this.$get = ['$window', '$log', '$sniffer', '$document',
11200      function($window, $log, $sniffer, $document) {
11201        return new Browser($window, $document, $log, $sniffer);
11202      }];
11203}
11204
11205/**
11206 * @ngdoc service
11207 * @name $cacheFactory
11208 *
11209 * @description
11210 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
11211 * them.
11212 *
11213 * ```js
11214 *
11215 *  var cache = $cacheFactory('cacheId');
11216 *  expect($cacheFactory.get('cacheId')).toBe(cache);
11217 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
11218 *
11219 *  cache.put("key", "value");
11220 *  cache.put("another key", "another value");
11221 *
11222 *  // We've specified no options on creation
11223 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
11224 *
11225 * ```
11226 *
11227 *
11228 * @param {string} cacheId Name or id of the newly created cache.
11229 * @param {object=} options Options object that specifies the cache behavior. Properties:
11230 *
11231 *   - `{number=}` `capacity` — turns the cache into LRU cache.
11232 *
11233 * @returns {object} Newly created cache object with the following set of methods:
11234 *
11235 * - `{object}` `info()` — Returns id, size, and options of cache.
11236 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
11237 *   it.
11238 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
11239 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
11240 * - `{void}` `removeAll()` — Removes all cached values.
11241 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
11242 *
11243 * @example
11244   <example module="cacheExampleApp">
11245     <file name="index.html">
11246       <div ng-controller="CacheController">
11247         <input ng-model="newCacheKey" placeholder="Key">
11248         <input ng-model="newCacheValue" placeholder="Value">
11249         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
11250
11251         <p ng-if="keys.length">Cached Values</p>
11252         <div ng-repeat="key in keys">
11253           <span ng-bind="key"></span>
11254           <span>: </span>
11255           <b ng-bind="cache.get(key)"></b>
11256         </div>
11257
11258         <p>Cache Info</p>
11259         <div ng-repeat="(key, value) in cache.info()">
11260           <span ng-bind="key"></span>
11261           <span>: </span>
11262           <b ng-bind="value"></b>
11263         </div>
11264       </div>
11265     </file>
11266     <file name="script.js">
11267       angular.module('cacheExampleApp', []).
11268         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
11269           $scope.keys = [];
11270           $scope.cache = $cacheFactory('cacheId');
11271           $scope.put = function(key, value) {
11272             if (angular.isUndefined($scope.cache.get(key))) {
11273               $scope.keys.push(key);
11274             }
11275             $scope.cache.put(key, angular.isUndefined(value) ? null : value);
11276           };
11277         }]);
11278     </file>
11279     <file name="style.css">
11280       p {
11281         margin: 10px 0 3px;
11282       }
11283     </file>
11284   </example>
11285 */
11286function $CacheFactoryProvider() {
11287
11288  this.$get = function() {
11289    var caches = {};
11290
11291    function cacheFactory(cacheId, options) {
11292      if (cacheId in caches) {
11293        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
11294      }
11295
11296      var size = 0,
11297          stats = extend({}, options, {id: cacheId}),
11298          data = createMap(),
11299          capacity = (options && options.capacity) || Number.MAX_VALUE,
11300          lruHash = createMap(),
11301          freshEnd = null,
11302          staleEnd = null;
11303
11304      /**
11305       * @ngdoc type
11306       * @name $cacheFactory.Cache
11307       *
11308       * @description
11309       * A cache object used to store and retrieve data, primarily used by
11310       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
11311       * templates and other data.
11312       *
11313       * ```js
11314       *  angular.module('superCache')
11315       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
11316       *      return $cacheFactory('super-cache');
11317       *    }]);
11318       * ```
11319       *
11320       * Example test:
11321       *
11322       * ```js
11323       *  it('should behave like a cache', inject(function(superCache) {
11324       *    superCache.put('key', 'value');
11325       *    superCache.put('another key', 'another value');
11326       *
11327       *    expect(superCache.info()).toEqual({
11328       *      id: 'super-cache',
11329       *      size: 2
11330       *    });
11331       *
11332       *    superCache.remove('another key');
11333       *    expect(superCache.get('another key')).toBeUndefined();
11334       *
11335       *    superCache.removeAll();
11336       *    expect(superCache.info()).toEqual({
11337       *      id: 'super-cache',
11338       *      size: 0
11339       *    });
11340       *  }));
11341       * ```
11342       */
11343      return caches[cacheId] = {
11344
11345        /**
11346         * @ngdoc method
11347         * @name $cacheFactory.Cache#put
11348         * @kind function
11349         *
11350         * @description
11351         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
11352         * retrieved later, and incrementing the size of the cache if the key was not already
11353         * present in the cache. If behaving like an LRU cache, it will also remove stale
11354         * entries from the set.
11355         *
11356         * It will not insert undefined values into the cache.
11357         *
11358         * @param {string} key the key under which the cached data is stored.
11359         * @param {*} value the value to store alongside the key. If it is undefined, the key
11360         *    will not be stored.
11361         * @returns {*} the value stored.
11362         */
11363        put: function(key, value) {
11364          if (isUndefined(value)) return;
11365          if (capacity < Number.MAX_VALUE) {
11366            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
11367
11368            refresh(lruEntry);
11369          }
11370
11371          if (!(key in data)) size++;
11372          data[key] = value;
11373
11374          if (size > capacity) {
11375            this.remove(staleEnd.key);
11376          }
11377
11378          return value;
11379        },
11380
11381        /**
11382         * @ngdoc method
11383         * @name $cacheFactory.Cache#get
11384         * @kind function
11385         *
11386         * @description
11387         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
11388         *
11389         * @param {string} key the key of the data to be retrieved
11390         * @returns {*} the value stored.
11391         */
11392        get: function(key) {
11393          if (capacity < Number.MAX_VALUE) {
11394            var lruEntry = lruHash[key];
11395
11396            if (!lruEntry) return;
11397
11398            refresh(lruEntry);
11399          }
11400
11401          return data[key];
11402        },
11403
11404
11405        /**
11406         * @ngdoc method
11407         * @name $cacheFactory.Cache#remove
11408         * @kind function
11409         *
11410         * @description
11411         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
11412         *
11413         * @param {string} key the key of the entry to be removed
11414         */
11415        remove: function(key) {
11416          if (capacity < Number.MAX_VALUE) {
11417            var lruEntry = lruHash[key];
11418
11419            if (!lruEntry) return;
11420
11421            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
11422            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
11423            link(lruEntry.n,lruEntry.p);
11424
11425            delete lruHash[key];
11426          }
11427
11428          if (!(key in data)) return;
11429
11430          delete data[key];
11431          size--;
11432        },
11433
11434
11435        /**
11436         * @ngdoc method
11437         * @name $cacheFactory.Cache#removeAll
11438         * @kind function
11439         *
11440         * @description
11441         * Clears the cache object of any entries.
11442         */
11443        removeAll: function() {
11444          data = createMap();
11445          size = 0;
11446          lruHash = createMap();
11447          freshEnd = staleEnd = null;
11448        },
11449
11450
11451        /**
11452         * @ngdoc method
11453         * @name $cacheFactory.Cache#destroy
11454         * @kind function
11455         *
11456         * @description
11457         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
11458         * removing it from the {@link $cacheFactory $cacheFactory} set.
11459         */
11460        destroy: function() {
11461          data = null;
11462          stats = null;
11463          lruHash = null;
11464          delete caches[cacheId];
11465        },
11466
11467
11468        /**
11469         * @ngdoc method
11470         * @name $cacheFactory.Cache#info
11471         * @kind function
11472         *
11473         * @description
11474         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
11475         *
11476         * @returns {object} an object with the following properties:
11477         *   <ul>
11478         *     <li>**id**: the id of the cache instance</li>
11479         *     <li>**size**: the number of entries kept in the cache instance</li>
11480         *     <li>**...**: any additional properties from the options object when creating the
11481         *       cache.</li>
11482         *   </ul>
11483         */
11484        info: function() {
11485          return extend({}, stats, {size: size});
11486        }
11487      };
11488
11489
11490      /**
11491       * makes the `entry` the freshEnd of the LRU linked list
11492       */
11493      function refresh(entry) {
11494        if (entry != freshEnd) {
11495          if (!staleEnd) {
11496            staleEnd = entry;
11497          } else if (staleEnd == entry) {
11498            staleEnd = entry.n;
11499          }
11500
11501          link(entry.n, entry.p);
11502          link(entry, freshEnd);
11503          freshEnd = entry;
11504          freshEnd.n = null;
11505        }
11506      }
11507
11508
11509      /**
11510       * bidirectionally links two entries of the LRU linked list
11511       */
11512      function link(nextEntry, prevEntry) {
11513        if (nextEntry != prevEntry) {
11514          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
11515          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
11516        }
11517      }
11518    }
11519
11520
11521  /**
11522   * @ngdoc method
11523   * @name $cacheFactory#info
11524   *
11525   * @description
11526   * Get information about all the caches that have been created
11527   *
11528   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
11529   */
11530    cacheFactory.info = function() {
11531      var info = {};
11532      forEach(caches, function(cache, cacheId) {
11533        info[cacheId] = cache.info();
11534      });
11535      return info;
11536    };
11537
11538
11539  /**
11540   * @ngdoc method
11541   * @name $cacheFactory#get
11542   *
11543   * @description
11544   * Get access to a cache object by the `cacheId` used when it was created.
11545   *
11546   * @param {string} cacheId Name or id of a cache to access.
11547   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
11548   */
11549    cacheFactory.get = function(cacheId) {
11550      return caches[cacheId];
11551    };
11552
11553
11554    return cacheFactory;
11555  };
11556}
11557
11558/**
11559 * @ngdoc service
11560 * @name $templateCache
11561 *
11562 * @description
11563 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
11564 * can load templates directly into the cache in a `script` tag, or by consuming the
11565 * `$templateCache` service directly.
11566 *
11567 * Adding via the `script` tag:
11568 *
11569 * ```html
11570 *   <script type="text/ng-template" id="templateId.html">
11571 *     <p>This is the content of the template</p>
11572 *   </script>
11573 * ```
11574 *
11575 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
11576 * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
11577 * element with ng-app attribute), otherwise the template will be ignored.
11578 *
11579 * Adding via the `$templateCache` service:
11580 *
11581 * ```js
11582 * var myApp = angular.module('myApp', []);
11583 * myApp.run(function($templateCache) {
11584 *   $templateCache.put('templateId.html', 'This is the content of the template');
11585 * });
11586 * ```
11587 *
11588 * To retrieve the template later, simply use it in your HTML:
11589 * ```html
11590 * <div ng-include=" 'templateId.html' "></div>
11591 * ```
11592 *
11593 * or get it via Javascript:
11594 * ```js
11595 * $templateCache.get('templateId.html')
11596 * ```
11597 *
11598 * See {@link ng.$cacheFactory $cacheFactory}.
11599 *
11600 */
11601function $TemplateCacheProvider() {
11602  this.$get = ['$cacheFactory', function($cacheFactory) {
11603    return $cacheFactory('templates');
11604  }];
11605}
11606
11607/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11608 *     Any commits to this file should be reviewed with security in mind.  *
11609 *   Changes to this file can potentially create security vulnerabilities. *
11610 *          An approval from 2 Core members with history of modifying      *
11611 *                         this file is required.                          *
11612 *                                                                         *
11613 *  Does the change somehow allow for arbitrary javascript to be executed? *
11614 *    Or allows for someone to change the prototype of built-in objects?   *
11615 *     Or gives undesired access to variables likes document or window?    *
11616 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11617
11618/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
11619 *
11620 * DOM-related variables:
11621 *
11622 * - "node" - DOM Node
11623 * - "element" - DOM Element or Node
11624 * - "$node" or "$element" - jqLite-wrapped node or element
11625 *
11626 *
11627 * Compiler related stuff:
11628 *
11629 * - "linkFn" - linking fn of a single directive
11630 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
11631 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
11632 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
11633 */
11634
11635
11636/**
11637 * @ngdoc service
11638 * @name $compile
11639 * @kind function
11640 *
11641 * @description
11642 * Compiles an HTML string or DOM into a template and produces a template function, which
11643 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
11644 *
11645 * The compilation is a process of walking the DOM tree and matching DOM elements to
11646 * {@link ng.$compileProvider#directive directives}.
11647 *
11648 * <div class="alert alert-warning">
11649 * **Note:** This document is an in-depth reference of all directive options.
11650 * For a gentle introduction to directives with examples of common use cases,
11651 * see the {@link guide/directive directive guide}.
11652 * </div>
11653 *
11654 * ## Comprehensive Directive API
11655 *
11656 * There are many different options for a directive.
11657 *
11658 * The difference resides in the return value of the factory function.
11659 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
11660 * or just the `postLink` function (all other properties will have the default values).
11661 *
11662 * <div class="alert alert-success">
11663 * **Best Practice:** It's recommended to use the "directive definition object" form.
11664 * </div>
11665 *
11666 * Here's an example directive declared with a Directive Definition Object:
11667 *
11668 * ```js
11669 *   var myModule = angular.module(...);
11670 *
11671 *   myModule.directive('directiveName', function factory(injectables) {
11672 *     var directiveDefinitionObject = {
11673 *       priority: 0,
11674 *       template: '<div></div>
11674', // or // function(tElement, tAttrs) { ... },
11675 *       // or
11676 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
11677 *       transclude: false,
11678 *       restrict: 'A',
11679 *       templateNamespace: 'html',
11680 *       scope: false,
11681 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
11682 *       controllerAs: 'stringIdentifier',
11683 *       bindToController: false,
11684 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
11685 *       compile: function compile(tElement, tAttrs, transclude) {
11686 *         return {
11687 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
11688 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
11689 *         }
11690 *         // or
11691 *         // return function postLink( ... ) { ... }
11692 *       },
11693 *       // or
11694 *       // link: {
11695 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
11696 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
11697 *       // }
11698 *       // or
11699 *       // link: function postLink( ... ) { ... }
11700 *     };
11701 *     return directiveDefinitionObject;
11702 *   });
11703 * ```
11704 *
11705 * <div class="alert alert-warning">
11706 * **Note:** Any unspecified options will use the default value. You can see the default values below.
11707 * </div>
11708 *
11709 * Therefore the above can be simplified as:
11710 *
11711 * ```js
11712 *   var myModule = angular.module(...);
11713 *
11714 *   myModule.directive('directiveName', function factory(injectables) {
11715 *     var directiveDefinitionObject = {
11716 *       link: function postLink(scope, iElement, iAttrs) { ... }
11717 *     };
11718 *     return directiveDefinitionObject;
11719 *     // or
11720 *     // return function postLink(scope, iElement, iAttrs) { ... }
11721 *   });
11722 * ```
11723 *
11724 *
11725 *
11726 * ### Directive Definition Object
11727 *
11728 * The directive definition object provides instructions to the {@link ng.$compile
11729 * compiler}. The attributes are:
11730 *
11731 * #### `multiElement`
11732 * When this property is set to true, the HTML compiler will collect DOM nodes between
11733 * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
11734 * together as the directive elements. It is recommended that this feature be used on directives
11735 * which are not strictly behavioral (such as {@link ngClick}), and which
11736 * do not manipulate or replace child nodes (such as {@link ngInclude}).
11737 *
11738 * #### `priority`
11739 * When there are multiple directives defined on a single DOM element, sometimes it
11740 * is necessary to specify the order in which the directives are applied. The `priority` is used
11741 * to sort the directives before their `compile` functions get called. Priority is defined as a
11742 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
11743 * are also run in priority order, but post-link functions are run in reverse order. The order
11744 * of directives with the same priority is undefined. The default priority is `0`.
11745 *
11746 * #### `terminal`
11747 * If set to true then the current `priority` will be the last set of directives
11748 * which will execute (any directives at the current priority will still execute
11749 * as the order of execution on same `priority` is undefined). Note that expressions
11750 * and other directives used in the directive's template will also be excluded from execution.
11751 *
11752 * #### `scope`
11753 * The scope property can be `true`, an object or a falsy value:
11754 *
11755 * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
11756 *
11757 * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
11758 * the directive's element. If multiple directives on the same element request a new scope,
11759 * only one new scope is created. The new scope rule does not apply for the root of the template
11760 * since the root of the template always gets a new scope.
11761 *
11762 * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
11763 * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
11764 * scope. This is useful when creating reusable components, which should not accidentally read or modify
11765 * data in the parent scope.
11766 *
11767 * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
11768 * directive's element. These local properties are useful for aliasing values for templates. The keys in
11769 * the object hash map to the name of the property on the isolate scope; the values define how the property
11770 * is bound to the parent scope, via matching attributes on the directive's element:
11771 *
11772 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
11773 *   always a string since DOM attributes are strings. If no `attr` name is specified then the
11774 *   attribute name is assumed to be the same as the local name. Given `<my-component
11775 *   my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
11776 *   the directive's scope property `localName` will reflect the interpolated value of `hello
11777 *   {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
11778 *   scope. The `name` is read from the parent scope (not the directive's scope).
11779 *
11780 * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
11781 *   passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
11782 *   If no `attr` name is specified then the attribute name is assumed to be the same as the local
11783 *   name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
11784 *   localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
11785 *   value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
11786 *   `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
11787 *   `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
11788 *   optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
11789 *   will be thrown upon discovering changes to the local value, since it will be impossible to sync
11790 *   them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
11791 *   method is used for tracking changes, and the equality check is based on object identity.
11792 *   However, if an object literal or an array literal is passed as the binding expression, the
11793 *   equality check is done by value (using the {@link angular.equals} function). It's also possible
11794 *   to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
11795 *   `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
11796 *
11797  * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
11798 *   expression passed via the attribute `attr`. The expression is evaluated in the context of the
11799 *   parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
11800 *   local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
11801 *
11802 *   For example, given `<my-component my-attr="parentModel">` and directive definition of
11803 *   `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
11804 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
11805 *   in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
11806 *   two caveats:
11807 *     1. one-way binding does not copy the value from the parent to the isolate scope, it simply
11808 *     sets the same value. That means if your bound value is an object, changes to its properties
11809 *     in the isolated scope will be reflected in the parent scope (because both reference the same object).
11810 *     2. one-way binding watches changes to the **identity** of the parent value. That means the
11811 *     {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
11812 *     to the value has changed. In most cases, this should not be of concern, but can be important
11813 *     to know if you one-way bind to an object, and then replace that object in the isolated scope.
11814 *     If you now change a property of the object in your parent scope, the change will not be
11815 *     propagated to the isolated scope, because the identity of the object on the parent scope
11816 *     has not changed. Instead you must assign a new object.
11817 *
11818 *   One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
11819 *   back to the parent. However, it does not make this completely impossible.
11820 *
11821 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
11822 *   no `attr` name is specified then the attribute name is assumed to be the same as the local name.
11823 *   Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
11824 *   localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
11825 *   the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
11826 *   via an expression to the parent scope. This can be done by passing a map of local variable names
11827 *   and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
11828 *   then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
11829 *
11830 * In general it's possible to apply more than one directive to one element, but there might be limitations
11831 * depending on the type of scope required by the directives. The following points will help explain these limitations.
11832 * For simplicity only two directives are taken into account, but it is also applicable for several directives:
11833 *
11834 * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
11835 * * **child scope** + **no scope** =>  Both directives will share one single child scope
11836 * * **child scope** + **child scope** =>  Both directives will share one single child scope
11837 * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
11838 * its parent's scope
11839 * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
11840 * be applied to the same element.
11841 * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
11842 * cannot be applied to the same element.
11843 *
11844 *
11845 * #### `bindToController`
11846 * This property is used to bind scope properties directly to the controller. It can be either
11847 * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
11848 * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
11849 * definition: `controller: 'myCtrl as myAlias'`.
11850 *
11851 * When an isolate scope is used for a directive (see above), `bindToController: true` will
11852 * allow a component to have its properties bound to the controller, rather than to scope.
11853 *
11854 * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
11855 * properties. You can access these bindings once they have been initialized by providing a controller method called
11856 * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
11857 * initialized.
11858 *
11859 * <div class="alert alert-warning">
11860 * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
11861 * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
11862 * code that relies upon bindings inside a `$onInit` method on the controller, instead.
11863 * </div>
11864 *
11865 * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
11866 * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
11867 * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
11868 * scope (useful for component directives).
11869 *
11870 * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
11871 *
11872 *
11873 * #### `controller`
11874 * Controller constructor function. The controller is instantiated before the
11875 * pre-linking phase and can be accessed by other directives (see
11876 * `require` attribute). This allows the directives to communicate with each other and augment
11877 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
11878 *
11879 * * `$scope` - Current scope associated with the element
11880 * * `$element` - Current element
11881 * * `$attrs` - Current attributes object for the element
11882 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
11883 *   `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
11884 *    * `scope`: (optional) override the scope.
11885 *    * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
11886 *    * `futureParentElement` (optional):
11887 *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
11888 *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
11889 *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
11890 *          and when the `cloneLinkinFn` is passed,
11891 *          as those elements need to created and cloned in a special way when they are defined outside their
11892 *          usual containers (e.g. like `<svg>`).
11893 *        * See also the `directive.templateNamespace` property.
11894 *    * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
11895 *      then the default translusion is provided.
11896 *    The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
11897 *    `true` if the specified slot contains content (i.e. one or more DOM nodes).
11898 *
11899 * The controller can provide the following methods that act as life-cycle hooks:
11900 * * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
11901 *   had their bindings initialized (and before the pre &amp; post linking functions for the directives on
11902 *   this element). This is a good place to put initialization code for your controller.
11903 *
11904 * #### `require`
11905 * Require another directive and inject its controller as the fourth argument to the linking function. The
11906 * `require` property can be a string, an array or an object:
11907 * * a **string** containing the name of the directive to pass to the linking function
11908 * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
11909 * linking function will be an array of controllers in the same order as the names in the `require` property
11910 * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
11911 * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
11912 * controllers.
11913 *
11914 * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
11915 * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
11916 * have been constructed but before `$onInit` is called.
11917 * See the {@link $compileProvider#component} helper for an example of how this can be used.
11918 *
11919 * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
11920 * raised (unless no link function is specified and the required controllers are not being bound to the directive
11921 * controller, in which case error checking is skipped). The name can be prefixed with:
11922 *
11923 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
11924 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
11925 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
11926 * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
11927 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
11928 *   `null` to the `link` fn if not found.
11929 * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
11930 *   `null` to the `link` fn if not found.
11931 *
11932 *
11933 * #### `controllerAs`
11934 * Identifier name for a reference to the controller in the directive's scope.
11935 * This allows the controller to be referenced from the directive template. This is especially
11936 * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
11937 * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
11938 * `controllerAs` reference might overwrite a property that already exists on the parent scope.
11939 *
11940 *
11941 * #### `restrict`
11942 * String of subset of `EACM` which restricts the directive to a specific directive
11943 * declaration style. If omitted, the defaults (elements and attributes) are used.
11944 *
11945 * * `E` - Element name (default): `<my-directive></my-directive>`
11946 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
11947 * * `C` - Class: `<div class="my-directive: exp;"></div>`
11948 * * `M` - Comment: `<!-- directive: my-directive exp -->`
11949 *
11950 *
11951 * #### `templateNamespace`
11952 * String representing the document type used by the markup in the template.
11953 * AngularJS needs this information as those elements need to be created and cloned
11954 * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
11955 *
11956 * * `html` - All root nodes in the template are HTML. Root nodes may also be
11957 *   top-level elements such as `<svg>` or `<math>`.
11958 * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
11959 * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
11960 *
11961 * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
11962 *
11963 * #### `template`
11964 * HTML markup that may:
11965 * * Replace the contents of the directive's element (default).
11966 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
11967 * * Wrap the contents of the directive's element (if `transclude` is true).
11968 *
11969 * Value may be:
11970 *
11971 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
11972 * * A function which takes two arguments `tElement` and `tAttrs` (described 
11972in the `compile`
11973 *   function api below) and returns a string value.
11974 *
11975 *
11976 * #### `templateUrl`
11977 * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
11978 *
11979 * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
11980 * for later when the template has been resolved.  In the meantime it will continue to compile and link
11981 * sibling and parent elements as though this element had not contained any directives.
11982 *
11983 * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
11984 * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
11985 * case when only one deeply nested directive has `templateUrl`.
11986 *
11987 * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
11988 *
11989 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
11990 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
11991 * a string value representing the url.  In either case, the template URL is passed through {@link
11992 * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
11993 *
11994 *
11995 * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
11996 * specify what the template should replace. Defaults to `false`.
11997 *
11998 * * `true` - the template will replace the directive's element.
11999 * * `false` - the template will replace the contents of the directive's element.
12000 *
12001 * The replacement process migrates all of the attributes / classes from the old element to the new
12002 * one. See the {@link guide/directive#template-expanding-directive
12003 * Directives Guide} for an example.
12004 *
12005 * There are very few scenarios where element replacement is required for the application function,
12006 * the main one being reusable custom components that are used within SVG contexts
12007 * (because SVG doesn't work with custom elements in the DOM tree).
12008 *
12009 * #### `transclude`
12010 * Extract the contents of the element where the directive appears and make it available to the directive.
12011 * The contents are compiled and provided to the directive as a **transclusion function**. See the
12012 * {@link $compile#transclusion Transclusion} section below.
12013 *
12014 *
12015 * #### `compile`
12016 *
12017 * ```js
12018 *   function compile(tElement, tAttrs, transclude) { ... }
12019 * ```
12020 *
12021 * The compile function deals with transforming the template DOM. Since most directives do not do
12022 * template transformation, it is not used often. The compile function takes the following arguments:
12023 *
12024 *   * `tElement` - template element - The element where the directive has been declared. It is
12025 *     safe to do template transformation on the element and child elements only.
12026 *
12027 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
12028 *     between all directive compile functions.
12029 *
12030 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
12031 *
12032 * <div class="alert alert-warning">
12033 * **Note:** The template instance and the link instance may be different objects if the template has
12034 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
12035 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
12036 * should be done in a linking function rather than in a compile function.
12037 * </div>
12038
12039 * <div class="alert alert-warning">
12040 * **Note:** The compile function cannot handle directives that recursively use themselves in their
12041 * own templates or compile functions. Compiling these directives results in an infinite loop and
12042 * stack overflow errors.
12043 *
12044 * This can be avoided by manually using $compile in the postLink function to imperatively compile
12045 * a directive's template instead of relying on automatic template compilation via `template` or
12046 * `templateUrl` declaration or manual compilation inside the compile function.
12047 * </div>
12048 *
12049 * <div class="alert alert-danger">
12050 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
12051 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
12052 *   to the link function instead.
12053 * </div>
12054
12055 * A compile function can have a return value which can be either a function or an object.
12056 *
12057 * * returning a (post-link) function - is equivalent to registering the linking function via the
12058 *   `link` property of the config object when the compile function is empty.
12059 *
12060 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
12061 *   control when a linking function should be called during the linking phase. See info about
12062 *   pre-linking and post-linking functions below.
12063 *
12064 *
12065 * #### `link`
12066 * This property is used only if the `compile` property is not defined.
12067 *
12068 * ```js
12069 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
12070 * ```
12071 *
12072 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
12073 * executed after the template has been cloned. This is where most of the directive logic will be
12074 * put.
12075 *
12076 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
12077 *     directive for registering {@link ng.$rootScope.Scope#$watch w
12077atches}.
12078 *
12079 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
12080 *     manipulate the children of the element only in `postLink` function since the children have
12081 *     already been linked.
12082 *
12083 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
12084 *     between all directive linking functions.
12085 *
12086 *   * `controller` - the directive's required controller instance(s) - Instances are shared
12087 *     among all directives, which allows the directives to use the controllers as a communication
12088 *     channel. The exact value depends on the directive's `require` property:
12089 *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
12090 *       * `string`: the controller instance
12091 *       * `array`: array of controller instances
12092 *
12093 *     If a required controller cannot be found, and it is optional, the instance is `null`,
12094 *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
12095 *
12096 *     Note that you can also require the directive's own controller - it will be made available like
12097 *     any other controller.
12098 *
12099 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
12100 *     This is the same as the `$transclude`
12101 *     parameter of directive controllers, see there for details.
12102 *     `function([scope], cloneLinkingFn, futureParentElement)`.
12103 *
12104 * #### Pre-linking function
12105 *
12106 * Executed before the child elements are linked. Not safe to do DOM transformation since the
12107 * compiler linking function will fail to locate the correct elements for linking.
12108 *
12109 * #### Post-linking function
12110 *
12111 * Executed after the child elements are linked.
12112 *
12113 * Note that child elements that contain `templateUrl` directives will not have been compiled
12114 * and linked since they are waiting for their template to load asynchronously and their own
12115 * compilation and linking has been suspended until that occurs.
12116 *
12117 * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
12118 * for their async templates to be resolved.
12119 *
12120 *
12121 * ### Transclusion
12122 *
12123 * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
12124 * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
12125 * scope from where they were taken.
12126 *
12127 * Transclusion is used (often with {@link ngTransclude}) to insert the
12128 * original contents of a directive's element into a specified place in the template of the directive.
12129 * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
12130 * content has access to the properties on the scope from which it was taken, even if the directive
12131 * has isolated scope.
12132 * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
12133 *
12134 * This makes it possible for the widget to have private state for its template, while the transcluded
12135 * content has access to its originating scope.
12136 *
12137 * <div class="alert alert-warning">
12138 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
12139 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
12140 * Testing Transclusion Directives}.
12141 * </div>
12142 *
12143 * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
12144 * directive's element, the entire element or multiple parts of the element contents:
12145 *
12146 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
12147 * * `'element'` - transclude the whole of the directive's element including any directives on this
12148 *   element that defined at a lower priority than this directive. When used, the `template`
12149 *   property is ignored.
12150 * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
12151 *
12152 * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
12153 *
12154 * This object is a map where the keys are the name of the slot to fill and the value is an element selector
12155 * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
12156 * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
12157 *
12158 * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
12159 *
12160 * If the element selector is prefixed with a `?` then that slot is optional.
12161 *
12162 * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
12163 * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
12164 *
12165 * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
12166 * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
12167 * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
12168 * injectable into the directive's controller.
12169 *
12170 *
12171 * #### Transclusion Functions
12172 *
12173 * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
12174 * function** to the directive's `link` function and `controller`. This transclusion function is a special
12175 * **linking function** that will return the compiled contents linked to a new transclusion scope.
12176 *
12177 * <div class="alert alert-info">
12178 * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
12179 * ngTransclude will deal with it for us.
12180 * </div>
12181 *
12182 * If you want to manually control the insertion and removal of the transcluded content in your directive
12183 * then you must use this transclude function. When you call a transclude function it returns a a jq
12183Lite/JQuery
12184 * object that contains the compiled DOM, which is linked to the correct transclusion scope.
12185 *
12186 * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
12187 * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
12188 * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
12189 *
12190 * <div class="alert alert-info">
12191 * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
12192 * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
12193 * </div>
12194 *
12195 * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
12196 * attach function**:
12197 *
12198 * ```js
12199 * var transcludedContent, transclusionScope;
12200 *
12201 * $transclude(function(clone, scope) {
12202 *   element.append(clone);
12203 *   transcludedContent = clone;
12204 *   transclusionScope = scope;
12205 * });
12206 * ```
12207 *
12208 * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
12209 * associated transclusion scope:
12210 *
12211 * ```js
12212 * transcludedContent.remove();
12213 * transclusionScope.$destroy();
12214 * ```
12215 *
12216 * <div class="alert alert-info">
12217 * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
12218 * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
12219 * then you are also responsible for calling `$destroy` on the transclusion scope.
12220 * </div>
12221 *
12222 * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
12223 * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
12224 * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
12225 *
12226 *
12227 * #### Transclusion Scopes
12228 *
12229 * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
12230 * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
12231 * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
12232 * was taken.
12233 *
12234 * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
12235 * like this:
12236 *
12237 * ```html
12238 * <div ng-app>
12239 *   <div isolate>
12240 *     <div transclusion>
12241 *     </div>
12242 *   </div>
12243 * </div>
12244 * ```
12245 *
12246 * The `$parent` scope hierarchy will look like this:
12247 *
12248   ```
12249   - $rootScope
12250     - isolate
12251       - transclusion
12252   ```
12253 *
12254 * but the scopes will inherit prototypically from different scopes to their `$parent`.
12255 *
12256   ```
12257   - $rootScope
12258     - transclusion
12259   - isolate
12260   ```
12261 *
12262 *
12263 * ### Attributes
12264 *
12265 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
12266 * `link()` or `compile()` functions. It has a variety of uses.
12267 *
12268 * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
12269 *   'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
12270 *   to the attributes.
12271 *
12272 * * *Directive inter-communication:* All directives share the same instance of the attributes
12273 *   object which allows the directives to use the attributes object as inter directive
12274 *   communication.
12275 *
12276 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
12277 *   allowing other directives to read the interpolated value.
12278 *
12279 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
12280 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
12281 *   the only way to easily get the actual value because during the linking phase the interpolation
12282 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
12283 *
12284 * ```js
12285 * function linkingFn(scope, elm, attrs, ctrl) {
12286 *   // get the attribute value
12287 *   console.log(attrs.ngModel);
12288 *
12289 *   // change the attribute
12290 *   attrs.$set('ngModel', 'new value');
12291 *
12292 *   // observe changes to interpolated attribute
12293 *   attrs.$observe('ngModel', function(value) {
12294 *     console.log('ngModel has changed value to ' + value);
12295 *   });
12296 * }
12297 * ```
12298 *
12299 * ## Example
12300 *
12301 * <div class="alert alert-warning">
12302 * **Note**: Typically directives are registered with `module.directive`. The example below is
12303 * to illustrate how `$compile` works.
12304 * </div>
12305 *
12306 <example module="compileExample">
12307   <file name="index.html">
12308    <script>
12309      angular.module('compileExample', [], function($compileProvider) {
12310        // configure new 'compile' directive by passing a directive
12311        // factory function. The factory function injects the '$compile'
12312        $compileProvider.directive('compile', function($compile) {
12313          // directive factory creates a link function
12314          return function(scope, element, attrs) {
12315            scope.$watch(
12316              function(scope) {
12317                 // watch the 'compile' expression for changes
12318                return scope.$eval(attrs.compile);
12319              },
12320              function(value) {
12321                // when the 'compile' expression changes
12322                // assign it into the current DOM
12323                element.html(value);
12324
12325                // compile the new DOM and link it to the current
12326                // scope.
12327                // NOTE: we only compile .childNodes so that
12328                // we don't get into infinite loop compiling ourselves
12329                $compile(element.contents())(scope);
12330              }
12331            );
12332          };
12333        });
12334      })
12335      .controller('GreeterController', ['$scope', function($scope) {
12336        $scope.name = 'Angular';
12337        $scope.html = 'Hello {{name}}';
12338      }]);
12339    </script>
12340    <div ng-controller="GreeterController">
12341      <input ng-model="name"> <br/>
12342      <textarea ng-model="html"></textarea> <br/>
12343      <div compile="html"></div>
12344    </div>
12345   </file>
12346   <file name="protractor.js" type="protractor">
12347     it('should auto compile', function() {
12348       var textarea = $('textarea');
12349       var output = $('div[compile]');
12350       // The initial state reads 'Hello Angular'.
12351       expect(output.getText()).toBe('Hello Angular');
12352       textarea.clear();
12353       textarea.sendKeys('{{name}}!');
12354       expect(output.getText()).toBe('Angular!');
12355     });
12356   </file>
12357 </example>
12358
12359 *
12360 *
12361 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
12362 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
12363 *
12364 * <div class="alert alert-danger">
12365 * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
12366 *   e.g. will not use the right outer scope. Please pass the transclude function as a
12367 *   `parentBoundTranscludeFn` to the link function instead.
12368 * </div>
12369 *
12370 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
12371 *                 root element(s), not their children)
12372 * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
12373 * (a DOM element/tree) to a scope. Where:
12374 *
12375 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
12376 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
12377 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
12378 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
12379 *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
12380 *
12381 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
12382 *      * `scope` - is the current scope with which the linking function is working with.
12383 *
12384 *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
12385 *  keys may be used to control linking behavior:
12386 *
12387 *      * `parentBoundTranscludeFn` - the transclude function made available to
12388 *        directives; if given, it will be passed through to the link functions of
12389 *        directives found in `element` during compilation.
12390 *      * `transcludeControllers` - an object hash with keys that map controller names
12391 *        to a hash with the key `instance`, which maps to the controller instance;
12392 *        if given, it will make the controllers available to directives on the compileNode:
12393 *        ```
12394 *        {
12395 *          parent: {
12396 *            instance: parentControllerInstance
12397 *          }
12398 *        }
12399 *        ```
12400 *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
12401 *        the cloned elements; only needed for transcludes that are allowed to contain non html
12402 *        elements (e.g. SVG elements). See also the directive.controller property.
12403 *
12404 * Calling the linking function returns the element of the template. It is either the original
12405 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
12406 *
12407 * After linking the view is not updated until after a call to $digest which typically is done by
12408 * Angular automatically.
12409 *
12410 * If you need access to the bound view, there are two ways to do it:
12411 *
12412 * - If you are not asking the linking function to clone the template, create the DOM element(s)
12413 *   before you send them to the compiler and keep this reference around.
12414 *   ```js
12415 *     var element = $compile('<p>{{total}}</p>')(scope);
12416 *   ```
12417 *
12418 * - if on the other hand, you need the element to be cloned, the view reference from the original
12419 *   example would not point to the clone, but rather to the original template that was cloned. In
12420 *   this case, you can access the clone via the cloneAttachFn:
12421 *   ```js
12422 *     var templateElement = angular.element('<p>{{total}}</p>'),
12423 *         scope = ....;
12424 *
12425 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
12426 *       //attach the clone to DOM document at the right place
12427 *     });
12428 *
12429 *     //now we have reference to the cloned DOM via `clonedElement`
12430 *   ```
12431 *
12432 *
12433 * For information on how the compiler works, see the
12434 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
12435 */
12436
12437var $compileMinErr = minErr('$compile');
12438
12439/**
12440 * @ngdoc provider
12441 * @name $compileProvider
12442 *
12443 * @description
12444 */
vendor: 4,870 bytes, lines 12445-12568
12445$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
12446function $CompileProvider($provide, $$sanitizeUriProvider) {
12447  var hasDirectives = {},
12448      Suffix = 'Directive',
12449      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
12450      CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
12451      ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
12452      REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
12453
12454  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
12455  // The assumption is that future DOM event attribute names will begin with
12456  // 'on' and be composed of only English letters.
12457  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
12458  var bindingCache = createMap();
12459
12460  function parseIsolateBindings(scope, directiveName, isController) {
12461    var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
12462
12463    var bindings = {};
12464
12465    forEach(scope, function(definition, scopeName) {
12466      if (definition in bindingCache) {
12467        bindings[scopeName] = bindingCache[definition];
12468        return;
12469      }
12470      var match = definition.match(LOCAL_REGEXP);
12471
12472      if (!match) {
12473        throw $compileMinErr('iscp',
12474            "Invalid {3} for directive '{0}'." +
12475            " Definition: {... {1}: '{2}' ...}",
12476            directiveName, scopeName, definition,
12477            (isController ? "controller bindings definition" :
12478            "isolate scope definition"));
12479      }
12480
12481      bindings[scopeName] = {
12482        mode: match[1][0],
12483        collection: match[2] === '*',
12484        optional: match[3] === '?',
12485        attrName: match[4] || scopeName
12486      };
12487      if (match[4]) {
12488        bindingCache[definition] = bindings[scopeName];
12489      }
12490    });
12491
12492    return bindings;
12493  }
12494
12495  function parseDirectiveBindings(directive, directiveName) {
12496    var bindings = {
12497      isolateScope: null,
12498      bindToController: null
12499    };
12500    if (isObject(directive.scope)) {
12501      if (directive.bindToController === true) {
12502        bindings.bindToController = parseIsolateBindings(directive.scope,
12503                                                         directiveName, true);
12504        bindings.isolateScope = {};
12505      } else {
12506        bindings.isolateScope = parseIsolateBindings(directive.scope,
12507                                                     directiveName, false);
12508      }
12509    }
12510    if (isObject(directive.bindToController)) {
12511      bindings.bindToController =
12512          parseIsolateBindings(directive.bindToController, directiveName, true);
12513    }
12514    if (isObject(bindings.bindToController)) {
12515      var controller = directive.controller;
12516      var controllerAs = directive.controllerAs;
12517      if (!controller) {
12518        // There is no controller, there may or may not be a controllerAs property
12519        throw $compileMinErr('noctrl',
12520              "Cannot bind to controller without directive '{0}'s controller.",
12521              directiveName);
12522      } else if (!identifierForController(controller, controllerAs)) {
12523        // There is a controller, but no identifier or controllerAs property
12524        throw $compileMinErr('noident',
12525              "Cannot bind to controller without identifier for directive '{0}'.",
12526              directiveName);
12527      }
12528    }
12529    return bindings;
12530  }
12531
12532  function assertValidDirectiveName(name) {
12533    var letter = name.charAt(0);
12534    if (!letter || letter !== lowercase(letter)) {
12535      throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
12536    }
12537    if (name !== name.trim()) {
12538      throw $compileMinErr('baddir',
12539            "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
12540            name);
12541    }
12542  }
12543
12544  /**
12545   * @ngdoc method
12546   * @name $compileProvider#directive
12547   * @kind function
12548   *
12549   * @description
12550   * Register a new directive with the compiler.
12551   *
12552   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
12553   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
12554   *    names and the values are the factories.
12555   * @param {Function|Array} directiveFactory An injectable directive factory function. See the
12556   *    {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
12557   * @returns {ng.$compileProvider} Self for chaining.
12558   */
12559  this.directive = function registerDirective(name, directiveFactory) {
12560    assertNotHasOwnProperty(name, 'directive');
12561    if (isString(name)) {
12562      assertValidDirectiveName(name);
12563      assertArg(directiveFactory, 'directiveFactory');
12564      if (!hasDirectives.hasOwnProperty(name)) {
12565        hasDirectives[name] = [];
12566        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
12567          function($injector, $exceptionHandler) {
12568            var directives = [];
12569            forEach(hasDirectives[name], function(directiveFactory, index) {
12570              try {
12571                var directive = $injector.invoke(directiveFactory);
12572                if (isFunction(directive)) {
12573                  directive = { compile: valueFn(directive) };
12574                } else if (!directive.compile && directive.link) {
12575                  directive.compile = valueFn(directive.link);
12576                }
12577                directive.priority = directive.priority || 0;
12578                directive.index = index;
12579                directive.name = directive.name || name;
12580                directive.require = directive.require || (directive.controller && directive.name);
12581                directive.restrict = directive.restrict || 'EA';
12582                directive.$$moduleName = directiveFactory.$$moduleName;
12583                directives.push(directive);
12584              } catch (e) {
12585                $exceptionHandler(e);
12586              }
12587            });
12588            return directives;
12589          }]);
12590      }
12591      hasDirectives[name].push(directiveFactory);
12592    } else {
12593      forEach(name, reverseParams(registerDirective));
12594    }
12595    return this;
12596  };
12597
12598  /**
12599   * @ngdoc method
12600   * @name $compileProvider#component
12601   * @module ng
12602   * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
12603   * @param {Object} options Component definition object (a simplified
12604   *    {@link ng.$compile#directive-definition-object directive definition object}),
12605   *    with the following properties (all optional):
12606   *
12607   *    - `controller` – `{(string|function()=}` – controller constructor function that should be
12608   *      associated with newly created scope or the name of a {@link ng.$compile#-controller-
12609   *      registered controller} if passed as a string. An empty `noop` function by default.
12610   *    - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
12611   *      If present, the controller will be published to scope under the `controllerAs` name.
12612   *      If not present, this will default to be `$ctrl`.
12613   *    - `template` – `{string=|function()=}` – html template as a string or a function that
12614   *      returns an html template as a string which should be used as the contents of this component.
12615   *      Empty string by default.
12616   *
12617   *      If `template` is a function, then it is {@link auto.$injector#invoke injected} with
12618   *      the following locals:
12619   *
12620   *      - `$element` - Current element
12621   *      - `$attrs` - Current attributes object for the element
12622   *
12623   *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
12624   *      template that should be used  as the contents of this component.
12625   *
12626   *      If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
12627   *      the following locals:
12628   *
12629   *      - `$element` - Current element
12630   *      - `$attrs` - Current attributes object for the element
12631   *
12632   *    - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
12633   *      Component properties are always bound to the component controller and not to the scope.
12634   *      See {@link ng.$compile#-bindtocontroller- `bindToController`}.
12635   *    - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
12636   *      Disabled by default.
12637   *    - `$...` – additional properties to attach to the directive factory function and the controller
12638   *      constructor function. (This is used by the component router to annotate)
12639   *
12640   * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
12641   * @description
12642   * Register a **component definition** with the compiler. This is a shorthand for registering a special
12643   * type of directive, which represents a self-contained UI component in your application. Such components
12644   * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
12645   *
12646   * Component definitions are very simple and do not require as much configuration as defining general
12647   * directives. Component definitions usually consist only of a template and a controller backing it.
12648   *
12649   * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
12650   * `bindToController`. They always have **isolate scope** and are restricted to elements.
12651   *
12652   * Here are a few examples of how you would usually define components:
12653   *
12654   * ```js
12655   *   var myMod = angular.module(...);
12656   *   myMod.component('myComp', {
12657   *     template: '<div>My name is {{$ctrl.name}}</div>',
12658   *     controller: function() {
12659   *       this.name = 'shahar';
12660   *     }
12661   *   });
12662   *
12663   *   myMod.component('myComp', {
12664   *     template: '<div>My name is {{$ctrl.name}}</div>',
12665   *     bindings: {name: '@'}
12666   *   });
12667   *
12668   *   myMod.component('myComp', {
12669   *     templateUrl: 'views/my-comp.html',
12670   *     controller: 'MyCtrl',
12671   *     controllerAs: 'ctrl',
12672   *     bindings: {name: '@'}
12673   *   });
12674   *
12675   * ```
12676   * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
12677   *
12678   * <br />
12679   * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
12680   */
12681  this.component = function registerComponent(name, options) {
12682    var controller = options.controller || noop;
12683
12684    function factory($injector) {
12685      function makeInjectable(fn) {
12686        if (isFunction(fn) || isArray(fn)) {
12687          return function(tElement, tAttrs) {
12688            return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
12689          };
12690        } else {
12691          return fn;
12692        }
12693      }
12694
12695      var template = (!options.template && !options.templateUrl ? '' : options.template);
12696      return {
12697        controller: controller,
12698        controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
12699        template: makeInjectable(template),
12700        templateUrl: makeInjectable(options.templateUrl),
12701        transclude: options.transclude,
12702        scope: {},
12703        bindToController: options.bindings || {},
12704        restrict: 'E',
12705        require: options.require
12706      };
12707    }
12708
12709    // Copy any annotation properties (starting with $) over to the factory function
12710    // These could be used by libraries such as the new component router
12711    forEach(options, function(val, key) {
12712      if (key.charAt(0) === '$') {
12713        factory[key] = val;
12714        controller[key] = val;
12715      }
12716    });
12717
12718    factory.$inject = ['$injector'];
12719
12720    return this.directive(name, factory);
12721  };
12722
12723
12724  /**
12725   * @ngdoc method
12726   * @name $compileProvider#aHrefSanitizationWhitelist
12727   * @kind function
12728   *
12729   * @description
12730   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12731   * urls during a[href] sanitization.
12732   *
12733   * The sanitization is a security measure aimed at preventing XSS attacks via html links.
12734   *
12735   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12736   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12737   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12738   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12739   *
12740   * @param {RegExp=} regexp New regexp to whitelist urls with.
12741   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12742   *    chaining otherwise.
12743   */
12744  this.aHrefSanitizationWhitelist = function(regexp) {
12745    if (isDefined(regexp)) {
12746      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
12747      return this;
12748    } else {
12749      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
12750    }
12751  };
12752
12753
12754  /**
12755   * @ngdoc method
12756   * @name $compileProvider#imgSrcSanitizationWhitelist
12757   * @kind function
12758   *
12759   * @description
12760   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12761   * urls during img[src] sanitization.
12762   *
12763   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12764   *
12765   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12766   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12767   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12768   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12769   *
12770   * @param {RegExp=} regexp New regexp to whitelist urls with.
12771   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12772   *    chaining otherwise.
12773   */
12774  this.imgSrcSanitizationWhitelist = function(regexp) {
12775    if (isDefined(regexp)) {
12776      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
12777      return this;
12778    } else {
12779      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
12780    }
12781  };
12782
12783  /**
12784   * @ngdoc method
12785   * @name  $compileProvider#debugInfoEnabled
12786   *
12787   * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
12788   * current debugInfoEnabled state
12789   * @returns {*} current value if used as getter or itself (chaining) if used as setter
12790   *
12791   * @kind function
12792   *
12793   * @description
12794   * Call this method to enable/disable various debug runtime information in the compiler such as adding
12795   * binding information and a reference to the current scope on to DOM elements.
12796   * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
12797   * * `ng-binding` CSS class
12798   * * `$binding` data property containing an array of the binding expressions
12799   *
12800   * You may want to disable this in production for a significant performance boost. See
12801   * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
12802   *
12803   * The default value is true.
12804   */
12805  var debugInfoEnabled = true;
12806  this.debugInfoEnabled = function(enabled) {
12807    if (isDefined(enabled)) {
12808      debugInfoEnabled = enabled;
12809      return this;
12810    }
12811    return debugInfoEnabled;
12812  };
12813
12814  this.$get = [
12815            '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
12816            '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
12817    function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
12818             $controller,   $rootScope,   $sce,   $animate,   $$sanitizeUri) {
12819
12820    var SIMPLE_ATTR_NAME = /^\w/;
12821    var specialAttrHolder = document.createElement('div');
12822    var Attributes = function(element, attributesToCopy) {
12823      if (attributesToCopy) {
12824        var keys = Object.keys(attributesToCopy);
12825        var i, l, key;
12826
12827        for (i = 0, l = keys.length; i < l; i++) {
12828          key = keys[i];
12829          this[key] = attributesToCopy[key];
12830        }
12831      } else {
12832        this.$attr = {};
12833      }
12834
12835      this.$$element = element;
12836    };
12837
12838    Attributes.prototype = {
12839      /**
12840       * @ngdoc method
12841       * @name $compile.directive.Attributes#$normalize
12842       * @kind function
12843       *
12844       * @description
12845       * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
12846       * `data-`) to its normalized, camelCase form.
12847       *
12848       * Also there is special case for Moz prefix starting with upper case letter.
12849       *
12850       * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
12851       *
12852       * @param {string} name Name to normalize
12853       */
12854      $normalize: directiveNormalize,
12855
12856
12857      /**
12858       * @ngdoc method
12859       * @name $compile.directive.Attributes#$addClass
12860       * @kind function
12861       *
12862       * @description
12863       * Adds the CSS class value specified by the classVal parameter to the element. If animations
12864       * are enabled then an animation will be triggered for the class addition.
12865       *
12866       * @param {string} classVal The className value that will be added to the element
12867       */
12868      $addClass: function(classVal) {
12869        if (classVal && classVal.length > 0) {
12870          $animate.addClass(this.$$element, classVal);
12871        }
12872      },
12873
12874      /**
12875       * @ngdoc method
12876       * @name $compile.directive.Attributes#$removeClass
12877       * @kind function
12878       *
12879       * @description
12880       * Removes the CSS class value specified by the classVal parameter from the element. If
12881       * animations are enabled then an animation will be triggered for the class removal.
12882       *
12883       * @param {string} classVal The className value that will be removed from the element
12884       */
12885      $removeClass: function(classVal) {
12886        if (classVal && classVal.length > 0) {
12887          $animate.removeClass(this.$$element, classVal);
12888        }
12889      },
12890
12891      /**
12892       * @ngdoc method
12893       * @name $compile.directive.Attributes#$updateClass
12894       * @kind function
12895       *
12896       * @description
12897       * Adds and removes the appropriate CSS class values to the element based on the difference
12898       * between the new and old CSS class values (specified as newClasses and oldClasses).
12899       *
12900       * @param {string} newClasses The current CSS className value
12901       * @param {string} oldClasses The former CSS className value
12902       */
12903      $updateClass: function(newClasses, oldClasses) {
12904        var toAdd = tokenDifference(newClasses, oldClasses);
12905        if (toAdd && toAdd.length) {
12906          $animate.addClass(this.$$element, toAdd);
12907        }
12908
12909        var toRemove = tokenDifference(oldClasses, newClasses);
12910        if (toRemove && toRemove.length) {
12911          $animate.removeClass(this.$$element, toRemove);
12912        }
12913      },
12914
12915      /**
12916       * Set a normalized attribute on the element in a way such that all directives
12917       * can share the attribute. This function properly handles boolean attributes.
12918       * @param {string} key Normalized key. (ie ngAttribute)
12919       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
12920       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
12921       *     Defaults to true.
12922       * @param {string=} attrName Optional none normalized name. Defaults to key.
12923       */
12924      $set: function(key, value, writeAttr, attrName) {
12925        // TODO: decide whether or not to throw an error if "class"
12926        //is set through this function since it may cause $updateClass to
12927        //become unstable.
12928
12929        var node = this.$$element[0],
12930            booleanKey = getBooleanAttrName(node, key),
12931            aliasedKey = getAliasedAttrName(key),
12932            observer = key,
12933            nodeName;
12934
12935        if (booleanKey) {
12936          this.$$element.prop(key, value);
12937          attrName = booleanKey;
12938        } else if (aliasedKey) {
12939          this[aliasedKey] = value;
12940          observer = aliasedKey;
12941        }
12942
12943        this[key] = value;
12944
12945        // translate normalized key to actual key
12946        if (attrName) {
12947          this.$attr[key] = attrName;
12948        } else {
12949          attrName = this.$attr[key];
12950          if (!attrName) {
12951            this.$attr[key] = attrName = snake_case(key, '-');
12952          }
12953        }
12954
12955        nodeName = nodeName_(this.$$element);
12956
12957        if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
12958            (nodeName === 'img' && key === 'src')) {
12959          // sanitize a[href] and img[src] values
12960          this[key] = value = $$sanitizeUri(value, key === 'src');
12961        } else if (nodeName === 'img' && key === 'srcset') {
12962          // sanitize img[srcset] values
12963          var result = "";
12964
12965          // first check if there are spaces because it's not the same pattern
12966          var trimmedSrcset = trim(value);
12967          //                (   999x   ,|   999w   ,|   ,|,   )
12968          var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
12969          var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
12970
12971          // split srcset into tuple of uri and descriptor except for the last item
12972          var rawUris = trimmedSrcset.split(pattern);
12973
12974          // for each tuples
12975          var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
12976          for (var i = 0; i < nbrUrisWith2parts; i++) {
12977            var innerIdx = i * 2;
12978            // sanitize the uri
12979            result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
12980            // add the descriptor
12981            result += (" " + trim(rawUris[innerIdx + 1]));
12982          }
12983
12984          // split the last item into uri and descriptor
12985          var lastTuple = trim(rawUris[i * 2]).split(/\s/);
12986
12987          // sanitize the last uri
12988          result += $$sanitizeUri(trim(lastTuple[0]), true);
12989
12990          // and add the last descriptor if any
12991          if (lastTuple.length === 2) {
12992            result += (" " + trim(lastTuple[1]));
12993          }
12994          this[key] = value = result;
12995        }
12996
12997        if (writeAttr !== false) {
12998          if (value === null || isUndefined(value)) {
12999            this.$$element.removeAttr(attrName);
13000          } else {
13001            if (SIMPLE_ATTR_NAME.test(attrName)) {
13002              this.$$element.attr(attrName, value);
13003            } else {
13004              setSpecialAttr(this.$$element[0], attrName, value);
13005            }
13006          }
13007        }
13008
13009        // fire observers
13010        var $$observers = this.$$observers;
13011        $$observers && forEach($$observers[observer], function(fn) {
13012          try {
13013            fn(value);
13014          } catch (e) {
13015            $exceptionHandler(e);
13016          }
13017        });
13018      },
13019
13020
13021      /**
13022       * @ngdoc method
13023       * @name $compile.directive.Attributes#$observe
13024       * @kind function
13025       *
13026       * @description
13027       * Observes an interpolated attribute.
13028       *
13029       * The observer function will be invoked once during the next `$digest` following
13030       * compilation. The observer is then invoked whenever the interpolated value
13031       * changes.
13032       *
13033       * @param {string} key Normalized key. (ie ngAttribute) .
13034       * @param {function(interpolatedValue)} fn Function that will be called whenever
13035                the interpolated value of the attribute changes.
13036       *        See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
13037       *        guide} for more info.
13038       * @returns {function()} Returns a deregistration function for this observer.
13039       */
13040      $observe: function(key, fn) {
13041        var attrs = this,
13042            $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
13043            listeners = ($$observers[key] || ($$observers[key] = []));
13044
13045        listeners.push(fn);
13046        $rootScope.$evalAsync(function() {
13047          if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
13048            // no one registered attribute interpolation function, so lets call it manually
13049            fn(attrs[key]);
13050          }
13051        });
13052
13053        return function() {
13054          arrayRemove(listeners, fn);
13055        };
13056      }
13057    };
13058
13059    function setSpecialAttr(element, attrName, value) {
13060      // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
13061      // so we have to jump through some hoops to get such an attribute
13062      // https://github.com/angular/angular.js/pull/13318
13063      specialAttrHolder.innerHTML = "<span " + attrName + ">";
13064      var attributes = specialAttrHolder.firstChild.attributes;
13065      var attribute = attributes[0];
13066      // We have to remove the attribute from its container element before we can add it to the destination element
13067      attributes.removeNamedItem(attribute.name);
13068      attribute.value = value;
13069      element.attributes.setNamedItem(attribute);
13070    }
13071
13072    function safeAddClass($element, className) {
vendor: 12,676 bytes, lines 13073-13379
13073      try {
13074        $element.addClass(className);
13075      } catch (e) {
13076        // ignore, since it means that we are trying to set class on
13077        // SVG element, where class name is read-only.
13078      }
13079    }
13080
13081
13082    var startSymbol = $interpolate.startSymbol(),
13083        endSymbol = $interpolate.endSymbol(),
13084        denormalizeTemplate = (startSymbol == '{{' && endSymbol  == '}}')
13085            ? identity
13086            : function denormalizeTemplate(template) {
13087              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
13088        },
13089        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
13090    var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
13091
13092    compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
13093      var bindings = $element.data('$binding') || [];
13094
13095      if (isArray(binding)) {
13096        bindings = bindings.concat(binding);
13097      } else {
13098        bindings.push(binding);
13099      }
13100
13101      $element.data('$binding', bindings);
13102    } : noop;
13103
13104    compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
13105      safeAddClass($element, 'ng-binding');
13106    } : noop;
13107
13108    compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
13109      var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
13110      $element.data(dataName, scope);
13111    } : noop;
13112
13113    compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
13114      safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
13115    } : noop;
13116
13117    compile.$$createComment = function(directiveName, comment) {
13118      var content = '';
13119      if (debugInfoEnabled) {
13120        content = ' ' + (directiveName || '') + ': ' + (comment || '') + ' ';
13121      }
13122      return document.createComment(content);
13123    };
13124
13125    return compile;
13126
13127    //================================
13128
13129    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
13130                        previousCompileContext) {
13131      if (!($compileNodes instanceof jqLite)) {
13132        // jquery always rewraps, whereas we need to preserve the original selector so that we can
13133        // modify it.
13134        $compileNodes = jqLite($compileNodes);
13135      }
13136      var compositeLinkFn =
13137              compileNodes($compileNodes, transcludeFn, $compileNodes,
13138                           maxPriority, ignoreDirective, previousCompileContext);
13139      compile.$$addScopeClass($compileNodes);
13140      var namespace = null;
13141      return function publicLinkFn(scope, cloneConnectFn, options) {
13142        assertArg(scope, 'scope');
13143
13144        if (previousCompileContext && previousCompileContext.needsNewScope) {
13145          // A parent directive did a replace and a directive on this element asked
13146          // for transclusion, which caused us to lose a layer of element on which
13147          // we could hold the new transclusion scope, so we will create it manually
13148          // here.
13149          scope = scope.$parent.$new();
13150        }
13151
13152        options = options || {};
13153        var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
13154          transcludeControllers = options.transcludeControllers,
13155          futureParentElement = options.futureParentElement;
13156
13157        // When `parentBoundTranscludeFn` is passed, it is a
13158        // `controllersBoundTransclude` function (it was previously passed
13159        // as `transclude` to directive.link) so we must unwrap it to get
13160        // its `boundTranscludeFn`
13161        if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
13162          parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
13163        }
13164
13165        if (!namespace) {
13166          namespace = detectNamespaceForChildElements(futureParentElement);
13167        }
13168        var $linkNode;
13169        if (namespace !== 'html') {
13170          // When using a directive with replace:true and templateUrl the $compileNodes
13171          // (or a child element inside of them)
13172          // might change, so we need to recreate the namespace adapted compileNodes
13173          // for call to the link function.
13174          // Note: This will already clone the nodes...
13175          $linkNode = jqLite(
13176            wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
13177          );
13178        } else if (cloneConnectFn) {
13179          // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
13180          // and sometimes changes the structure of the DOM.
13181          $linkNode = JQLitePrototype.clone.call($compileNodes);
13182        } else {
13183          $linkNode = $compileNodes;
13184        }
13185
13186        if (transcludeControllers) {
13187          for (var controllerName in transcludeControllers) {
13188            $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
13189          }
13190        }
13191
13192        compile.$$addScopeInfo($linkNode, scope);
13193
13194        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
13195        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
13196        return $linkNode;
13197      };
13198    }
13199
13200    function detectNamespaceForChildElements(parentElement) {
13201      // TODO: Make this detect MathML as well...
13202      var node = parentElement && parentElement[0];
13203      if (!node) {
13204        return 'html';
13205      } else {
13206        return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
13207      }
13208    }
13209
13210    /**
13211     * Compile function matches each node in nodeList against the directives. Once all directives
13212     * for a particular node are collected their compile functions are executed. The compile
13213     * functions return values - the linking functions - are combined into a composite linking
13214     * function, which is the a linking function for the node.
13215     *
13216     * @param {NodeList} nodeList an array of nodes or NodeList to compile
13217     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
13218     *        scope argument is auto-generated to the new child of the transcluded parent scope.
13219     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
13220     *        the rootElement must be set the jqLite collection of the compile root. This is
13221     *        needed so that the jqLite collection items can be replaced with widgets.
13222     * @param {number=} maxPriority Max directive priority.
13223     * @returns {Function} A composite linking function of all of the matched directives or null.
13224     */
13225    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
13226                            previousCompileContext) {
13227      var linkFns = [],
13228          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
13229
13230      for (var i = 0; i < nodeList.length; i++) {
13231        attrs = new Attributes();
13232
13233        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
13234        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
13235                                        ignoreDirective);
13236
13237        nodeLinkFn = (directives.length)
13238            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
13239                                      null, [], [], previousCompileContext)
13240            : null;
13241
13242        if (nodeLinkFn && nodeLinkFn.scope) {
13243          compile.$$addScopeClass(attrs.$$element);
13244        }
13245
13246        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
13247                      !(childNodes = nodeList[i].childNodes) ||
13248                      !childNodes.length)
13249            ? null
13250            : compileNodes(childNodes,
13251                 nodeLinkFn ? (
13252                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
13253                     && nodeLinkFn.transclude) : transcludeFn);
13254
13255        if (nodeLinkFn || childLinkFn) {
13256          linkFns.push(i, nodeLinkFn, childLinkFn);
13257          linkFnFound = true;
13258          nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
13259        }
13260
13261        //use the previous context only for the first element in the virtual group
13262        previousCompileContext = null;
13263      }
13264
13265      // return a linking function if we have found anything, null otherwise
13266      return linkFnFound ? compositeLinkFn : null;
13267
13268      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
13269        var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
13270        var stableNodeList;
13271
13272
13273        if (nodeLinkFnFound) {
13274          // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
13275          // offsets don't get screwed up
13276          var nodeListLength = nodeList.length;
13277          stableNodeList = new Array(nodeListLength);
13278
13279          // create a sparse array by only copying the elements which have a linkFn
13280          for (i = 0; i < linkFns.length; i+=3) {
13281            idx = linkFns[i];
13282            stableNodeList[idx] = nodeList[idx];
13283          }
13284        } else {
13285          stableNodeList = nodeList;
13286        }
13287
13288        for (i = 0, ii = linkFns.length; i < ii;) {
13289          node = stableNodeList[linkFns[i++]];
13290          nodeLinkFn = linkFns[i++];
13291          childLinkFn = linkFns[i++];
13292
13293          if (nodeLinkFn) {
13294            if (nodeLinkFn.scope) {
13295              childScope = scope.$new();
13296              compile.$$addScopeInfo(jqLite(node), childScope);
13297            } else {
13298              childScope = scope;
13299            }
13300
13301            if (nodeLinkFn.transcludeOnThisElement) {
13302              childBoundTranscludeFn = createBoundTranscludeFn(
13303                  scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
13304
13305            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
13306              childBoundTranscludeFn = parentBoundTranscludeFn;
13307
13308            } else if (!parentBoundTranscludeFn && transcludeFn) {
13309              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
13310
13311            } else {
13312              childBoundTranscludeFn = null;
13313            }
13314
13315            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
13316
13317          } else if (childLinkFn) {
13318            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
13319          }
13320        }
13321      }
13322    }
13323
13324    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
13325
13326      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
13327
13328        if (!transcludedScope) {
13329          transcludedScope = scope.$new(false, containingScope);
13330          transcludedScope.$$transcluded = true;
13331        }
13332
13333        return transcludeFn(transcludedScope, cloneFn, {
13334          parentBoundTranscludeFn: previousBoundTranscludeFn,
13335          transcludeControllers: controllers,
13336          futureParentElement: futureParentElement
13337        });
13338      };
13339
13340      // We need  to attach the transclusion slots onto the `boundTranscludeFn`
13341      // so that they are available inside the `controllersBoundTransclude` function
13342      var boundSlots = boundTranscludeFn.$$slots = createMap();
13343      for (var slotName in transcludeFn.$$slots) {
13344        if (transcludeFn.$$slots[slotName]) {
13345          boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
13346        } else {
13347          boundSlots[slotName] = null;
13348        }
13349      }
13350
13351      return boundTranscludeFn;
13352    }
13353
13354    /**
13355     * Looks for directives on the given node and adds them to the directive collection which is
13356     * sorted.
13357     *
13358     * @param node Node to search.
13359     * @param directives An array to which the directives are added to. This array is sorted before
13360     *        the function returns.
13361     * @param attrs The shared attrs object which is used to populate the normalized attributes.
13362     * @param {number=} maxPriority Max directive priority.
13363     */
13364    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
13365      var nodeType = node.nodeType,
13366          attrsMap = attrs.$attr,
13367          match,
13368          className;
13369
13370      switch (nodeType) {
13371        case NODE_TYPE_ELEMENT: /* Element */
13372          // use the node name: <directive>
13373          addDirective(directives,
13374              directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
13375
13376          // iterate over the attributes
13377          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
13378                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
13379            var attrStartName = false;
13380            var attrEndName = false;
13381
13382            attr = nAttrs[j];
13383            name = attr.name;
13384            value = trim(attr.value);
13385
13386            // support ngAttr attribute binding
13387            ngAttrName = directiveNormalize(name);
13388            if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
13389              name = name.replace(PREFIX_REGEXP, '')
13390                .substr(8).replace(/_(.)/g, function(match, letter) {
13391                  return letter.toUpperCase();
13392                });
13393            }
13394
13395            var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
13396            if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
13397              attrStartName = name;
13398              attrEndName = name.substr(0, name.length - 5) + 'end';
13399              name = name.substr(0, name.length - 6);
13400            }
13401
13402            nName = directiveNormalize(name.toLowerCase());
13403            attrsMap[nName] = name;
13404            if (isNgAttr || !attrs.hasOwnProperty(nName)) {
13405                attrs[nName] = value;
13406                if (getBooleanAttrName(node, nName)) {
13407                  attrs[nName] = true; // presence means true
13408                }
13409            }
13410            addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
13411            addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
13412                          attrEndName);
13413          }
13414
13415          // use class as directive
13416          className = node.className;
13417          if (isObject(className)) {
13418              // Maybe SVGAnimatedString
13419              className = className.animVal;
13420          }
13421          if (isString(className) && className !== '') {
13422            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
13423              nName = directiveNormalize(match[2]);
13424              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
13425                attrs[nName] = trim(match[3]);
13426              }
13427              className = className.substr(match.index + match[0].length);
13428            }
13429          }
13430          break;
13431        case NODE_TYPE_TEXT: /* Text Node */
13432          if (msie === 11) {
13433            // Workaround for #11781
13434            while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
13435              node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
13436              node.parentNode.removeChild(node.nextSibling);
13437            }
13438          }
13439          addTextInterpolateDirective(directives, node.nodeValue);
13440          break;
13441        case NODE_TYPE_COMMENT: /* Comment */
13442          try {
13443            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
13444            if (match) {
13445              nName = directiveNormalize(match[1]);
13446              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
13447                attrs[nName] = trim(match[2]);
13448              }
13449            }
13450          } catch (e) {
13451            // turns out that under some circumstances IE9 throws errors when one attempts to read
13452            // comment's node value.
13453            // Just ignore it and continue. (Can't seem to reproduce in test case.)
13454          }
13455          break;
13456      }
13457
13458      directives.sort(byPriority);
13459      return directives;
13460    }
13461
13462    /**
13463     * Given a node with an directive-start it collects all of the siblings until it finds
13464     * directive-end.
13465     * @param node
13466     * @param attrStart
13467     * @param attrEnd
13468     * @returns {*}
13469     */
13470    function groupScan(node, attrStart, attrEnd) {
13471      var nodes = [];
13472      var depth = 0;
13473      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
13474        do {
13475          if (!node) {
13476            throw $compileMinErr('uterdir',
13477                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
13478                      attrStart, attrEnd);
13479          }
13480          if (node.nodeType == NODE_TYPE_ELEMENT) {
13481            if (node.hasAttribute(attrStart)) depth++;
13482            if (node.hasAttribute(attrEnd)) depth--;
13483          }
13484          nodes.push(node);
13485          node = node.nextSibling;
13486        } while (depth > 0);
13487      } else {
13488        nodes.push(node);
13489      }
13490
13491      return jqLite(nodes);
13492    }
13493
13494    /**
13495     * Wrapper for linking function which converts normal linking function into a grouped
13496     * linking function.
13497     * @param linkFn
13498     * @param attrStart
13499     * @param attrEnd
13500     * @returns {Function}
13501     */
13502    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
13503      return function(scope, element, attrs, controllers, transcludeFn) {
13504        element = groupScan(element[0], attrStart, attrEnd);
13505        return linkFn(scope, element, attrs, controllers, transcludeFn);
13506      };
13507    }
13508
13509    /**
13510     * A function generator that is used to support both eager and lazy compilation
13511     * linking function.
13512     * @param eager
13513     * @param $compileNodes
13514     * @param transcludeFn
13515     * @param maxPriority
13516     * @param ignoreDirective
13517     * @param previousCompileContext
13518     * @returns {Function}
13519     */
13520    function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
13521      var compiled;
13522
13523      if (eager) {
13524        return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
13525      }
13526      return function() {
13527        if (!compiled) {
13528          compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
13529
13530          // Null out all of these references in order to make them eligible for garbage collection
13531          // since this is a potentially long lived closure
13532          $compileNodes = transcludeFn = previousCompileContext = null;
13533        }
13534        return compiled.apply(this, arguments);
13535      };
13536    }
13537
13538    /**
13539     * Once the directives have been collected, their compile functions are executed. This method
13540     * is responsible for inlining directive templates as well as terminating the application
13541     * of the directives if the terminal directive has been reached.
13542     *
13543     * @param {Array} directives Array of collected directives to execute their compile function.
13544     *        this needs to be pre-sorted by priority order.
13545     * @param {Node} compileNode The raw DOM node to apply the compile functions to
13546     * @param {Object} templateAttrs The shared attribute function
13547     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
13548     *                                                  scope argument is auto-generated to the new
13549     *                                                  child of the transcluded parent scope.
13550     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
13551     *                              argument has the root jqLite array so that we can replace nodes
13552     *                              on it.
13553     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
13554     *                                           compiling the transclusion.
13555     * @param {Array.<Function>} preLinkFns
13556     * @param {Array.<Function>} postLinkFns
13557     * @param {Object} previousCompileContext Context used for previous compilation of the current
13558     *                                        node
13559     * @returns {Function} linkFn
13560     */
13561    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
13562                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
13563                                   previousCompileContext) {
13564      previousCompileContext = previousCompileContext || {};
13565
13566      var terminalPriority = -Number.MAX_VALUE,
13567          newScopeDirective = previousCompileContext.newScopeDirective,
13568          controllerDirectives = previousCompileContext.controllerDirectives,
13569          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
13570          templateDirective = previousCompileContext.templateDirective,
13571          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
13572          hasTranscludeDirective = false,
13573          hasTemplate = false,
13574          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
13575          $compileNode = templateAttrs.$$element = jqLite(compileNode),
13576          directive,
13577          directiveName,
13578          $template,
13579          replaceDirective = originalReplaceDirective,
13580          childTranscludeFn = transcludeFn,
13581          linkFn,
13582          didScanForMultipleTransclusion = false,
13583          mightHaveMultipleTransclusionError = false,
13584          directiveValue;
13585
13586      // executes all directives on the current element
13587      for (var i = 0, ii = directives.length; i < ii; i++) {
13588        directive = directives[i];
13589        var attrStart = directive.$$start;
13590        var attrEnd = directive.$$end;
13591
13592        // collect multiblock sections
13593        if (attrStart) {
13594          $compileNode = groupScan(compileNode, attrStart, attrEnd);
13595        }
13596        $template = undefined;
13597
13598        if (terminalPriority > directive.priority) {
13599          break; // prevent further processing of directives
13600        }
13601
13602        if (directiveValue = directive.scope) {
13603
13604          // skip the check for directives with async templates, we'll check the derived sync
13605          // directive when the template arrives
13606          if (!directive.templateUrl) {
13607            if (isObject(directiveValue)) {
13608              // This directive is trying to add an isolated scope.
13609              // Check that there is no scope of any kind already
13610              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
13611                                directive, $compileNode);
13612              newIsolateScopeDirective = directive;
13613            } else {
13614              // This directive is trying to add a child scope.
13615              // Check that there is no isolated scope already
13616              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
13617                                $compileNode);
13618            }
13619          }
13620
13621          newScopeDirective = newScopeDirective || directive;
13622        }
13623
13624        directiveName = directive.name;
13625
13626        // If we encounter a condition that can result in transclusion on the directive,
13627        // then scan ahead in the remaining directives for others that may cause a multiple
13628        // transclusion error to be thrown during the compilation process.  If a matching directive
13629        // is found, then we know that when we encounter a transcluded directive, we need to eagerly
13630        // compile the `transclude` function rather than doing it lazily in order to throw
13631        // exceptions at the correct time
13632        if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
13633            || (directive.transclude && !directive.$$tlb))) {
13634                var candidateDirective;
13635
13636                for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
13637                    if ((candidateDirective.transclude && !candidateDirective.$$tlb)
13638                        || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
13639                        mightHaveMultipleTransclusionError = true;
13640                        break;
13641                    }
13642                }
13643
13644                didScanForMultipleTransclusion = true;
13645        }
13646
13647        if (!directive.templateUrl && directive.controller) {
13648          directiveValue = directive.controller;
13649          controllerDirectives = controllerDirectives || createMap();
13650          assertNoDuplicate("'" + directiveName + "' controller",
13651              controllerDirectives[directiveName], directive, $compileNode);
13652          controllerDirectives[directiveName] = directive;
13653        }
13654
13655        if (directiveValue = directive.transclude) {
13656          hasTranscludeDirective = true;
13657
13658          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
13659          // This option should only be used by directives that know how to safely handle element transclusion,
13660          // where the transcluded nodes are added or replaced after linking.
13661          if (!directive.$$tlb) {
13662            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
13663            nonTlbTranscludeDirective = directive;
13664          }
13665
13666          if (directiveValue == 'element') {
13667            hasElementTranscludeDirective = true;
13668            terminalPriority = directive.priority;
13669            $template = $compileNode;
13670            $compileNode = templateAttrs.$$element =
13671                jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
13672            compileNode = $compileNode[0];
13673            replaceWith(jqCollection, sliceArgs($template), compileNode);
13674
13675            childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
13676                                        replaceDirective && replaceDirective.name, {
13677                                          // Don't pass in:
13678                                          // - controllerDirectives - otherwise we'll create duplicates controllers
13679                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 22,091 bytes, lines 13679-14183
13679ining templates with
13680                                          //   element transclusion doesn't make sense.
13681                                          //
13682                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
13683                                          // on the same element more than once.
13684                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
13685                                        });
13686          } else {
13687
13688            var slots = createMap();
13689
13690            $template = jqLite(jqLiteClone(compileNode)).contents();
13691
13692            if (isObject(directiveValue)) {
13693
13694              // We have transclusion slots,
13695              // collect them up, compile them and store their transclusion functions
13696              $template = [];
13697
13698              var slotMap = createMap();
13699              var filledSlots = createMap();
13700
13701              // Parse the element selectors
13702              forEach(directiveValue, function(elementSelector, slotName) {
13703                // If an element selector starts with a ? then it is optional
13704                var optional = (elementSelector.charAt(0) === '?');
13705                elementSelector = optional ? elementSelector.substring(1) : elementSelector;
13706
13707                slotMap[elementSelector] = slotName;
13708
13709                // We explicitly assign `null` since this implies that a slot was defined but not filled.
13710                // Later when calling boundTransclusion functions with a slot name we only error if the
13711                // slot is `undefined`
13712                slots[slotName] = null;
13713
13714                // filledSlots contains `true` for all slots that are either optional or have been
13715                // filled. This is used to check that we have not missed any required slots
13716                filledSlots[slotName] = optional;
13717              });
13718
13719              // Add the matching elements into their slot
13720              forEach($compileNode.contents(), function(node) {
13721                var slotName = slotMap[directiveNormalize(nodeName_(node))];
13722                if (slotName) {
13723                  filledSlots[slotName] = true;
13724                  slots[slotName] = slots[slotName] || [];
13725                  slots[slotName].push(node);
13726                } else {
13727                  $template.push(node);
13728                }
13729              });
13730
13731              // Check for required slots that were not filled
13732              forEach(filledSlots, function(filled, slotName) {
13733                if (!filled) {
13734                  throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
13735                }
13736              });
13737
13738              for (var slotName in slots) {
13739                if (slots[slotName]) {
13740                  // Only define a transclusion function if the slot was filled
13741                  slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
13742                }
13743              }
13744            }
13745
13746            $compileNode.empty(); // clear contents
13747            childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
13748                undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
13749            childTranscludeFn.$$slots = slots;
13750          }
13751        }
13752
13753        if (directive.template) {
13754          hasTemplate = true;
13755          assertNoDuplicate('template', templateDirective, directive, $compileNode);
13756          templateDirective = directive;
13757
13758          directiveValue = (isFunction(directive.template))
13759              ? directive.template($compileNode, templateAttrs)
13760              : directive.template;
13761
13762          directiveValue = denormalizeTemplate(directiveValue);
13763
13764          if (directive.replace) {
13765            replaceDirective = directive;
13766            if (jqLiteIsTextNode(directiveValue)) {
13767              $template = [];
13768            } else {
13769              $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
13770            }
13771            compileNode = $template[0];
13772
13773            if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
13774              throw $compileMinErr('tplrt',
13775                  "Template for directive '{0}' must have exactly one root element. {1}",
13776                  directiveName, '');
13777            }
13778
13779            replaceWith(jqCollection, $compileNode, compileNode);
13780
13781            var newTemplateAttrs = {$attr: {}};
13782
13783            // combine directives from the original node and from the template:
13784            // - take the array of directives for this element
13785            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
13786            // - collect directives from the template and sort them by priority
13787            // - combine directives as: processed + template + unprocessed
13788            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
13789            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
13790
13791            if (newIsolateScopeDirective || newScopeDirective) {
13792              // The original directive caused the current element to be replaced but this element
13793              // also needs to have a new scope, so we need to tell the template directives
13794              // that they would need to get their scope from further up, if they require transclusion
13795              markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
13796            }
13797            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
13798            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
13799
13800            ii = directives.length;
13801          } else {
13802            $compileNode.html(directiveValue);
13803          }
13804        }
13805
13806        if (directive.templateUrl) {
13807          hasTemplate = true;
13808          assertNoDuplicate('template', templateDirective, directive, $compileNode);
13809          templateDirective = directive;
13810
13811          if (directive.replace) {
13812            replaceDirective = directive;
13813          }
13814
13815          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
13816              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
13817                controllerDirectives: controllerDirectives,
13818                newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
13819                newIsolateScopeDirective: newIsolateScopeDirective,
13820                templateDirective: templateDirective,
13821                nonTlbTranscludeDirective: nonTlbTranscludeDirective
13822              });
13823          ii = directives.length;
13824        } else if (directive.compile) {
13825          try {
13826            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
13827            if (isFunction(linkFn)) {
13828              addLinkFns(null, linkFn, attrStart, attrEnd);
13829            } else if (linkFn) {
13830              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
13831            }
13832          } catch (e) {
13833            $exceptionHandler(e, startingTag($compileNode));
13834          }
13835        }
13836
13837        if (directive.terminal) {
13838          nodeLinkFn.terminal = true;
13839          terminalPriority = Math.max(terminalPriority, directive.priority);
13840        }
13841
13842      }
13843
13844      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
13845      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
13846      nodeLinkFn.templateOnThisElement = hasTemplate;
13847      nodeLinkFn.transclude = childTranscludeFn;
13848
13849      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
13850
13851      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
13852      return nodeLinkFn;
13853
13854      ////////////////////
13855
13856      function addLinkFns(pre, post, attrStart, attrEnd) {
13857        if (pre) {
13858          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
13859          pre.require = directive.require;
13860          pre.directiveName = directiveName;
13861          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
13862            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
13863          }
13864          preLinkFns.push(pre);
13865        }
13866        if (post) {
13867          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
13868          post.require = directive.require;
13869          post.directiveName = directiveName;
13870          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
13871            post = cloneAndAnnotateFn(post, {isolateScope: true});
13872          }
13873          postLinkFns.push(post);
13874        }
13875      }
13876
13877      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
13878        var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
13879            attrs, removeScopeBindingWatches, removeControllerBindingWatches;
13880
13881        if (compileNode === linkNode) {
13882          attrs = templateAttrs;
13883          $element = templateAttrs.$$element;
13884        } else {
13885          $element = jqLite(linkNode);
13886          attrs = new Attributes($element, templateAttrs);
13887        }
13888
13889        controllerScope = scope;
13890        if (newIsolateScopeDirective) {
13891          isolateScope = scope.$new(true);
13892        } else if (newScopeDirective) {
13893          controllerScope = scope.$parent;
13894        }
13895
13896        if (boundTranscludeFn) {
13897          // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
13898          // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
13899          transcludeFn = controllersBoundTransclude;
13900          transcludeFn.$$boundTransclude = boundTranscludeFn;
13901          // expose the slots on the `$transclude` function
13902          transcludeFn.isSlotFilled = function(slotName) {
13903            return !!boundTranscludeFn.$$slots[slotName];
13904          };
13905        }
13906
13907        if (controllerDirectives) {
13908          elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
13909        }
13910
13911        if (newIsolateScopeDirective) {
13912          // Initialize isolate scope bindings for new isolate scope directive.
13913          compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
13914              templateDirective === newIsolateScopeDirective.$$originalDirective)));
13915          compile.$$addScopeClass($element, true);
13916          isolateScope.$$isolateBindings =
13917              newIsolateScopeDirective.$$isolateBindings;
13918          removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
13919                                        isolateScope.$$isolateBindings,
13920                                        newIsolateScopeDirective);
13921          if (removeScopeBindingWatches) {
13922            isolateScope.$on('$destroy', removeScopeBindingWatches);
13923          }
13924        }
13925
13926        // Initialize bindToController bindings
13927        for (var name in elementControllers) {
13928          var controllerDirective = controllerDirectives[name];
13929          var controller = elementControllers[name];
13930          var bindings = controllerDirective.$$bindings.bindToController;
13931
13932          if (controller.identifier && bindings) {
13933            removeControllerBindingWatches =
13934              initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
13935          }
13936
13937          var controllerResult = controller();
13938          if (controllerResult !== controller.instance) {
13939            // If the controller constructor has a return value, overwrite the instance
13940            // from setupControllers
13941            controller.instance = controllerResult;
13942            $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
13943            removeControllerBindingWatches && removeControllerBindingWatches();
13944            removeControllerBindingWatches =
13945              initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
13946          }
13947        }
13948
13949        // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
13950        forEach(controllerDirectives, function(controllerDirective, name) {
13951          var require = controllerDirective.require;
13952          if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
13953            extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
13954          }
13955        });
13956
13957        // Trigger the `$onInit` method on all controllers that have one
13958        forEach(elementControllers, function(controller) {
13959          if (isFunction(controller.instance.$onInit)) {
13960            controller.instance.$onInit();
13961          }
13962        });
13963
13964        // PRELINKING
13965        for (i = 0, ii = preLinkFns.length; i < ii; i++) {
13966          linkFn = preLinkFns[i];
13967          invokeLinkFn(linkFn,
13968              linkFn.isolateScope ? isolateScope : scope,
13969              $element,
13970              attrs,
13971              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
13972              transcludeFn
13973          );
13974        }
13975
13976        // RECURSION
13977        // We only pass the isolate scope, if the isolate directive has a template,
13978        // otherwise the child elements do not belong to the isolate directive.
13979        var scopeToChild = scope;
13980        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
13981          scopeToChild = isolateScope;
13982        }
13983        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
13984
13985        // POSTLINKING
13986        for (i = postLinkFns.length - 1; i >= 0; i--) {
13987          linkFn = postLinkFns[i];
13988          invokeLinkFn(linkFn,
13989              linkFn.isolateScope ? isolateScope : scope,
13990              $element,
13991              attrs,
13992              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
13993              transcludeFn
13994          );
13995        }
13996
13997        // This is the function that is injected as `$transclude`.
13998        // Note: all arguments are optional!
13999        function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
14000          var transcludeControllers;
14001          // No scope passed in:
14002          if (!isScope(scope)) {
14003            slotName = futureParentElement;
14004            futureParentElement = cloneAttachFn;
14005            cloneAttachFn = scope;
14006            scope = undefined;
14007          }
14008
14009          if (hasElementTranscludeDirective) {
14010            transcludeControllers = elementControllers;
14011          }
14012          if (!futureParentElement) {
14013            futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
14014          }
14015          if (slotName) {
14016            // slotTranscludeFn can be one of three things:
14017            //  * a transclude function - a filled slot
14018            //  * `null` - an optional slot that was not filled
14019            //  * `undefined` - a slot that was not declared (i.e. invalid)
14020            var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
14021            if (slotTranscludeFn) {
14022              return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
14023            } else if (isUndefined(slotTranscludeFn)) {
14024              throw $compileMinErr('noslot',
14025               'No parent directive that requires a transclusion with slot name "{0}". ' +
14026               'Element: {1}',
14027               slotName, startingTag($element));
14028            }
14029          } else {
14030            return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
14031          }
14032        }
14033      }
14034    }
14035
14036    function getControllers(directiveName, require, $element, elementControllers) {
14037      var value;
14038
14039      if (isString(require)) {
14040        var match = require.match(REQUIRE_PREFIX_REGEXP);
14041        var name = require.substring(match[0].length);
14042        var inheritType = match[1] || match[3];
14043        var optional = match[2] === '?';
14044
14045        //If only parents then start at the parent element
14046        if (inheritType === '^^') {
14047          $element = $element.parent();
14048        //Otherwise attempt getting the controller from elementControllers in case
14049        //the element is transcluded (and has no data) and to avoid .data if possible
14050        } else {
14051          value = elementControllers && elementControllers[name];
14052          value = value && value.instance;
14053        }
14054
14055        if (!value) {
14056          var dataName = '$' + name + 'Controller';
14057          value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
14058        }
14059
14060        if (!value && !optional) {
14061          throw $compileMinErr('ctreq',
14062              "Controller '{0}', required by directive '{1}', can't be found!",
14063              name, directiveName);
14064        }
14065      } else if (isArray(require)) {
14066        value = [];
14067        for (var i = 0, ii = require.length; i < ii; i++) {
14068          value[i] = getControllers(directiveName, require[i], $element, elementControllers);
14069        }
14070      } else if (isObject(require)) {
14071        value = {};
14072        forEach(require, function(controller, property) {
14073          value[property] = getControllers(directiveName, controller, $element, elementControllers);
14074        });
14075      }
14076
14077      return value || null;
14078    }
14079
14080    function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
14081      var elementControllers = createMap();
14082      for (var controllerKey in controllerDirectives) {
14083        var directive = controllerDirectives[controllerKey];
14084        var locals = {
14085          $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
14086          $element: $element,
14087          $attrs: attrs,
14088          $transclude: transcludeFn
14089        };
14090
14091        var controller = directive.controller;
14092        if (controller == '@') {
14093          controller = attrs[directive.name];
14094        }
14095
14096        var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
14097
14098        // For directives with element transclusion the element is a comment.
14099        // In this case .data will not attach any data.
14100        // Instead, we save the controllers for the element in a local hash and attach to .data
14101        // later, once we have the actual element.
14102        elementControllers[directive.name] = controllerInstance;
14103        $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
14104      }
14105      return elementControllers;
14106    }
14107
14108    // Depending upon the context in which a directive finds itself it might need to have a new isolated
14109    // or child scope created. For instance:
14110    // * if the directive has been pulled into a template because another directive with a higher priority
14111    // asked for element transclusion
14112    // * if the directive itself asks for transclusion but it is at the root of a template and the original
14113    // element was replaced. See https://github.com/angular/angular.js/issues/12936
14114    function markDirectiveScope(directives, isolateScope, newScope) {
14115      for (var j = 0, jj = directives.length; j < jj; j++) {
14116        directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
14117      }
14118    }
14119
14120    /**
14121     * looks up the directive and decorates it with exception handling and proper parameters. We
14122     * call this the boundDirective.
14123     *
14124     * @param {string} name name of the directive to look up.
14125     * @param {string} location The directive must be found in specific format.
14126     *   String containing any of theses characters:
14127     *
14128     *   * `E`: element name
14129     *   * `A': attribute
14130     *   * `C`: class
14131     *   * `M`: comment
14132     * @returns {boolean} true if directive was added.
14133     */
14134    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
14135                          endAttrName) {
14136      if (name === ignoreDirective) return null;
14137      var match = null;
14138      if (hasDirectives.hasOwnProperty(name)) {
14139        for (var directive, directives = $injector.get(name + Suffix),
14140            i = 0, ii = directives.length; i < ii; i++) {
14141          try {
14142            directive = directives[i];
14143            if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
14144                 directive.restrict.indexOf(location) != -1) {
14145              if (startAttrName) {
14146                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
14147              }
14148              if (!directive.$$bindings) {
14149                var bindings = directive.$$bindings =
14150                    parseDirectiveBindings(directive, directive.name);
14151                if (isObject(bindings.isolateScope)) {
14152                  directive.$$isolateBindings = bindings.isolateScope;
14153                }
14154              }
14155              tDirectives.push(directive);
14156              match = directive;
14157            }
14158          } catch (e) { $exceptionHandler(e); }
14159        }
14160      }
14161      return match;
14162    }
14163
14164
14165    /**
14166     * looks up the directive and returns true if it is a multi-element directive,
14167     * and therefore requires DOM nodes between -start and -end markers to be grouped
14168     * together.
14169     *
14170     * @param {string} name name of the directive to look up.
14171     * @returns true if directive was registered as multi-element.
14172     */
14173    function directiveIsMultiElement(name) {
14174      if (hasDirectives.hasOwnProperty(name)) {
14175        for (var directive, directives = $injector.get(name + Suffix),
14176            i = 0, ii = directives.length; i < ii; i++) {
14177          directive = directives[i];
14178          if (directive.multiElement) {
14179            return true;
14180          }
14181        }
14182      }
14183      return false;
14184    }
14185
14186    /**
14187     * When the element is replaced with HTML template then the new attributes
14188     * on the template need to be merged with the existing attributes in the DOM.
14189     * The desired effect is to have both of the attributes present.
14190     *
14191     * @param {object} dst destination attributes (original DOM)
14192     * @param {object} src source attributes (from the directive template)
14193     */
14194    function mergeTemplateAttributes(dst, src) {
14195      var srcAttr = src.$attr,
14196          dstAttr = dst.$attr,
14197          $element = dst.$$element;
14198
14199      // reapply the old attributes to the new element
14200      forEach(dst, function(value, key) {
14201        if (key.charAt(0) != '$') {
14202          if (src[key] && src[key] !== value) {
14203            value += (key === 'style' ? ';' : ' ') + src[key];
14204          }
14205          dst.$set(key, value, true, srcAttr[key]);
14206        }
14207      });
14208
14209      // copy the new attributes on the old attrs object
14210      forEach(src, function(value, key) {
14211        if (key == 'class') {
14212          safeAddClass($element, value);
14213          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
14214        } else if (key == 'style') {
14215          $element.attr('style', $element.attr('style') + ';' + value);
14216          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
14217          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
14218          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
14219          // have an attribute like "has-own-property" or "data-has-own-property", etc.
14220        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
14221          dst[key] = value;
14222          dstAttr[key] = srcAttr[key];
14223        }
14224      });
14225    }
14226
14227
14228    function compileTemplateUrl(directives, $compileNode, tAttrs,
14229        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
14230      var linkQueue = [],
14231          afterTemplateNodeLinkFn,
14232          afterTemplateChildLinkFn,
14233          beforeTemplateCompileNode = $compileNode[0],
14234          origAsyncDirective = directives.shift(),
14235          derivedSyncDirective = inherit(origAsyncDirective, {
14236            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
14237          }),
14238          templateUrl = (isFunction(origAsyncDirective.templateUrl))
14239              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
14240              : origAsyncDirective.templateUrl,
14241          templateNamespace = origAsyncDirective.templateNamespace;
14242
14243      $compileNode.empty();
14244
14245      $templateRequest(templateUrl)
14246        .then(function(content) {
14247          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
14248
14249          content = denormalizeTemplate(content);
14250
14251          if (origAsyncDirective.replace) {
14252            if (jqLiteIsTextNode(content)) {
14253              $template = [];
14254            } else {
14255              $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
14256            }
14257            compileNode = $template[0];
14258
14259            if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
14260              throw $compileMinErr('tplrt',
14261                  "Template for directive '{0}' must have exactly one root element. {1}",
14262                  origAsyncDirective.name, templateUrl);
14263            }
14264
14265            tempTemplateAttrs = {$attr: {}};
14266            replaceWith($rootElement, $compileNode, compileNode);
14267            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
14268
14269            if (isObject(origAsyncDirective.scope)) {
14270              // the original directive that caused the template to be loaded async required
14271              // an isolate scope
14272              markDirectiveScope(templateDirectives, true);
14273            }
14274            directives = templateDirectives.concat(directives);
14275            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
14276          } else {
14277            compileNode = beforeTemplateCompileNode;
14278            $compileNode.html(content);
14279          }
14280
14281          directives.unshift(derivedSyncDirective);
14282
14283          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
14284              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
14285              previousCompileContext);
vendor: 11,978 bytes, lines 14286-14579
14286          forEach($rootElement, function(node, i) {
14287            if (node == compileNode) {
14288              $rootElement[i] = $compileNode[0];
14289            }
14290          });
14291          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
14292
14293          while (linkQueue.length) {
14294            var scope = linkQueue.shift(),
14295                beforeTemplateLinkNode = linkQueue.shift(),
14296                linkRootElement = linkQueue.shift(),
14297                boundTranscludeFn = linkQueue.shift(),
14298                linkNode = $compileNode[0];
14299
14300            if (scope.$$destroyed) continue;
14301
14302            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
14303              var oldClasses = beforeTemplateLinkNode.className;
14304
14305              if (!(previousCompileContext.hasElementTranscludeDirective &&
14306                  origAsyncDirective.replace)) {
14307                // it was cloned therefore we have to clone as well.
14308                linkNode = jqLiteClone(compileNode);
14309              }
14310              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
14311
14312              // Copy in CSS classes from original node
14313              safeAddClass(jqLite(linkNode), oldClasses);
14314            }
14315            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
14316              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
14317            } else {
14318              childBoundTranscludeFn = boundTranscludeFn;
14319            }
14320            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
14321              childBoundTranscludeFn);
14322          }
14323          linkQueue = null;
14324        });
14325
14326      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
14327        var childBoundTranscludeFn = boundTranscludeFn;
14328        if (scope.$$destroyed) return;
14329        if (linkQueue) {
14330          linkQueue.push(scope,
14331                         node,
14332                         rootElement,
14333                         childBoundTranscludeFn);
14334        } else {
14335          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
14336            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
14337          }
14338          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
14339        }
14340      };
14341    }
14342
14343
14344    /**
14345     * Sorting function for bound directives.
14346     */
14347    function byPriority(a, b) {
14348      var diff = b.priority - a.priority;
14349      if (diff !== 0) return diff;
14350      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
14351      return a.index - b.index;
14352    }
14353
14354    function assertNoDuplicate(what, previousDirective, directive, element) {
14355
14356      function wrapModuleNameIfDefined(moduleName) {
14357        return moduleName ?
14358          (' (module: ' + moduleName + ')') :
14359          '';
14360      }
14361
14362      if (previousDirective) {
14363        throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
14364            previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
14365            directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
14366      }
14367    }
14368
14369
14370    function addTextInterpolateDirective(directives, text) {
14371      var interpolateFn = $interpolate(text, true);
14372      if (interpolateFn) {
14373        directives.push({
14374          priority: 0,
14375          compile: function textInterpolateCompileFn(templateNode) {
14376            var templateNodeParent = templateNode.parent(),
14377                hasCompileParent = !!templateNodeParent.length;
14378
14379            // When transcluding a template that has bindings in the root
14380            // we don't have a parent and thus need to add the class during linking fn.
14381            if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
14382
14383            return function textInterpolateLinkFn(scope, node) {
14384              var parent = node.parent();
14385              if (!hasCompileParent) compile.$$addBindingClass(parent);
14386              compile.$$addBindingInfo(parent, interpolateFn.expressions);
14387              scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
14388                node[0].nodeValue = value;
14389              });
14390            };
14391          }
14392        });
14393      }
14394    }
14395
14396
14397    function wrapTemplate(type, template) {
14398      type = lowercase(type || 'html');
14399      switch (type) {
14400      case 'svg':
14401      case 'math':
14402        var wrapper = document.createElement('div');
14403        wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
14404        return wrapper.childNodes[0].childNodes;
14405      default:
14406        return template;
14407      }
14408    }
14409
14410
14411    function getTrustedContext(node, attrNormalizedName) {
14412      if (attrNormalizedName == "srcdoc") {
14413        return $sce.HTML;
14414      }
14415      var tag = nodeName_(node);
14416      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
14417      if (attrNormalizedName == "xlinkHref" ||
14418          (tag == "form" && attrNormalizedName == "action") ||
14419          (tag != "img" && (attrNormalizedName == "src" ||
14420                            attrNormalizedName == "ngSrc"))) {
14421        return $sce.RESOURCE_URL;
14422      }
14423    }
14424
14425
14426    function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
14427      var trustedContext = getTrustedContext(node, name);
14428      allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
14429
14430      var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
14431
14432      // no interpolation found -> ignore
14433      if (!interpolateFn) return;
14434
14435
14436      if (name === "multiple" && nodeName_(node) === "select") {
14437        throw $compileMinErr("selmulti",
14438            "Binding to the 'multiple' attribute is not supported. Element: {0}",
14439            startingTag(node));
14440      }
14441
14442      directives.push({
14443        priority: 100,
14444        compile: function() {
14445            return {
14446              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
14447                var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
14448
14449                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
14450                  throw $compileMinErr('nodomevents',
14451                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
14452                          "ng- versions (such as ng-click instead of onclick) instead.");
14453                }
14454
14455                // If the attribute has changed since last $interpolate()ed
14456                var newValue = attr[name];
14457                if (newValue !== value) {
14458                  // we need to interpolate again since the attribute value has been updated
14459                  // (e.g. by another directive's compile function)
14460                  // ensure unset/empty values make interpolateFn falsy
14461                  interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
14462                  value = newValue;
14463                }
14464
14465                // if attribute was updated so that there is no interpolation going on we don't want to
14466                // register any observers
14467                if (!interpolateFn) return;
14468
14469                // initialize attr object so that it's ready in case we need the value for isolate
14470                // scope initialization, otherwise the value would not be available from isolate
14471                // directive's linking fn during linking phase
14472                attr[name] = interpolateFn(scope);
14473
14474                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
14475                (attr.$$observers && attr.$$observers[name].$$scope || scope).
14476                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
14477                    //special case for class attribute addition + removal
14478                    //so that class changes can tap into the animation
14479                    //hooks provided by the $animate service. Be sure to
14480                    //skip animations when the first digest occurs (when
14481                    //both the new and the old values are the same) since
14482                    //the CSS classes are the non-interpolated values
14483                    if (name === 'class' && newValue != oldValue) {
14484                      attr.$updateClass(newValue, oldValue);
14485                    } else {
14486                      attr.$set(name, newValue);
14487                    }
14488                  });
14489              }
14490            };
14491          }
14492      });
14493    }
14494
14495
14496    /**
14497     * This is a special jqLite.replaceWith, which can replace items which
14498     * have no parents, provided that the containing jqLite collection is provided.
14499     *
14500     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
14501     *                               in the root of the tree.
14502     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
14503     *                                  the shell, but replace its DOM node reference.
14504     * @param {Node} newNode The new DOM node.
14505     */
14506    function replaceWith($rootElement, elementsToRemove, newNode) {
14507      var firstElementToRemove = elementsToRemove[0],
14508          removeCount = elementsToRemove.length,
14509          parent = firstElementToRemove.parentNode,
14510          i, ii;
14511
14512      if ($rootElement) {
14513        for (i = 0, ii = $rootElement.length; i < ii; i++) {
14514          if ($rootElement[i] == firstElementToRemove) {
14515            $rootElement[i++] = newNode;
14516            for (var j = i, j2 = j + removeCount - 1,
14517                     jj = $rootElement.length;
14518                 j < jj; j++, j2++) {
14519              if (j2 < jj) {
14520                $rootElement[j] = $rootElement[j2];
14521              } else {
14522                delete $rootElement[j];
14523              }
14524            }
14525            $rootElement.length -= removeCount - 1;
14526
14527            // If the replaced element is also the jQuery .context then replace it
14528            // .context is a deprecated jQuery api, so we should set it only when jQuery set it
14529            // http://api.jquery.com/context/
14530            if ($rootElement.context === firstElementToRemove) {
14531              $rootElement.context = newNode;
14532            }
14533            break;
14534          }
14535        }
14536      }
14537
14538      if (parent) {
14539        parent.replaceChild(newNode, firstElementToRemove);
14540      }
14541
14542      // Append all the `elementsToRemove` to a fragment. This will...
14543      // - remove them from the DOM
14544      // - allow them to still be traversed with .nextSibling
14545      // - allow a single fragment.qSA to fetch all elements being removed
14546      var fragment = document.createDocumentFragment();
14547      for (i = 0; i < removeCount; i++) {
14548        fragment.appendChild(elementsToRemove[i]);
14549      }
14550
14551      if (jqLite.hasData(firstElementToRemove)) {
14552        // Copy over user data (that includes Angular's $scope etc.). Don't copy private
14553        // data here because there's no public interface in jQuery to do that and copying over
14554        // event listeners (which is the main use of private data) wouldn't work anyway.
14555        jqLite.data(newNode, jqLite.data(firstElementToRemove));
14556
14557        // Remove $destroy event listeners from `firstElementToRemove`
14558        jqLite(firstElementToRemove).off('$destroy');
14559      }
14560
14561      // Cleanup any data/listeners on the elements and children.
14562      // This includes invoking the $destroy event on any elements with listeners.
14563      jqLite.cleanData(fragment.querySelectorAll('*'));
14564
14565      // Update the jqLite collection to only contain the `newNode`
14566      for (i = 1; i < removeCount; i++) {
14567        delete elementsToRemove[i];
14568      }
14569      elementsToRemove[0] = newNode;
14570      elementsToRemove.length = 1;
14571    }
14572
14573
14574    function cloneAndAnnotateFn(fn, annotation) {
14575      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
14576    }
14577
14578
14579    function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
14580      try {
14581        linkFn(scope, $element, attrs, controllers, transcludeFn);
14582      } catch (e) {
14583        $exceptionHandler(e, startingTag($element));
14584      }
14585    }
14586
14587
14588    // Set up $watches for isolate scope and controller bindings. This process
14589    // only occurs for isolate scopes and new scopes with controllerAs.
14590    function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
14591      var removeWatchCollection = [];
14592      forEach(bindings, function(definition, scopeName) {
14593        var attrName = definition.attrName,
14594        optional = definition.optional,
14595        mode = definition.mode, // @, =, or &
14596        lastValue,
14597        parentGet, parentSet, compare, removeWatch;
14598
14599        switch (mode) {
14600
14601          case '@':
14602            if (!optional && !hasOwnProperty.call(attrs, attrName)) {
14603              destination[scopeName] = attrs[attrName] = void 0;
14604            }
14605            attrs.$observe(attrName, function(value) {
14606              if (isString(value)) {
14607                destination[scopeName] = value;
14608              }
14609            });
14610            attrs.$$observers[attrName].$$scope = scope;
14611            lastValue = attrs[attrName];
14612            if (isString(lastValue)) {
14613              // If the attribute has been provided then we trigger an interpolation to ensure
14614              // the value is there for use in the link fn
14615              destination[scopeName] = $interpolate(lastValue)(scope);
14616            } else if (isBoolean(lastValue)) {
14617              // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
14618              // the value to boolean rather than a string, so we special case this situation
14619              destination[scopeName] = lastValue;
14620            }
14621            break;
14622
14623          case '=':
14624            if (!hasOwnProperty.call(attrs, attrName)) {
14625              if (optional) break;
14626              attrs[attrName] = void 0;
14627            }
14628            if (optional && !attrs[attrName]) break;
14629
14630            parentGet = $parse(attrs[attrName]);
14631            if (parentGet.literal) {
14632              compare = equals;
14633            } else {
14634              compare = function(a, b) { return a === b || (a !== a && b !== b); };
14635            }
14636            parentSet = parentGet.assign || function() {
14637              // reset the change, or we will throw this exception on every $digest
14638              lastValue = destination[scopeName] = parentGet(scope);
14639              throw $compileMinErr('nonassign',
14640                  "Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
14641                  attrs[attrName], attrName, directive.name);
14642            };
14643            lastValue = destination[scopeName] = parentGet(scope);
14644            var parentValueWatch = function parentValueWatch(parentValue) {
14645              if (!compare(parentValue, destination[scopeName])) {
14646                // we are out of sync and need to copy
14647                if (!compare(parentValue, lastValue)) {
14648                  // parent changed and it has precedence
14649                  destination[scopeName] = parentValue;
14650                } else {
14651                  // if the parent can be assigned then do so
14652                  parentSet(scope, parentValue = destination[scopeName]);
14653                }
14654              }
14655              return lastValue = parentValue;
14656            };
14657            parentValueWatch.$stateful = true;
14658            if (definition.collection) {
14659              removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
14660            } else {
14661              removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
14662            }
14663            removeWatchCollection.push(removeWatch);
14664            break;
14665
14666          case '<':
14667            if (!hasOwnProperty.call(attrs, attrName)) {
14668              if (optional) break;
14669              attrs[attrName] = void 0;
14670            }
14671            if (optional && !attrs[attrName]) break;
14672
14673            parentGet = $parse(attrs[attrName]);
14674
14675            destination[scopeName] = parentGet(scope);
14676
14677            removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
14678              destination[scopeName] = newParentValue;
14679            }, parentGet.literal);
14680
14681            removeWatchCollection.push(removeWatch);
14682            break;
14683
14684          case '&':
14685            // Don't assign Object.prototype method to scope
14686            parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
14687
14688            // Don't assign noop to destination if expression is not val
vendor: 5,751 bytes, lines 14688-14894
14688id
14689            if (parentGet === noop && optional) break;
14690
14691            destination[scopeName] = function(locals) {
14692              return parentGet(scope, locals);
14693            };
14694            break;
14695        }
14696      });
14697
14698      return removeWatchCollection.length && function removeWatches() {
14699        for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
14700          removeWatchCollection[i]();
14701        }
14702      };
14703    }
14704  }];
14705}
14706
14707var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
14708/**
14709 * Converts all accepted directives format into proper directive name.
14710 * @param name Name to normalize
14711 */
14712function directiveNormalize(name) {
14713  return camelCase(name.replace(PREFIX_REGEXP, ''));
14714}
14715
14716/**
14717 * @ngdoc type
14718 * @name $compile.directive.Attributes
14719 *
14720 * @description
14721 * A shared object between directive compile / linking functions which contains normalized DOM
14722 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
14723 * needed since all of these are treated as equivalent in Angular:
14724 *
14725 * ```
14726 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
14727 * ```
14728 */
14729
14730/**
14731 * @ngdoc property
14732 * @name $compile.directive.Attributes#$attr
14733 *
14734 * @description
14735 * A map of DOM element attribute names to the normalized name. This is
14736 * needed to do reverse lookup from normalized name back to actual name.
14737 */
14738
14739
14740/**
14741 * @ngdoc method
14742 * @name $compile.directive.Attributes#$set
14743 * @kind function
14744 *
14745 * @description
14746 * Set DOM element attribute value.
14747 *
14748 *
14749 * @param {string} name Normalized element attribute name of the property to modify. The name is
14750 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
14751 *          property to the original name.
14752 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
14753 */
14754
14755
14756
14757/**
14758 * Closure compiler type information
14759 */
14760
14761function nodesetLinkingFn(
14762  /* angular.Scope */ scope,
14763  /* NodeList */ nodeList,
14764  /* Element */ rootElement,
14765  /* function(Function) */ boundTranscludeFn
14766) {}
14767
14768function directiveLinkingFn(
14769  /* nodesetLinkingFn */ nodesetLinkingFn,
14770  /* angular.Scope */ scope,
14771  /* Node */ node,
14772  /* Element */ rootElement,
14773  /* function(Function) */ boundTranscludeFn
14774) {}
14775
14776function tokenDifference(str1, str2) {
14777  var values = '',
14778      tokens1 = str1.split(/\s+/),
14779      tokens2 = str2.split(/\s+/);
14780
14781  outer:
14782  for (var i = 0; i < tokens1.length; i++) {
14783    var token = tokens1[i];
14784    for (var j = 0; j < tokens2.length; j++) {
14785      if (token == tokens2[j]) continue outer;
14786    }
14787    values += (values.length > 0 ? ' ' : '') + token;
14788  }
14789  return values;
14790}
14791
14792function removeComments(jqNodes) {
14793  jqNodes = jqLite(jqNodes);
14794  var i = jqNodes.length;
14795
14796  if (i <= 1) {
14797    return jqNodes;
14798  }
14799
14800  while (i--) {
14801    var node = jqNodes[i];
14802    if (node.nodeType === NODE_TYPE_COMMENT) {
14803      splice.call(jqNodes, i, 1);
14804    }
14805  }
14806  return jqNodes;
14807}
14808
14809var $controllerMinErr = minErr('$controller');
14810
14811
14812var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
14813function identifierForController(controller, ident) {
14814  if (ident && isString(ident)) return ident;
14815  if (isString(controller)) {
14816    var match = CNTRL_REG.exec(controller);
14817    if (match) return match[3];
14818  }
14819}
14820
14821
14822/**
14823 * @ngdoc provider
14824 * @name $controllerProvider
14825 * @description
14826 * The {@link ng.$controller $controller service} is used by Angular to create new
14827 * controllers.
14828 *
14829 * This provider allows controller registration via the
14830 * {@link ng.$controllerProvider#register register} method.
14831 */
14832function $ControllerProvider() {
14833  var controllers = {},
14834      globals = false;
14835
14836  /**
14837   * @ngdoc method
14838   * @name $controllerProvider#has
14839   * @param {string} name Controller name to check.
14840   */
14841  this.has = function(name) {
14842    return controllers.hasOwnProperty(name);
14843  };
14844
14845  /**
14846   * @ngdoc method
14847   * @name $controllerProvider#register
14848   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
14849   *    the names and the values are the constructors.
14850   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
14851   *    annotations in the array notation).
14852   */
14853  this.register = function(name, constructor) {
14854    assertNotHasOwnProperty(name, 'controller');
14855    if (isObject(name)) {
14856      extend(controllers, name);
14857    } else {
14858      controllers[name] = constructor;
14859    }
14860  };
14861
14862  /**
14863   * @ngdoc method
14864   * @name $controllerProvider#allowGlobals
14865   * @description If called, allows `$controller` to find controller constructors on `window`
14866   */
14867  this.allowGlobals = function() {
14868    globals = true;
14869  };
14870
14871
14872  this.$get = ['$injector', '$window', function($injector, $window) {
14873
14874    /**
14875     * @ngdoc service
14876     * @name $controller
14877     * @requires $injector
14878     *
14879     * @param {Function|string} constructor If called with a function then it's considered to be the
14880     *    controller constructor function. Otherwise it's considered to be a string which is used
14881     *    to retrieve the controller constructor using the following steps:
14882     *
14883     *    * check if a controller with given name is registered via `$controllerProvider`
14884     *    * check if evaluating the string on the current scope returns a constructor
14885     *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
14886     *      `window` object (not recommended)
14887     *
14888     *    The string can use the `controller as property` syntax, where the controller instance is published
14889     *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
14890     *    to work correctly.
14891     *
14892     * @param {Object} locals Injection locals for Controller.
14893     * @return {Object} Instance of given controller.
14894     *
14895     * @description
14896     * `$controller` service is responsible for instantiating controllers.
14897     *
14898     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
14899     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
14900     */
14901    return function(expression, locals, later, ident) {
14902      // PRIVATE API:
14903      //   param `later` --- indicates that the controller's constructor is invoked at a later time.
14904      //                     If true, $controller will allocate the object with the correct
14905      //                     prototype chain, but will not invoke the controller until a returned
14906      //                     callback is invoked.
14907      //   param `ident` --- An optional label which overrides the label parsed from the controller
14908      //                     expression, if any.
14909      var instance, match, constructor, identifier;
14910      later = later === true;
14911      if (ident && isString(ident)) {
14912        identifier = ident;
14913      }
14914
14915      if (isString(expression)) {
14916        match = expression.match(CNTRL_REG);
14917        if (!match) {
14918          throw $controllerMinErr('ctrlfmt',
14919            "Badly formed controller string '{0}'. " +
14920            "Must match `__name__ as __id__` or `__name__`.", expression);
14921        }
14922        constructor = match[1],
14923        identifier = identifier || match[3];
14924        expression = controllers.hasOwnProperty(constructor)
14925            ? controllers[constructor]
14926            : getter(locals.$scope, constructor, true) ||
14927                (globals ? getter($window, constructor, true) : undefined);
14928
14929        assertArgFn(expression, constructor, true);
14930      }
14931
14932      if (later) {
14933        // Instantiate controller later:
14934        // This machinery is used to create an instance of the object before calling the
14935        // controller's constructor itself.
14936        //
14937        // This allows properties to be added to the controller before the constructor is
14938        // invoked. Primarily, this is used for isolate scope bindings in $compile.
14939        //
14940        // This feature is not intended for use by applications, and is thus not documented
14941        // publicly.
14942        // Object creation: http://jsperf.com/create-constructor/2
14943        var controllerPrototype = (isArray(expression) ?
14944          expression[expression.length - 1] : expression).prototype;
14945        instance = Object.create(controllerPrototype || null);
14946
14947        if (identifier) {
14948          addIdentifier(locals, identifier, instance, constructor || expression.name);
14949        }
14950
14951        var instantiate;
14952        return instantiate = extend(function() {
14953          var result = $injector.invoke(expression, instance, locals, constructor);
14954          if (result !== instance && (isObject(result) || isFunction(result))) {
14955            instance = result;
14956            if (identifier) {
14957              // If result changed, re-assign controllerAs value to scope.
14958              addIdentifier(locals, identifier, instance, constructor || expression.name);
14959            }
14960          }
14961          return instance;
14962        }, {
14963          instance: instance,
14964          identifier: identifier
14965        });
14966      }
14967
14968      instance = $injector.instantiate(expression, locals, constructor);
14969
14970      if (identifier) {
14971        addIdentifier(locals, identifier, instance, constructor || expression.name);
14972      }
14973
14974      return instance;
14975    };
14976
14977    function addIdentifier(locals, identifier, instance, name) {
14978      if (!(locals && isObject(locals.$scope))) {
14979        throw minErr('$controller')('noscp',
14980          "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
14981          name, identifier);
14982      }
14983
14984      locals.$scope[identifier] = instance;
14985    }
14986  }];
14987}
14988
14989/**
14990 * @ngdoc service
14991 * @name $document
14992 * @requires $window
14993 *
14994 * @description
14995 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
14996 *
14997 * @example
14998   <example module="documentExample">
14999     <file name="index.html">
15000       <div ng-controller="ExampleController">
15001         <p>$document title: <b ng-bind="title"></b></p>
15002         <p>window.document title: <b ng-bind="windowTitle"></b></p>
15003       </div>
15004     </file>
15005     <file name="script.js">
15006       angular.module('documentExample', [])
15007         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
15008           $scope.title = $document[0].title;
15009           $scope.windowTitle = angular.element(window.document)[0].title;
15010         }]);
15011     </file>
15012   </example>
15013 */
15014function $DocumentProvider() {
15015  this.$get = ['$window', function(window) {
15016    return jqLite(window.document);
15017  }];
15018}
15019
15020/**
15021 * @ngdoc service
15022 * @name $exceptionHandler
15023 * @requires ng.$log
15024 *
15025 * @description
15026 * Any uncaught exception in angular expressions is delegated to this service.
15027 * The default implementation simply delegates to `$log.error` which logs it into
15028 * the browser console.
15029 *
15030 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
15031 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
15032 *
15033 * ## Example:
15034 *
15035 * ```js
15036 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
15037 *     return function(exception, cause) {
15038 *       exception.message += ' (caused by "' + cause + '")';
15039 *       throw exception;
15040 *     };
15041 *   });
15042 * ```
15043 *
15044 * This example will override the normal action of `$exceptionHandler`, to make angular
15045 * exceptions fail hard when they happen, instead of just logging to the console.
15046 *
15047 * <hr />
15048 * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
15049 * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
15050 * (unless executed during a digest).
15051 *
15052 * If you wish, you can manually delegate exceptions, e.g.
15053 * `try { ... } catch(e) { $exceptionHandler(e); }`
15054 *
15055 * @param {Error} exception Exception associated with the error.
15056 * @param {string=} cause optional information about the context in which
15057 *       the error was thrown.
15058 *
15059 */
15060function $ExceptionHandlerProvider() {
15061  this.$get = ['$log', function($log) {
15062    return function(exception, cause) {
15063      $log.error.apply($log, arguments);
15064    };
15065  }];
15066}
15067
15068var $$ForceReflowProvider = function() {
15069  this.$get = ['$document', function($document) {
15070    return function(domNode) {
15071      //the line below will force the browser to perform a repaint so
15072      //that all the animated elements within the animation frame will
15073      //be properly updated and drawn on screen. This is required to
15074      //ensure that the preparation animation is properly flushed so that
15075      //the active state picks up from there. DO NOT REMOVE THIS LINE.
15076      //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
15077      //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
15078      //WILL TAKE YEARS AWAY FROM YOUR LIFE.
15079      if (domNode) {
15080        if (!domNode.nodeType && domNode instanceof jqLite) {
15081          domNode = domNode[0];
15082        }
15083      } else {
15084        domNode = $document[0].body;
15085      }
15086      return domNode.offsetWidth + 1;
15087    };
15088  }];
15089};
15090
15091var APPLICATION_JSON = 'application/json';
15092var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
15093var JSON_START = /^\[|^\{(?!\{)/;
15094var JSON_ENDS = {
15095  '[': /]$/,
15096  '{': /}$/
15097};
15098var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
15099var $httpMinErr = minErr('$http');
15100var $httpMinErrLegacyFn = function(method) {
15101  return function() {
15102    throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
15103  };
15104};
15105
15106function serializeValue(v) {
15107  if (isObject(v)) {
15108    return isDate(v) ? v.toISOString() : toJson(v);
15109  }
15110  return v;
15111}
15112
15113
15114function $HttpParamSerializerProvider() {
15115  /**
15116   * @ngdoc service
15117   * @name $httpParamSerializer
15118   * @description
15119   *
15120   * Default {@link $http `$http`} params serializer that converts objects to strings
15121   * according to the following rules:
15122   *
15123   * * `{'foo': 'bar'}` results in `foo=bar`
15124   * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
15125   * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
15126   * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
15127   *
15128   * Note that serializer will sort the request parameters alphabetically.
15129   * */
15130
15131  this.$get = function() {
15132    return function ngParamSerializer(params) {
15133      if (!params) return '';
15134      var parts = [];
vendor: 3,682 bytes, lines 15135-15261
15135      forEachSorted(params, function(value, key) {
15136        if (value === null || isUndefined(value)) return;
15137        if (isArray(value)) {
15138          forEach(value, function(v, k) {
15139            parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
15140          });
15141        } else {
15142          parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
15143        }
15144      });
15145
15146      return parts.join('&');
15147    };
15148  };
15149}
15150
15151function $HttpParamSerializerJQLikeProvider() {
15152  /**
15153   * @ngdoc service
15154   * @name $httpParamSerializerJQLike
15155   * @description
15156   *
15157   * Alternative {@link $http `$http`} params serializer that follows
15158   * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
15159   * The serializer will also sort the params alphabetically.
15160   *
15161   * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
15162   *
15163   * ```js
15164   * $http({
15165   *   url: myUrl,
15166   *   method: 'GET',
15167   *   params: myParams,
15168   *   paramSerializer: '$httpParamSerializerJQLike'
15169   * });
15170   * ```
15171   *
15172   * It is also possible to set it as the default `paramSerializer` in the
15173   * {@link $httpProvider#defaults `$httpProvider`}.
15174   *
15175   * Additionally, you can inject the serializer and use it explicitly, for example to serialize
15176   * form data for submission:
15177   *
15178   * ```js
15179   * .controller(function($http, $httpParamSerializerJQLike) {
15180   *   //...
15181   *
15182   *   $http({
15183   *     url: myUrl,
15184   *     method: 'POST',
15185   *     data: $httpParamSerializerJQLike(myData),
15186   *     headers: {
15187   *       'Content-Type': 'application/x-www-form-urlencoded'
15188   *     }
15189   *   });
15190   *
15191   * });
15192   * ```
15193   *
15194   * */
15195  this.$get = function() {
15196    return function jQueryLikeParamSerializer(params) {
15197      if (!params) return '';
15198      var parts = [];
15199      serialize(params, '', true);
15200      return parts.join('&');
15201
15202      function serialize(toSerialize, prefix, topLevel) {
15203        if (toSerialize === null || isUndefined(toSerialize)) return;
15204        if (isArray(toSerialize)) {
15205          forEach(toSerialize, function(value, index) {
15206            serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
15207          });
15208        } else if (isObject(toSerialize) && !isDate(toSerialize)) {
15209          forEachSorted(toSerialize, function(value, key) {
15210            serialize(value, prefix +
15211                (topLevel ? '' : '[') +
15212                key +
15213                (topLevel ? '' : ']'));
15214          });
15215        } else {
15216          parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
15217        }
15218      }
15219    };
15220  };
15221}
15222
15223function defaultHttpResponseTransform(data, headers) {
15224  if (isString(data)) {
15225    // Strip json vulnerability protection prefix and trim whitespace
15226    var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
15227
15228    if (tempData) {
15229      var contentType = headers('Content-Type');
15230      if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
15231        data = fromJson(tempData);
15232      }
15233    }
15234  }
15235
15236  return data;
15237}
15238
15239function isJsonLike(str) {
15240    var jsonStart = str.match(JSON_START);
15241    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
15242}
15243
15244/**
15245 * Parse headers into key value object
15246 *
15247 * @param {string} headers Raw headers as a string
15248 * @returns {Object} Parsed headers as key value object
15249 */
15250function parseHeaders(headers) {
15251  var parsed = createMap(), i;
15252
15253  function fillInParsed(key, val) {
15254    if (key) {
15255      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
15256    }
15257  }
15258
15259  if (isString(headers)) {
15260    forEach(headers.split('\n'), function(line) {
15261      i = line.indexOf(':');
vendor: 4,132 bytes, lines 15262-15398
15262      fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
15263    });
15264  } else if (isObject(headers)) {
15265    forEach(headers, function(headerVal, headerKey) {
15266      fillInParsed(lowercase(headerKey), trim(headerVal));
15267    });
15268  }
15269
15270  return parsed;
15271}
15272
15273
15274/**
15275 * Returns a function that provides access to parsed headers.
15276 *
15277 * Headers are lazy parsed when first requested.
15278 * @see parseHeaders
15279 *
15280 * @param {(string|Object)} headers Headers to provide access to.
15281 * @returns {function(string=)} Returns a getter function which if called with:
15282 *
15283 *   - if called with single an argument returns a single header value or null
15284 *   - if called with no arguments returns an object containing all headers.
15285 */
15286function headersGetter(headers) {
15287  var headersObj;
15288
15289  return function(name) {
15290    if (!headersObj) headersObj =  parseHeaders(headers);
15291
15292    if (name) {
15293      var value = headersObj[lowercase(name)];
15294      if (value === void 0) {
15295        value = null;
15296      }
15297      return value;
15298    }
15299
15300    return headersObj;
15301  };
15302}
15303
15304
15305/**
15306 * Chain all given functions
15307 *
15308 * This function is used for both request and response transforming
15309 *
15310 * @param {*} data Data to transform.
15311 * @param {function(string=)} headers HTTP headers getter fn.
15312 * @param {number} status HTTP status code of the response.
15313 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
15314 * @returns {*} Transformed data.
15315 */
15316function transformData(data, headers, status, fns) {
15317  if (isFunction(fns)) {
15318    return fns(data, headers, status);
15319  }
15320
15321  forEach(fns, function(fn) {
15322    data = fn(data, headers, status);
15323  });
15324
15325  return data;
15326}
15327
15328
15329function isSuccess(status) {
15330  return 200 <= status && status < 300;
15331}
15332
15333
15334/**
15335 * @ngdoc provider
15336 * @name $httpProvider
15337 * @description
15338 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
15339 * */
15340function $HttpProvider() {
15341  /**
15342   * @ngdoc property
15343   * @name $httpProvider#defaults
15344   * @description
15345   *
15346   * Object containing default values for all {@link ng.$http $http} requests.
15347   *
15348   * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with
15349   * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
15350   * by default. See {@link $http#caching $http Caching} for more information.
15351   *
15352   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
15353   * Defaults value is `'XSRF-TOKEN'`.
15354   *
15355   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
15356   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
15357   *
15358   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
15359   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
15360   * setting default headers.
15361   *     - **`defaults.headers.common`**
15362   *     - **`defaults.headers.post`**
15363   *     - **`defaults.headers.put`**
15364   *     - **`defaults.headers.patch`**
15365   *
15366   *
15367   * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
15368   *  used to the prepare string representation of request parameters (specified as an object).
15369   *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
15370   *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
15371   *
15372   **/
15373  var defaults = this.defaults = {
15374    // transform incoming response data
15375    transformResponse: [defaultHttpResponseTransform],
15376
15377    // transform outgoing request data
15378    transformRequest: [function(d) {
15379      return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
15380    }],
15381
15382    // default headers
15383    headers: {
15384      common: {
15385        'Accept': 'application/json, text/plain, */*'
15386      },
15387      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
15388      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
15389      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
15390    },
15391
15392    xsrfCookieName: 'XSRF-TOKEN',
15393    xsrfHeaderName: 'X-XSRF-TOKEN',
15394
15395    paramSerializer: '$httpParamSerializer'
15396  };
15397
15398  var useApplyAsync = false;
vendor: 4,307 bytes, lines 15399-15509
15399  /**
15400   * @ngdoc method
15401   * @name $httpProvider#useApplyAsync
15402   * @description
15403   *
15404   * Configure $http service to combine processing of multiple http responses received at around
15405   * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
15406   * significant performance improvement for bigger applications that make many HTTP requests
15407   * concurrently (common during application bootstrap).
15408   *
15409   * Defaults to false. If no value is specified, returns the current configured value.
15410   *
15411   * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
15412   *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
15413   *    to load and share the same digest cycle.
15414   *
15415   * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
15416   *    otherwise, returns the current configured value.
15417   **/
15418  this.useApplyAsync = function(value) {
15419    if (isDefined(value)) {
15420      useApplyAsync = !!value;
15421      return this;
15422    }
15423    return useApplyAsync;
15424  };
15425
15426  var useLegacyPromise = true;
15427  /**
15428   * @ngdoc method
15429   * @name $httpProvider#useLegacyPromiseExtensions
15430   * @description
15431   *
15432   * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
15433   * This should be used to make sure that applications work without these methods.
15434   *
15435   * Defaults to true. If no value is specified, returns the current configured value.
15436   *
15437   * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
15438   *
15439   * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
15440   *    otherwise, returns the current configured value.
15441   **/
15442  this.useLegacyPromiseExtensions = function(value) {
15443    if (isDefined(value)) {
15444      useLegacyPromise = !!value;
15445      return this;
15446    }
15447    return useLegacyPromise;
15448  };
15449
15450  /**
15451   * @ngdoc property
15452   * @name $httpProvider#interceptors
15453   * @description
15454   *
15455   * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
15456   * pre-processing of request or postprocessing of responses.
15457   *
15458   * These service factories are ordered by request, i.e. they are applied in the same order as the
15459   * array, on request, but reverse order, on response.
15460   *
15461   * {@link ng.$http#interceptors Interceptors detailed info}
15462   **/
15463  var interceptorFactories = this.interceptors = [];
15464
15465  this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
15466      function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
15467
15468    var defaultCache = $cacheFactory('$http');
15469
15470    /**
15471     * Make sure that default param serializer is exposed as a function
15472     */
15473    defaults.paramSerializer = isString(defaults.paramSerializer) ?
15474      $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
15475
15476    /**
15477     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
15478     * The reversal is needed so that we can build up the interception chain around the
15479     * server request.
15480     */
15481    var reversedInterceptors = [];
15482
15483    forEach(interceptorFactories, function(interceptorFactory) {
15484      reversedInterceptors.unshift(isString(interceptorFactory)
15485          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
15486    });
15487
15488    /**
15489     * @ngdoc service
15490     * @kind function
15491     * @name $http
15492     * @requires ng.$httpBackend
15493     * @requires $cacheFactory
15494     * @requires $rootScope
15495     * @requires $q
15496     * @requires $injector
15497     *
15498     * @description
15499     * The `$http` service is a core Angular service that facilitates communication with the remote
15500     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
15501     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
15502     *
15503     * For unit testing applications that use `$http` service, see
15504     * {@link ngMock.$httpBackend $httpBackend mock}.
15505     *
15506     * For a higher level of abstraction, please check out the {@link ngResource.$resource
15507     * $resource} service.
15508     *
15509     * The $http API is based on the {@link ng.$q deferred/promise APIs}
15509 exposed by
15510     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
15511     * it is important to familiarize yourself with these APIs and the guarantees they provide.
15512     *
15513     *
15514     * ## General usage
15515     * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
15516     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
15517     *
15518     * ```js
15519     *   // Simple GET request example:
15520     *   $http({
15521     *     method: 'GET',
15522     *     url: '/someUrl'
15523     *   }).then(function successCallback(response) {
15524     *       // this callback will be called asynchronously
15525     *       // when the response is available
15526     *     }, function errorCallback(response) {
15527     *       // called asynchronously if an error occurs
15528     *       // or server returns response with an error status.
15529     *     });
15530     * ```
15531     *
15532     * The response object has these properties:
15533     *
15534     *   - **data** – `{string|Object}` – The response body transformed with the transform
15535     *     functions.
15536     *   - **status** – `{number}` – HTTP status code of the response.
15537     *   - **headers** – `{function([headerName])}` – Header getter function.
15538     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
15539     *   - **statusText** – `{string}` – HTTP status text of the response.
15540     *
15541     * A response status code between 200 and 299 is considered a success status and
15542     * will result in the success callback being called. Note that if the response is a redirect,
15543     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
15544     * called for such responses.
15545     *
15546     *
15547     * ## Shortcut methods
15548     *
15549     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
15550     * request data must be passed in for POST/PUT requests. An optional config can be passed as the
15551     * last argument.
15552     *
15553     * ```js
15554     *   $http.get('/someUrl', config).then(successCallback, errorCallback);
15555     *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
15556     * ```
15557     *
15558     * Complete list of shortcut methods:
15559     *
15560     * - {@link ng.$http#get $http.get}
15561     * - {@link ng.$http#head $http.head}
15562     * - {@link ng.$http#post $http.post}
15563     * - {@link ng.$http#put $http.put}
15564     * - {@link ng.$http#delete $http.delete}
15565     * - {@link ng.$http#jsonp $http.jsonp}
15566     * - {@link ng.$http#patch $http.patch}
15567     *
15568     *
15569     * ## Writing Unit Tests that use $http
15570     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
15571     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
15572     * request using trained responses.
15573     *
15574     * ```
15575     * $httpBackend.expectGET(...);
15576     * $http.get(...);
15577     * $httpBackend.flush();
15578     * ```
15579     *
15580     * ## Deprecation Notice
15581     * <div class="alert alert-danger">
15582     *   The `$http` legacy promise methods `success` and `error` have been deprecated.
15583     *   Use the standard `then` method instead.
15584     *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
15585     *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
15586     * </div>
15587     *
15588     * ## Setting HTTP Headers
15589     *
15590     * The $http service will automatically add certain HTTP headers to all requests. These defaults
15591     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
15592     * object, which currently contains this default configuration:
15593     *
15594     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
15595     *   - `Accept: application/json, text/plain, * / *`
15596     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
15597     *   - `Content-Type: application/json`
15598     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
15599     *   - `Content-Type: application/json`
15600     *
15601     * To add or overwrite these defaults, simply add or remove a property from these configuration
15602     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
15603     * with the lowercased HTTP method name as the key, e.g.
15604     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
15605     *
15606     * The defaults can also be set at runtime via the `$http.defaults` object in the same
15607     * fashion. For example:
15608     *
15609     * ```
15610     * module.run(function($http) {
15611     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
15612     * });
15613     * ```
15614     *
15615     * In addition, you can supply a `headers` property in the config object passed when
15616     * calling `$http(config)`, which overrides the defaults without changing them globally.
15617     *
15618     * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
15619     * Use the `headers` property, setting the desired header to `undefined`. For example:
15620     *
15621     * ```js
15622     * var req = {
15623     *  method: 'POST',
15624     *  url: 'http://example.com',
15625     *  headers: {
15626     *    'Content-Type': undefined
15627     *  },
15628     *  data: { test: 'test' }
15629     * }
15630     *
15631     * $http(req).then(function(){...}, function(){...});
15632     * ```
15633     *
15634     * ## Transforming Requests and Responses
15635     *
15636     * Both requests and responses can be transformed using transformation functions: `transformRequest`
15637     * and `transformResponse`. These properties can be a single function that returns
15638     * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
15639     * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
15640     *
15641     * <div class="alert alert-warning">
15642     * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
15643     * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
15644     * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
15645     * function will be reflected on the scope and in any templates where the object is data-bound.
15646     * To prevent his, transform functions should have no side-effects.
15647     * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
15648     * </div>
15649     *
15650     * ### Default Transformations
15651     *
15652     * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
15653     * `defaults.transformResponse` properties. If a request does not provide its own transformations
15654     * then these will be applied.
15655     *
15656     * You can augment or replace the default transformations by modifying these properties by adding to or
15657     * replacing the array.
15658     *
15659     * Angular provides the following default transformations:
15660     *
15661     * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
15662     *
15663     * - If the `data` property of the request configuration object contains an object, serialize it
15664     *   into JSON format.
15665     *
15666     * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
15667     *
15668     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
15669     *  - If JSON response is detected, deserialize it using a JSON parser.
15670     *
15671     *
15672     * ### Overriding the Default Transformations Per Request
15673     *
15674     * If you wish override the request/response transformations only for a single request then provide
15675     * `transformRequest` and/or `transformResponse` properties on the configuration object passed
15676     * into `$http`.
15677     *
15678     * Note that if you provide these properties on the config object the default transformations will be
15679     * overwritten. If you wish to augment the default transformations then you must include them in your
15680     * local transformation array.
15681     *
15682     * The following code demonstrates adding a new response transformation to be run after the default response
15683     * transformations have been run.
15684     *
15685     * ```js
15686     * function appendTransform(defaults, transform) {
15687     *
15688     *   // We can't guarantee that the default transformation is an array
15689     *   defaults = angular.isArray(defaults) ? defaults : [defaults];
15690     *
15691     *   // Append the new transformation to the defaults
15692     *   return defaults.concat(transform);
15693     * }
15694     *
15695     * $http({
15696     *   url: '...',
15697     *   method: 'GET',
15698     *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
15699     *     return doTransform(value);
15700     *   })
15701     * });
15702     * ```
15703     *
15704     *
15705     * ## Caching
15706     *
15707     * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must
15708     * set the config.cache value or the default cache value to TRUE or to a cache object (created
15709     * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes
15710     * precedence over the default cache value.
15711     *
15712     * In order to:
15713     *   * cache all responses - set the default cache value to TRUE or to a cache object
15714     *   * cache a specific response - set config.cache value to TRUE or to a cache object
15715     *
15716     * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
15717     * then the default `$cacheFactory($http)` object is used.
15718     *
15719     * The default cache value can be set by updating the
15720     * {@link ng.$http#defaults `$http.defaults.cache`} property or the
15721     * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.
15722     *
15723     * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using
15724     * the relevant cache object. The next time the same request is made, the response is returned
15725     * from the cache without sending a request to the server.
15726     *
15727     * Take note that:
15728     *
15729     *   * Only GET and JSONP requests are cached.
15730     *   * The cache key is the request URL including search parameters; headers are not considered.
15731     *   * Cached responses are returned asynchronously, in the same way as responses from the server.
15732     *   * If multiple identical requests are made using the same cache, which is not yet populated,
15733     *     one request will be made to the server and remaining requests will return the same response.
15734     *   * A cache-control header on the response does not affect if or how responses are cached.
15735     *
15736     *
15737     * ## Interceptors
15738     *
15739     * Before you start creating interceptors, be sure to understand the
15740     * {@link ng.$q $q and deferred/promise APIs}.
15741     *
15742     * For purposes of global error handling, authentication, or any kind of synchronous or
15743     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
15744     * able to intercept requests before they are handed to the server and
15745     * responses before they are handed over to the application code that
15746     * initiated these requests. The interceptors leverage the {@link ng.$q
15747     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
15748     *
15749     * The interceptors are service factories that are registered with the `$httpProvider` by
15750     * adding them to the `$httpProvider.interceptors` array. The factory is called and
15751     * injected with dependencies (if specified) and returns the interceptor.
15752     *
15753     * There are two kinds of interceptors (and two kinds of rejection interceptors):
15754     *
15755     *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
15756     *     modify the `config` object or create a new one. The function needs to return the `config`
15757     *     object directly, or a promise containing the `config` or a new `config` object.
15758     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
15759     *     resolved with a rejection.
15760     *   * `response`: interceptors get called with http `response` object. The function is free to
15761     *     modify the `response` object or create a new one. The function needs to return the `response`
15762     *     object directly, or as a promise containing the `response` or a new `response` object.
15763     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
15764     *     resolved with a rejection.
15765     *
15766     *
15767     * ```js
15768     *   // register the interceptor as a service
15769     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
15770     *     return {
15771     *       // optional method
15772     *       'request': function(config) {
15773     *         // do something on success
15774     *         return config;
15775     *       },
15776     *
15777     *       // optional method
15778     *      'requestError': function(rejection) {
15779     *         // do something on error
15780     *         if (canRecover(rejection)) {
15781     *           return responseOrNewPromise
15782     *         }
15783     *         return $q.reject(rejection);
15784     *       },
15785     *
15786     *
15787     *
15788     *       // optional method
15789     *       'response': function(response) {
15790     *         // do something on success
15791     *         return response;
15792     *       },
15793     *
15794     *       // optional method
15795     *      'responseError': function(rejection) {
15796     *         // do something on error
15797     *         if (canRecover(rejection)) {
15798     *           return responseOrNewPromise
15799     *         }
15800     *         return $q.reject(rejection);
15801     *       }
15802     *     };
15803     *   });
15804     *
15805     *   $httpProvider.interceptors.push('myHttpInterceptor');
15806     *
15807     *
15808     *   // alternatively, register the interceptor via an anonymous factory
15809     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
15810     *     return {
15811     *      'request': function(config) {
15812     *          // same as above
15813     *       },
15814     *
15815     *       'response': function(response) {
15816     *          // same as above
15817     *       }
15818     *     };
15819     *   });
15820     * ```
15821     *
15822     * ## Security Considerations
15823     *
15824     * When designing web applications, consider security threats from:
15825     *
15826     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
15827     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
15828     *
15829     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
15830     * pre-configured with strategies that address these issues, but for this to work backend server
15831     * cooperation is required.
15832     *
15833     * ### JSON Vulnerability Protection
15834     *
15835     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
15836     * allows third party website to turn your JSON resource URL into
15837     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
15838     * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
15839     * Angular will automatically strip the prefix before processing it as JSON.
15840     *
15841     * For example if your server needs to return:
15842     * ```js
15843     * ['one','two']
15844     * ```
15845     *
15846     * which is vulnerable to attack, your server can return:
15847     * ```js
15848     * )]}',
15849     * ['one','two']
15850     * ```
15851     *
15852     * Angular will strip the prefix, before processing the JSON.
15853     *
15854     *
15855     * ### Cross Site Request Forgery (XSRF) Protection
15856     *
15857     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
15858     * which the attacker can trick an authenticated user into unknowingly executing actions on your
15859     * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
15860     * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
15861     * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
15862     * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
15863     * The header will not be set for cross-domain requests.
15864     *
15865     * To take advantage of this, your server needs to set a token in a JavaScript readable session
15866     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
15867     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
15868     * that only JavaScript running on your domain could have sent the request. The token must be
15869     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
15870     * making up its own tokens). We recommend that the token is a digest of your site's
15871     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
15872     * for added security.
15873     *
15874     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
15875     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
15876     * or the per-request config object.
15877     *
15878     * In order to prevent collisions in environments where multiple Angular apps share the
15879     * same domain or subdomain, we recommend that each application uses unique cookie name.
15880     *
15881     * @param {object} config Object describing the request to be made and how it should be
15882     *    processed. The object has following properties:
15883     *
15884     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
15885     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
15886     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
15887     *      with the `paramSerializer` and appended as GET parameters.
15888     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
15889     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
15890     *      HTTP headers to send to the server. If the return value of a function is null, the
15891     *      header will not be sent. Functions accept a config object as an argument.
15892     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
15893     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
15894     *    - **transformRequest** –
15895     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>
15895}` –
15896     *      transform function or an array of such functions. The transform function takes the http
15897     *      request body and headers and returns its transformed (typically serialized) version.
15898     *      See {@link ng.$http#overriding-the-default-transformations-per-request
15899     *      Overriding the Default Transformations}
15900     *    - **transformResponse** –
15901     *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
15902     *      transform function or an array of such functions. The transform function takes the http
15903     *      response body, headers and status and returns its transformed (typically deserialized) version.
15904     *      See {@link ng.$http#overriding-the-default-transformations-per-request
15905     *      Overriding the Default Transformations}
15906     *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
15907     *      prepare the string representation of request parameters (specified as an object).
15908     *      If specified as string, it is interpreted as function registered with the
15909     *      {@link $injector $injector}, which means you can create your own serializer
15910     *      by registering it as a {@link auto.$provide#service service}.
15911     *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
15912     *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
15913     *    - **cache** – `{boolean|Object}` – A boolean value or object created with
15914     *      {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
15915     *      See {@link $http#caching $http Caching} for more information.
15916     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
15917     *      that should abort the request when resolved.
15918     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
15919     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
15920     *      for more information.
15921     *    - **responseType** - `{string}` - see
15922     *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
15923     *
15924     * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
15925     *                        when the request succeeds or fails.
15926     *
15927     *
15928     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
15929     *   requests. This is primarily meant to be used for debugging purposes.
15930     *
15931     *
15932     * @example
15933<example module="httpExample">
15934<file name="index.html">
15935  <div ng-controller="FetchController">
15936    <select ng-model="method" aria-label="Request method">
15937      <option>GET</option>
15938      <option>JSONP</option>
15939    </select>
15940    <input type="text" ng-model="url" size="80" aria-label="URL" />
15941    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
15942    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
15943    <button id="samplejsonpbtn"
15944      ng-click="updateModel('JSONP',
15945                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
15946      Sample JSONP
15947    </button>
15948    <button id="invalidjsonpbtn"
15949      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
15950        Invalid JSONP
15951      </button>
15952    <pre>http status code: {{status}}</pre>
15953    <pre>http response data: {{data}}</pre>
15954  </div>
15955</file>
15956<file name="script.js">
15957  angular.module('httpExample', [])
15958    .controller('FetchController', ['$scope', '$http', '$templateCache',
15959      function($scope, $http, $templateCache) {
15960        $scope.method = 'GET';
15961        $scope.url = 'http-hello.html';
15962
15963        $scope.fetch = function() {
15964          $scope.code = null;
15965          $scope.response = null;
15966
15967          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
15968            then(function(response) {
15969              $scope.status = response.status;
15970              $scope.data = response.data;
15971            }, function(response) {
15972              $scope.data = response.data || "Request failed";
15973              $scope.status = response.status;
15974          });
15975        };
15976
15977        $scope.updateModel = function(method, url) {
15978          $scope.method = method;
15979          $scope.url = url;
15980        };
15981      }]);
15982</file>
15983<file name="http-hello.html">
15984  Hello, $http!
15985</file>
15986<file name="protractor.js" type="protractor">
15987  var status = element(by.binding('status'));
15988  var data = element(by.binding('data'));
15989  var fetchBtn = element(by.id('fetchbtn'));
15990  var sampleGetBtn = element(by.id('samplegetbtn'));
15991  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
15992  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
15993
15994  it('should make an xhr GET request', function() {
15995    sampleGetBtn.click();
15996    fetchBtn.click();
15997    expect(status.getText()).toMatch('200');
15998    expect(data.getText()).toMatch(/Hello, \$http!/);
15999  });
16000
16001// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
16002// it('should make a JSONP request to angularjs.org', function() {
16003//   sampleJsonpBtn.click();
16004//   fetchBtn.click();
16005//   expect(status.getText()).toMatch('200');
16006//   expect(data.getText()).toMatch(/Super Hero!/);
16007// });
16008
16009  it('should make JSONP request to invalid URL and invoke the error handler',
16010      function() {
16011    invalidJsonpBtn.click();
16012    fetchBtn.click();
16013    expect(status.getText()).toMatch('0');
16014    expect(data.getText()).toMatch('Request failed');
16015  });
16016</file>
16017</example>
16018     */
16019    function $http(requestConfig) {
16020
16021      if (!isObject(requestConfig)) {
16022        throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
16023      }
16024
16025      if (!isString(requestConfig.url)) {
16026        throw minErr('$http')('badreq', 'Http request configuration url must be a string.  Received: {0}', requestConfig.url);
16027      }
16028
16029      var config = extend({
16030        method: 'get',
16031        transformRequest: defaults.transformRequest,
16032        transformResponse: defaults.transformResponse,
16033        paramSerializer: defaults.paramSerializer
16034      }, requestConfig);
16035
16036      config.headers = mergeHeaders(requestConfig);
16037      config.method = uppercase(config.method);
16038      config.paramSerializer = isString(config.paramSerializer) ?
16039        $injector.get(config.paramSerializer) : config.paramSerializer;
16040
16041      var serverRequest = function(config) {
16042        var headers = config.headers;
16043        var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
16044
16045        // strip content-type if data is undefined
16046        if (isUndefined(reqData)) {
16047          forEach(headers, function(value, header) {
16048            if (lowercase(header) === 'content-type') {
16049                delete headers[header];
16050            }
16051          });
16052        }
16053
16054        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
16055          config.withCredentials = defaults.withCredentials;
16056        }
16057
16058        // send request
16059        return sendReq(config, reqData).then(transformResponse, transformResponse);
16060      };
16061
16062      var chain = [serverRequest, undefined];
16063      var promise = $q.when(config);
16064
16065      // apply interceptors
16066      forEach(reversedInterceptors, function(interceptor) {
16067        if (interceptor.request || interceptor.requestError) {
16068          chain.unshift(interceptor.request, interceptor.requestError);
16069        }
16070        if (interceptor.response || interceptor.responseError) {
16071          chain.push(interceptor.response, interceptor.responseError);
16072        }
16073      });
16074
16075      while (chain.length) {
16076        var thenFn = chain.shift();
16077        var rejectFn = chain.shift();
16078
16079        promise = promise.then(thenFn, rejectFn);
16080      }
16081
16082      if (useLegacyPromise) {
16083        promise.success = function(fn) {
16084          assertArgFn(fn, 'fn');
16085
16086          promise.then(function(response) {
16087            fn(response.data, response.status, response.headers, config);
16088          });
16089          return promise;
16090        };
16091
16092        promise.error = function(fn) {
16093          assertArgFn(fn, 'fn');
16094
16095          promise.then(null, function(response) {
16096            fn(response.data, response.status, response.headers, config);
16097          });
16098          return promise;
16099        };
16100      } else {
16101        promise.success = $httpMinErrLegacyFn('success');
16102        promise.error = $httpMinErrLegacyFn('error');
16103      }
16104
16105      return promise;
16106
16107      function transformResponse(response) {
16108        // make a copy since the response must be cacheable
16109        var resp = extend({}, response);
16110        resp.data = transformData(response.data, response.headers, response.status,
16111                                  config.transformResponse);
16112        return (isSuccess(response.status))
16113          ? resp
16114          : $q.reject(resp);
16115      }
16116
16117      function executeHeaderFns(headers, config) {
16118        var headerContent, processedHeaders = {};
16119
16120        forEach(headers, function(headerFn, header) {
16121          if (isFunction(headerFn)) {
16122            headerContent = headerFn(config);
16123            if (headerContent != null) {
16124              processedHeaders[header] = headerContent;
16125            }
16126          } else {
16127            processedHeaders[header] = headerFn;
16128          }
16129        });
16130
16131        return processedHeaders;
16132      }
16133
16134      function mergeHeaders(config) {
16135        var defHeaders = defaults.headers,
16136            reqHeaders = extend({}, config.headers),
16137            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
16138
16139        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
16140
vendor: 9,099 bytes, lines 16141-16441
16141        // using for-in instead of forEach to avoid unnecessary iteration after header has been found
16142        defaultHeadersIteration:
16143        for (defHeaderName in defHeaders) {
16144          lowercaseDefHeaderName = lowercase(defHeaderName);
16145
16146          for (reqHeaderName in reqHeaders) {
16147            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
16148              continue defaultHeadersIteration;
16149            }
16150          }
16151
16152          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
16153        }
16154
16155        // execute if header value is a function for merged headers
16156        return executeHeaderFns(reqHeaders, shallowCopy(config));
16157      }
16158    }
16159
16160    $http.pendingRequests = [];
16161
16162    /**
16163     * @ngdoc method
16164     * @name $http#get
16165     *
16166     * @description
16167     * Shortcut method to perform `GET` request.
16168     *
16169     * @param {string} url Relative or absolute URL specifying the destination of the request
16170     * @param {Object=} config Optional configuration object
16171     * @returns {HttpPromise} Future object
16172     */
16173
16174    /**
16175     * @ngdoc method
16176     * @name $http#delete
16177     *
16178     * @description
16179     * Shortcut method to perform `DELETE` request.
16180     *
16181     * @param {string} url Relative or absolute URL specifying the destination of the request
16182     * @param {Object=} config Optional configuration object
16183     * @returns {HttpPromise} Future object
16184     */
16185
16186    /**
16187     * @ngdoc method
16188     * @name $http#head
16189     *
16190     * @description
16191     * Shortcut method to perform `HEAD` request.
16192     *
16193     * @param {string} url Relative or absolute URL specifying the destination of the request
16194     * @param {Object=} config Optional configuration object
16195     * @returns {HttpPromise} Future object
16196     */
16197
16198    /**
16199     * @ngdoc method
16200     * @name $http#jsonp
16201     *
16202     * @description
16203     * Shortcut method to perform `JSONP` request.
16204     *
16205     * @param {string} url Relative or absolute URL specifying the destination of the request.
16206     *                     The name of the callback should be the string `JSON_CALLBACK`.
16207     * @param {Object=} config Optional configuration object
16208     * @returns {HttpPromise} Future object
16209     */
16210    createShortMethods('get', 'delete', 'head', 'jsonp');
16211
16212    /**
16213     * @ngdoc method
16214     * @name $http#post
16215     *
16216     * @description
16217     * Shortcut method to perform `POST` request.
16218     *
16219     * @param {string} url Relative or absolute URL specifying the destination of the request
16220     * @param {*} data Request content
16221     * @param {Object=} config Optional configuration object
16222     * @returns {HttpPromise} Future object
16223     */
16224
16225    /**
16226     * @ngdoc method
16227     * @name $http#put
16228     *
16229     * @description
16230     * Shortcut method to perform `PUT` request.
16231     *
16232     * @param {string} url Relative or absolute URL specifying the destination of the request
16233     * @param {*} data Request content
16234     * @param {Object=} config Optional configuration object
16235     * @returns {HttpPromise} Future object
16236     */
16237
16238     /**
16239      * @ngdoc method
16240      * @name $http#patch
16241      *
16242      * @description
16243      * Shortcut method to perform `PATCH` request.
16244      *
16245      * @param {string} url Relative or absolute URL specifying the destination of the request
16246      * @param {*} data Request content
16247      * @param {Object=} config Optional configuration object
16248      * @returns {HttpPromise} Future object
16249      */
16250    createShortMethodsWithData('post', 'put', 'patch');
16251
16252        /**
16253         * @ngdoc property
16254         * @name $http#defaults
16255         *
16256         * @description
16257         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
16258         * default headers, withCredentials as well as request and response transformations.
16259         *
16260         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
16261         */
16262    $http.defaults = defaults;
16263
16264
16265    return $http;
16266
16267
16268    function createShortMethods(names) {
16269      forEach(arguments, function(name) {
16270        $http[name] = function(url, config) {
16271          return $http(extend({}, config || {}, {
16272            method: name,
16273            url: url
16274          }));
16275        };
16276      });
16277    }
16278
16279
16280    function createShortMethodsWithData(name) {
16281      forEach(arguments, function(name) {
16282        $http[name] = function(url, data, config) {
16283          return $http(extend({}, config || {}, {
16284            method: name,
16285            url: url,
16286            data: data
16287          }));
16288        };
16289      });
16290    }
16291
16292
16293    /**
16294     * Makes the request.
16295     *
16296     * !!! ACCESSES CLOSURE VARS:
16297     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
16298     */
16299    function sendReq(config, reqData) {
16300      var deferred = $q.defer(),
16301          promise = deferred.promise,
16302          cache,
16303          cachedResp,
16304          reqHeaders = config.headers,
16305          url = buildUrl(config.url, config.paramSerializer(config.params));
16306
16307      $http.pendingRequests.push(config);
16308      promise.then(removePendingReq, removePendingReq);
16309
16310
16311      if ((config.cache || defaults.cache) && config.cache !== false &&
16312          (config.method === 'GET' || config.method === 'JSONP')) {
16313        cache = isObject(config.cache) ? config.cache
16314              : isObject(defaults.cache) ? defaults.cache
16315              : defaultCache;
16316      }
16317
16318      if (cache) {
16319        cachedResp = cache.get(url);
16320        if (isDefined(cachedResp)) {
16321          if (isPromiseLike(cachedResp)) {
16322            // cached request has already been sent, but there is no response yet
16323            cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
16324          } else {
16325            // serving from cache
16326            if (isArray(cachedResp)) {
16327              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
16328            } else {
16329              resolvePromise(cachedResp, 200, {}, 'OK');
16330            }
16331          }
16332        } else {
16333          // put the promise for the non-transformed response into cache as a placeholder
16334          cache.put(url, promise);
16335        }
16336      }
16337
16338
16339      // if we won't have the response in cache, set the xsrf headers and
16340      // send the request to the backend
16341      if (isUndefined(cachedResp)) {
16342        var xsrfValue = urlIsSameOrigin(config.url)
16343            ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
16344            : undefined;
16345        if (xsrfValue) {
16346          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
16347        }
16348
16349        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
16350            config.withCredentials, config.responseType);
16351      }
16352
16353      return promise;
16354
16355
16356      /**
16357       * Callback registered to $httpBackend():
16358       *  - caches the response if desired
16359       *  - resolves the raw $http promise
16360       *  - calls $apply
16361       */
16362      function done(status, response, headersString, statusText) {
16363        if (cache) {
16364          if (isSuccess(status)) {
16365            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
16366          } else {
16367            // remove promise from the cache
16368            cache.remove(url);
16369          }
16370        }
16371
16372        function resolveHttpPromise() {
16373          resolvePromise(response, status, headersString, statusText);
16374        }
16375
16376        if (useApplyAsync) {
16377          $rootScope.$applyAsync(resolveHttpPromise);
16378        } else {
16379          resolveHttpPromise();
16380          if (!$rootScope.$$phase) $rootScope.$apply();
16381        }
16382      }
16383
16384
16385      /**
16386       * Resolves the raw $http promise.
16387       */
16388      function resolvePromise(response, status, headers, statusText) {
16389        //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
16390        status = status >= -1 ? status : 0;
16391
16392        (isSuccess(status) ? deferred.resolve : deferred.reject)({
16393          data: response,
16394          status: status,
16395          headers: headersGetter(headers),
16396          config: config,
16397          statusText: statusText
16398        });
16399      }
16400
16401      function resolvePromiseWithResult(result) {
16402        resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
16403      }
16404
16405      function removePendingReq() {
16406        var idx = $http.pendingRequests.indexOf(config);
16407        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
16408      }
16409    }
16410
16411
16412    function buildUrl(url, serializedParams) {
16413      if (serializedParams.length > 0) {
16414        url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
16415      }
16416      return url;
16417    }
16418  }];
16419}
16420
16421/**
16422 * @ngdoc service
16423 * @name $xhrFactory
16424 *
16425 * @description
16426 * Factory function used to create XMLHttpRequest objects.
16427 *
16428 * Replace or decorate this service to create your own custom XMLHttpRequest objects.
16429 *
16430 * ```
16431 * angular.module('myApp', [])
16432 * .factory('$xhrFactory', function() {
16433 *   return function createXhr(method, url) {
16434 *     return new window.XMLHttpRequest({mozSystem: true});
16435 *   };
16436 * });
16437 * ```
16438 *
16439 * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
16440 * @param {string} url URL of the request.
16441 */
16442function $xhrFactoryProvider() {
16443  this.$get = function() {
16444    return function createXhr() {
16445      return new window.XMLHttpRequest();
16446    };
16447  };
16448}
16449
16450/**
16451 * @ngdoc service
16452 * @name $httpBackend
16453 * @requires $window
16454 * @requires $document
16455 * @requires $xhrFactory
16456 *
16457 * @description
16458 * HTTP backend used by the {@link ng.$http service} that delegates to
16459 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
16460 *
16461 * You should never need to use this service directly, instead use the higher-level abstractions:
16462 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
16463 *
16464 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
16465 * $httpBackend} which can be trained with responses.
16466 */
16467function $HttpBackendProvider() {
16468  this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
16469    return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
16470  }];
16471}
16472
16473function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
16474  // TODO(vojta): fix the signature
16475  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
16476    $browser.$$incOutstandingRequestCount();
16477    url = url || $browser.url();
16478
16479    if (lowercase(method) == 'jsonp') {
16480      var callbackId = '_' + (callbacks.counter++).toString(36);
16481      callbacks[callbackId] = function(data) {
16482        callbacks[callbackId].data = data;
16483        callbacks[callbackId].called = true;
16484      };
16485
16486      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
16487          callbackId, function(status, text) {
16488        completeRequest(callback, status, callbacks[callbackId].data, "", text);
16489        callbacks[callbackId] = noop;
16490      });
16491    } else {
16492
16493      var xhr = createXhr(method, url);
16494
16495      xhr.open(method, url, true);
16496      forEach(headers, function(value, key) {
16497        if (isDefined(value)) {
16498            xhr.setRequestHeader(key, value);
16499        }
16500      });
16501
16502      xhr.onload = function requestLoaded() {
16503        var statusText = xhr.statusText || '';
16504
16505        // responseText is the old-school way of retrieving response (supported by IE9)
16506        // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
16507        var response = ('response' in xhr) ? xhr.response : xhr.responseText;
16508
16509        // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
16510        var status = xhr.status === 1223 ? 204 : xhr.status;
16511
16512        // fix status code when it is 0 (0 status is undocumented).
16513        // Occurs when accessing file resources or on Android 4.1 stock browser
16514        // while retrieving files from application cache.
16515        if (status === 0) {
16516          status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
16517        }
16518
16519        completeRequest(callback,
16520            status,
16521            response,
16522            xhr.getAllResponseHeaders(),
16523            statusText);
16524      };
16525
16526      var requestError = function() {
16527        // The response is always empty
16528        // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
16529        completeRequest(callback, -1, null, null, '');
16530      };
16531
16532      xhr.onerror = requestError;
16533      xhr.onabort = requestError;
16534
16535      if (withCredentials) {
16536        xhr.withCredentials = true;
16537      }
16538
16539      if (responseType) {
16540        try {
16541          xhr.responseType = responseType;
16542        } catch (e) {
16543          // WebKit added support for the json responseType value on 09/03/2013
16544          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
16545          // known to throw when setting the value "json" as the response type. Other older
16546          // browsers implementing the responseType
16547          //
16548          // The json response type can be ignored if not supported, because JSON payloads are
16549          // parsed on the client-side regardless.
16550          if (responseType !== 'json') {
16551            throw e;
16552          }
16553        }
16554      }
16555
16556      xhr.send(isUndefined(post) ? null : post);
16557    }
16558
16559    if (timeout > 0) {
16560      var timeoutId = $browserDefer(timeoutRequest, timeout);
16561    } else if (isPromiseLike(timeout)) {
16562      timeout.then(timeoutRequest);
16563    }
16564
16565
16566    function timeoutRequest() {
16567      jsonpDone && jsonpDone();
16568      xhr && xhr.abort();
16569    }
16570
16571    function completeRequest(callback, status, response, headersString, statusText) {
16572      // cancel timeout and subsequent timeout promise resolution
16573      if (isDefined(timeoutId)) {
16574        $browserDefer.cancel(timeoutId);
16575      }
16576      jsonpDone = xhr = null;
16577
16578      callback(status, response, headersString, statusText);
16579      $browser.$$completeOutstandingRequest(noop);
16580    }
16581  };
16582
16583  function jsonpReq(url, callbackId, done) {
16584    // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
16585    // - fetches local scripts via XHR and evals them
16586    // - adds and immediately removes script elements from the document
16587    var script = rawDocument.createElement('script'), callback = null;
16588    script.type = "text/javascript";
16589    script.src = url;
16590    script.async = true;
16591
16592    callback = function(event) {
16593      removeEventListenerFn(script, "load", callback);
16594      removeEventListenerFn(script, "error", callback);
16595      rawDocument.body.removeChild(script);
16596      script = null;
16597      var status = -1;
16598      var text = "unknown";
16599
16600      if (event) {
16601        if (event.type === "load" && !callbacks[callbackId].called) {
16602          event = { type: "error" };
16603        }
16604        text = event.type;
16605        status = event.type === "error" ? 404 : 200;
16606      }
16607
16608      if (done) {
16609        done(status, text);
16610      }
16611    };
16612
16613    addEventListenerFn(script, "load", callback);
16614    addEventListenerFn(script, "error", callback);
16615    rawDocument.body.appendChild(script);
16616    return callback;
16617  }
16618}
16619
16620var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
16621$interpolateMinErr.throwNoconcat = function(text) {
16622  throw $interpolateMinErr('noconcat',
16623      "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
16624      "interpolations that concatenate multiple expressions when a trusted value is " +
16625      "required.  See http://docs.angularjs.org/api/ng.$sce", text);
16626};
16627
16628$interpolateMinErr.interr = function(text, err) {
16629  return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
16630};
16631
16632/**
16633 * @ngdoc provider
16634 * @name $interpolateProvider
16635 *
16636 * @description
16637 *
16638 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
16639 *
16640 * <div class="alert alert-danger">
16641 * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
16642 * template within a Python Jinja template (or any other template language). Mixing templating
16643 * languages is **very dangerous**. The embedding template language will not safely escape Angular
16644 * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
16645 * security bugs!
16646 * </div>
16647 *
16648 * @example
16649<example name="custom-interpolation-markup" module="customInterpolationApp">
16650<file name="index.html">
16651<script>
16652  var customInterpolationApp = angular.module('customInterpolationApp', []);
16653
16654  customInterpolationApp.config(function($interpolateProvider) {
16655    $interpolateProvider.startSymbol('//');
16656    $interpolateProvider.endSymbol('//');
16657  });
16658
16659
16660  customInterpolationApp.controller('DemoController', function() {
16661      this.label = "This binding is brought you by // interpolation symbols.";
16662  });
16663</script>
16664<div ng-controller="DemoController as demo">
16665    //demo.label//
16666</div>
16667</file>
16668<file name="protractor.js" type="protractor">
16669  it('should interpolate binding with custom symbols', function() {
16670    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
16671  });
16672</file>
16673</example>
16674 */
16675function $InterpolateProvider() {
16676  var startSymbol = '{{';
16677  var endSymbol = '}}';
16678
16679  /**
16680   * @ngdoc method
16681   * @name $interpolateProvider#startSymbol
16682   * @description
16683   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
16684   *
16685   * @param {string=} value new value to set the starting symbol to.
16686   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
16687   */
16688  this.startSymbol = function(value) {
16689    if (value) {
16690      startSymbol = value;
16691      return this;
16692    } else {
16693      return startSymbol;
16694    }
16695  };
16696
16697  /**
16698   * @ngdoc method
16699   * @name $interpolateProvider#endSymbol
16700   * @description
16701   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
16702   *
16703   * @param {string=} value new value to set the ending symbol to.
16704   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
16705   */
16706  this.endSymbol = function(value) {
16707    if (value) {
16708      endSymbol = value;
16709      return this;
16710    } else {
16711      return endSymbol;
16712    }
16713  };
16714
16715
16716  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
16717    var startSymbolLength = startSymbol.length,
16718        endSymbolLength = endSymbol.length,
16719        escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
16720        escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
16721
16722    function escape(ch) {
16723      return '\\\\\\' + ch;
16724    }
16725
16726    function unescapeText(text) {
16727      return text.replace(escapedStartRegexp, startSymbol).
16728        replace(escapedEndRegexp, endSymbol);
16729    }
16730
16731    function stringify(value) {
16732      if (value == null) { // null || undefined
16733        return '';
16734      }
16735      switch (typeof value) {
16736        case 'string':
16737          break;
16738        case 'number':
16739          value = '' + value;
16740          break;
16741        default:
16742          value = toJson(value);
16743      }
16744
16745      return value;
16746    }
16747
16748    //TODO: this is the same as the constantWatchDelegate in parse.js
16749    function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
16750      var unwatch;
16751      return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
16752        unwatch();
16753        return constantInterp(scope);
16754      }, listener, objectEquality);
16755    }
16756
16757    /**
16758     * @ngdoc service
16759     * @name $interpolate
16760     * @kind function
16761     *
16762     * @requires $parse
16763     * @requires $sce
16764     *
16765     * @description
16766     *
16767     * Compiles a string with markup into an interpolation function. This service is used by the
16768     * HTML {@link ng.$compile $compile} service for data binding. See
16769     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
16770     * interpolation markup.
16771     *
16772     *
16773     * ```js
16774     *   var $interpolate = ...; // injected
16775     *   var exp = $interpolate('Hello {{name | uppercase}}!');
16776     *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
16777     * ```
16778     *
16779     * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
16780     * `true`, the interpolation function will return `undefined` unless all embedded expressions
16781     * evaluate to a value other than `undefined`.
16782     *
16783     * ```js
16784     *   var $interpolate = ...; // injected
16785     *   var context = {greeting: 'Hello', name: undefined };
16786     *
16787     *   // default "forgiving" mode
16788     *   var exp = $interpolate('{{greeting}} {{name}}!');
16789     *   expect(exp(context)).toEqual('Hello !');
16790     *
16791     *   // "allOrNothing" mode
16792     *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
16793     *   expect(exp(context)).toBeUndefined();
16794     *   context.name = 'Angular';
16795     *   expect(exp(context)).toEqual('Hello Angular!');
16796     * ```
16797     *
16798     * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
16799     *
16800     * ####Escaped Interpolation
16801     * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
16802     * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
16803     * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
16804     * or binding.
16805     *
16806     * This enables web-servers to prevent script injection attacks and defacing attacks, to some
16807     * degree, while also enabling code examples to work without relying on the
16808     * {@link ng.directive:ngNonBindable ngNonBindable} directive.
16809     *
16810     * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
16811     * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
16812     * interpolation start/end markers with their escaped counterparts.**
16813     *
16814     * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
16815     * output when the $interpolate service processes the text. So, for HTML elements interpolated
16816     * by {@link ng.$compile $compile}
16816, or otherwise interpolated with the `mustHaveExpression` parameter
16817     * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
16818     * this is typically useful only when user-data is used in rendering a template from the server, or
16819     * when otherwise untrusted data is used by a directive.
16820     *
16821     * <example>
16822     *  <file name="index.html">
16823     *    <div ng-init="username='A user'">
16824     *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
16825     *        </p>
16826     *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
16827     *        application, but fails to accomplish their task, because the server has correctly
16828     *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
16829     *        characters.</p>
16830     *      <p>Instead, the result of the attempted script injection is visible, and can be removed
16831     *        from the database by an administrator.</p>
16832     *    </div>
16833     *  </file>
16834     * </example>
16835     *
16836     * @param {string} text The text with markup to interpolate.
16837     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
16838     *    embedded expression in order to return an interpolation function. Strings with no
16839     *    embedded expression will return null for the interpolation function.
16840     * @param {string=} trustedContext when provided, the returned function passes the interpolated
16841     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
16842     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
16843     *    provides Strict Contextual Escaping for details.
16844     * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
16845     *    unless all embedded expressions evaluate to a value other than `undefined`.
16846     * @returns {function(context)} an interpolation function which is used to compute the
16847     *    interpolated string. The function has these parameters:
16848     *
16849     * - `context`: evaluation context for all expressions embedded in the interpolated text
16850     */
16851    function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
16852      // Provide a quick exit and simplified result function for text with no interpolation
16853      if (!text.length || text.indexOf(startSymbol) === -1) {
16854        var constantInterp;
16855        if (!mustHaveExpression) {
16856          var unescapedText = unescapeText(text);
16857          constantInterp = valueFn(unescapedText);
16858          constantInterp.exp = text;
16859          constantInterp.expressions = [];
16860          constantInterp.$$watchDelegate = constantWatchDelegate;
16861        }
16862        return constantInterp;
16863      }
16864
16865      allOrNothing = !!allOrNothing;
16866      var startIndex,
16867          endIndex,
16868          index = 0,
16869          expressions = [],
16870          parseFns = [],
16871          textLength = text.length,
16872          exp,
16873          concat = [],
16874          expressionPositions = [];
16875
16876      while (index < textLength) {
16877        if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
16878             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
16879          if (index !== startIndex) {
16880            concat.push(unescapeText(text.substring(index, startIndex)));
16881          }
16882          exp = text.substring(startIndex + startSymbolLength, endIndex);
16883          expressions.push(exp);
16884          parseFns.push($parse(exp, parseStringifyInterceptor));
16885          index = endIndex + endSymbolLength;
16886          expressionPositions.push(concat.length);
16887          concat.push('');
16888        } else {
16889          // we did not find an interpolation, so we have to add the remainder to the separators array
16890          if (index !== textLength) {
16891            concat.push(unescapeText(text.substring(index)));
16892          }
16893          break;
16894        }
16895      }
16896
16897      // Concatenating expressions makes it hard to reason about whether some combination of
16898      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
16899      // single expression be used for iframe[src], object[src], etc., we ensure that the value
16900      // that's used is assigned or constructed by some JS code somewhere that is more testable or
16901      // make it obvious that you bound the value to some user controlled value.  This helps reduce
16902      // the load when auditing for XSS issues.
16903      if (trustedContext && concat.length > 1) {
16904          $interpolateMinErr.throwNoconcat(text);
16905      }
16906
16907      if (!mustHaveExpression || expressions.length) {
16908        var compute = function(values) {
16909          for (var i = 0, ii = expressions.length; i < ii; i++) {
16910            if (allOrNothing && isUndefined(values[i])) return;
16911            concat[expressionPositions[i]] = values[i];
16912          }
16913          return concat.join('');
16914        };
16915
16916        var getValue = function(value) {
16917          return trustedContext ?
16918            $sce.getTrusted(trustedContext, value) :
16919            $sce.valueOf(value);
16920        };
16921
16922        return extend(function interpolationFn(context) {
16923            var i = 0;
16924            var ii = expressions.length;
16925            var values = new Array(ii);
16926
16927            try {
16928              for (; i < ii; i++) {
16929                values[i] = parseFns[i](context);
16930              }
16931
16932              return compute(values);
16933            } catch (err) {
16934              $exceptionHandler($interpolateMinErr.interr(text, err));
16935            }
16936
16937          }, {
16938          // all of these properties are undocumented for now
16939          exp: text, //just for compatibility with regular watchers created via $watch
16940          expressions: expressions,
16941          $$watchDelegate: function(scope, listener) {
16942            var lastValue;
16943            return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
16944              var currValue = compute(values);
16945              if (isFunction(listener)) {
16946                listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
16947              }
16948              lastValue = currValue;
16949            });
16950          }
16951        });
16952      }
16953
16954      function parseStringifyInterceptor(value) {
16955        try {
16956          value = getValue(value);
16957          return allOrNothing && !isDefined(value) ? value : stringify(value);
16958        } catch (err) {
16959          $exceptionHandler($interpolateMinErr.interr(text, err));
16960        }
16961      }
16962    }
16963
16964
16965    /**
16966     * @ngdoc method
16967     * @name $interpolate#startSymbol
16968     * @description
16969     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
16970     *
16971     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
16972     * the symbol.
16973     *
16974     * @returns {string} start symbol.
16975     */
16976    $interpolate.startSymbol = function() {
16977      return startSymbol;
16978    };
16979
16980
16981    /**
16982     * @ngdoc method
16983     * @name $interpolate#endSymbol
16984     * @description
16985     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
16986     *
16987     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
16988     * the symbol.
16989     *
16990     * @returns {string} end symbol.
16991     */
16992    $interpolate.endSymbol = function() {
16993      return endSymbol;
16994    };
16995
16996    return $interpolate;
16997  }];
16998}
16999
17000function $IntervalProvider() {
17001  this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
17002       function($rootScope,   $window,   $q,   $$q,   $browser) {
17003    var intervals = {};
17004
17005
17006     /**
17007      * @ngdoc service
17008      * @name $interval
17009      *
17010      * @description
17011      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
17012      * milliseconds.
17013      *
17014      * The return value of registering an interval function is a promise. This promise will be
17015      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
17016      * run indefinitely if `count` is not defined. The value of the notification will be the
17017      * number of iterations that have run.
17018      * To cancel an interval, call `$interval.cancel(promise)`.
17019      *
17020      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
17021      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
17022      * time.
17023      *
17024      * <div class="alert alert-warning">
17025      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
17026      * with them.  In particular they are not automatically destroyed when a controller's scope or a
17027      * directive's element are destroyed.
17028      * You should take this into consideration and make sure to always cancel the interval at the
17029      * appropriate moment.  See the example below for more details on how and when to do this.
17030      * </div>
17031      *
17032      * @param {function()} fn A function that should be called repeatedly.
17033      * @param {number} delay Number of milliseconds between each function call.
17034      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
17035      *   indefinitely.
17036      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17037      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17038      * @param {...*=} Pass additional parameters to the executed function.
17039      * @returns {promise} A promise which will be notified on each iteration.
17040      *
17041      * @example
17042      * <example module="intervalExample">
17043      * <file name="index.html">
17044      *   <script>
17045      *     angular.module('intervalExample', [])
17046      *       .controller('ExampleController', ['$scope', '$interval',
17047      *         function($scope, $interval) {
17048      *           $scope.format = 'M/d/yy h:mm:ss a';
17049      *           $scope.blood_1 = 100;
17050      *           $scope.blood_2 = 120;
17051      *
17052      *           var stop;
17053      *           $scope.fight = function() {
17054      *             // Don't start a new fight if we are already fighting
17055      *             if ( angular.isDefined(stop) ) return;
17056      *
17057      *             stop = $interval(function() {
17058      *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
17059      *                 $scope.blood_1 = $scope.blood_1 - 3;
17060      *                 $scope.blood_2 = $scope.blood_2 - 4;
17061      *               } else {
17062      *                 $scope.stopFight();
17063      *               }
17064      *             }, 100);
17065      *           };
17066      *
17067      *           $scope.stopFight = function() {
17068      *             if (angular.isDefined(stop)) {
17069      *               $interval.cancel(stop);
17070      *               stop = undefined;
17071      *             }
17072      *           };
17073      *
17074      *           $scope.resetFight = function() {
17075      *             $scope.blood_1 = 100;
17076      *             $scope.blood_2 = 120;
17077      *           };
17078      *
17079      *           $scope.$on('$destroy', function() {
17080      *             // Make sure that the interval is destroyed too
17081      *             $scope.stopFight();
17082      *           });
17083      *         }])
17084      *       // Register the 'myCurrentTime' directive factory method.
17085      *       // We inject $interval and dateFilter service since the factory method is DI.
17086      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
17087      *         function($interval, dateFilter) {
17088      *           // return the directive link function. (compile function not needed)
17089      *           return function(scope, element, attrs) {
17090      *             var format,  // date format
17091      *                 stopTime; // so that we can cancel the time updates
17092      *
17093      *             // used to update the UI
17094      *             function updateTime() {
17095      *               element.text(dateFilter(new Date(), format));
17096      *             }
17097      *
17098      *             // watch the expression, and update the UI on change.
17099      *             scope.$watch(attrs.myCurrentTime, function(value) {
17100      *               format = value;
17101      *               updateTime();
17102      *             });
17103      *
17104      *             stopTime = $interval(updateTime, 1000);
17105      *
17106      *             // listen on DOM destroy (removal) event, and cancel the next UI update
17107      *             // to prevent updating time after the DOM element was removed.
17108      *             element.on('$destroy', function() {
17109      *               $interval.cancel(stopTime);
17110      *             });
17111      *           }
17112      *         }]);
17113      *   </script>
17114      *
17115      *   <div>
17116      *     <div ng-controller="ExampleController">
17117      *       <label>Date format: <input ng-model="format"></label> <hr/>
17118      *       Current time is: <span my-current-time="format"></span>
17119      *       <hr/>
17120      *       Blood 1 : <font color='red'>{{blood_1}}</font>
17121      *       Blood 2 : <font color='red'>{{blood_2}}</font>
17122      *       <button type="button" data-ng-click="fight()">Fight</button>
17123      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
17124      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
17125      *     </div>
17126      *   </div>
17127      *
17128      * </file>
17129      * </example>
17130      */
17131    function interval(fn, delay, count, invokeApply) {
17132      var hasParams = arguments.length > 4,
17133          args = hasParams ? sliceArgs(arguments, 4) : [],
17134          setInterval = $window.setInterval,
17135          clearInterval = $window.clearInterval,
17136          iteration = 0,
17137          skipApply = (isDefined(invokeApply) && !invokeApply),
17138          deferred = (skipApply ? $$q : $q).defer(),
17139          promise = deferred.promise;
17140
17141      count = isDefined(count) ? count : 0;
17142
17143      promise.$$intervalId = setInterval(function tick() {
17144        if (skipApply) {
17145          $browser.defer(callback);
17146        } else {
17147          $rootScope.$evalAsync(callback);
17148        }
17149        deferred.notify(iteration++);
17150
17151        if (count > 0 && iteration >= count) {
17152          deferred.resolve(iteration);
17153          clearInterval(promise.$$intervalId);
17154          delete intervals[promise.$$intervalId];
17155        }
17156
17157        if (!skipApply) $rootScope.$apply();
17158
17159      }, delay);
17160
17161      intervals[promise.$$intervalId] = deferred;
17162
17163      return promise;
17164
17165      function callback() {
17166        if (!hasParams) {
17167          fn(iteration);
17168        } else {
17169          fn.apply(null, args);
17170        }
17171      }
17172    }
17173
17174
17175     /**
17176      * @ngdoc method
17177      * @name $interval#cancel
17178      *
17179      * @description
17180      * Cancels a task associated with the `promise`.
17181      *
17182      * @param {Promise=} promise returned by the `$interval` function.
17183      * @returns {boolean} Returns `true` if the task was successfully canceled.
17184      */
17185    interval.cancel = function(promise) {
17186      if (promise && promise.$$intervalId in intervals) {
17187        intervals[promise.$$intervalId].reject('canceled');
17188        $window.clearInterval(promise.$$intervalId);
17189        delete intervals[promise.$$intervalId];
17190        return true;
17191      }
17192      return false;
17193    };
17194
17195    return interval;
17196  }];
17197}
17198
17199/**
17200 * @ngdoc service
17201 * @name $locale
17202 *
17203 * @description
17204 * $locale service provides localization rules for various Angular components. As of right now the
17205 * only public api is:
17206 *
17207 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
17208 */
17209
17210var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
17211    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
17212var $locationMinErr = minErr('$location');
17213
17214
17215/**
17216 * Encode path using encodeUriSegment, ignoring forward slashes
17217 *
17218 * @param {string} path Path to encode
17219 * @returns {string}
17220 */
17221function encodePath(path) {
17222  var segments = path.split('/'),
17223      i = segments.length;
17224
17225  while (i--) {
17226    segments[i] = encodeUriSegment(segments[i]);
17227  }
17228
17229  return segments.join('/');
17230}
17231
17232function parseAbsoluteUrl(absoluteUrl, locationObj) {
17233  var parsedUrl = urlResolve(absoluteUrl);
17234
17235  locationObj.$$protocol = parsedUrl.protocol;
17236  locationObj.$$host = parsedUrl.hostname;
17237  locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
17238}
17239
17240
17241function parseAppUrl(relativeUrl, locationObj) {
17242  var prefixed = (relativeUrl.charAt(0) !== '/');
17243  if (prefixed) {
17244    relativeUrl = '/' + relativeUrl;
17245  }
17246  var match = urlResolve(relativeUrl);
17247  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
17248      match.pathname.substring(1) : match.pathname);
17249  locationObj.$$search = parseKeyValue(match.search);
17250  locationObj.$$hash = decodeURIComponent(match.hash);
17251
17252  // make sure path starts with '/';
17253  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
17254    locationObj.$$path = '/' + locationObj.$$path;
17255  }
17256}
17257
17258
17259/**
17260 *
17261 * @param {string} begin
17262 * @param {string} whole
17263 * @returns {string} returns text from whole after begin or undefined if it does not begin with
17264 *                   expected string.
17265 */
17266function beginsWith(begin, whole) {
17267  if (whole.indexOf(begin) === 0) {
17268    return whole.substr(begin.length);
17269  }
17270}
17271
17272
17273function stripHash(url) {
17274  var index = url.indexOf('#');
17275  return index == -1 ? url : url.substr(0, index);
17276}
17277
17278function trimEmptyHash(url) {
17279  return url.replace(/(#.+)|#$/, '$1');
17280}
17281
17282
17283function stripFile(url) {
17284  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
17285}
17286
17287/* return the server only (scheme://host:port) */
17288function serverBase(url) {
17289  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
17290}
17291
17292
17293/**
17294 * LocationHtml5Url represents an url
17295 * This object is exposed as $location service when HTML5 mode is enabled and supported
17296 *
17297 * @constructor
17298 * @param {string} appBase application base URL
17299 * @param {string} appBaseNoFile application base URL stripped of any filename
17300 * @param {string} basePrefix url path prefix
17301 */
17302function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
17303  this.$$html5 = true;
17304  basePrefix = basePrefix || '';
17305  parseAbsoluteUrl(appBase, this);
17306
17307
17308  /**
17309   * Parse given html5 (regular) url string into properties
17310   * @param {string} url HTML5 url
17311   * @private
17312   */
17313  this.$$parse = function(url) {
17314    var pathUrl = beginsWith(appBaseNoFile, url);
17315    if (!isString(pathUrl)) {
17316      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
17317          appBaseNoFile);
17318    }
17319
17320    parseAppUrl(pathUrl, this);
17321
17322    if (!this.$$path) {
17323      this.$$path = '/';
17324    }
17325
17326    this.$$compose();
17327  };
17328
17329  /**
17330   * Compose url and update `absUrl` property
17331   * @private
17332   */
17333  this.$$compose = function() {
17334    var search = toKeyValue(this.$$search),
17335        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
17336
17337    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
17338    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
17339  };
17340
17341  this.$$parseLinkUrl = function(url, relHref) {
17342    if (relHref && relHref[0] === '#') {
17343      // special case for links to hash fragments:
17344      // keep the old url and only replace the hash fragment
17345      this.hash(relHref.slice(1));
17346      return true;
17347    }
17348    var appUrl, prevAppUrl;
17349    var rewrittenUrl;
17350
17351    if (isDefined(appUrl = beginsWith(appBase, url))) {
17352      prevAppUrl = appUrl;
17353      if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
17354        rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
17355      } else {
17356        rewrittenUrl = appBase + prevAppUrl;
17357      }
17358    } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
17359      rewrittenUrl = appBaseNoFile + appUrl;
17360    } else if (appBaseNoFile == url + '/') {
17361      rewrittenUrl = appBaseNoFile;
17362    }
17363    if (rewrittenUrl) {
17364      this.$$parse(rewrittenUrl);
17365    }
17366    return !!rewrittenUrl;
17367  };
17368}
17369
17370
17371/**
17372 * LocationHashbangUrl represents url
17373 * This object is exposed as $location service when developer doesn't opt into html5 mode.
17374 * It also serves as the base class for html5 mode fallback on legacy browsers.
17375 *
17376 * @constructor
17377 * @param {string} appBase application base URL
17378 * @param {string} appBaseNoFile application base URL stripped of any filename
17379 * @param {string} hashPrefix hashbang prefix
17380 */
17381function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
17382
17383  parseAbsoluteUrl(appBase, this);
17384
17385
17386  /**
17387   * Parse given hashbang url into properties
17388   * @param {string} url Hashbang url
17389   * @private
17390   */
17391  this.$$parse = function(url) {
17392    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
17393    var withoutHashUrl;
17394
17395    if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
17396
17397      // The rest of the url starts with a hash so we have
17398      // got either a hashbang path or a plain hash fragment
17399      withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
17400      if (isUndefined(withoutHashUrl)) {
17401        // There was no hashbang prefix so we just have a hash fragment
17402        withoutHashUrl = withoutBaseUrl;
17403      }
17404
17405    } else {
17406      // There was no hashbang path nor hash fragment:
17407      // If we are in HTML5 mode we use what is left as the path;
17408      // Otherwise we ignore what is left
17409      if (this.$$html5) {
17410        withoutHashUrl = withoutBaseUrl;
17411      } else {
17412        withoutHashUrl = '';
17413        if (isUndefined(withoutBaseUrl)) {
17414          appBase = url;
17415          this.replace();
17416        }
17417      }
17418    }
17419
17420    parseAppUrl(withoutHashUrl, this);
17421
17422    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
17423
17424    this.$$compose();
17425
17426    /*
17427     * In Windows, on an anchor node on documents loaded from
17428     * the filesystem, the browser will return a pathname
17429     * prefixed with the drive name ('/C:/path') when a
17430     * pathname without a drive is set:
17431     *  * a.setAttribute('href', '/foo')
17432     *   * a.pathname === '/C:/foo' //true
17433     *
17434     * Inside of Angular, we're always using pathnames that
17435     * do not include drive names for routing.
17436     */
17437    function removeWindowsDriveName(path, url, base) {
17438      /*
17439      Matches paths for file protocol on windows,
17440      such as /C:/foo/bar, and captures only /foo/bar.
17441      */
17442      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
17443
17444      var firstPathSegmentMatch;
17445
17446      //Get the relative path from the input URL.
17447      if (url.indexOf(base) === 0) {
17448        url = url.replace(base, '');
17449      }
17450
17451      // The input URL intentionally contains a first path segment that ends with a colon.
17452      if (windowsFilePathExp.exec(url)) {
17453        return path;
17454      }
17455
17456      firstPathSegmentMatch = windowsFilePathExp.exec(path);
17457      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
17458    }
17459  };
17460
17461  /**
17462   * Compose hashbang url and update `absUrl` property
17463   * @private
17464   */
17465  this.$$compose = function() {
17466    var search = toKeyValue(this.$$search),
17467        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
17468
17469    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
17470    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
17471  };
17472
17473  this.$$parseLinkUrl = function(url, relHref) {
17474    if (stripHash(appBase) == stripHash(url)) {
17475      this.$$parse(url);
17476      return true;
17477    }
17478    return false;
17479  };
17480}
17481
17482
17483/**
17484 * LocationHashbangUrl represents url
17485 * This object is exposed as $location service when html5 history api is enabled but the browser
17486 * does not support it.
17487 *
17488 * @constructor
17489 * @param {string} appBase application base URL
17490 * @param {string} appBaseNoFile application base URL stripped of any filename
17491 * @param {string} hashPrefix hashbang prefix
17492 */
17493function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
17494  this.$$html5 = true;
17495  LocationHashbangUrl.apply(this, arguments);
17496
17497  this.$$parseLinkUrl = function(url, relHref) {
17498    if (relHref && relHref[0] === '#') {
17499      // special case for links to hash fragments:
17500      // keep the old url and only replace the hash fragment
17501      this.hash(relHref.slice(1));
17502      return true;
17503    }
17504
17505    var rewrittenUrl;
17506    var appUrl;
17507
17508    if (appBase == stripHash(url)) {
17509      rewrittenUrl = url;
17510    } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
17511      rewrittenUrl = appBase + hashPrefix + appUrl;
17512    } else if (appBaseNoFile === url + '/') {
17513      rewrittenUrl = appBaseNoFile;
17514    }
17515    if (rewrittenUrl) {
17516      this.$$parse(rewrittenUrl);
17517    }
17518    return !!rewrittenUrl;
17519  };
17520
17521  this.$$compose = function() {
17522    var search = toKeyValue(this.$$search),
17523        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
17524
17525    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
17526    // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
17527    this.$$absUrl = appBase + hashPrefix + this.$$url;
17528  };
17529
17530}
17531
17532
17533var locationPrototype = {
17534
17535  /**
17536   * Are we in html5 mode?
17537   * @private
17538   */
17539  $$html5: false,
17540
17541  /**
17542   * Has any change been replacing?
17543   * @private
17544   */
17545  $$replace: false,
17546
17547  /**
17548   * @ngdoc method
17549   * @name $location#absUrl
17550   *
17551   * @description
17552   * This method is getter only.
17553   *
17554   * Return full url representation with all segments encoded according to rules specified in
17555   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
17556   *
17557   *
17558   * ```js
17559   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17560   * var absUrl = $location.absUrl();
17561   * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
17562   * ```
17563   *
17564   * @return {string} full url
17565   */
17566  absUrl: locationGetter('$$absUrl'),
17567
17568  /**
17569   * @ngdoc method
17570   * @name $location#url
17571   *
17572   * @description
17573   * This method is getter / setter.
17574   *
17575   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
17576   *
17577   * Change path, search and hash, when called with parameter and return `$location`.
17578   *
17579   *
17580   * ```js
17581   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17582   * var url = $location.url();
17583   * // => "/some/path?foo=bar&baz=xoxo"
17584   * ```
17585   *
17586   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
17587   * @return {string} url
17588   */
17589  url: function(url) {
17590    if (isUndefined(url)) {
17591      return this.$$url;
17592    }
17593
17594    var match = PATH_MATCH.exec(url);
17595    if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
17596    if (match[2] || match[1] || url === '') this.search(match[3] || '');
17597    this.hash(match[5] || '');
17598
17599    return this;
17600  },
17601
17602  /**
17603   * @ngdoc method
17604   * @name $location#protocol
17605   *
17606   * @description
17607   * This method is getter only.
17608   *
17609   * Return protocol of current url.
17610   *
17611   *
17612   * ```js
17613   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17614   * var protocol = $location.protocol();
17615   * // => "http"
17616   * ```
17617   *
17618   * @return {string} protocol of current url
17619   */
17620  protocol: locationGetter('$$protocol'),
17621
17622  /**
17623   * @ngdoc method
17624   * @name $location#host
17625   *
17626   * @description
17627   * This method is getter only.
17628   *
17629   * Return host of current url.
17630   *
17631   * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
17632   *
17633   *
17634   * ```js
17635   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17636   * var host = $location.host();
17637   * // => "example.com"
17638   *
17639   * // given url http://user:[email protected]:8080/#/some/path?foo=bar&baz=xoxo
17640   * host = $location.host();
17641   * // => "example.com"
17642   * host = location.host;
17643   * // => "example.com:8080"
17644   * ```
17645   *
17646   * @return {string} host of current url.
17647   */
17648  host: locationGetter('$$host'),
17649
17650  /**
17651   * @ngdoc method
17652   * @name $location#port
17653   *
17654   * @description
17655   * This method is getter only.
17656   *
17657   * Return port of current url.
17658   *
17659   *
17660   * ```js
17661   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17662   * var port = $location.port();
17663   * // => 80
17664   * ```
17665   *
17666   * @return {Number} port
17667   */
17668  port: locationGetter('$$port'),
17669
17670  /**
17671   * @ngdoc method
17672   * @name $location#path
17673   *
17674   * @description
17675   * This method is getter / setter.
17676   *
17677   * Return path of current url when called without any parameter.
17678   *
17679   * Change path when called with parameter and return `$location`.
17680   *
17681   * Note: Path should always begin with forward slash (/), this method will add the forward slash
17682   * if it is missing.
17683   *
17684   *
17685   * ```js
17686   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17687   * var path = $location.path();
17688   * // => "/some/path"
17689   * ```
17690   *
17691   * @param {(string|number)=} path New path
17692   * @return {string} path
17693   */
17694  path: locationGetterSetter('$$path', function(path) {
17695    path = path !== null ? path.toString() : '';
17696    return path.charAt(0) == '/' ? path : '/' + path;
17697  }),
17698
17699  /**
17700   * @ngdoc method
17701   * @name $location#search
17702   *
17703   * @description
17704   * This method is getter / setter.
17705   *
17706   * Return search part (as object) of current url when called without any parameter.
17707   *
17708   * Change search part when called with parameter and return `$location`.
17709   *
17710   *
17711   * ```js
17712   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
17713   * var searchObject = $location.search();
17714   * // => {foo: 'bar', baz: 'xoxo'}
17715   *
17716   * // set foo to 'yipee'
17717   * $location.search('foo', 'yipee');
17718   * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
17719   * ```
17720   *
17721   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
17722   * hash object.
17723   *
17724   * When called with a single argument the method acts as a setter, setting the `search` component
17725   * of `$location` to the specified value.
17726   *
17727   * If the argument is a hash object containing an array of values, these values will be encoded
17728   * as duplicate search parameters in the url.
17729   *
17730   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
17731   * will override only a single search property.
17732   *
17733   * If `paramValue` is an array, it will override the property of the `search` component of
17734   * `$location` specified via the first argument.
17735   *
17736   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
17737   *
17738   * If `paramValue` is `true`, the property specified via the first argument will be added with no
17739   * value nor trailing equal sign.
17740   *
17741   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
17742   * one or more arguments returns `$location` object itself.
17743   */
17744  search: function(search, paramValue) {
17745    switch (arguments.length) {
17746      case 0:
17747        return this.$$search;
17748      case 1:
17749        if (isString(search) || isNumber(search)) {
17750          search = search.toString();
17751          this.$$search = parseKeyValue(search);
17752        } else if (isObject(search)) {
17753          search = copy(search, {});
17754          // remove object undefined or null properties
17755          forEach(search, function(value, key) {
17756            if (value == null) delete search[key];
17757          });
17758
17759          this.$$search = search;
17760        } else {
17761          throw $locationMinErr('isrcharg',
17762              'The first argument of the `$location#search()` call must be a string or an object.');
17763        }
17764        break;
17765      default:
17766        if (isUndefined(paramValue) || paramValue === null) {
17767          delete this.$$search[search];
17768        } else {
17769          this.$$search[search] = paramValue;
17770        }
17771    }
17772
17773    this.$$compose();
17774    return this;
17775  },
17776
17777  /**
17778   * @ngdoc method
17779   * @name $location#hash
17780   *
17781   * @description
17782   * This method is getter / setter.
17783   *
17784   * Returns the hash fragment when called without any parameters.
17785   *
17786   * Changes the hash fragment when called with a parameter and returns `$location`.
17787   *
17788   *
17789   * ```js
17790   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
17791   * var hash = $location.hash();
17792   * // => "hashValue"
17793   * ```
17794   *
17795   * @param {(string|number)=} hash New hash fragment
17796   * @return {string} hash
17797   */
17798  hash: locationGetterSetter('$$hash', function(hash) {
17799    return hash !== null ? hash.toString() : '';
17800  }),
17801
17802  /**
17803   * @ngdoc method
17804   * @name $location#replace
17805   *
17806   * @description
17807   * If called, all changes to $location during the current `$digest` will replace the current history
17808   * record, instead of adding a new one.
17809   */
17810  replace: function() {
17811    this.$$replace = true;
17812    return this;
17813  }
17814};
17815
17816forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
17817  Location.prototype = Object.create(locationPrototype);
17818
17819  /**
17820   * @ngdoc method
17821   * @name $location#state
17822   *
17823   * @description
17824   * This method is getter / setter.
17825   *
17826   * Return the history state object when called without any parameter.
17827   *
17828   * Change the history state object when called with one parameter and return `$location`.
17829   * The state object is later passed to `pushState` or `replaceState`.
17830   *
17831   * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
17832   * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
17833   * older browsers (like IE9 or Android < 4.0), don't use this method.
17834   *
17835   * @param {object=} state State object for pushState or replaceState
17836   * @return {object} state
17837   */
17838  Location.prototype.state = function(state) {
17839    if (!arguments.length) {
17840      return this.$$state;
17841    }
17842
17843    if (Location !== LocationHtml5Url || !this.$$html5) {
17844      throw $locationMinErr('nostate', 'History API state support is available only ' +
17845        'in HTML5 mode and only in browsers supporting HTML5 History API');
17846    }
17847    // The user might modify `stateObject` after invoking `$location.state(stateObject)`
17848    // but we're changing the $$state reference to $browser.state() during the $digest
17849    // so the modification window is narrow.
17850    this.$$state = isUndefined(state) ? null : state;
17851
17852    return this;
17853  };
17854});
17855
17856
17857function locationGetter(property) {
17858  return function() {
17859    return this[property];
17860  };
17861}
17862
17863
17864function locationGetterSetter(property, preprocess) {
17865  return function(value) {
17866    if (isUndefined(value)) {
17867      return this[property];
17868    }
17869
17870    this[property] = preprocess(value);
17871    this.$$compose();
17872
17873    return this;
17874  };
17875}
17876
17877
17878/**
17879 * @ngdoc service
17880 * @name $location
17881 *
17882 * @requires $rootElement
17883 *
17884 * @description
17885 * The $location service parses the URL in the browser address bar (based on the
17886 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
17887 * available to your application. Changes to the URL in the address bar are reflected into
17888 * $location service and changes to $location are reflected into the browser address bar.
17889 *
17890 * **The $location service:**
17891 *
17892 * - Exposes the current URL in the browser address bar, so you can
17893 *   - Watch and observe the URL.
17894 *   - Change the URL.
17895 * - Synchronizes the URL with the browser when the user
17896 *   - Changes the address bar.
17897 *   - Clicks the back or forward button (or clicks a History link).
17898 *   - Clicks on a link.
17899 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
17900 *
17901 * For more information see {@link guide/$location Developer Guide: Using $location}
17902 */
17903
17904/**
17905 * @ngdoc provider
17906 * @name $locationProvider
17907 * @description
17908 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
17909 */
17910function $LocationProvider() {
17911  var hashPrefix = '',
17912      html5Mode = {
17913        enabled: false,
17914        requireBase: true,
17915        rewriteLinks: true
17916      };
17917
17918  /**
17919   * @ngdoc method
17920   * @name $locationProvider#hashPrefix
17921   * @description
17922   * @param {string=} prefix Prefix for hash part (containing path and search)
17923   * @returns {*} current value if used as getter or itself (chaining) if used as setter
17924   */
17925  this.hashPrefix = function(prefix) {
17926    if (isDefined(prefix)) {
17927      hashPrefix = prefix;
17928      return this;
17929    } else {
17930      return hashPrefix;
17931    }
17932  };
17933
17934  /**
17935   * @ngdoc method
17936   * @name $locationProvider#html5Mode
17937   * @description
17938   * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
17939   *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
17940   *   properties:
17941   *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
17942   *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
17943   *     support `pushState`.
17944   *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
17945   *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
17946   *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
17947   *     See the {@link guide/$location $location guide for more information}
17948   *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
17949   *     enables/disables url rewriting for relative links.
17950   *
17951   * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
17952   */
17953  this.html5Mode = function(mode) {
17954    if (isBoolean(mode)) {
17955      html5Mode.enabled = mode;
17956      return this;
17957    } else if (isObject(mode)) {
17958
17959      if (isBoolean(mode.enabled)) {
17960        html5Mode.enabled = mode.enabled;
17961      }
17962
17963      if (isBoolean(mode.requireBase)) {
17964        html5Mode.requireBase = mode.requireBase;
17965      }
17966
17967      if (isBoolean(mode.rewriteLinks)) {
17968        html5Mode.rewriteLinks = mode.rewriteLinks;
17969      }
17970
17971      return this;
17972    } else {
17973      return html5Mode;
17974    }
17975  };
17976
17977  /**
17978   * @ngdoc event
17979   * @name $location#$locationChangeStart
17980   * @eventType broadcast on root scope
17981   * @description
17982   * Broadcasted before a URL will change.
17983   *
17984   * This change can be prevented by calling
17985   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
17986   * details about event object. Upon successful change
17987   * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
17988   *
17989   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
17990   * the browser supports the HTML5 History API.
17991   *
17992   * @param {Object} angularEvent Synthetic event object.
17993   * @param {string} newUrl New URL
17994   * @param {string=} oldUrl URL that was before it was changed.
17995   * @param {string=} newState New history state object
17996   * @param {string=} oldState History state object that was before it was changed.
17997   */
17998
17999  /**
18000   * @ngdoc event
18001   * @name $location#$locationChangeSuccess
18002   * @eventType broadcast on root scope
18003   * @description
18004   * Broadcasted after a URL was changed.
18005   *
18006   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
18007   * the browser supports the HTML5 History API.
18008   *
18009   * @param {Object} angularEvent Synthetic event object.
18010   * @param {string} newUrl New URL
18011   * @param {string=} oldUrl URL that was before it was changed.
18012   * @param {string=} newState New history state object
18013   * @param {string=} oldState History state object that was before it was changed.
18014   */
18015
18016  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
18017      function($rootScope, $browser, $sniffer, $rootElement, $window) {
18018    var $location,
18019        LocationMode,
18020        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
18021        initialUrl = $browser.url(),
18022        appBase;
18023
18024    if (html5Mode.enabled) {
18025      if (!baseHref && html5Mode.requireBase) {
18026        throw $locationMinErr('nobase',
18027          "$location in HTML5 mode requires a <base> tag to be present!");
18028      }
18029      appBase = serverBase(initialUrl) + (baseHref || '/');
18030      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
18031    } else {
18032      appBase = stripHash(initialUrl);
18033      LocationMode = LocationHashbangUrl;
18034    }
18035    var appBaseNoFile = stripFile(appBase);
18036
18037    $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
18038    $location.$$parseLinkUrl(initialUrl, initialUrl);
18039
18040    $location.$$state = $browser.state();
18041
18042    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
18043
18044    function setBrowserUrlWithFallback(url, replace, state) {
18045      var oldUrl = $location.url();
18046      var oldState = $location.$$state;
18047      try {
18048        $browser.url(url, replace, state);
18049
18050        // Make sure $location.state() returns referentially identical (not just deeply equal)
18051        // state object; this makes possible quick checking if the state changed in the digest
18052        // loop. Checking deep equality would be too expensive.
18053        $location.$$state = $browser.state();
18054      } catch (e) {
18055        // Restore old values if pushState fails
18056        $location.url(oldUrl);
18057        $location.$$state = oldState;
18058
18059        throw e;
18060      }
18061    }
18062
18063    $rootElement.on('click', function(event) {
18064      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
18065      // currently we open nice url link and redirect then
18066
18067      if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
18068
18069      var elm = jqLite(event.target);
18070
18071      // traverse the DOM up to find first A tag
18072      while (nodeName_(elm[0]) !== 'a') {
18073        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
18074        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
18075      }
18076
18077      var absHref = elm.prop('href');
18078      // get the actual href attribute - see
18079      // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
18080      var relHref = elm.attr('href') || elm.attr('xlink:href');
18081
18082      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
18083        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
18084        // an animation.
18085        absHref = urlResolve(absHref.animVal).href;
18086      }
18087
18088      // Ignore when url is started with javascript: or mailto:
18089      if (IGNORE_URI_REGEXP.test(absHref)) return;
18090
18091      if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
18092        if ($location.$$parseLinkUrl(absHref, relHref)) {
18093          // We do a preventDefault for all urls that are part of the angular application,
18094          // in html5mode and also without, so that we are able to abort navigation without
18095          // getting double entries in the location history.
18096          event.preventDefault();
18097          // update location manually
18098          if ($location.absUrl() != $browser.url()) {
18099            $rootScope.$apply();
18100            // hack to work around FF6 bug 684208 when scenario runner clicks on links
18101            $window.angular['ff-684208-preventDefault'] = true;
18102          }
18103        }
18104      }
18105    });
18106
18107
18108    // rewrite hashbang url <> html5 url
18109    if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
18110      $browser.url($location.absUrl(), true);
18111    }
18112
18113    var initializing = true;
18114
18115    // update $location when $browser url changes
18116    $browser.onUrlChange(function(newUrl, newState) {
18117
18118      if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
18119        // If we are navigating outside of the app then force a reload
18120        $window.location.href = newUrl;
18121        return;
18122      }
18123
18124      $rootScope.$evalAsync(function() {
18125        var oldUrl = $location.absUrl();
18126        var oldState = $location.$$state;
18127        var defaultPrevented;
18128        newUrl = trimEmptyHash(newUrl);
18129        $location.$$parse(newUrl);
18130        $location.$$state = newState;
18131
18132        defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
18133            newState, oldState).defaultPrevented;
18134
18135        // if the location was changed by a `$locationChangeStart` handler then stop
18136        // processing this location change
18137        if ($location.absUrl() !== newUrl) return;
18138
18139        if (defaultPrevented) {
18140          $location.$$parse(oldUrl);
18141          $location.$$state = oldState;
18142          setBrowserUrlWithFallback(oldUrl, false, oldState);
18143        } else {
18144          initializing = false;
vendor: 4,210 bytes, lines 18145-18287
18145          afterLocationChange(oldUrl, oldState);
18146        }
18147      });
18148      if (!$rootScope.$$phase) $rootScope.$digest();
18149    });
18150
18151    // update browser
18152    $rootScope.$watch(function $locationWatch() {
18153      var oldUrl = trimEmptyHash($browser.url());
18154      var newUrl = trimEmptyHash($location.absUrl());
18155      var oldState = $browser.state();
18156      var currentReplace = $location.$$replace;
18157      var urlOrStateChanged = oldUrl !== newUrl ||
18158        ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
18159
18160      if (initializing || urlOrStateChanged) {
18161        initializing = false;
18162
18163        $rootScope.$evalAsync(function() {
18164          var newUrl = $location.absUrl();
18165          var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
18166              $location.$$state, oldState).defaultPrevented;
18167
18168          // if the location was changed by a `$locationChangeStart` handler then stop
18169          // processing this location change
18170          if ($location.absUrl() !== newUrl) return;
18171
18172          if (defaultPrevented) {
18173            $location.$$parse(oldUrl);
18174            $location.$$state = oldState;
18175          } else {
18176            if (urlOrStateChanged) {
18177              setBrowserUrlWithFallback(newUrl, currentReplace,
18178                                        oldState === $location.$$state ? null : $location.$$state);
18179            }
18180            afterLocationChange(oldUrl, oldState);
18181          }
18182        });
18183      }
18184
18185      $location.$$replace = false;
18186
18187      // we don't need to return anything because $evalAsync will make the digest loop dirty when
18188      // there is a change
18189    });
18190
18191    return $location;
18192
18193    function afterLocationChange(oldUrl, oldState) {
18194      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
18195        $location.$$state, oldState);
18196    }
18197}];
18198}
18199
18200/**
18201 * @ngdoc service
18202 * @name $log
18203 * @requires $window
18204 *
18205 * @description
18206 * Simple service for logging. Default implementation safely writes the message
18207 * into the browser's console (if present).
18208 *
18209 * The main purpose of this service is to simplify debugging and troubleshooting.
18210 *
18211 * The default is to log `debug` messages. You can use
18212 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
18213 *
18214 * @example
18215   <example module="logExample">
18216     <file name="script.js">
18217       angular.module('logExample', [])
18218         .controller('LogController', ['$scope', '$log', function($scope, $log) {
18219           $scope.$log = $log;
18220           $scope.message = 'Hello World!';
18221         }]);
18222     </file>
18223     <file name="index.html">
18224       <div ng-controller="LogController">
18225         <p>Reload this page with open console, enter text and hit the log button...</p>
18226         <label>Message:
18227         <input type="text" ng-model="message" /></label>
18228         <button ng-click="$log.log(message)">log</button>
18229         <button ng-click="$log.warn(message)">warn</button>
18230         <button ng-click="$log.info(message)">info</button>
18231         <button ng-click="$log.error(message)">error</button>
18232         <button ng-click="$log.debug(message)">debug</button>
18233       </div>
18234     </file>
18235   </example>
18236 */
18237
18238/**
18239 * @ngdoc provider
18240 * @name $logProvider
18241 * @description
18242 * Use the `$logProvider` to configure how the application logs messages
18243 */
18244function $LogProvider() {
18245  var debug = true,
18246      self = this;
18247
18248  /**
18249   * @ngdoc method
18250   * @name $logProvider#debugEnabled
18251   * @description
18252   * @param {boolean=} flag enable or disable debug level messages
18253   * @returns {*} current value if used as getter or itself (chaining) if used as setter
18254   */
18255  this.debugEnabled = function(flag) {
18256    if (isDefined(flag)) {
18257      debug = flag;
18258    return this;
18259    } else {
18260      return debug;
18261    }
18262  };
18263
18264  this.$get = ['$window', function($window) {
18265    return {
18266      /**
18267       * @ngdoc method
18268       * @name $log#log
18269       *
18270       * @description
18271       * Write a log message
18272       */
18273      log: consoleLog('log'),
18274
18275      /**
18276       * @ngdoc method
18277       * @name $log#info
18278       *
18279       * @description
18280       * Write an information message
18281       */
18282      info: consoleLog('info'),
18283
18284      /**
18285       * @ngdoc method
18286       * @name $log#warn
18287       *
18288       * @description
18289       * Write a warning message
18290       */
18291      warn: consoleLog('warn'),
18292
18293      /**
18294       * @ngdoc method
18295       * @name $log#error
18296       *
18297       * @description
18298       * Write an error message
18299       */
18300      error: consoleLog('error'),
18301
18302      /**
18303       * @ngdoc method
18304       * @name $log#debug
18305       *
18306       * @description
18307       * Write a debug message
18308       */
18309      debug: (function() {
18310        var fn = consoleLog('debug');
18311
18312        return function() {
18313          if (debug) {
18314            fn.apply(self, arguments);
18315          }
18316        };
18317      }())
18318    };
18319
18320    function formatError(arg) {
18321      if (arg instanceof Error) {
18322        if (arg.stack) {
18323          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
18324              ? 'Error: ' + arg.message + '\n' + arg.stack
18325              : arg.stack;
18326        } else if (arg.sourceURL) {
18327          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
18328        }
18329      }
18330      return arg;
18331    }
18332
18333    function consoleLog(type) {
18334      var console = $window.console || {},
18335          logFn = console[type] || console.log || noop,
18336          hasApply = false;
18337
18338      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
18339      // The reason behind this is that console.log has type "object" in IE8...
18340      try {
18341        hasApply = !!logFn.apply;
18342      } catch (e) {}
18343
18344      if (hasApply) {
18345        return function() {
18346          var args = [];
18347          forEach(arguments, function(arg) {
18348            args.push(formatError(arg));
18349          });
18350          return logFn.apply(console, args);
18351        };
18352      }
18353
18354      // we are IE which either doesn't have window.console => this is noop and we do nothing,
18355      // or we are IE where console.log doesn't have apply so we log at least first 2 args
18356      return function(arg1, arg2) {
18357        logFn(arg1, arg2 == null ? '' : arg2);
18358      };
18359    }
18360  }];
18361}
18362
18363/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18364 *     Any commits to this file should be reviewed with security in mind.  *
18365 *   Changes to this file can potentially create security vulnerabilities. *
18366 *          An approval from 2 Core members with history of modifying      *
18367 *                         this file is required.                          *
18368 *                                                                         *
18369 *  Does the change somehow allow for arbitrary javascript to be executed? *
18370 *    Or allows for someone to change the prototype of built-in objects?   *
18371 *     Or gives undesired access to variables likes document or window?    *
18372 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18373
18374var $parseMinErr = minErr('$parse');
18375
18376// Sandboxing Angular Expressions
18377// ------------------------------
18378// Angular expressions are generally considered safe because these expressions only have direct
18379// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
18380// obtaining a reference to native JS functions such as the Function constructor.
18381//
18382// As an example, consider the following Angular expression:
18383//
18384//   {}.toString.constructor('alert("evil JS code")')
18385//
18386// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
18387// against the expression language, but not to prevent exploits that were enabled by exposing
18388// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
18389// practice and therefore we are not even trying to protect against interaction with an object
18390// explicitly exposed in this way.
18391//
18392// In general, it is not possible to access a Window object from an angular expression unless a
18393// window or some DOM object that has a reference to window is published onto a Scope.
18394// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
18395// native objects.
18396//
18397// See https://docs.angularjs.org/guide/security
18398
18399
18400function ensureSafeMemberName(name, fullExpression) {
18401  if (name === "__defineGetter__" || name === "__defineSetter__"
18402      || name === "__lookupGetter__" || name === "__lookupSetter__"
18403      || name === "__proto__") {
18404    throw $parseMinErr('isecfld',
18405        'Attempting to access a disallowed field in Angular expressions! '
18406        + 'Expression: {0}', fullExpression);
18407  }
18408  return name;
18409}
18410
18411function getStringValue(name) {
18412  // Property names must be strings. This means that non-string objects cannot be used
18413  // as keys in an object. Any non-string object, including a number, is typecasted
18414  // into a string via the toString method.
18415  // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
18416  //
18417  // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
18418  // to a string. It's not always possible. If `name` is an object and its `toString` method is
18419  // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
18420  //
18421  // TypeError: Cannot convert object to primitive value
18422  //
18423  // For performance reasons, we don't catch this error here and allow it to propagate up the call
18424  // stack. Note that you'll get the same error in JavaScript if you try to access a property using
18425  // such a 'broken' object as a key.
18426  return name + '';
18427}
18428
18429function ensureSafeObject(obj, fullExpression) {
18430  // nifty check if obj is Function that is fast and works across iframes and other contexts
18431  if (obj) {
18432    if (obj.constructor === obj) {
18433      throw $parseMinErr('isecfn',
18434          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
18435          fullExpression);
18436    } else if (// isWindow(obj)
18437        obj.window === obj) {
18438      throw $parseMinErr('isecwindow',
18439          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
18440          fullExpression);
18441    } else if (// isElement(obj)
18442        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
18443      throw $parseMinErr('isecdom',
18444          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
18445          fullExpression);
18446    } else if (// block Object so that we can't get hold of dangerous Object.* methods
18447        obj === Object) {
18448      throw $parseMinErr('isecobj',
18449          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
18450          fullExpression);
18451    }
18452  }
18453  return obj;
18454}
18455
18456var CALL = Function.prototype.call;
18457var APPLY = Function.prototype.apply;
18458var BIND = Function.prototype.bind;
18459
18460function ensureSafeFunction(obj, fullExpression) {
18461  if (obj) {
18462    if (obj.constructor === obj) {
18463      throw $parseMinErr('isecfn',
18464        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
18465        fullExpression);
18466    } else if (obj === CALL || obj === APPLY || obj === BIND) {
18467      throw $parseMinErr('isecff',
18468        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
18469        fullExpression);
18470    }
18471  }
18472}
18473
18474function ensureSafeAssignContext(obj, fullExpression) {
18475  if (obj) {
18476    if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
18477        obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
18478      throw $parseMinErr('isecaf',
18479        'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
18480    }
18481  }
18482}
18483
18484var OPERATORS = createMap();
18485forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
18486var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
18487
18488
vendor: 48,343 bytes, lines 18489-20012
18489/////////////////////////////////////////
18490
18491
18492/**
18493 * @constructor
18494 */
18495var Lexer = function(options) {
18496  this.options = options;
18497};
18498
18499Lexer.prototype = {
18500  constructor: Lexer,
18501
18502  lex: function(text) {
18503    this.text = text;
18504    this.index = 0;
18505    this.tokens = [];
18506
18507    while (this.index < this.text.length) {
18508      var ch = this.text.charAt(this.index);
18509      if (ch === '"' || ch === "'") {
18510        this.readString(ch);
18511      } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
18512        this.readNumber();
18513      } else if (this.isIdent(ch)) {
18514        this.readIdent();
18515      } else if (this.is(ch, '(){}[].,;:?')) {
18516        this.tokens.push({index: this.index, text: ch});
18517        this.index++;
18518      } else if (this.isWhitespace(ch)) {
18519        this.index++;
18520      } else {
18521        var ch2 = ch + this.peek();
18522        var ch3 = ch2 + this.peek(2);
18523        var op1 = OPERATORS[ch];
18524        var op2 = OPERATORS[ch2];
18525        var op3 = OPERATORS[ch3];
18526        if (op1 || op2 || op3) {
18527          var token = op3 ? ch3 : (op2 ? ch2 : ch);
18528          this.tokens.push({index: this.index, text: token, operator: true});
18529          this.index += token.length;
18530        } else {
18531          this.throwError('Unexpected next character ', this.index, this.index + 1);
18532        }
18533      }
18534    }
18535    return this.tokens;
18536  },
18537
18538  is: function(ch, chars) {
18539    return chars.indexOf(ch) !== -1;
18540  },
18541
18542  peek: function(i) {
18543    var num = i || 1;
18544    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
18545  },
18546
18547  isNumber: function(ch) {
18548    return ('0' <= ch && ch <= '9') && typeof ch === "string";
18549  },
18550
18551  isWhitespace: function(ch) {
18552    // IE treats non-breaking space as \u00A0
18553    return (ch === ' ' || ch === '\r' || ch === '\t' ||
18554            ch === '\n' || ch === '\v' || ch === '\u00A0');
18555  },
18556
18557  isIdent: function(ch) {
18558    return ('a' <= ch && ch <= 'z' ||
18559            'A' <= ch && ch <= 'Z' ||
18560            '_' === ch || ch === '$');
18561  },
18562
18563  isExpOperator: function(ch) {
18564    return (ch === '-' || ch === '+' || this.isNumber(ch));
18565  },
18566
18567  throwError: function(error, start, end) {
18568    end = end || this.index;
18569    var colStr = (isDefined(start)
18570            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
18571            : ' ' + end);
18572    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
18573        error, colStr, this.text);
18574  },
18575
18576  readNumber: function() {
18577    var number = '';
18578    var start = this.index;
18579    while (this.index < this.text.length) {
18580      var ch = lowercase(this.text.charAt(this.index));
18581      if (ch == '.' || this.isNumber(ch)) {
18582        number += ch;
18583      } else {
18584        var peekCh = this.peek();
18585        if (ch == 'e' && this.isExpOperator(peekCh)) {
18586          number += ch;
18587        } else if (this.isExpOperator(ch) &&
18588            peekCh && this.isNumber(peekCh) &&
18589            number.charAt(number.length - 1) == 'e') {
18590          number += ch;
18591        } else if (this.isExpOperator(ch) &&
18592            (!peekCh || !this.isNumber(peekCh)) &&
18593            number.charAt(number.length - 1) == 'e') {
18594          this.throwError('Invalid exponent');
18595        } else {
18596          break;
18597        }
18598      }
18599      this.index++;
18600    }
18601    this.tokens.push({
18602      index: start,
18603      text: number,
18604      constant: true,
18605      value: Number(number)
18606    });
18607  },
18608
18609  readIdent: function() {
18610    var start = this.index;
18611    while (this.index < this.text.length) {
18612      var ch = this.text.charAt(this.index);
18613      if (!(this.isIdent(ch) || this.isNumber(ch))) {
18614        break;
18615      }
18616      this.index++;
18617    }
18618    this.tokens.push({
18619      index: start,
18620      text: this.text.slice(start, this.index),
18621      identifier: true
18622    });
18623  },
18624
18625  readString: function(quote) {
18626    var start = this.index;
18627    this.index++;
18628    var string = '';
18629    var rawString = quote;
18630    var escape = false;
18631    while (this.index < this.text.length) {
18632      var ch = this.text.charAt(this.index);
18633      rawString += ch;
18634      if (escape) {
18635        if (ch === 'u') {
18636          var hex = this.text.substring(this.index + 1, this.index + 5);
18637          if (!hex.match(/[\da-f]{4}/i)) {
18638            this.throwError('Invalid unicode escape [\\u' + hex + ']');
18639          }
18640          this.index += 4;
18641          string += String.fromCharCode(parseInt(hex, 16));
18642        } else {
18643          var rep = ESCAPE[ch];
18644          string = string + (rep || ch);
18645        }
18646        escape = false;
18647      } else if (ch === '\\') {
18648        escape = true;
18649      } else if (ch === quote) {
18650        this.index++;
18651        this.tokens.push({
18652          index: start,
18653          text: rawString,
18654          constant: true,
18655          value: string
18656        });
18657        return;
18658      } else {
18659        string += ch;
18660      }
18661      this.index++;
18662    }
18663    this.throwError('Unterminated quote', start);
18664  }
18665};
18666
18667var AST = function(lexer, options) {
18668  this.lexer = lexer;
18669  this.options = options;
18670};
18671
18672AST.Program = 'Program';
18673AST.ExpressionStatement = 'ExpressionStatement';
18674AST.AssignmentExpression = 'AssignmentExpression';
18675AST.ConditionalExpression = 'ConditionalExpression';
18676AST.LogicalExpression = 'LogicalExpression';
18677AST.BinaryExpression = 'BinaryExpression';
18678AST.UnaryExpression = 'UnaryExpression';
18679AST.CallExpression = 'CallExpression';
18680AST.MemberExpression = 'MemberExpression';
18681AST.Identifier = 'Identifier';
18682AST.Literal = 'Literal';
18683AST.ArrayExpression = 'ArrayExpression';
18684AST.Property = 'Property';
18685AST.ObjectExpression = 'ObjectExpression';
18686AST.ThisExpression = 'ThisExpression';
18687AST.LocalsExpression = 'LocalsExpression';
18688
18689// Internal use only
18690AST.NGValueParameter = 'NGValueParameter';
18691
18692AST.prototype = {
18693  ast: function(text) {
18694    this.text = text;
18695    this.tokens = this.lexer.lex(text);
18696
18697    var value = this.program();
18698
18699    if (this.tokens.length !== 0) {
18700      this.throwError('is an unexpected token', this.tokens[0]);
18701    }
18702
18703    return value;
18704  },
18705
18706  program: function() {
18707    var body = [];
18708    while (true) {
18709      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
18710        body.push(this.expressionStatement());
18711      if (!this.expect(';')) {
18712        return { type: AST.Program, body: body};
18713      }
18714    }
18715  },
18716
18717  expressionStatement: function() {
18718    return { type: AST.ExpressionStatement, expression: this.filterChain() };
18719  },
18720
18721  filterChain: function() {
18722    var left = this.expression();
18723    var token;
18724    while ((token = this.expect('|'))) {
18725      left = this.filter(left);
18726    }
18727    return left;
18728  },
18729
18730  expression: function() {
18731    return this.assignment();
18732  },
18733
18734  assignment: function() {
18735    var result = this.ternary();
18736    if (this.expect('=')) {
18737      result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
18738    }
18739    return result;
18740  },
18741
18742  ternary: function() {
18743    var test = this.logicalOR();
18744    var alternate;
18745    var consequent;
18746    if (this.expect('?')) {
18747      alternate = this.expression();
18748      if (this.consume(':')) {
18749        consequent = this.expression();
18750        return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
18751      }
18752    }
18753    return test;
18754  },
18755
18756  logicalOR: function() {
18757    var left = this.logicalAND();
18758    while (this.expect('||')) {
18759      left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
18760    }
18761    return left;
18762  },
18763
18764  logicalAND: function() {
18765    var left = this.equality();
18766    while (this.expect('&&')) {
18767      left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
18768    }
18769    return left;
18770  },
18771
18772  equality: function() {
18773    var left = this.relational();
18774    var token;
18775    while ((token = this.expect('==','!=','===','!=='))) {
18776      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
18777    }
18778    return left;
18779  },
18780
18781  relational: function() {
18782    var left = this.additive();
18783    var token;
18784    while ((token = this.expect('<', '>', '<=', '>='))) {
18785      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
18786    }
18787    return left;
18788  },
18789
18790  additive: function() {
18791    var left = this.multiplicative();
18792    var token;
18793    while ((token = this.expect('+','-'))) {
18794      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
18795    }
18796    return left;
18797  },
18798
18799  multiplicative: function() {
18800    var left = this.unary();
18801    var token;
18802    while ((token = this.expect('*','/','%'))) {
18803      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
18804    }
18805    return left;
18806  },
18807
18808  unary: function() {
18809    var token;
18810    if ((token = this.expect('+', '-', '!'))) {
18811      return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
18812    } else {
18813      return this.primary();
18814    }
18815  },
18816
18817  primary: function() {
18818    var primary;
18819    if (this.expect('(')) {
18820      primary = this.filterChain();
18821      this.consume(')');
18822    } else if (this.expect('[')) {
18823      primary = this.arrayDeclaration();
18824    } else if (this.expect('{')) {
18825      primary = this.object();
18826    } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
18827      primary = copy(this.selfReferential[this.consume().text]);
18828    } else if (this.options.literals.hasOwnProperty(this.peek().text)) {
18829      primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
18830    } else if (this.peek().identifier) {
18831      primary = this.identifier();
18832    } else if (this.peek().constant) {
18833      primary = this.constant();
18834    } else {
18835      this.throwError('not a primary expression', this.peek());
18836    }
18837
18838    var next;
18839    while ((next = this.expect('(', '[', '.'))) {
18840      if (next.text === '(') {
18841        primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
18842        this.consume(')');
18843      } else if (next.text === '[') {
18844        primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
18845        this.consume(']');
18846      } else if (next.text === '.') {
18847        primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
18848      } else {
18849        this.throwError('IMPOSSIBLE');
18850      }
18851    }
18852    return primary;
18853  },
18854
18855  filter: function(baseExpression) {
18856    var args = [baseExpression];
18857    var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
18858
18859    while (this.expect(':')) {
18860      args.push(this.expression());
18861    }
18862
18863    return result;
18864  },
18865
18866  parseArguments: function() {
18867    var args = [];
18868    if (this.peekToken().text !== ')') {
18869      do {
18870        args.push(this.expression());
18871      } while (this.expect(','));
18872    }
18873    return args;
18874  },
18875
18876  identifier: function() {
18877    var token = this.consume();
18878    if (!token.identifier) {
18879      this.throwError('is not a valid identifier', token);
18880    }
18881    return { type: AST.Identifier, name: token.text };
18882  },
18883
18884  constant: function() {
18885    // TODO check that it is a constant
18886    return { type: AST.Literal, value: this.consume().value };
18887  },
18888
18889  arrayDeclaration: function() {
18890    var elements = [];
18891    if (this.peekToken().text !== ']') {
18892      do {
18893        if (this.peek(']')) {
18894          // Support trailing commas per ES5.1.
18895          break;
18896        }
18897        elements.push(this.expression());
18898      } while (this.expect(','));
18899    }
18900    this.consume(']');
18901
18902    return { type: AST.ArrayExpression, elements: elements };
18903  },
18904
18905  object: function() {
18906    var properties = [], property;
18907    if (this.peekToken().text !== '}') {
18908      do {
18909        if (this.peek('}')) {
18910          // Support trailing commas per ES5.1.
18911          break;
18912        }
18913        property = {type: AST.Property, kind: 'init'};
18914        if (this.peek().constant) {
18915          property.key = this.constant();
18916        } else if (this.peek().identifier) {
18917          property.key = this.identifier();
18918        } else {
18919          this.throwError("invalid key", this.peek());
18920        }
18921        this.consume(':');
18922        property.value = this.expression();
18923        properties.push(property);
18924      } while (this.expect(','));
18925    }
18926    this.consume('}');
18927
18928    return {type: AST.ObjectExpression, properties: properties };
18929  },
18930
18931  throwError: function(msg, token) {
18932    throw $parseMinErr('syntax',
18933        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
18934          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
18935  },
18936
18937  consume: function(e1) {
18938    if (this.tokens.length === 0) {
18939      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
18940    }
18941
18942    var token = this.expect(e1);
18943    if (!token) {
18944      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
18945    }
18946    return token;
18947  },
18948
18949  peekToken: function() {
18950    if (this.tokens.length === 0) {
18951      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
18952    }
18953    return this.tokens[0];
18954  },
18955
18956  peek: function(e1, e2, e3, e4) {
18957    return this.peekAhead(0, e1, e2, e3, e4);
18958  },
18959
18960  peekAhead: function(i, e1, e2, e3, e4) {
18961    if (this.tokens.length > i) {
18962      var token = this.tokens[i];
18963      var t = token.text;
18964      if (t === e1 || t === e2 || t === e3 || t === e4 ||
18965          (!e1 && !e2 && !e3 && !e4)) {
18966        return token;
18967      }
18968    }
18969    return false;
18970  },
18971
18972  expect: function(e1, e2, e3, e4) {
18973    var token = this.peek(e1, e2, e3, e4);
18974    if (token) {
18975      this.tokens.shift();
18976      return token;
18977    }
18978    return false;
18979  },
18980
18981  selfReferential: {
18982    'this': {type: AST.ThisExpression },
18983    '$locals': {type: AST.LocalsExpression }
18984  }
18985};
18986
18987function ifDefined(v, d) {
18988  return typeof v !== 'undefined' ? v : d;
18989}
18990
18991function plusFn(l, r) {
18992  if (typeof l === 'undefined') return r;
18993  if (typeof r === 'undefined') return l;
18994  return l + r;
18995}
18996
18997function isStateless($filter, filterName) {
18998  var fn = $filter(filterName);
18999  return !fn.$stateful;
19000}
19001
19002function findConstantAndWatchExpressions(ast, $filter) {
19003  var allConstants;
19004  var argsToWatch;
19005  switch (ast.type) {
19006  case AST.Program:
19007    allConstants = true;
19008    forEach(ast.body, function(expr) {
19009      findConstantAndWatchExpressions(expr.expression, $filter);
19010      allConstants = allConstants && expr.expression.constant;
19011    });
19012    ast.constant = allConstants;
19013    break;
19014  case AST.Literal:
19015    ast.constant = true;
19016    ast.toWatch = [];
19017    break;
19018  case AST.UnaryExpression:
19019    findConstantAndWatchExpressions(ast.argument, $filter);
19020    ast.constant = ast.argument.constant;
19021    ast.toWatch = ast.argument.toWatch;
19022    break;
19023  case AST.BinaryExpression:
19024    findConstantAndWatchExpressions(ast.left, $filter);
19025    findConstantAndWatchExpressions(ast.right, $filter);
19026    ast.constant = ast.left.constant && ast.right.constant;
19027    ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
19028    break;
19029  case AST.LogicalExpression:
19030    findConstantAndWatchExpressions(ast.left, $filter);
19031    findConstantAndWatchExpressions(ast.right, $filter);
19032    ast.constant = ast.left.constant && ast.right.constant;
19033    ast.toWatch = ast.constant ? [] : [ast];
19034    break;
19035  case AST.ConditionalExpression:
19036    findConstantAndWatchExpressions(ast.test, $filter);
19037    findConstantAndWatchExpressions(ast.alternate, $filter);
19038    findConstantAndWatchExpressions(ast.consequent, $filter);
19039    ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
19040    ast.toWatch = ast.constant ? [] : [ast];
19041    break;
19042  case AST.Identifier:
19043    ast.constant = false;
19044    ast.toWatch = [ast];
19045    break;
19046  case AST.MemberExpression:
19047    findConstantAndWatchExpressions(ast.object, $filter);
19048    if (ast.computed) {
19049      findConstantAndWatchExpressions(ast.property, $filter);
19050    }
19051    ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
19052    ast.toWatch = [ast];
19053    break;
19054  case AST.CallExpression:
19055    allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
19056    argsToWatch = [];
19057    forEach(ast.arguments, function(expr) {
19058      findConstantAndWatchExpressions(expr, $filter);
19059      allConstants = allConstants && expr.constant;
19060      if (!expr.constant) {
19061        argsToWatch.push.apply(argsToWatch, expr.toWatch);
19062      }
19063    });
19064    ast.constant = allConstants;
19065    ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
19066    break;
19067  case AST.AssignmentExpression:
19068    findConstantAndWatchExpressions(ast.left, $filter);
19069    findConstantAndWatchExpressions(ast.right, $filter);
19070    ast.constant = ast.left.constant && ast.right.constant;
19071    ast.toWatch = [ast];
19072    break;
19073  case AST.ArrayExpression:
19074    allConstants = true;
19075    argsToWatch = [];
19076    forEach(ast.elements, function(expr) {
19077      findConstantAndWatchExpressions(expr, $filter);
19078      allConstants = allConstants && expr.constant;
19079      if (!expr.constant) {
19080        argsToWatch.push.apply(argsToWatch, expr.toWatch);
19081      }
19082    });
19083    ast.constant = allConstants;
19084    ast.toWatch = argsToWatch;
19085    break;
19086  case AST.ObjectExpression:
19087    allConstants = true;
19088    argsToWatch = [];
19089    forEach(ast.properties, function(property) {
19090      findConstantAndWatchExpressions(property.value, $filter);
19091      allConstants = allConstants && property.value.constant;
19092      if (!property.value.constant) {
19093        argsToWatch.push.apply(argsToWatch, property.value.toWatch);
19094      }
19095    });
19096    ast.constant = allConstants;
19097    ast.toWatch = argsToWatch;
19098    break;
19099  case AST.ThisExpression:
19100    ast.constant = false;
19101    ast.toWatch = [];
19102    break;
19103  case AST.LocalsExpression:
19104    ast.constant = false;
19105    ast.toWatch = [];
19106    break;
19107  }
19108}
19109
19110function getInputs(body) {
19111  if (body.length != 1) return;
19112  var lastExpression = body[0].expression;
19113  var candidate = lastExpression.toWatch;
19114  if (candidate.length !== 1) return candidate;
19115  return candidate[0] !== lastExpression ? candidate : undefined;
19116}
19117
19118function isAssignable(ast) {
19119  return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
19120}
19121
19122function assignableAST(ast) {
19123  if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
19124    return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
19125  }
19126}
19127
19128function isLiteral(ast) {
19129  return ast.body.length === 0 ||
19130      ast.body.length === 1 && (
19131      ast.body[0].expression.type === AST.Literal ||
19132      ast.body[0].expression.type === AST.ArrayExpression ||
19133      ast.body[0].expression.type === AST.ObjectExpression);
19134}
19135
19136function isConstant(ast) {
19137  return ast.constant;
19138}
19139
19140function ASTCompiler(astBuilder, $filter) {
19141  this.astBuilder = astBuilder;
19142  this.$filter = $filter;
19143}
19144
19145ASTCompiler.prototype = {
19146  compile: function(expression, expensiveChecks) {
19147    var self = this;
19148    var ast = this.astBuilder.ast(expression);
19149    this.state = {
19150      nextId: 0,
19151      filters: {},
19152      expensiveChecks: expensiveChecks,
19153      fn: {vars: [], body: [], own: {}},
19154      assign: {vars: [], body: [], own: {}},
19155      inputs: []
19156    };
19157    findConstantAndWatchExpressions(ast, self.$filter);
19158    var extra = '';
19159    var assignable;
19160    this.stage = 'assign';
19161    if ((assignable = assignableAST(ast))) {
19162      this.state.computing = 'assign';
19163      var result = this.nextId();
19164      this.recurse(assignable, result);
19165      this.return_(result);
19166      extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
19167    }
19168    var toWatch = getInputs(ast.body);
19169    self.stage = 'inputs';
19170    forEach(toWatch, function(watch, key) {
19171      var fnKey = 'fn' + key;
19172      self.state[fnKey] = {vars: [], body: [], own: {}};
19173      self.state.computing = fnKey;
19174      var intoId = self.nextId();
19175      self.recurse(watch, intoId);
19176      self.return_(intoId);
19177      self.state.inputs.push(fnKey);
19178      watch.watchId = key;
19179    });
19180    this.state.computing = 'fn';
19181    this.stage = 'main';
19182    this.recurse(ast);
19183    var fnString =
19184      // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
19185      // This is a workaround for this until we do a better job at only removing the prefix only when we should.
19186      '"' + this.USE + ' ' + this.STRICT + '";\n' +
19187      this.filterPrefix() +
19188      'var fn=' + this.generateFunction('fn', 's,l,a,i') +
19189      extra +
19190      this.watchFns() +
19191      'return fn;';
19192
19193    /* jshint -W054 */
19194    var fn = (new Function('$filter',
19195        'ensureSafeMemberName',
19196        'ensureSafeObject',
19197        'ensureSafeFunction',
19198        'getStringValue',
19199        'ensureSafeAssignContext',
19200        'ifDefined',
19201        'plus',
19202        'text',
19203        fnString))(
19204          this.$filter,
19205          ensureSafeMemberName,
19206          ensureSafeObject,
19207          ensureSafeFunction,
19208          getStringValue,
19209          ensureSafeAssignContext,
19210          ifDefined,
19211          plusFn,
19212          expression);
19213    /* jshint +W054 */
19214    this.state = this.stage = undefined;
19215    fn.literal = isLiteral(ast);
19216    fn.constant = isConstant(ast);
19217    return fn;
19218  },
19219
19220  USE: 'use',
19221
19222  STRICT: 'strict',
19223
19224  watchFns: function() {
19225    var result = [];
19226    var fns = this.state.inputs;
19227    var self = this;
19228    forEach(fns, function(name) {
19229      result.push('var ' + name + '=' + self.generateFunction(name, 's'));
19230    });
19231    if (fns.length) {
19232      result.push('fn.inputs=[' + fns.join(',') + '];');
19233    }
19234    return result.join('');
19235  },
19236
19237  generateFunction: function(name, params) {
19238    return 'function(' + params + '){' +
19239        this.varsPrefix(name) +
19240        this.body(name) +
19241        '};';
19242  },
19243
19244  filterPrefix: function() {
19245    var parts = [];
19246    var self = this;
19247    forEach(this.state.filters, function(id, filter) {
19248      parts.push(id + '=$filter(' + self.escape(filter) + ')');
19249    });
19250    if (parts.length) return 'var ' + parts.join(',') + ';';
19251    return '';
19252  },
19253
19254  varsPrefix: function(section) {
19255    return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
19256  },
19257
19258  body: function(section) {
19259    return this.state[section].body.join('');
19260  },
19261
19262  recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
19263    var left, right, self = this, args, expression;
19264    recursionFn = recursionFn || noop;
19265    if (!skipWatchIdCheck && isDefined(ast.watchId)) {
19266      intoId = intoId || this.nextId();
19267      this.if_('i',
19268        this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
19269        this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
19270      );
19271      return;
19272    }
19273    switch (ast.type) {
19274    case AST.Program:
19275      forEach(ast.body, function(expression, pos) {
19276        self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
19277        if (pos !== ast.body.length - 1) {
19278          self.current().body.push(right, ';');
19279        } else {
19280          self.return_(right);
19281        }
19282      });
19283      break;
19284    case AST.Literal:
19285      expression = this.escape(ast.value);
19286      this.assign(intoId, expression);
19287      recursionFn(expression);
19288      break;
19289    case AST.UnaryExpression:
19290      this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
19291      expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
19292      this.assign(intoId, expression);
19293      recursionFn(expression);
19294      break;
19295    case AST.BinaryExpression:
19296      this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
19297      this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
19298      if (ast.operator === '+') {
19299        expression = this.plus(left, right);
19300      } else if (ast.operator === '-') {
19301        expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
19302      } else {
19303        expression = '(' + left + ')' + ast.operator + '(' + right + ')';
19304      }
19305      this.assign(intoId, expression);
19306      recursionFn(expression);
19307      break;
19308    case AST.LogicalExpression:
19309      intoId = intoId || this.nextId();
19310      self.recurse(ast.left, intoId);
19311      self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
19312      recursionFn(intoId);
19313      break;
19314    case AST.ConditionalExpression:
19315      intoId = intoId || this.nextId();
19316      self.recurse(ast.test, intoId);
19317      self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
19318      recursionFn(intoId);
19319      break;
19320    case AST.Identifier:
19321      intoId = intoId || this.nextId();
19322      if (nameId) {
19323        nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
19324        nameId.computed = false;
19325        nameId.name = ast.name;
19326      }
19327      ensureSafeMemberName(ast.name);
19328      self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
19329        function() {
19330          self.if_(self.stage === 'inputs' || 's', function() {
19331            if (create && create !== 1) {
19332              self.if_(
19333                self.not(self.nonComputedMember('s', ast.name)),
19334                self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
19335            }
19336            self.assign(intoId, self.nonComputedMember('s', ast.name));
19337          });
19338        }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
19339        );
19340      if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
19341        self.addEnsureSafeObject(intoId);
19342      }
19343      recursionFn(intoId);
19344      break;
19345    case AST.MemberExpression:
19346      left = nameId && (nameId.context = this.nextId()) || this.nextId();
19347      intoId = intoId || this.nextId();
19348      self.recurse(ast.object, left, undefined, function() {
19349        self.if_(self.notNull(left), function() {
19350          if (create && create !== 1) {
19351            self.addEnsureSafeAssignContext(left);
19352          }
19353          if (ast.computed) {
19354            right = self.nextId();
19355            self.recurse(ast.property, right);
19356            self.getStringValue(right);
19357            self.addEnsureSafeMemberName(right);
19358            if (create && create !== 1) {
19359              self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
19360            }
19361            expression = self.ensureSafeObject(self.computedMember(left, right));
19362            self.assign(intoId, expression);
19363            if (nameId) {
19364              nameId.computed = true;
19365              nameId.name = right;
19366            }
19367          } else {
19368            ensureSafeMemberName(ast.property.name);
19369            if (create && create !== 1) {
19370              self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
19371            }
19372            expression = self.nonComputedMember(left, ast.property.name);
19373            if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
19374              expression = self.ensureSafeObject(expression);
19375            }
19376            self.assign(intoId, expression);
19377            if (nameId) {
19378              nameId.computed = false;
19379              nameId.name = ast.property.name;
19380            }
19381          }
19382        }, function() {
19383          self.assign(intoId, 'undefined');
19384        });
19385        recursionFn(intoId);
19386      }, !!create);
19387      break;
19388    case AST.CallExpression:
19389      intoId = intoId || this.nextId();
19390      if (ast.filter) {
19391        right = self.filter(ast.callee.name);
19392        args = [];
19393        forEach(ast.arguments, function(expr) {
19394          var argument = self.nextId();
19395          self.recurse(expr, argument);
19396          args.push(argument);
19397        });
19398        expression = right + '(' + args.join(',') + ')';
19399        self.assign(intoId, expression);
19400        recursionFn(intoId);
19401      } else {
19402        right = self.nextId();
19403        left = {};
19404        args = [];
19405        self.recurse(ast.callee, right, left, function() {
19406          self.if_(self.notNull(right), function() {
19407            self.addEnsureSafeFunction(right);
19408            forEach(ast.arguments, function(expr) {
19409              self.recurse(expr, self.nextId(), undefined, function(argument) {
19410                args.push(self.ensureSafeObject(argument));
19411              });
19412            });
19413            if (left.name) {
19414              if (!self.state.expensiveChecks) {
19415                self.addEnsureSafeObject(left.context);
19416              }
19417              expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
19418            } else {
19419              expression = right + '(' + args.join(',') + ')';
19420            }
19421            expression = self.ensureSafeObject(expression);
19422            self.assign(intoId, expression);
19423          }, function() {
19424            self.assign(intoId, 'undefined');
19425          });
19426          recursionFn(intoId);
19427        });
19428      }
19429      break;
19430    case AST.AssignmentExpression:
19431      right = this.nextId();
19432      left = {};
19433      if (!isAssignable(ast.left)) {
19434        throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
19435      }
19436      this.recurse(ast.left, undefined, left, function() {
19437        self.if_(self.notNull(left.context), function() {
19438          self.recurse(ast.right, right);
19439          self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
19440          self.addEnsureSafeAssignContext(left.context);
19441          expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
19442          self.assign(intoId, expression);
19443          recursionFn(intoId || expression);
19444        });
19445      }, 1);
19446      break;
19447    case AST.ArrayExpression:
19448      args = [];
19449      forEach(ast.elements, function(expr) {
19450        self.recurse(expr, self.nextId(), undefined, function(argument) {
19451          args.push(argument);
19452        });
19453      });
19454      expression = '[' + args.join(',') + ']';
19455      this.assign(intoId, expression);
19456      recursionFn(expression);
19457      break;
19458    case AST.ObjectExpression:
19459      args = [];
19460      forEach(ast.properties, function(property) {
19461        self.recurse(property.value, self.nextId(), undefined, function(expr) {
19462          args.push(self.escape(
19463              property.key.type === AST.Identifier ? property.key.name :
19464                ('' + property.key.value)) +
19465              ':' + expr);
19466        });
19467      });
19468      expression = '{' + args.join(',') + '}';
19469      this.assign(intoId, expression);
19470      recursionFn(expression);
19471      break;
19472    case AST.ThisExpression:
19473      this.assign(intoId, 's');
19474      recursionFn('s');
19475      break;
19476    case AST.LocalsExpression:
19477      this.assign(intoId, 'l');
19478      recursionFn('l');
19479      break;
19480    case AST.NGValueParameter:
19481      this.assign(intoId, 'v');
19482      recursionFn('v');
19483      break;
19484    }
19485  },
19486
19487  getHasOwnProperty: function(element, property) {
19488    var key = element + '.' + property;
19489    var own = this.current().own;
19490    if (!own.hasOwnProperty(key)) {
19491      own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
19492    }
19493    return own[key];
19494  },
19495
19496  assign: function(id, value) {
19497    if (!id) return;
19498    this.current().body.push(id, '=', value, ';');
19499    return id;
19500  },
19501
19502  filter: function(filterName) {
19503    if (!this.state.filters.hasOwnProperty(filterName)) {
19504      this.state.filters[filterName] = this.nextId(true);
19505    }
19506    return this.state.filters[filterName];
19507  },
19508
19509  ifDefined: function(id, defaultValue) {
19510    return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
19511  },
19512
19513  plus: function(left, right) {
19514    return 'plus(' + left + ',' + right + ')';
19515  },
19516
19517  return_: function(id) {
19518    this.current().body.push('return ', id, ';');
19519  },
19520
19521  if_: function(test, alternate, consequent) {
19522    if (test === true) {
19523      alternate();
19524    } else {
19525      var body = this.current().body;
19526      body.push('if(', test, '){');
19527      alternate();
19528      body.push('}');
19529      if (consequent) {
19530        body.push('else{');
19531        consequent();
19532        body.push('}');
19533      }
19534    }
19535  },
19536
19537  not: function(expression) {
19538    return '!(' + expression + ')';
19539  },
19540
19541  notNull: function(expression) {
19542    return expression + '!=null';
19543  },
19544
19545  nonComputedMember: function(left, right) {
19546    return left + '.' + right;
19547  },
19548
19549  computedMember: function(left, right) {
19550    return left + '[' + right + ']';
19551  },
19552
19553  member: function(left, right, computed) {
19554    if (computed) return this.computedMember(left, right);
19555    return this.nonComputedMember(left, right);
19556  },
19557
19558  addEnsureSafeObject: function(item) {
19559    this.current().body.push(this.ensureSafeObject(item), ';');
19560  },
19561
19562  addEnsureSafeMemberName: function(item) {
19563    this.current().body.push(this.ensureSafeMemberName(item), ';');
19564  },
19565
19566  addEnsureSafeFunction: function(item) {
19567    this.current().body.push(this.ensureSafeFunction(item), ';');
19568  },
19569
19570  addEnsureSafeAssignContext: function(item) {
19571    this.current().body.push(this.ensureSafeAssignContext(item), ';');
19572  },
19573
19574  ensureSafeObject: function(item) {
19575    return 'ensureSafeObject(' + item + ',text)';
19576  },
19577
19578  ensureSafeMemberName: function(item) {
19579    return 'ensureSafeMemberName(' + item + ',text)';
19580  },
19581
19582  ensureSafeFunction: function(item) {
19583    return 'ensureSafeFunction(' + item + ',text)';
19584  },
19585
19586  getStringValue: function(item) {
19587    this.assign(item, 'getStringValue(' + item + ')');
19588  },
19589
19590  ensureSafeAssignContext: function(item) {
19591    return 'ensureSafeAssignContext(' + item + ',text)';
19592  },
19593
19594  lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
19595    var self = this;
19596    return function() {
19597      self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
19598    };
19599  },
19600
19601  lazyAssign: function(id, value) {
19602    var self = this;
19603    return function() {
19604      self.assign(id, value);
19605    };
19606  },
19607
19608  stringEscapeRegex: /[^ a-zA-Z0-9]/g,
19609
19610  stringEscapeFn: function(c) {
19611    return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
19612  },
19613
19614  escape: function(value) {
19615    if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
19616    if (isNumber(value)) return value.toString();
19617    if (value === true) return 'true';
19618    if (value === false) return 'false';
19619    if (value === null) return 'null';
19620    if (typeof value === 'undefined') return 'undefined';
19621
19622    throw $parseMinErr('esc', 'IMPOSSIBLE');
19623  },
19624
19625  nextId: function(skip, init) {
19626    var id = 'v' + (this.state.nextId++);
19627    if (!skip) {
19628      this.current().vars.push(id + (init ? '=' + init : ''));
19629    }
19630    return id;
19631  },
19632
19633  current: function() {
19634    return this.state[this.state.computing];
19635  }
19636};
19637
19638
19639function ASTInterpreter(astBuilder, $filter) {
19640  this.astBuilder = astBuilder;
19641  this.$filter = $filter;
19642}
19643
19644ASTInterpreter.prototype = {
19645  compile: function(expression, expensiveChecks) {
19646    var self = this;
19647    var ast = this.astBuilder.ast(expression);
19648    this.expression = expression;
19649    this.expensiveChecks = expensiveChecks;
19650    findConstantAndWatchExpressions(ast, self.$filter);
19651    var assignable;
19652    var assign;
19653    if ((assignable = assignableAST(ast))) {
19654      assign = this.recurse(assignable);
19655    }
19656    var toWatch = getInputs(ast.body);
19657    var inputs;
19658    if (toWatch) {
19659      inputs = [];
19660      forEach(toWatch, function(watch, key) {
19661        var input = self.recurse(watch);
19662        watch.input = input;
19663        inputs.push(input);
19664        watch.watchId = key;
19665      });
19666    }
19667    var expressions = [];
19668    forEach(ast.body, function(expression) {
19669      expressions.push(self.recurse(expression.expression));
19670    });
19671    var fn = ast.body.length === 0 ? noop :
19672             ast.body.length === 1 ? expressions[0] :
19673             function(scope, locals) {
19674               var lastValue;
19675               forEach(expressions, function(exp) {
19676                 lastValue = exp(scope, locals);
19677               });
19678               return lastValue;
19679             };
19680    if (assign) {
19681      fn.assign = function(scope, value, locals) {
19682        return assign(scope, locals, value);
19683      };
19684    }
19685    if (inputs) {
19686      fn.inputs = inputs;
19687    }
19688    fn.literal = isLiteral(ast);
19689    fn.constant = isConstant(ast);
19690    return fn;
19691  },
19692
19693  recurse: function(ast, context, create) {
19694    var left, right, self = this, args, expression;
19695    if (ast.input) {
19696      return this.inputs(ast.input, ast.watchId);
19697    }
19698    switch (ast.type) {
19699    case AST.Literal:
19700      return this.value(ast.value, context);
19701    case AST.UnaryExpression:
19702      right = this.recurse(ast.argument);
19703      return this['unary' + ast.operator](right, context);
19704    case AST.BinaryExpression:
19705      left = this.recurse(ast.left);
19706      right = this.recurse(ast.right);
19707      return this['binary' + ast.operator](left, right, context);
19708    case AST.LogicalExpression:
19709      left = this.recurse(ast.left);
19710      right = this.recurse(ast.right);
19711      return this['binary' + ast.operator](left, right, context);
19712    case AST.ConditionalExpression:
19713      return this['ternary?:'](
19714        this.recurse(ast.test),
19715        this.recurse(ast.alternate),
19716        this.recurse(ast.consequent),
19717        context
19718      );
19719    case AST.Identifier:
19720      ensureSafeMemberName(ast.name, self.expression);
19721      return self.identifier(ast.name,
19722                             self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
19723                             context, create, self.expression);
19724    case AST.MemberExpression:
19725      left = this.recurse(ast.object, false, !!create);
19726      if (!ast.computed) {
19727        ensureSafeMemberName(ast.property.name, self.expression);
19728        right = ast.property.name;
19729      }
19730      if (ast.computed) right = this.recurse(ast.property);
19731      return ast.computed ?
19732        this.computedMember(left, right, context, create, self.expression) :
19733        this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
19734    case AST.CallExpression:
19735      args = [];
19736      forEach(ast.arguments, function(expr) {
19737        args.push(self.recurse(expr));
19738      });
19739      if (ast.filter) right = this.$filter(ast.callee.name);
19740      if (!ast.filter) right = this.recurse(ast.callee, true);
19741      return ast.filter ?
19742        function(scope, locals, assign, inputs) {
19743          var values = [];
19744          for (var i = 0; i < args.length; ++i) {
19745            values.push(args[i](scope, locals, assign, inputs));
19746          }
19747          var value = right.apply(undefined, values, inputs);
19748          return context ? {context: undefined, name: undefined, value: value} : value;
19749        } :
19750        function(scope, locals, assign, inputs) {
19751          var rhs = right(scope, locals, assign, inputs);
19752          var value;
19753          if (rhs.value != null) {
19754            ensureSafeObject(rhs.context, self.expression);
19755            ensureSafeFunction(rhs.value, self.expression);
19756            var values = [];
19757            for (var i = 0; i < args.length; ++i) {
19758              values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
19759            }
19760            value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
19761          }
19762          return context ? {value: value} : value;
19763        };
19764    case AST.AssignmentExpression:
19765      left = this.recurse(ast.left, true, 1);
19766      right = this.recurse(ast.right);
19767      return function(scope, locals, assign, inputs) {
19768        var lhs = left(scope, locals, assign, inputs);
19769        var rhs = right(scope, locals, assign, inputs);
19770        ensureSafeObject(lhs.value, self.expression);
19771        ensureSafeAssignContext(lhs.context);
19772        lhs.context[lhs.name] = rhs;
19773        return context ? {value: rhs} : rhs;
19774      };
19775    case AST.ArrayExpression:
19776      args = [];
19777      forEach(ast.elements, function(expr) {
19778        args.push(self.recurse(expr));
19779      });
19780      return function(scope, locals, assign, inputs) {
19781        var value = [];
19782        for (var i = 0; i < args.length; ++i) {
19783          value.push(args[i](scope, locals, assign, inputs));
19784        }
19785        return context ? {value: value} : value;
19786      };
19787    case AST.ObjectExpression:
19788      args = [];
19789      forEach(ast.properties, function(property) {
19790        args.push({key: property.key.type === AST.Identifier ?
19791                        property.key.name :
19792                        ('' + property.key.value),
19793                   value: self.recurse(property.value)
19794        });
19795      });
19796      return function(scope, locals, assign, inputs) {
19797        var value = {};
19798        for (var i = 0; i < args.length; ++i) {
19799          value[args[i].key] = args[i].value(scope, locals, assign, inputs);
19800        }
19801        return context ? {value: value} : value;
19802      };
19803    case AST.ThisExpression:
19804      return function(scope) {
19805        return context ? {value: scope} : scope;
19806      };
19807    case AST.LocalsExpression:
19808      return function(scope, locals) {
19809        return context ? {value: locals} : locals;
19810      };
19811    case AST.NGValueParameter:
19812      return function(scope, locals, assign, inputs) {
19813        return context ? {value: assign} : assign;
19814      };
19815    }
19816  },
19817
19818  'unary+': function(argument, context) {
19819    return function(scope, locals, assign, inputs) {
19820      var arg = argument(scope, locals, assign, inputs);
19821      if (isDefined(arg)) {
19822        arg = +arg;
19823      } else {
19824        arg = 0;
19825      }
19826      return context ? {value: arg} : arg;
19827    };
19828  },
19829  'unary-': function(argument, context) {
19830    return function(scope, locals, assign, inputs) {
19831      var arg = argument(scope, locals, assign, inputs);
19832      if (isDefined(arg)) {
19833        arg = -arg;
19834      } else {
19835        arg = 0;
19836      }
19837      return context ? {value: arg} : arg;
19838    };
19839  },
19840  'unary!': function(argument, context) {
19841    return function(scope, locals, assign, inputs) {
19842      var arg = !argument(scope, locals, assign, inputs);
19843      return context ? {value: arg} : arg;
19844    };
19845  },
19846  'binary+': function(left, right, context) {
19847    return function(scope, locals, assign, inputs) {
19848      var lhs = left(scope, locals, assign, inputs);
19849      var rhs = right(scope, locals, assign, inputs);
19850      var arg = plusFn(lhs, rhs);
19851      return context ? {value: arg} : arg;
19852    };
19853  },
19854  'binary-': function(left, right, context) {
19855    return function(scope, locals, assign, inputs) {
19856      var lhs = left(scope, locals, assign, inputs);
19857      var rhs = right(scope, locals, assign, inputs);
19858      var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
19859      return context ? {value: arg} : arg;
19860    };
19861  },
19862  'binary*': function(left, right, context) {
19863    return function(scope, locals, assign, inputs) {
19864      var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
19865      return context ? {value: arg} : arg;
19866    };
19867  },
19868  'binary/': function(left, right, context) {
19869    return function(scope, locals, assign, inputs) {
19870      var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
19871      return context ? {value: arg} : arg;
19872    };
19873  },
19874  'binary%': function(left, right, context) {
19875    return function(scope, locals, assign, inputs) {
19876      var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
19877      return context ? {value: arg} : arg;
19878    };
19879  },
19880  'binary===': function(left, right, context) {
19881    return function(scope, locals, assign, inputs) {
19882      var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
19883      return context ? {value: arg} : arg;
19884    };
19885  },
19886  'binary!==': function(left, right, context) {
19887    return function(scope, locals, assign, inputs) {
19888      var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
19889      return context ? {value: arg} : arg;
19890    };
19891  },
19892  'binary==': function(left, right, context) {
19893    return function(scope, locals, assign, inputs) {
19894      var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
19895      return context ? {value: arg} : arg;
19896    };
19897  },
19898  'binary!=': function(left, right, context) {
19899    return function(scope, locals, assign, inputs) {
19900      var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
19901      return context ? {value: arg} : arg;
19902    };
19903  },
19904  'binary<': function(left, right, context) {
19905    return function(scope, locals, assign, inputs) {
19906      var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
19907      return context ? {value: arg} : arg;
19908    };
19909  },
19910  'binary>': function(left, right, context) {
19911    return function(scope, locals, assign, inputs) {
19912      var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
19913      return context ? {value: arg} : arg;
19914    };
19915  },
19916  'binary<=': function(left, right, context) {
19917    return function(scope, locals, assign, inputs) {
19918      var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
19919      return context ? {value: arg} : arg;
19920    };
19921  },
19922  'binary>=': function(left, right, context) {
19923    return function(scope, locals, assign, inputs) {
19924      var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
19925      return context ? {value: arg} : arg;
19926    };
19927  },
19928  'binary&&': function(left, right, context) {
19929    return function(scope, locals, assign, inputs) {
19930      var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
19931      return context ? {value: arg} : arg;
19932    };
19933  },
19934  'binary||': function(left, right, context) {
19935    return function(scope, locals, assign, inputs) {
19936      var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
19937      return context ? {value: arg} : arg;
19938    };
19939  },
19940  'ternary?:': function(test, alternate, consequent, context) {
19941    return function(scope, locals, assign, inputs) {
19942      var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
19943      return context ? {value: arg} : arg;
19944    };
19945  },
19946  value: function(value, context) {
19947    return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
19948  },
19949  identifier: function(name, expensiveChecks, context, create, expression) {
19950    return function(scope, locals, assign, inputs) {
19951      var base = locals && (name in locals) ? locals : scope;
19952      if (create && create !== 1 && base && !(base[name])) {
19953        base[name] = {};
19954      }
19955      var value = base ? base[name] : undefined;
19956      if (expensiveChecks) {
19957        ensureSafeObject(value, expression);
19958      }
19959      if (context) {
19960        return {context: base, name: name, value: value};
19961      } else {
19962        return value;
19963      }
19964    };
19965  },
19966  computedMember: function(left, right, context, create, expression) {
19967    return function(scope, locals, assign, inputs) {
19968      var lhs = left(scope, locals, assign, inputs);
19969      var rhs;
19970      var value;
19971      if (lhs != null) {
19972        rhs = right(scope, locals, assign, inputs);
19973        rhs = getStringValue(rhs);
19974        ensureSafeMemberName(rhs, expression);
19975        if (create && create !== 1) {
19976          ensureSafeAssignContext(lhs);
19977          if (lhs && !(lhs[rhs])) {
19978            lhs[rhs] = {};
19979          }
19980        }
19981        value = lhs[rhs];
19982        ensureSafeObject(value, expression);
19983      }
19984      if (context) {
19985        return {context: lhs, name: rhs, value: value};
19986      } else {
19987        return value;
19988      }
19989    };
19990  },
19991  nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
19992    return function(scope, locals, assign, inputs) {
19993      var lhs = left(scope, locals, assign, inputs);
19994      if (create && create !== 1) {
19995        ensureSafeAssignContext(lhs);
19996        if (lhs && !(lhs[right])) {
19997          lhs[right] = {};
19998        }
19999      }
20000      var value = lhs != null ? lhs[right] : undefined;
20001      if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
20002        ensureSafeObject(value, expression);
20003      }
20004      if (context) {
20005        return {context: lhs, name: right, value: value};
20006      } else {
20007        return value;
20008      }
20009    };
20010  },
20011  inputs: function(input, watchId) {
20012    return function(scope, value, locals, inputs) {
20013      if (inputs) return inputs[watchId];
20014      return input(scope, value, locals);
20015    };
20016  }
20017};
20018
20019/**
20020 * @constructor
20021 */
20022var Parser = function(lexer, $filter, options) {
20023  this.lexer = lexer;
20024  this.$filter = $filter;
20025  this.options = options;
20026  this.ast = new AST(lexer, options);
20027  this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
20028                                   new ASTCompiler(this.ast, $filter);
20029};
20030
20031Parser.prototype = {
20032  constructor: Parser,
20033
20034  parse: function(text) {
20035    return this.astCompiler.compile(text, this.options.expensiveChecks);
20036  }
20037};
20038
20039function isPossiblyDangerousMemberName(name) {
20040  return name == 'constructor';
20041}
20042
20043var objectValueOf = Object.prototype.valueOf;
20044
20045function getValueOf(value) {
20046  return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
20047}
20048
20049///////////////////////////////////
20050
20051/**
20052 * @ngdoc service
20053 * @name $parse
20054 * @kind function
20055 *
20056 * @description
20057 *
20058 * Converts Angular {@link guide/expression expression} into a function.
20059 *
20060 * ```js
20061 *   var getter = $parse('user.name');
20062 *   var setter = getter.assign;
20063 *   var context = {user:{name:'angular'}};
20064 *   var locals = {user:{name:'local'}};
20065 *
20066 *   expect(getter(context)).toEqual('angular');
20067 *   setter(context, 'newValue');
20068 *   expect(context.user.name).toEqual('newValue');
20069 *   expect(getter(context, locals)).toEqual('local');
20070 * ```
20071 *
20072 *
20073 * @param {string} expression String expression to compile.
20074 * @returns {function(context, locals)} a function which represents the compiled expression:
20075 *
20076 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
20077 *      are evaluated against (typically a scope object).
20078 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
20079 *      `context`.
20080 *
20081 *    The returned function also has the following properties:
20082 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
20083 *        literal.
20084 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
20085 *        constant literals.
20086 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
20087 *        set to a function to change its value on the given context.
20088 *
20089 */
20090
20091
20092/**
20093 * @ngdoc provider
20094 * @name $parseProvider
20095 *
20096 * @description
20097 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
20098 *  service.
20099 */
20100function $ParseProvider() {
20101  var cacheDefault = createMap();
20102  var cacheExpensive = createMap();
20103  var literals = {
20104    'true': true,
20105    'false': false,
20106    'null': null,
20107    'undefined': undefined
20108  };
20109
20110  /**
20111   * @ngdoc method
20112   * @name $parseProvider#addLiteral
20113   * @description
20114   *
20115   * Configure $parse service to add literal values that will be present as literal at expressions.
20116   *
20117   * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
20118   * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
20119   *
20120   **/
20121  this.addLiteral = function(literalName, literalValue) {
20122    literals[literalName] = literalValue;
20123  };
20124
20125  this.$get = ['$filter', function($filter) {
20126    var noUnsafeEval = csp().noUnsafeEval;
20127    var $parseOptions = {
20128          csp: noUnsafeEval,
20129          expensiveChecks: false,
20130          literals: copy(literals)
20131        },
20132        $parseOptionsExpensive = {
20133          csp: noUnsafeEval,
20134          expensiveChecks: true,
20135          literals: copy(literals)
20136        };
20137    var runningChecksEnabled = false;
20138
20139    $parse.$$runningExpensiveChecks = function() {
20140      return runningChecksEnabled;
20141    };
20142
20143    return $parse;
20144
20145    function $parse(exp, interceptorFn, expensiveChecks) {
20146      var parsedExpression, oneTime, cacheKey;
20147
20148      expensiveChecks = expensiveChecks || runningChecksEnabled;
20149
20150      switch (typeof exp) {
20151        case 'string':
20152          exp = exp.trim();
20153          cacheKey = exp;
20154
20155          var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
20156          parsedExpression = cache[cacheKey];
20157
20158          if (!parsedExpression) {
20159            if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
20160              oneTime = true;
20161              exp = exp.substring(2);
20162            }
20163            var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
20164            var lexer = new Lexer(parseOptions);
20165            var parser = new Parser(lexer, $filter, parseOptions);
20166            parsedExpression = parser.parse(exp);
20167            if (parsedExpression.constant) {
20168              parsedExpression.$$watchDelegate = constantWatchDelegate;
20169            } else if (oneTime) {
20170              parsedExpression.$$watchDelegate = parsedExpression.literal ?
20171                  oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
20172            } else if (parsedExpression.inputs) {
20173              parsedExpression.$$watchDelegate = inputsWatchDelegate;
20174            }
20175            if (expensiveChecks) {
20176              parsedExpression = expensiveChecksInterceptor(parsedExpression);
20177            }
20178            cache[cacheKey] = parsedExpression;
20179          }
20180          return addInterceptor(parsedExpression, interceptorFn);
20181
20182        case 'function':
20183          return addInterceptor(exp, interceptorFn);
20184
20185        default:
20186          return addInterceptor(noop, interceptorFn);
20187      }
20188    }
20189
20190    function expensiveChecksInterceptor(fn) {
20191      if (!fn) return fn;
20192      expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
20193      expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
20194      expensiveCheckFn.constant = fn.constant;
20195      expensiveCheckFn.literal = fn.literal;
20196      for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
20197        fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
20198      }
20199      expensiveCheckFn.inputs = fn.inputs;
20200
20201      return expensiveCheckFn;
20202
20203      function expensiveCheckFn(scope, locals, assign, inputs) {
20204        var expensiveCheckOldValue = runningChecksEnabled;
20205        runningChecksEnabled = true;
20206        try {
20207          return fn(scope, locals, assign, inputs);
20208        } finally {
20209          runningChecksEnabled = expensiveCheckOldValue;
20210        }
20211      }
20212    }
20213
20214    function expressionInputDirtyCheck(newValue, oldValueOfValue) {
20215
20216      if (newValue == null || oldValueOfValue == null) { // null/undefined
20217        return newValue === oldValueOfValue;
20218      }
20219
20220      if (typeof newValue === 'object') {
20221
20222        // attempt to convert the value to a primitive type
20223        // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
20224        //             be cheaply dirty-checked
20225        newValue = getValueOf(newValue);
20226
20227        if (typeof newValue === 'object') {
20228          // objects/arrays are not supported - deep-watching them would be too expensive
20229          return false;
20230        }
20231
20232        // fall-through to the primitive equality check
20233      }
20234
20235      //Primitive or NaN
20236      return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
20237    }
20238
20239    function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
20240      var inputExpressions = parsedExpression.inputs;
20241      var lastResult;
20242
20243      if (inputExpressions.length === 1) {
20244        var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
20245        inputExpressions = inputExpressions[0];
20246        return scope.$watch(function expressionInputWatch(scope) {
20247          var newInputValue = inputExpressions(scope);
20248          if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
20249            lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
20250            oldInputValueOf = newInputValue && getValueOf(newInputValue);
20251          }
20252          return lastResult;
20253        }, listener, objectEquality, prettyPrintExpression);
20254      }
20255
20256      var oldInputValueOfValues = [];
20257      var oldInputValues = [];
20258      for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
20259        oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
20260        oldInputValues[i] = null;
20261      }
20262
20263      return scope.$watch(function expressionInputsWatch(scope) {
20264        var changed = false;
20265
20266        for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
20267          var newInputValue = inputExpressions[i](scope);
20268          if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
20269            oldInputValues[i] = newInputValue;
20270            oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
20271          }
20272        }
20273
20274        if (changed) {
20275          lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
20276        }
20277
20278        return lastResult;
20279      }, listener, objectEquality, prettyPrintExpression);
20280    }
20281
20282    function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
20283      var unwatch, lastValue;
20284      return unwatch = scope.$watch(function oneTimeWatch(scope) {
20285        return parsedExpression(scope);
20286      }, function oneTimeListener(value, old, scope) {
20287        lastValue = value;
20288        if (isFunction(listener)) {
20289          listener.apply(this, arguments);
20290        }
20291        if (isDefined(value)) {
20292          scope.$$postDigest(function() {
20293            if (isDefined(lastValue)) {
20294              unwatch();
20295            }
20296          });
20297        }
20298      }, objectEquality);
20299    }
20300
20301    function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
20302      var unwatch, lastValue;
20303      return unwatch = scope.$watch(function oneTimeWatch(scope) {
20304        return parsedExpression(scope);
20305      }, function oneTimeListener(value, old, scope) {
20306        lastValue = value;
20307        if (isFunction(listener)) {
20308          listener.call(this, value, old, scope);
20309        }
20310        if (isAllDefined(value)) {
20311          scope.$$postDigest(function() {
20312            if (isAllDefined(lastValue)) unwatch();
20313          });
20314        }
20315      }, objectEquality);
20316
20317      function isAllDefined(value) {
20318        var allDefined = true;
20319        forEach(value, function(val) {
20320          if (!isDefined(val)) allDefined = false;
20321        });
20322        return allDefined;
20323      }
20324    }
20325
20326    function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
20327      var unwatch;
20328      return unwatch = scope.$watch(function constantWatch(scope) {
20329        unwatch();
20330        return parsedExpression(scope);
20331      }, listener, objectEquality);
20332    }
20333
20334    function addInterceptor(parsedExpression, interceptorFn) {
20335      if (!interceptorFn) return parsedExpression;
20336      var watchDelegate = parsedExpression.$$watchDelegate;
20337      var useInputs = false;
20338
20339      var regularWatch =
20340          watchDelegate !== oneTimeLiteralWatchDelegate &&
20341          watchDelegate !== oneTimeWatchDelegate;
20342
20343      var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
20344        var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
20345        return interceptorFn(value, scope, locals);
20346      } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
20347        var value = parsedExpression(scope, locals, assign, inputs);
20348        var result = interceptorFn(value, scope, locals);
20349        // we only return the interceptor's result if the
20350        // initial value is defined (for bind-once)
20351        return isDefined(value) ? result : value;
20352      };
20353
20354      // Propagate $$watchDelegates other then inputsWatchDelegate
20355      if (parsedExpression.$$watchDelegate &&
20356          parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
20357        fn.$$watchDelegate = parsedExpression.$$watchDelegate;
20358      } else if (!interceptorFn.$stateful) {
20359        // If there is an interceptor, but no watchDelegate then treat the interceptor like
20360        // we treat filters - it is assumed to be a pure function unless flagged with $stateful
20361        fn.$$watchDelegate = inputsWatchDelegate;
20362        useInputs = !parsedExpression.inputs;
20363        fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
20364      }
20365
20366      return fn;
20367    }
20368  }];
20369}
20370
20371/**
20372 * @ngdoc service
20373 * @name $q
20374 * @requires $rootScope
20375 *
20376 * @description
20377 * A service that helps you run functions asynchronously, and use their return values (or exceptions)
20378 * when they are done processing.
20379 *
20380 * This is an implementation of promises/deferred objects inspired by
20381 * [Kris Kowal's Q](https://github.com/kriskowal/q).
20382 *
20383 * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
20384 * implementations, and the other which resembles ES6 promises to some degree.
20385 *
20386 * # $q constructor
20387 *
20388 * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
20389 * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
20390 * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
20391 *
20392 * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
20393 * available yet.
20394 *
20395 * It can be used like so:
20396 *
20397 * ```js
20398 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
20399 *   // are available in the current lexical scope (they could have been injected or passed in).
20400 *
20401 *   function asyncGreet(name) {
20402 *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
20403 *     return $q(function(resolve, reject) {
20404 *       setTimeout(function() {
20405 *         if (okToGreet(name)) {
20406 *           resolve('Hello, ' + name + '!');
20407 *         } else {
20408 *           reject('Greeting ' + name + ' is not allowed.');
20409 *         }
20410 *       }, 1000);
20411 *     });
20412 *   }
20413 *
20414 *   var promise = asyncGreet('Robin Hood');
20415 *   promise.then(function(greeting) {
20416 *     alert('Success: ' + greeting);
20417 *   }, function(reason) {
20418 *     alert('Failed: ' + reason);
20419 *   });
20420 * ```
20421 *
20422 * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
20423 *
20424 * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
20425 *
20426 * However, the more traditional CommonJS-style usage is still available, and documented below.
20427 *
20428 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
20429 * interface for interacting with an object that represents the result of an action that is
20430 * performed asynchronously, and may or may not be finished at any given point in time.
20431 *
20432 * From the perspective of dealing with error handling, deferred and promise APIs are to
20433 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
20434 *
20435 * ```js
20436 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
20437 *   // are available in the current lexical scope (they could have been injected or passed in).
20438 *
20439 *   function asyncGreet(name) {
20440 *     var deferred = $q.defer();
20441 *
20442 *     setTimeout(function() {
20443 *       deferred.notify('About to greet ' + name + '.');
20444 *
20445 *       if (okToGreet(name)) {
20446 *         deferred.resolve('Hello, ' + name + '!');
20447 *       } else {
20448 *         deferred.reject('Greeting ' + name + ' is not allowed.');
20449 *       }
20450 *     }, 1000);
20451 *
20452 *     return deferred.promise;
20453 *   }
20454 *
20455 *   var promise = asyncGreet('Robin Hood');
20456 *   promise.then(function(greeting) {
20457 *     alert('Success: ' + greeting);
20458 *   }, function(reason) {
20459 *     alert('Failed: ' + reason);
20460 *   }, function(update) {
20461 *     alert('Got notification: ' + update);
20462 *   });
20463 * ```
20464 *
20465 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
20466 * comes in the way of guarantees that promise and deferred APIs make, see
20467 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
20468 *
20469 * Additionally the promise api allows for composition that is very hard to do with the
20470 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
20471 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
20472 * section on serial or parallel joining of promises.
20473 *
20474 * # The Deferred API
20475 *
20476 * A new instance of deferred is constructed by calling `$q.defer()`.
20477 *
20478 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
20479 * that can be used for signaling the successful or unsuccessful completion, as well as the status
20480 * of the task.
20481 *
20482 * **Methods**
20483 *
20484 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
20485 *   constructed via `$q.reject`, the promise will be rejected instead.
20486 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
20487 *   resolving it with a rejection constructed via `$q.reject`.
20488 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
20489 *   multiple times before the promise is either resolved or rejected.
20490 *
20491 * **Properties**
20492 *
20493 * - promise – `{Promise}` – promise object associated with this deferred.
20494 *
20495 *
20496 * # The Promise API
20497 *
20498 * A new promise instance is created when a deferred instance is created and can be retrieved by
20499 * calling `deferred.promise`.
20500 *
20501 * The purpose of the promise object is to allow for interested parties to get access to the result
20502 * of the deferred task when it completes.
20503 *
20504 * **Methods**
20505 *
20506 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
20507 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
20508 *   as soon as the result is available. The callbacks are called with a single argument: the result
20509 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
20510 *   provide a progress indication, before the promise is resolved or rejected.
20511 *
20512 *   This method *returns a new promise* which is resolved or rejected via the return value of the
20513 *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
20514 *   with the value which is resolved in that promise using
20515 *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
20516 *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
20517 *   resolved or rejected from the notifyCallback method.
20518 *
20519 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
20520 *
20521 * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
20522 *   but to do so without modifying the final value. This is useful to release resources or do some
20523 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
20524 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
20525 *   more information.
20526 *
20527 * # Chaining promises
20528 *
20529 * Because calling the `then` method of a promise returns a new derived promise, it is easily
20530 * possible to create a chain of promises:
20531 *
20532 * ```js
20533 *   promiseB = promiseA.then(function(result) {
20534 *     return result + 1;
20535 *   });
20536 *
20537 *   // promiseB will be resolved immediately after promiseA is resolved and its value
20538 *   // will be the result of promiseA incremented by 1
20539 * ```
20540 *
20541 * It is possible to create chains of any length and since a promise can be resolved with another
20542 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
20543 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
20544 * $http's response interceptors.
20545 *
20546 *
20547 * # Differences between Kris Kowal's Q and $q
20548 *
20549 *  There are two main differences:
20550 *
20551 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
20552 *   mechanism in angular, which means faster propagation of resolution or rejection into your
20553 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
20554 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
20555 *   all the important functionality needed for common async tasks.
20556 *
20557 * # Testing
20558 *
20559 *  ```js
20560 *    it('should simulate promise', inject(function($q, $rootScope) {
20561 *      var deferred = $q.defer();
20562 *      var promise = deferred.promise;
20563 *      var resolvedValue;
20564 *
20565 *      promise.then(function(value) { resolvedValue = value; });
20566 *      expect(resolvedValue).toBeUndefined();
20567 *
20568 *      // Simulate resolving of promise
20569 *      deferred.resolve(123);
20570 *      // Note that the 'then' function does not get called synchronously.
20571 *      // This is because we want the promise API to always be async, whether or not
20572 *      // it got called synchronously or asynchronously.
20573 *      expect(resolvedValue).toBeUndefined();
20574 *
20575 *      // Propagate promise resolution to 'then' functions using $apply().
20576 *      $rootScope.$apply();
20577 *      expect(resolvedValue).toEqual(123);
20578 *    }));
20579 *  ```
20580 *
20581 * @param {function(function, function)} resolver Function which is responsible for resolving or
20582 *   rejecting the newly created promise. The first parameter is a function which resolves the
20583 *   promise, the second parameter is a function which rejects the promise.
20584 *
20585 * @returns {Promise} The newly created promise.
20586 */
20587function $QProvider() {
20588
20589  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
20590    return qFactory(function(callback) {
20591      $rootScope.$evalAsync(callback);
20592    }, $exceptionHandler);
20593  }];
20594}
20595
20596function $$QProvider() {
20597  this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
20598    return qFactory(function(callback) {
20599      $browser.defer(callback);
20600    }, $exceptionHandler);
20601  }];
20602}
20603
20604/**
20605 * Constructs a promise manager.
20606 *
20607 * @param {function(function)} nextTick Function for executing functions in the next turn.
20608 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
20609 *     debugging purposes.
20610 * @returns {object} Promise manager.
20611 */
20612function qFactory(nextTick, exceptionHandler) {
20613  var $qMinErr = minErr('$q', TypeError);
20614
20615  /**
20616   * @ngdoc method
20617   * @name ng.$q#defer
20618   * @kind function
20619   *
20620   * @description
20621   * Creates a `Deferred` object which represents a task which will finish in the future.
20622   *
20623   * @returns {Deferred} Returns a new instance of deferred.
20624   */
20625  var defer = function() {
20626    var d = new Deferred();
20627    //Necessary to support unbound execution :/
20628    d.resolve = simpleBind(d, d.resolve);
20629    d.reject = simpleBind(d, d.reject);
20630    d.notify = simpleBind(d, d.notify);
20631    return d;
20632  };
20633
20634  function Promise() {
20635    this.$$state = { status: 0 };
20636  }
20637
20638  extend(Promise.prototype, {
20639    then: function(onFulfilled, onRejected, progressBack) {
20640      if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
20641        return this;
20642      }
20643      var result = new Deferred();
20644
20645      this.$$state.pending = this.$$state.pending || [];
20646      this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
20647      if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
20648
20649      return result.promise;
20650    },
20651
20652    "catch": function(callback) {
20653      return this.then(null, callback);
20654    },
20655
20656    "finally": function(callback, progressBack) {
20657      return this.then(function(value) {
20658        return handleCallback(value, true, callback);
20659      }, function(error) {
20660        return handleCallback(error, false, callback);
20661      }, progressBack);
20662    }
20663  });
20664
20665  //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
20666  function simpleBind(context, fn) {
20667    return function(value) {
20668      fn.call(context, value);
20669    };
20670  }
20671
20672  function processQueue(state) {
20673    var fn, deferred, pending;
20674
20675    pending = state.pending;
20676    state.processScheduled = false;
20677    state.pending = undefined;
20678    for (var i = 0, ii = pending.length; i < ii; ++i) {
20679      deferred = pending[i][0];
20680      fn = pending[i][state.status];
20681      try {
20682        if (isFunction(fn)) {
20683          deferred.resolve(fn(state.value));
20684        } else if (state.status === 1) {
20685          deferred.resolve(state.value);
20686        } else {
20687          deferred.reject(state.value);
20688        }
20689      } catch (e) {
20690        deferred.reject(e);
20691        exceptionHandler(e);
20692      }
20693    }
20694  }
20695
20696  function scheduleProcessQueue(state) {
20697    if (state.processScheduled || !state.pending) return;
20698    state.processScheduled = true;
20699    nextTick(function() { processQueue(state); });
20700  }
20701
20702  function Deferred() {
20703    this.promise = new Promise();
20704  }
20705
20706  extend(Deferred.prototype, {
20707    resolve: function(val) {
20708      if (this.promise.$$state.status) return;
20709      if (val === this.promise) {
20710        this.$$reject($qMinErr(
20711          'qcycle',
20712          "Expected promise to be resolved with value other than 
20712itself '{0}'",
20713          val));
20714      } else {
20715        this.$$resolve(val);
20716      }
20717
20718    },
20719
20720    $$resolve: function(val) {
20721      var then;
20722      var that = this;
20723      var done = false;
20724      try {
20725        if ((isObject(val) || isFunction(val))) then = val && val.then;
20726        if (isFunction(then)) {
20727          this.promise.$$state.status = -1;
20728          then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
20729        } else {
20730          this.promise.$$state.value = val;
20731          this.promise.$$state.status = 1;
20732          scheduleProcessQueue(this.promise.$$state);
20733        }
20734      } catch (e) {
20735        rejectPromise(e);
20736        exceptionHandler(e);
20737      }
20738
20739      function resolvePromise(val) {
20740        if (done) return;
20741        done = true;
20742        that.$$resolve(val);
20743      }
20744      function rejectPromise(val) {
20745        if (done) return;
20746        done = true;
20747        that.$$reject(val);
20748      }
20749    },
20750
20751    reject: function(reason) {
20752      if (this.promise.$$state.status) return;
20753      this.$$reject(reason);
20754    },
20755
20756    $$reject: function(reason) {
20757      this.promise.$$state.value = reason;
20758      this.promise.$$state.status = 2;
20759      scheduleProcessQueue(this.promise.$$state);
20760    },
20761
20762    notify: function(progress) {
20763      var callbacks = this.promise.$$state.pending;
20764
20765      if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
20766        nextTick(function() {
20767          var callback, result;
20768          for (var i = 0, ii = callbacks.length; i < ii; i++) {
20769            result = callbacks[i][0];
20770            callback = callbacks[i][3];
20771            try {
20772              result.notify(isFunction(callback) ? callback(progress) : progress);
20773            } catch (e) {
20774              exceptionHandler(e);
20775            }
20776          }
20777        });
20778      }
20779    }
20780  });
20781
20782  /**
20783   * @ngdoc method
20784   * @name $q#reject
20785   * @kind function
20786   *
20787   * @description
20788   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
20789   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
20790   * a promise chain, you don't need to worry about it.
20791   *
20792   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
20793   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
20794   * a promise error callback and you want to forward the error to the promise derived from the
20795   * current promise, you have to "rethrow" the error by returning a rejection constructed via
20796   * `reject`.
20797   *
20798   * ```js
20799   *   promiseB = promiseA.then(function(result) {
20800   *     // success: do something and resolve promiseB
20801   *     //          with the old or a new result
20802   *     return result;
20803   *   }, function(reason) {
20804   *     // error: handle the error if possible and
20805   *     //        resolve promiseB with newPromiseOrValue,
20806   *     //        otherwise forward the rejection to promiseB
20807   *     if (canHandle(reason)) {
20808   *      // handle the error and recover
20809   *      return newPromiseOrValue;
20810   *     }
20811   *     return $q.reject(reason);
20812   *   });
20813   * ```
20814   *
20815   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
20816   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
20817   */
20818  var reject = function(reason) {
20819    var result = new Deferred();
20820    result.reject(reason);
20821    return result.promise;
20822  };
20823
20824  var makePromise = function makePromise(value, resolved) {
20825    var result = new Deferred();
20826    if (resolved) {
20827      result.resolve(value);
20828    } else {
20829      result.reject(value);
20830    }
20831    return result.promise;
20832  };
20833
20834  var handleCallback = function handleCallback(value, isResolved, callback) {
20835    var callbackOutput = null;
20836    try {
20837      if (isFunction(callback)) callbackOutput = callback();
20838    } catch (e) {
20839      return makePromise(e, false);
20840    }
20841    if (isPromiseLike(callbackOutput)) {
20842      return callbackOutput.then(function() {
20843        return makePromise(value, isResolved);
20844      }, function(error) {
20845        return makePromise(error, false);
20846      });
20847    } else {
20848      return makePromise(value, isResolved);
20849    }
20850  };
20851
20852  /**
20853   * @ngdoc method
20854   * @name $q#when
20855   * @kind function
20856   *
20857   * @description
20858   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
20859   * This is useful when you are dealing with an object that might or might not be a promise, or if
20860   * the promise comes from a source that can't be trusted.
20861   *
20862   * @param {*} value Value or a promise
20863   * @param {Function=} successCallback
20864   * @param {Function=} errorCallback
20865   * @param {Function=} progressCallback
20866   * @returns {Promise} Returns a promise of the passed value or promise
20867   */
20868
20869
20870  var when = function(value, callback, errback, progressBack) {
20871    var result = new Deferred();
20872    result.resolve(value);
20873    return result.promise.then(callback, errback, progressBack);
20874  };
20875
20876  /**
20877   * @ngdoc method
20878   * @name $q#resolve
20879   * @kind function
20880   *
20881   * @description
20882   * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
20883   *
20884   * @param {*} value Value or a promise
20885   * @param {Function=} successCallback
20886   * @param {Function=} errorCallback
20887   * @param {Function=} progressCallback
20888   * @returns {Promise} Returns a promise of the passed value or promise
20889   */
20890  var resolve = when;
20891
20892  /**
20893   * @ngdoc method
20894   * @name $q#all
20895   * @kind function
20896   *
20897   * @description
20898   * Combines multiple promises into a single promise that is resolved when all of the input
20899   * promises are resolved.
20900   *
20901   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
20902   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
20903   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
20904   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
20905   *   with the same rejection value.
20906   */
20907
20908  function all(promises) {
20909    var deferred = new Deferred(),
20910        counter = 0,
20911        results = isArray(promises) ? [] : {};
20912
20913    forEach(promises, function(promise, key) {
20914      counter++;
20915      when(promise).then(function(value) {
20916        if (results.hasOwnProperty(key)) return;
20917        results[key] = value;
20918        if (!(--counter)) deferred.resolve(results);
20919      }, function(reason) {
20920        if (results.hasOwnProperty(key)) return;
20921        deferred.reject(reason);
20922      });
20923    });
20924
20925    if (counter === 0) {
20926      deferred.resolve(results);
20927    }
20928
20929    return deferred.promise;
20930  }
20931
20932  var $Q = function Q(resolver) {
20933    if (!isFunction(resolver)) {
20934      throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
20935    }
20936
20937    var deferred = new Deferred();
20938
20939    function resolveFn(value) {
20940      deferred.resolve(value);
20941    }
20942
20943    function rejectFn(reason) {
20944      deferred.reject(reason);
20945    }
20946
20947    resolver(resolveFn, rejectFn);
20948
20949    return deferred.promise;
20950  };
20951
20952  // Let's make the instanceof operator work for promises, so that
20953  // `new $q(fn) instanceof $q` would evaluate to true.
20954  $Q.prototype = Promise.prototype;
20955
20956  $Q.defer = defer;
20957  $Q.reject = reject;
20958  $Q.when = when;
20959  $Q.resolve = resolve;
20960  $Q.all = all;
20961
20962  return $Q;
20963}
20964
20965function $$RAFProvider() { //rAF
20966  this.$get = ['$window', '$timeout', function($window, $timeout) {
20967    var requestAnimationFrame = $window.requestAnimationFrame ||
20968                                $window.webkitRequestAnimationFrame;
20969
20970    var cancelAnimationFrame = $window.cancelAnimationFrame ||
20971                               $window.webkitCancelAnimationFrame ||
20972                               $window.webkitCancelRequestAnimationFrame;
20973
20974    var rafSupported = !!requestAnimationFrame;
20975    var raf = rafSupported
20976      ? function(fn) {
20977          var id = requestAnimationFrame(fn);
20978          return function() {
20979            cancelAnimationFrame(id);
20980          };
20981        }
20982      : function(fn) {
20983          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
20984          return function() {
20985            $timeout.cancel(timer);
20986          };
20987        };
20988
20989    raf.supported = rafSupported;
20990
20991    return raf;
20992  }];
20993}
20994
20995/**
20996 * DESIGN NOTES
20997 *
20998 * The design decisions behind the scope are heavily favored for speed and memory consumption.
20999 *
21000 * The typical use of scope is to watch the expressions, which most of the time return the same
21001 * value as last time so we optimize the operation.
21002 *
21003 * Closures construction is expensive in terms of speed as well as memory:
21004 *   - No closures, instead use prototypical inheritance for API
21005 *   - Internal state needs to be stored on scope directly, which means that private state is
21006 *     exposed as $$____ properties
21007 *
21008 * Loop operations are optimized by using while(count--) { ... }
21009 *   - This means that in order to keep the same order of execution as addition we have to add
21010 *     items to the array at the beginning (unshift) instead of at the end (push)
21011 *
21012 * Child scopes are created and removed often
21013 *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
21014 *
21015 * There are fewer watches than observers. This is why you don't want the observer to be implemented
21016 * in the same way as watch. Watch requires return of the initialization function which is expensive
21017 * to construct.
21018 */
21019
21020
21021/**
21022 * @ngdoc provider
21023 * @name $rootScopeProvider
21024 * @description
21025 *
21026 * Provider for the $rootScope service.
21027 */
21028
21029/**
21030 * @ngdoc method
21031 * @name $rootScopeProvider#digestTtl
21032 * @description
21033 *
21034 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
21035 * assuming that the model is unstable.
21036 *
21037 * The current default is 10 iterations.
21038 *
21039 * In complex applications it's possible that the dependencies between `$watch`s will result in
21040 * several digest iterations. However if an application needs more than the default 10 digest
21041 * iterations for its model to stabilize then you should investigate what is causing the model to
21042 * continuously change during the digest.
21043 *
21044 * Increasing the TTL could have performance implications, so you should not change it without
21045 * proper justification.
21046 *
21047 * @param {number} limit The number of digest iterations.
21048 */
21049
21050
21051/**
21052 * @ngdoc service
21053 * @name $rootScope
21054 * @description
21055 *
21056 * Every application has a single root {@link ng.$rootScope.Scope scope}.
21057 * All other scopes are descendant scopes of the root scope. Scopes provide separation
21058 * between the model and the view, via a mechanism for watching the model for changes.
21059 * They also provide event emission/broadcast and subscription facility. See the
21060 * {@link guide/scope developer guide on scopes}.
21061 */
21062function $RootScopeProvider() {
21063  var TTL = 10;
21064  var $rootScopeMinErr = minErr('$rootScope');
21065  var lastDirtyWatch = null;
21066  var applyAsyncId = null;
21067
21068  this.digestTtl = function(value) {
21069    if (arguments.length) {
21070      TTL = value;
21071    }
21072    return TTL;
21073  };
21074
21075  function createChildScopeClass(parent) {
21076    function ChildScope() {
21077      this.$$watchers = this.$$nextSibling =
21078          this.$$childHead = this.$$childTail = null;
21079      this.$$listeners = {};
21080      this.$$listenerCount = {};
21081      this.$$watchersCount = 0;
21082      this.$id = nextUid();
21083      this.$$ChildScope = null;
21084    }
21085    ChildScope.prototype = parent;
21086    return ChildScope;
21087  }
21088
21089  this.$get = ['$exceptionHandler', '$parse', '$browser',
21090      function($exceptionHandler, $parse, $browser) {
21091
21092    function destroyChildScope($event) {
21093        $event.currentScope.$$destroyed = true;
21094    }
21095
21096    function cleanUpScope($scope) {
21097
21098      if (msie === 9) {
21099        // There is a memory leak in IE9 if all child scopes are not disconnected
21100        // completely when a scope is destroyed. So this code will recurse up through
21101        // all this scopes children
21102        //
21103        // See issue https://github.com/angular/angular.js/issues/10706
21104        $scope.$$childHead && cleanUpScope($scope.$$childHead);
21105        $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
21106      }
21107
21108      // The code below works around IE9 and V8's memory leaks
21109      //
21110      // See:
21111      // - https://code.google.com/p/v8/issues/detail?id=2073#c26
21112      // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
21113      // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
21114
21115      $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
21116          $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
21117    }
21118
21119    /**
21120     * @ngdoc type
21121     * @name $rootScope.Scope
21122     *
21123     * @description
21124     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
21125     * {@link auto.$injector $injector}. Child scopes are created using the
21126     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
21127     * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
21128     * an in-depth introduction and usage examples.
21129     *
21130     *
21131     * # Inheritance
21132     * A scope can inherit from a parent scope, as in this example:
21133     * ```js
21134         var parent = $rootScope;
21135         var child = parent.$new();
21136
21137         parent.salutation = "Hello";
21138         expect(child.salutation).toEqual('Hello');
21139
21140         child.salutation = "Welcome";
21141         expect(child.salutation).toEqual('Welcome');
21142         expect(parent.salutation).toEqual('Hello');
21143     * ```
21144     *
21145     * When interacting with `Scope` in tests, additional helper methods are available on the
21146     * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
21147     * details.
21148     *
21149     *
21150     * @param {Object.<string, function()>=} providers Map of service factory which need to be
21151     *                                       provided for the current scope. Defaults to {@link ng}.
21152     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
21153     *                              append/override services provided by `providers`. This is handy
21154     *                              when unit-testing and having the need to override a default
21155     *                              service.
21156     * @returns {Object} Newly created scope.
21157     *
21158     */
21159    function Scope() {
21160      this.$id = nextUid();
21161      this.$$phase = this.$parent = this.$$watchers =
21162                     this.$$nextSibling = this.$$prevSibling =
21163                     this.$$childHead = this.$$childTail = null;
21164      this.$root = this;
21165      this.$$destroyed = false;
21166      this.$$listeners = {};
21167      this.$$listenerCount = {};
21168      this.$$watchersCount = 0;
21169      this.$$isolateBindings = null;
21170    }
21171
21172    /**
21173     * @ngdoc property
21174     * @name $rootScope.Scope#$id
21175     *
21176     * @description
21177     * Unique scope ID (monotonically increasing) useful for debugging.
21178     */
21179
21180     /**
21181      * @ngdoc property
21182      * @name $rootScope.Scope#$parent
21183      *
21184      * @description
21185      * Reference to the parent scope.
21186      */
21187
21188      /**
21189       * @ngdoc property
21190       * @name $rootScope.Scope#$root
21191       *
21192       * @description
21193       * Reference to the root scope.
21194       */
21195
21196    Scope.prototype = {
21197      constructor: Scope,
21198      /**
21199       * @ngdoc method
21200       * @name $rootScope.Scope#$new
21201       * @kind function
21202       *
21203       * @description
21204       * Creates a new child {@link ng.$rootScope.Scope scope}.
21205       *
21206       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
21207       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
21208       *
21209       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
21210       * desired for the scope and its child scopes to be permanently detached from the parent and
21211       * thus stop participating in model change detection and listener notification by invoking.
21212       *
21213       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
21214       *         parent scope. The scope is isolated, as it can not see parent scope properties.
21215       *         When creating widgets, it is useful for the widget to not accidentally read parent
21216       *         state.
21217       *
21218       * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
21219       *                              of the newly created scope. Defaults to `this` scope if not provided.
21220       *                              This is used when creating a transclude scope to correctly place it
21221       *                              in the scope hierarchy while maintaining the correct prototypical
21222       *                              inheritance.
21223       *
21224       * @returns {Object} The newly created child scope.
21225       *
21226       */
21227      $new: function(isolate, parent) {
21228        var child;
21229
21230        parent = parent || this;
21231
21232        if (isolate) {
21233          child = new Scope();
21234          child.$root = this.$root;
21235        } else {
21236          // Only create a child scope class if somebody asks for one,
21237          // but cache it to allow the VM to optimize lookups.
21238          if (!this.$$ChildScope) {
21239            this.$$ChildScope = createChildScopeClass(this);
21240          }
21241          child = new this.$$ChildScope();
21242        }
21243        child.$parent = parent;
21244        child.$$prevSibling = parent.$$childTail;
21245        if (parent.$$childHead) {
21246          parent.$$childTail.$$nextSibling = child;
21247          parent.$$childTail = child;
21248        } else {
21249          parent.$$childHead = parent.$$childTail = child;
21250        }
21251
21252        // When the new scope is not isolated or we inherit from `this`, and
21253        // the parent scope is destroyed, the property `$$destroyed` is inherited
21254        // prototypically. In all other cases, this property needs to be set
21255        // when the parent scope is destroyed.
21256        // The listener needs to be added after the parent is set
21257        if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
21258
21259        return child;
21260      },
21261
21262      /**
21263       * @ngdoc method
21264       * @name $rootScope.Scope#$watch
21265       * @kind function
21266       *
21267       * @description
21268       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
21269       *
21270       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
21271       *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
21272       *   its value when executed multiple times with the same input because it may be executed multiple
21273       *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
21274       *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
21275       * - The `listener` is called only when the value from the current `watchExpression` and the
21276       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
21277       *   see below). Inequality is determined according to reference inequality,
21278       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
21279       *    via the `!==` Javascript operator, unless `objectEquality == true`
21280       *   (see next point)
21281       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
21282       *   according to the {@link angular.equals} function. To save the value of the object for
21283       *   later comparison, the {@link angular.copy} function is used. This therefore means that
21284       *   watching complex objects will have adverse memory and performance implications.
21285       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
21286       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
21287       *   iteration limit is 10 to prevent an infinite loop deadlock.
21288       *
21289       *
21290       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
21291       * you can register a `watchExpression` function with no `listener`. (Be prepared for
21292       * multiple calls to your `watchExpression` because it will execute multiple times in a
21293       * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
21294       *
21295       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
21296       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
21297       * watcher. In rare cases, this is undesirable because the listener is called when the result
21298       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
21299       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
21300       * listener was called due to initialization.
21301       *
21302       *
21303       *
21304       * # Example
21305       * ```js
21306           // let's assume that scope was dependency injected as the $rootScope
21307           var scope = $rootScope;
21308           scope.name = 'misko';
21309           scope.counter = 0;
21310
21311           expect(scope.counter).toEqual(0);
21312           scope.$watch('name', function(newValue, oldValue) {
21313             scope.counter = scope.counter + 1;
21314           });
21315           expect(scope.counter).toEqual(0);
21316
21317           scope.$digest();
21318           // the listener is always called during the first $digest loop after it was registered
21319           expect(scope.counter).toEqual(1);
21320
21321           scope.$digest();
21322           // but now it will not be called unless the value changes
21323           expect(scope.counter).toEqual(1);
21324
21325           scope.name = 'adam';
21326           scope.$digest();
21327           expect(scope.counter).toEqual(2);
21328
21329
21330
21331           // Using a function as a watchExpression
21332           var food;
21333           scope.foodCounter = 0;
21334           expect(scope.foodCounter).toEqual(0);
21335           scope.$watch(
21336             // This function returns the value being watched. It is called for each turn of the $digest loop
21337             function() { return food; },
21338             // This is the change listener, called when the value returned from the above function changes
21339             function(newValue, oldValue) {
21340               if ( newValue !== oldValue ) {
21341                 // Only increment the counter if the value changed
21342                 scope.foodCounter = scope.foodCounter + 1;
21343               }
21344             }
21345           );
21346           // No digest has been run so the counter will be zero
21347           expect(scope.foodCounter).toEqual(0);
21348
21349           // Run the digest but since food has not changed count will still be zero
21350           scope.$digest();
21351           expect(scope.foodCounter).toEqual(0);
21352
21353           // Update food and run digest.  Now the counter will increment
21354           food = 'cheeseburger';
21355           scope.$digest();
21356           expect(scope.foodCounter).toEqual(1);
21357
21358       * ```
21359       *
21360       *
21361       *
21362       * @param {(function()|string)} watchExpression Expression that is evaluated on each
21363       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
21364       *    a call to the `listener`.
21365       *
21366       *    - `string`: Evaluated as {@link guide/expression expression}
21367       *    - `function(scope)`: called with current `scope` as a parameter.
21368       * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
21369       *    of `watchExpression` changes.
21370       *
21371       *    - `newVal` contains the current value of the `watchExpression`
21372       *    - `oldVal` contains the previous value of the `watchExpression`
21373       *    - `scope` refers to the current scope
21374       * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
21375       *     comparing for reference equality.
21376       * @returns {function()} Returns a deregistration function for this listener.
21377       */
21378      $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
21379        var get = $parse(watchExp);
21380
21381        if (get.$$watchDelegate) {
21382          return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
21383        }
21384        var scope = this,
21385            array = scope.$$watchers,
21386            watcher = {
21387              fn: listener,
21388              last: initWatchVal,
21389              get: get,
21390              exp: prettyPrintExpression || watchExp,
21391              eq: !!objectEquality
21392            };
21393
21394        lastDirtyWatch = null;
21395
21396        if (!isFunction(listener)) {
21397          watcher.fn = noop;
21398        }
21399
21400        if (!array) {
21401          array = scope.$$watchers = [];
21402        }
21403        // we use unshift since we use a while loop in $digest for speed.
21404        // the while loop reads in reverse order.
21405        array.unshift(watcher);
21406        incrementWatchersCount(this, 1);
21407
21408        return function deregisterWatch() {
21409          if (arrayRemove(array, watcher) >= 0) {
21410            incrementWatchersCount(scope, -1);
21411          }
21412          lastDirtyWatch = null;
21413        };
21414      },
21415
21416      /**
21417       * @ngdoc method
21418       * @name $rootScope.Scope#$watchGroup
21419       * @kind function
21420       *
21421       * @description
21422       * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
21423       * If any one expression in the collection changes the `listener` is executed.
21424       *
21425       * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
21426       *   call to $digest() to see if any items changes.
21427       * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
21428       *
21429       * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
21430       * watched using {@link ng.$rootScope.Scope#$watch $watch()}
21431       *
21432       * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
21433       *    expression in `watchExpressions` changes
21434       *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
21435       *    those of `watchExpression`
21436       *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
21437       *    those of `watchExpression`
21438       *    The `scope` refers to the current scope.
21439       * @returns {function()} Returns a de-registration function for all listeners.
21440       */
21441      $watchGroup: function(watchExpressions, listener) {
21442        var oldValues = new Array(watchExpressions.length);
21443        var newValues = new Array(watchExpressions.length);
21444        var deregisterFns = [];
21445        var self = this;
21446        var changeReactionScheduled = false;
vendor: 10,192 bytes, lines 21447-21709
21447        var firstRun = true;
21448
21449        if (!watchExpressions.length) {
21450          // No expressions means we call the listener ASAP
21451          var shouldCall = true;
21452          self.$evalAsync(function() {
21453            if (shouldCall) listener(newValues, newValues, self);
21454          });
21455          return function deregisterWatchGroup() {
21456            shouldCall = false;
21457          };
21458        }
21459
21460        if (watchExpressions.length === 1) {
21461          // Special case size of one
21462          return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
21463            newValues[0] = value;
21464            oldValues[0] = oldValue;
21465            listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
21466          });
21467        }
21468
21469        forEach(watchExpressions, function(expr, i) {
21470          var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
21471            newValues[i] = value;
21472            oldValues[i] = oldValue;
21473            if (!changeReactionScheduled) {
21474              changeReactionScheduled = true;
21475              self.$evalAsync(watchGroupAction);
21476            }
21477          });
21478          deregisterFns.push(unwatchFn);
21479        });
21480
21481        function watchGroupAction() {
21482          changeReactionScheduled = false;
21483
21484          if (firstRun) {
21485            firstRun = false;
21486            listener(newValues, newValues, self);
21487          } else {
21488            listener(newValues, oldValues, self);
21489          }
21490        }
21491
21492        return function deregisterWatchGroup() {
21493          while (deregisterFns.length) {
21494            deregisterFns.shift()();
21495          }
21496        };
21497      },
21498
21499
21500      /**
21501       * @ngdoc method
21502       * @name $rootScope.Scope#$watchCollection
21503       * @kind function
21504       *
21505       * @description
21506       * Shallow watches the properties of an object and fires whenever any of the properties change
21507       * (for arrays, this implies watching the array items; for object maps, this implies watching
21508       * the properties). If a change is detected, the `listener` callback is fired.
21509       *
21510       * - The `obj` collection is observed via standard $watch operation and is examined on every
21511       *   call to $digest() to see if any items have been added, removed, or moved.
21512       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
21513       *   adding, removing, and moving items belonging to an object or array.
21514       *
21515       *
21516       * # Example
21517       * ```js
21518          $scope.names = ['igor', 'matias', 'misko', 'james'];
21519          $scope.dataCount = 4;
21520
21521          $scope.$watchCollection('names', function(newNames, oldNames) {
21522            $scope.dataCount = newNames.length;
21523          });
21524
21525          expect($scope.dataCount).toEqual(4);
21526          $scope.$digest();
21527
21528          //still at 4 ... no changes
21529          expect($scope.dataCount).toEqual(4);
21530
21531          $scope.names.pop();
21532          $scope.$digest();
21533
21534          //now there's been a change
21535          expect($scope.dataCount).toEqual(3);
21536       * ```
21537       *
21538       *
21539       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
21540       *    expression value should evaluate to an object or an array which is observed on each
21541       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
21542       *    collection will trigger a call to the `listener`.
21543       *
21544       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
21545       *    when a change is detected.
21546       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
21547       *    - The `oldCollection` object is a copy of the former collection data.
21548       *      Due to performance considerations, the`oldCollection` value is computed only if the
21549       *      `listener` function declares two or more arguments.
21550       *    - The `scope` argument refers to the current scope.
21551       *
21552       * @returns {function()} Returns a de-registration function for this listener. When the
21553       *    de-registration function is executed, the internal watch operation is terminated.
21554       */
21555      $watchCollection: function(obj, listener) {
21556        $watchCollectionInterceptor.$stateful = true;
21557
21558        var self = this;
21559        // the current value, updated on each dirty-check run
21560        var newValue;
21561        // a shallow copy of the newValue from the last dirty-check run,
21562        // updated to match newValue during dirty-check run
21563        var oldValue;
21564        // a shallow copy of the newValue from when the last change happened
21565        var veryOldValue;
21566        // only track veryOldValue if the listener is asking for it
21567        var trackVeryOldValue = (listener.length > 1);
21568        var changeDetected = 0;
21569        var changeDetector = $parse(obj, $watchCollectionInterceptor);
21570        var internalArray = [];
21571        var internalObject = {};
21572        var initRun = true;
21573        var oldLength = 0;
21574
21575        function $watchCollectionInterceptor(_value) {
21576          newValue = _value;
21577          var newLength, key, bothNaN, newItem, oldItem;
21578
21579          // If the new value is undefined, then return undefined as the watch may be a one-time watch
21580          if (isUndefined(newValue)) return;
21581
21582          if (!isObject(newValue)) { // if primitive
21583            if (oldValue !== newValue) {
21584              oldValue = newValue;
21585              changeDetected++;
21586            }
21587          } else if (isArrayLike(newValue)) {
21588            if (oldValue !== internalArray) {
21589              // we are transitioning from something which was not an array into array.
21590              oldValue = internalArray;
21591              oldLength = oldValue.length = 0;
21592              changeDetected++;
21593            }
21594
21595            newLength = newValue.length;
21596
21597            if (oldLength !== newLength) {
21598              // if lengths do not match we need to trigger change notification
21599              changeDetected++;
21600              oldValue.length = oldLength = newLength;
21601            }
21602            // copy the items to oldValue and look for changes.
21603            for (var i = 0; i < newLength; i++) {
21604              oldItem = oldValue[i];
21605              newItem = newValue[i];
21606
21607              bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
21608              if (!bothNaN && (oldItem !== newItem)) {
21609                changeDetected++;
21610                oldValue[i] = newItem;
21611              }
21612            }
21613          } else {
21614            if (oldValue !== internalObject) {
21615              // we are transitioning from something which was not an object into object.
21616              oldValue = internalObject = {};
21617              oldLength = 0;
21618              changeDetected++;
21619            }
21620            // copy the items to oldValue and look for changes.
21621            newLength = 0;
21622            for (key in newValue) {
21623              if (hasOwnProperty.call(newValue, key)) {
21624                newLength++;
21625                newItem = newValue[key];
21626                oldItem = oldValue[key];
21627
21628                if (key in oldValue) {
21629                  bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
21630                  if (!bothNaN && (oldItem !== newItem)) {
21631                    changeDetected++;
21632                    oldValue[key] = newItem;
21633                  }
21634                } else {
21635                  oldLength++;
21636                  oldValue[key] = newItem;
21637                  changeDetected++;
21638                }
21639              }
21640            }
21641            if (oldLength > newLength) {
21642              // we used to have more keys, need to find them and destroy them.
21643              changeDetected++;
21644              for (key in oldValue) {
21645                if (!hasOwnProperty.call(newValue, key)) {
21646                  oldLength--;
21647                  delete oldValue[key];
21648                }
21649              }
21650            }
21651          }
21652          return changeDetected;
21653        }
21654
21655        function $watchCollectionAction() {
21656          if (initRun) {
21657            initRun = false;
21658            listener(newValue, newValue, self);
21659          } else {
21660            listener(newValue, veryOldValue, self);
21661          }
21662
21663          // make a copy for the next time a collection is changed
21664          if (trackVeryOldValue) {
21665            if (!isObject(newValue)) {
21666              //primitive
21667              veryOldValue = newValue;
21668            } else if (isArrayLike(newValue)) {
21669              veryOldValue = new Array(newValue.length);
21670              for (var i = 0; i < newValue.length; i++) {
21671                veryOldValue[i] = newValue[i];
21672              }
21673            } else { // if object
21674              veryOldValue = {};
21675              for (var key in newValue) {
21676                if (hasOwnProperty.call(newValue, key)) {
21677                  veryOldValue[key] = newValue[key];
21678                }
21679              }
21680            }
21681          }
21682        }
21683
21684        return this.$watch(changeDetector, $watchCollectionAction);
21685      },
21686
21687      /**
21688       * @ngdoc method
21689       * @name $rootScope.Scope#$digest
21690       * @kind function
21691       *
21692       * @description
21693       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
21694       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
21695       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
21696       * until no more listeners are firing. This means that it is possible to get into an infinite
21697       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
21698       * iterations exceeds 10.
21699       *
21700       * Usually, you don't call `$digest()` directly in
21701       * {@link ng.directive:ngController controllers} or in
21702       * {@link ng.$compileProvider#directive directives}.
21703       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
21704       * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
21705       *
21706       * If you want to be notified whenever `$digest()` is called,
21707       * you can register a `watchExpression` function with
21708       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
21709       *
21710       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
21711       *
21712       * # Example
21713       * ```js
21714           var scope = ...;
21715           scope.name = 'misko';
21716           scope.counter = 0;
21717
21718           expect(scope.counter).toEqual(0);
21719           scope.$watch('name', function(newValue, oldValue) {
21720             scope.counter = scope.counter + 1;
21721           });
21722           expect(scope.counter).toEqual(0);
21723
21724           scope.$digest();
21725           // the listener is always called during the first $digest loop after it was registered
21726           expect(scope.counter).toEqual(1);
21727
21728           scope.$digest();
21729           // but now it will not be called unless the value changes
21730           expect(scope.counter).toEqual(1);
21731
21732           scope.name = 'adam';
21733           scope.$digest();
21734           expect(scope.counter).toEqual(2);
21735       * ```
21736       *
21737       */
21738      $digest: function() {
21739        var watch, value, last, fn, get,
21740            watchers,
21741            length,
21742            dirty, ttl = TTL,
21743            next, current, target = this,
21744            watchLog = [],
21745            logIdx, logMsg, asyncTask;
21746
21747        beginPhase('$digest');
21748        // Check for changes to browser url that happened in sync before the call to $digest
21749        $browser.$$checkUrlChange();
21750
21751        if (this === $rootScope && applyAsyncId !== null) {
21752          // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
21753          // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
21754          $browser.defer.cancel(applyAsyncId);
21755          flushApplyAsync();
21756        }
21757
21758        lastDirtyWatch = null;
21759
21760        do { // "while dirty" loop
21761          dirty = false;
21762          current = target;
21763
21764          while (asyncQueue.length) {
21765            try {
21766              asyncTask = asyncQueue.shift();
21767              asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
21768            } catch (e) {
21769              $exceptionHandler(e);
21770            }
21771            lastDirtyWatch = null;
21772          }
21773
21774          traverseScopesLoop:
21775          do { // "traverse the scopes" loop
21776            if ((watchers = current.$$watchers)) {
21777              // process our watches
21778              length = watchers.length;
21779              while (length--) {
21780                try {
21781                  watch = watchers[length];
21782                  // Most common watches are on primitives, in which case we can short
21783                  // circuit it with === operator, only when === fails do we use .equals
21784                  if (watch) {
21785                    get = watch.get;
21786                    if ((value = get(current)) !== (last = watch.last) &&
21787                        !(watch.eq
21788                            ? equals(value, last)
21789                            : (typeof value === 'number' && typeof last === 'number'
21790                               && isNaN(value) && isNaN(last)))) {
21791                      dirty = true;
21792                      lastDirtyWatch = watch;
21793                      watch.last = watch.eq ? copy(value, null) : value;
21794                      fn = watch.fn;
21795                      fn(value, ((last === initWatchVal) ? value : last), current);
21796                      if (ttl < 5) {
21797                        logIdx = 4 - ttl;
21798                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
21799                        watchLog[logIdx].push({
21800                          msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
21801                          newVal: value,
21802                          oldVal: last
21803                        });
21804                      }
21805                    } else if (watch === lastDirtyWatch) {
21806                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
21807                      // have already been tested.
21808                      dirty = false;
21809                      break traverseScopesLoop;
21810                    }
21811                  }
21812                } catch (e) {
21813                  $exceptionHandler(e);
21814                }
21815              }
21816            }
21817
21818            // Insanity Warning: scope depth-first traversal
21819            // yes, this code is a bit crazy, but it works and we have tests to prove it!
21820            // this piece should be kept in sync with the traversal in $broadcast
21821            if (!(next = ((current.$$watchersCount && current.$$childHead) ||
21822                (current !== target && current.$$nextSibling)))) {
21823              while (current !== target && !(next = current.$$nextSibling)) {
21824                current = current.$parent;
21825              }
21826            }
21827          } while ((current = next));
21828
21829          // `break traverseScopesLoop;` takes us to here
21830
21831          if ((dirty || asyncQueue.length) && !(ttl--)) {
21832            clearPhase();
21833            throw $rootScopeMinErr('infdig',
21834                '{0} $digest() iterations reached. Aborting!\n' +
21835                'Watchers fired in the last 5 iterations: {1}',
21836                TTL, watchLog);
21837          }
21838
21839        }
vendor: 4,632 bytes, lines 21839-21958
21839 while (dirty || asyncQueue.length);
21840
21841        clearPhase();
21842
21843        while (postDigestQueue.length) {
21844          try {
21845            postDigestQueue.shift()();
21846          } catch (e) {
21847            $exceptionHandler(e);
21848          }
21849        }
21850      },
21851
21852
21853      /**
21854       * @ngdoc event
21855       * @name $rootScope.Scope#$destroy
21856       * @eventType broadcast on scope being destroyed
21857       *
21858       * @description
21859       * Broadcasted when a scope and its children are being destroyed.
21860       *
21861       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
21862       * clean up DOM bindings before an element is removed from the DOM.
21863       */
21864
21865      /**
21866       * @ngdoc method
21867       * @name $rootScope.Scope#$destroy
21868       * @kind function
21869       *
21870       * @description
21871       * Removes the current scope (and all of its children) from the parent scope. Removal implies
21872       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
21873       * propagate to the current scope and its children. Removal also implies that the current
21874       * scope is eligible for garbage collection.
21875       *
21876       * The `$destroy()` is usually used by directives such as
21877       * {@link ng.directive:ngRepeat ngRepeat} for managing the
21878       * unrolling of the loop.
21879       *
21880       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
21881       * Application code can register a `$destroy` event handler that will give it a chance to
21882       * perform any necessary cleanup.
21883       *
21884       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
21885       * clean up DOM bindings before an element is removed from the DOM.
21886       */
21887      $destroy: function() {
21888        // We can't destroy a scope that has been already destroyed.
21889        if (this.$$destroyed) return;
21890        var parent = this.$parent;
21891
21892        this.$broadcast('$destroy');
21893        this.$$destroyed = true;
21894
21895        if (this === $rootScope) {
21896          //Remove handlers attached to window when $rootScope is removed
21897          $browser.$$applicationDestroyed();
21898        }
21899
21900        incrementWatchersCount(this, -this.$$watchersCount);
21901        for (var eventName in this.$$listenerCount) {
21902          decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
21903        }
21904
21905        // sever all the references to parent scopes (after this cleanup, the current scope should
21906        // not be retained by any of our references and should be eligible for garbage collection)
21907        if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
21908        if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
21909        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
21910        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
21911
21912        // Disable listeners, watchers and apply/digest methods
21913        this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
21914        this.$on = this.$watch = this.$watchGroup = function() { return noop; };
21915        this.$$listeners = {};
21916
21917        // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
21918        this.$$nextSibling = null;
21919        cleanUpScope(this);
21920      },
21921
21922      /**
21923       * @ngdoc method
21924       * @name $rootScope.Scope#$eval
21925       * @kind function
21926       *
21927       * @description
21928       * Executes the `expression` on the current scope and returns the result. Any exceptions in
21929       * the expression are propagated (uncaught). This is useful when evaluating Angular
21930       * expressions.
21931       *
21932       * # Example
21933       * ```js
21934           var scope = ng.$rootScope.Scope();
21935           scope.a = 1;
21936           scope.b = 2;
21937
21938           expect(scope.$eval('a+b')).toEqual(3);
21939           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
21940       * ```
21941       *
21942       * @param {(string|function())=} expression An angular expression to be executed.
21943       *
21944       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
21945       *    - `function(scope)`: execute the function with the current `scope` parameter.
21946       *
21947       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
21948       * @returns {*} The result of evaluating the expression.
21949       */
21950      $eval: function(expr, locals) {
21951        return $parse(expr)(this, locals);
21952      },
21953
21954      /**
21955       * @ngdoc method
21956       * @name $rootScope.Scope#$evalAsync
21957       * @kind function
21958       *
21959       * @description
21960       * Executes the expression on the current scope at a later point in time.
21961       *
21962       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
21963       * that:
21964       *
21965       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
21966       *     rendering).
21967       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
21968       *     `expression` execution.
21969       *
21970       * Any exceptions from the execution of the expression are forwarded to the
21971       * {@link ng.$exceptionHandler $exceptionHandler} service.
21972       *
21973       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
21974       * will be scheduled. However, it is encouraged to always call code that changes the model
21975       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
21976       *
21977       * @param {(string|function())=} expression An angular expression to be executed.
21978       *
21979       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
21980       *    - `function(scope)`: execute the function with the current `scope` parameter.
21981       *
21982       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
21983       */
21984      $evalAsync: function(expr, locals) {
21985        // if we are outside of an $digest loop and this is the first time we are scheduling async
21986        // task also schedule async auto-flush
21987        if (!$rootScope.$$phase && !asyncQueue.length) {
21988          $browser.defer(function() {
21989            if (asyncQueue.length) {
21990              $rootScope.$digest();
21991            }
21992          });
21993        }
21994
21995        asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
21996      },
21997
21998      $$postDigest: function(fn) {
21999        postDigestQueue.push(fn);
22000      },
22001
22002      /**
22003       * @ngdoc method
22004       * @name $rootScope.Scope#$apply
22005       * @kind function
22006       *
22007       * @description
22008       * `$apply()` is used to execute an expression in angular from outside of the angular
22009       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
22010       * Because we are calling into the angular framework we need to perform proper scope life
22011       * cycle of {@link ng.$exceptionHandler exception handling},
22012       * {@link ng.$rootScope.Scope#$digest executing watches}.
22013       *
22014       * ## Life cycle
22015       *
22016       * # Pseudo-Code of `$apply()`
22017       * ```js
22018           function $apply(expr) {
22019             try {
22020               return $eval(expr);
22021             } catch (e) {
22022               $exceptionHandler(e);
22023             } finally {
22024               $root.$digest();
22025             }
22026           }
22027       * ```
22028       *
22029       *
22030       * Scope's `$apply()` method transitions through the following stages:
22031       *
22032       * 1. The {@link guide/expression expression} is executed using the
22033       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
22034       * 2. Any exceptions from the execution of the expression are forwarded to the
22035       *    {@link ng.$exceptionHandler $exceptionHandler} service.
22036       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
22037       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
22038       *
22039       *
22040       * @param {(string|function())=} exp An angular expression to be executed.
22041       *
22042       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
22043       *    - `function(scope)`: execute the function with current `scope` parameter.
22044       *
22045       * @returns {*} The result of evaluating the expression.
22046       */
22047      $apply: function(expr) {
22048        try {
22049          beginPhase('$apply');
22050          try {
22051            return this.$eval(expr);
22052          } finally {
22053            clearPhase();
22054          }
22055        } catch (e) {
22056          $exceptionHandler(e);
22057        } finally {
22058          try {
22059            $rootScope.$digest();
22060          } catch (e) {
22061            $exceptionHandler(e);
22062            throw e;
22063          }
22064        }
22065      },
22066
22067      /**
22068       * @ngdoc method
22069       * @name $rootScope.Scope#$applyAsync
22070       * @kind function
22071       *
22072       * @description
22073       * Schedule the invocation of $apply to occur at a later time. The actual time difference
22074       * varies across browsers, but is typically around ~10 milliseconds.
22075       *
22076       * This can be used to queue up multiple expressions which need to be evaluated in the same
22077       * digest.
22078       *
22079       * @param {(string|function())=} exp An angular expression to be executed.
22080       *
22081       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
22082       *    - `function(scope)`: execute the function with current `scope` parameter.
22083       */
22084      $applyAsync: function(expr) {
22085        var scope = this;
22086        expr && applyAsyncQueue.push($applyAsyncExpression);
22087        expr = $parse(expr);
22088        scheduleApplyAsync();
22089
22090        function $applyAsyncExpression() {
22091          scope.$eval(expr);
22092        }
22093      },
22094
22095      /**
22096       * @ngdoc method
22097       * @name $rootScope.Scope#$on
22098       * @kind function
22099       *
22100       * @description
22101       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
22102       * discussion of event life cycle.
22103       *
22104       * The event listener function format is: `function(event, args...)`. The `event` object
22105       * passed into the listener has the following attributes:
22106       *
22107       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
22108       *     `$broadcast`-ed.
22109       *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
22110       *     event propagates through the scope hierarchy, this property is set to null.
22111       *   - `name` - `{string}`: name of the event.
22112       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
22113       *     further event propagation (available only for events that were `$emit`-ed).
22114       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
22115       *     to true.
22116       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
22117       *
22118       * @param {string} name Event name to listen on.
22119       * @param {function(event, ...args)} listener Function to call when the event is emitted.
22120       * @returns {function()} Returns a deregistration function for this listener.
22121       */
22122      $on: function(name, listener) {
22123        var namedListeners = this.$$listeners[name];
22124        if (!namedListeners) {
22125          this.$$listeners[name] = namedListeners = [];
22126        }
22127        namedListeners.push(listener);
22128
22129        var current = this;
22130        do {
22131          if (!current.$$listenerCount[name]) {
22132            current.$$listenerCount[name] = 0;
22133          }
22134          current.$$listenerCount[name]++;
22135        } while ((current = current.$parent));
22136
22137        var self = this;
22138        return function() {
22139          var indexOfListener = namedListeners.indexOf(listener);
22140          if (indexOfListener !== -1) {
22141            namedListeners[indexOfListener] = null;
22142            decrementListenerCount(self, 1, name);
22143          }
22144        };
22145      },
22146
22147
22148      /**
22149       * @ngdoc method
22150       * @name $rootScope.Scope#$emit
22151       * @kind function
22152       *
22153       * @description
22154       * Dispatches an event `name` upwards through the scope hierarchy notifying the
22155       * registered {@link ng.$rootScope.Scope#$on} listeners.
22156       *
22157       * The event life cycle starts at the scope on which `$emit` was called. All
22158       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
22159       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
22160       * registered listeners along the way. The event will stop propagating if one of the listeners
22161       * cancels it.
22162       *
22163       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
22164       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
22165       *
22166       * @param {string} name Event name to emit.
22167       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
22168       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
22169       */
22170      $emit: function(name, args) {
22171        var empty = [],
22172            namedListeners,
22173            scope = this,
22174            stopPropagation = false,
22175            event = {
22176              name: name,
22177              targetScope: scope,
22178              stopPropagation: function() {stopPropagation = true;},
22179              preventDefault: function() {
22180                event.defaultPrevented = true;
22181              },
22182              defaultPrevented: false
22183            },
22184            listenerArgs = concat([event], arguments, 1),
22185            i, length;
22186
22187        do {
22188          namedListeners = scope.$$listeners[name] || empty;
22189          event.currentScope = scope;
22190          for (i = 0, length = namedListeners.length; i < length; i++) {
22191
22192            // if listeners were deregistered, defragment the array
22193            if (!namedListeners[i]) {
22194              namedListeners.splice(i, 1);
22195              i--;
22196              length--;
22197              continue;
22198            }
22199            try {
22200              //allow all listeners attached to the current scope to run
22201              namedListeners[i].apply(null, listenerArgs);
22202            } catch (e) {
22203              $exceptionHandler(e);
22204            }
22205          }
22206          //if any listener on the current scope stops propagation, prevent bubbling
22207          if (stopPropagation) {
22208            event.currentScope = null;
22209            return event;
22210          }
22211          //traverse upwards
22212          scope = scope.$parent;
22213        } while (scope);
22214
22215        event.currentScope = null;
22216
22217        return event;
22218      },
22219
22220
22221      /**
22222       * @ngdoc method
22223       * @name $rootScope.Scope#$broadcast
22224       * @kind function
22225       *
22226       * @description
22227       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
22228       * registered {@link ng.$rootScope.Scope#$on} listeners.
22229       *
22230       * The event life cycle starts at the scope on which `$broadcast` was called. All
22231       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
22232       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
22233       * scope and calls all registered listeners along the way. The event cannot be canceled.
22234       *
22235       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
22236       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
22237       *
22238       * @param {string} name Event name to broadcast.
22239       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
22240       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
22241       */
22242      $broadcast: function(name, args) {
22243        var target = this,
22244            current = target,
22245            next = target,
22246            event = {
22247              name: name,
22248              targetScope: target,
22249              preventDefault: function() {
22250                event.defaultPrevented = true;
22251              },
22252              defaultPrevented: false
22253            };
22254
22255        if (!target.$$listenerCount[name]) return event;
22256
22257        var listenerArgs = concat([event], arguments, 1),
22258            listeners, i, length;
22259
22260        //down while you can, then up and next sibling or up and next sibling until back at root
22261        while ((current = next)) {
22262          event.currentScope = current;
22263          listeners = current.$$listeners[name] || [];
22264          for (i = 0, length = listeners.length; i < length; i++) {
22265            // if listeners were deregistered, defragment the array
22266            if (!listeners[i]) {
22267              listeners.splice(i, 1);
22268              i--;
22269              length--;
22270              continue;
22271            }
22272
22273            try {
22274              listeners[i].apply(null, listenerArgs);
22275            } catch (e) {
22276              $exceptionHandler(e);
22277            }
22278          }
22279
22280          // Insanity Warning: scope depth-first traversal
22281          // yes, this code is a bit crazy, but it works and we have tests to prove it!
22282          // this piece should be kept in sync with the traversal in $digest
22283          // (though it differs due to having the extra check for $$listenerCount)
22284          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
22285              (current !== target && current.$$nextSibling)))) {
22286            while (current !== target && !(next = current.$$nextSibling)) {
22287              current = current.$parent;
22288            }
22289          }
22290        }
22291
22292        event.currentScope = null;
22293        return event;
22294      }
22295    };
22296
22297    var $rootScope = new Scope();
22298
22299    //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
22300    var asyncQueue = $rootScope.$$asyncQueue = [];
22301    var postDigestQueue = $rootScope.$$postDigestQueue = [];
22302    var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
22303
22304    return $rootScope;
22305
22306
22307    function beginPhase(phase) {
22308      if ($rootScope.$$phase) {
22309        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
22310      }
22311
22312      $rootScope.$$phase = phase;
22313    }
22314
22315    function clearPhase() {
22316      $rootScope.$$phase = null;
22317    }
22318
22319    function incrementWatchersCount(current, count) {
22320      do {
22321        current.$$watchersCount += count;
22322      } while ((current = current.$parent));
22323    }
22324
22325    function decrementListenerCount(current, count, name) {
22326      do {
22327        current.$$listenerCount[name] -= count;
22328
22329        if (current.$$listenerCount[name] === 0) {
22330          delete current.$$listenerCount[name];
22331        }
22332      } while ((current = current.$parent));
22333    }
22334
22335    /**
22336     * function used as an initial value for watchers.
22337     * because it's unique we can easily tell it apart from other values
22338     */
22339    function initWatchVal() {}
22340
22341    function flushApplyAsync() {
vendor: 5,358 bytes, lines 22342-22484
22342      while (applyAsyncQueue.length) {
22343        try {
22344          applyAsyncQueue.shift()();
22345        } catch (e) {
22346          $exceptionHandler(e);
22347        }
22348      }
22349      applyAsyncId = null;
22350    }
22351
22352    function scheduleApplyAsync() {
22353      if (applyAsyncId === null) {
22354        applyAsyncId = $browser.defer(function() {
22355          $rootScope.$apply(flushApplyAsync);
22356        });
22357      }
22358    }
22359  }];
22360}
22361
22362/**
22363 * @ngdoc service
22364 * @name $rootElement
22365 *
22366 * @description
22367 * The root element of Angular application. This is either the element where {@link
22368 * ng.directive:ngApp ngApp} was declared or the element passed into
22369 * {@link angular.bootstrap}. The element represents the root element of application. It is also the
22370 * location where the application's {@link auto.$injector $injector} service gets
22371 * published, and can be retrieved using `$rootElement.injector()`.
22372 */
22373
22374
22375// the implementation is in angular.bootstrap
22376
22377/**
22378 * @description
22379 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
22380 */
22381function $$SanitizeUriProvider() {
22382  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
22383    imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
22384
22385  /**
22386   * @description
22387   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
22388   * urls during a[href] sanitization.
22389   *
22390   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
22391   *
22392   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
22393   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
22394   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
22395   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
22396   *
22397   * @param {RegExp=} regexp New regexp to whitelist urls with.
22398   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
22399   *    chaining otherwise.
22400   */
22401  this.aHrefSanitizationWhitelist = function(regexp) {
22402    if (isDefined(regexp)) {
22403      aHrefSanitizationWhitelist = regexp;
22404      return this;
22405    }
22406    return aHrefSanitizationWhitelist;
22407  };
22408
22409
22410  /**
22411   * @description
22412   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
22413   * urls during img[src] sanitization.
22414   *
22415   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
22416   *
22417   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
22418   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
22419   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
22420   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
22421   *
22422   * @param {RegExp=} regexp New regexp to whitelist urls with.
22423   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
22424   *    chaining otherwise.
22425   */
22426  this.imgSrcSanitizationWhitelist = function(regexp) {
22427    if (isDefined(regexp)) {
22428      imgSrcSanitizationWhitelist = regexp;
22429      return this;
22430    }
22431    return imgSrcSanitizationWhitelist;
22432  };
22433
22434  this.$get = function() {
22435    return function sanitizeUri(uri, isImage) {
22436      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
22437      var normalizedVal;
22438      normalizedVal = urlResolve(uri).href;
22439      if (normalizedVal !== '' && !normalizedVal.match(regex)) {
22440        return 'unsafe:' + normalizedVal;
22441      }
22442      return uri;
22443    };
22444  };
22445}
22446
22447/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22448 *     Any commits to this file should be reviewed with security in mind.  *
22449 *   Changes to this file can potentially create security vulnerabilities. *
22450 *          An approval from 2 Core members with history of modifying      *
22451 *                         this file is required.                          *
22452 *                                                                         *
22453 *  Does the change somehow allow for arbitrary javascript to be executed? *
22454 *    Or allows for someone to change the prototype of built-in objects?   *
22455 *     Or gives undesired access to variables likes document or window?    *
22456 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22457
22458var $sceMinErr = minErr('$sce');
22459
22460var SCE_CONTEXTS = {
22461  HTML: 'html',
22462  CSS: 'css',
22463  URL: 'url',
22464  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
22465  // url.  (e.g. ng-include, script src, templateUrl)
22466  RESOURCE_URL: 'resourceUrl',
22467  JS: 'js'
22468};
22469
22470// Helper functions follow.
22471
22472function adjustMatcher(matcher) {
22473  if (matcher === 'self') {
22474    return matcher;
22475  } else if (isString(matcher)) {
22476    // Strings match exactly except for 2 wildcards - '*' and '**'.
22477    // '*' matches any character except those from the set ':/.?&'.
22478    // '**' matches any character (like .* in a RegExp).
22479    // More than 2 *'s raises an error as it's ill defined.
22480    if (matcher.indexOf('***') > -1) {
22481      throw $sceMinErr('iwcard',
22482          'Illegal sequence *** in string matcher.  String: {0}', matcher);
22483    }
22484    matcher = escapeForRegexp(matcher).
22485                  replace('\\*\\*', '.*').
22486                  replace('\\*', '[^:/.?&;]*');
22487    return new RegExp('^' + matcher + '$');
22488  } else if (isRegExp(matcher)) {
22489    // The only other type of matcher allowed is a Regexp.
22490    // Match entire URL / disallow partial matches.
22491    // Flags are reset (i.e. no global, ignoreCase or multiline)
22492    return new RegExp('^' + matcher.source + '$');
22493  } else {
22494    throw $sceMinErr('imatcher',
22495        'Matchers may only be "self", string patterns or RegExp objects');
22496  }
22497}
22498
22499
22500function adjustMatchers(matchers) {
22501  var adjustedMatchers = [];
22502  if (isDefined(matchers)) {
22503    forEach(matchers, function(matcher) {
22504      adjustedMatchers.push(adjustMatcher(matcher));
22505    });
22506  }
22507  return adjustedMatchers;
22508}
22509
22510
22511/**
22512 * @ngdoc service
22513 * @name $sceDelegate
22514 * @kind function
22515 *
22516 * @description
22517 *
22518 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
22519 * Contextual Escaping (SCE)} services to AngularJS.
22520 *
22521 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
22522 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
22523 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
22524 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
22525 * work because `$sce` delegates to `$sceDelegate` for these operations.
22526 *
22527 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
22528 *
22529 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
22530 * can override it completely to change the behavior of `$sce`, the common case would
22531 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
22532 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
22533 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
22534 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
22535 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
22536 */
22537
22538/**
22539 * @ngdoc provider
22540 * @name $sceDelegateProvider
22541 * @description
22542 *
22543 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
22544 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
22545 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
22546 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
22547 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
22548 *
22549 * For the general details about this service in Angular, read the main page for {@link ng.$sce
22550 * Strict Contextual Escaping (SCE)}.
22551 *
22552 * **Example**:  Consider the following case. <a name="example"></a>
22553 *
22554 * - your app is hosted at url `http://myapp.example.com/`
22555 * - but some of your templates are hosted on other domains you control such as
22556 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
22557 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
22558 *
22559 * Here is what a secure configuration for this scenario might look like:
22560 *
22561 * ```
22562 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
22563 *    $sceDelegateProvider.resourceUrlWhitelist([
22564 *      // Allow same origin resource loads.
22565 *      'self',
22566 *      // Allow loading from our assets domain.  Notice the difference between * and **.
22567 *      'http://srv*.assets.example.com/**'
22568 *    ]);
22569 *
22570 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
22571 *    $sceDelegateProvider.resourceUrlBlacklist([
22572 *      'http://myapp.example.com/clickThru**'
22573 *    ]);
22574 *  });
22575 * ```
22576 */
22577
22578function $SceDelegateProvider() {
22579  this.SCE_CONTEXTS = SCE_CONTEXTS;
22580
22581  // Resource URLs can also be trusted by policy.
22582  var resourceUrlWhitelist = ['self'],
22583      resourceUrlBlacklist = [];
22584
22585  /**
22586   * @ngdoc method
22587   * @name $sceDelegateProvider#resourceUrlWhitelist
22588   * @kind function
22589   *
22590   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
22591   *    provided.  This must be an array or null.  A snapshot of this array is used so further
22592   *    changes to the array are ignored.
22593   *
22594   *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
22595   *    allowed in this array.
22596   *
22597   *    <div class="alert alert-warning">
22598   *    **Note:** an empty whitelist array will block all URLs!
22599   *    </div>
22600   *
22601   * @return {Array} the currently set whitelist array.
22602   *
22603   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
22604   * same origin resource requests.
22605   *
22606   * @description
22607   * Sets/Gets the whitelist of trusted resource URLs.
22608   */
22609  this.resourceUrlWhitelist = function(value) {
22610    if (arguments.length) {
22611      resourceUrlWhitelist = adjustMatchers(value);
22612    }
22613    return resourceUrlWhitelist;
22614  };
22615
22616  /**
22617   * @ngdoc method
22618   * @name $sceDelegateProvider#resourceUrlBlacklist
22619   * @kind function
22620   *
22621   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
22622   *    provided.  This must be an array or null.  A snapshot of this array is used so further
22623   *    changes to the array are ignored.
22624   *
22625   *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
22626   *    allowed in this array.
22627   *
22628   *    The typical usage for the blacklist is to **block
22629   *    [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
22630   *    these would otherwise be trusted but actually return content from the redirected domain.
22631   *
22632   *    Finally, **the blacklist overrides the whitelist** and has the final say.
22633   *
22634   * @return {Array} the currently set blacklist array.
22635   *
22636   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
22637   * is no blacklist.)
22638   *
22639   * @description
22640   * Sets/Gets the blacklist of trusted resource URLs.
22641   */
22642
22643  this.resourceUrlBlacklist = function(value) {
22644    if (arguments.length) {
22645      resourceUrlBlacklist = adjustMatchers(value);
22646    }
22647    return resourceUrlBlacklist;
22648  };
22649
22650  this.$get = ['$injector', function($injector) {
22651
22652    var htmlSanitizer = function htmlSanitizer(html) {
22653      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
22654    };
22655
22656    if ($injector.has('$sanitize')) {
22657      htmlSanitizer = $injector.get('$sanitize');
22658    }
22659
22660
22661    function matchUrl(matcher, parsedUrl) {
22662      if (matcher === 'self') {
22663        return urlIsSameOrigin(parsedUrl);
22664      } else {
22665        // definitely a regex.  See adjustMatchers()
22666        return !!matcher.exec(parsedUrl.href);
22667      }
22668    }
22669
22670    function isResourceUrlAllowedByPolicy(url) {
22671      var parsedUrl = urlResolve(url.toString());
22672      var i, n, allowed = false;
22673      // Ensure that at least one item from the whitelist allows this url.
22674      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
22675        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
22676          allowed = true;
22677          break;
22678        }
22679      }
22680      if (allowed) {
22681        // Ensure that no item from the blacklist blocked this url.
22682        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
22683          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
22684            allowed = false;
22685            break;
22686          }
22687        }
22688      }
22689      return allowed;
22690    }
22691
22692    function generateHolderType(Base) {
22693      var holderType = function TrustedValueHolderType(trustedValue) {
22694        this.$$unwrapTrustedValue = function() {
22695          return trustedValue;
22696        };
22697      };
22698      if (Base) {
22699        holderType.prototype = new Base();
22700      }
22701      holderType.prototype.valueOf = function sceValueOf() {
22702        return this.$$unwrapTrustedValue();
22703      };
22704      holderType.prototype.toString = function sceToString() {
22705        return this.$$unwrapTrustedValue().toString();
22706      };
22707      return holderType;
22708    }
22709
22710    var trustedValueHolderBase = generateHolderType(),
22711        byType = {};
22712
22713    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
22714    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
22715    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
22716    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
22717    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
22718
22719    /**
22720     * @ngdoc method
22721     * @name $sceDelegate#trustAs
22722     *
22723     * @description
22724     * Returns an object that is trusted by angular for use in specified strict
22725     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
22726     * attribute interpolation, any dom event binding attribute interpolation
22727     * such as for onclick,  etc.) that uses the provided value.
22728     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
22729     *
22730     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
22731     *   resourceUrl, html, js and css.
22732     * @param {*} value The value that that should be considered trusted/safe.
22733     * @returns {*} A value that can be used to stand in for the provided `value` in places
22734     * where Angular expects a $sce.trustAs() return value.
22735     */
22736    function trustAs(type, trustedValue) {
22737      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
22738      if (!Constructor) {
22739        throw $sceMinErr('icontext',
22740            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
22741            type, trustedValue);
22742      }
22743      if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
22744        return trustedValue;
22745      }
22746      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
22747      // mutable objects, we ensure here that the value passed in is actually a string.
22748      if (typeof trustedValue !== 'string') {
22749        throw $sceMinErr('itype',
22750            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
22751            type);
22752      }
22753      return new Constructor(trustedValue);
22754    }
22755
22756    /**
22757     * @ngdoc method
22758     * @name $sceDelegate#valueOf
22759     *
22760     * @description
22761     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
22762     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
22763     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
22764     *
22765     * If the passed parameter is not a value that had been returned by {@link
22766     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
22767     *
22768     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
22769     *      call or anything else.
22770     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
22771     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
22772     *     `value` unchanged.
22773     */
22774    function valueOf(maybeTrusted) {
22775      if (maybeTrusted instanceof trustedValueHolderBase) {
22776        return maybeTrusted.$$unwrapTrustedValue();
22777      } else {
22778        return maybeTrusted;
22779      }
22780    }
22781
22782    /**
22783     * @ngdoc method
22784     * @name $sceDelegate#getTrusted
22785     *
22786     * @description
22787     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
22788     * returns the originally supplied value if the queried context type is a supertype of the
22789     * created type.  If this condition isn't satisfied, throws an exception.
22790     *
22791     * <div class="alert alert-danger">
22792     * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
22793     * (XSS) vulnerability in your application.
22794     * </div>
22795     *
22796     * @param {string} type The kind of context in which this value is to be used.
22797     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
22798     *     `$sceDelegate.trustAs`} call.
22799     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
22800     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
22801     */
22802    function getTrusted(type, maybeTrusted) {
22803      if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
22804        return maybeTrusted;
22805      }
22806      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
22807      if (constructor && maybeTrusted instanceof constructor) {
22808        return maybeTrusted.$$unwrapTrustedValue();
22809      }
22810      // If we get here, then we may only take one of two actions.
22811      // 1. sanitize the value for the requested type, or
22812      // 2. throw an exception.
22813      if (type === SCE_CONTEXTS.RESOURCE_URL) {
22814        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
22815          return maybeTrusted;
22816        } else {
22817          throw $sceMinErr('insecurl',
22818              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
22819              maybeTrusted.toString());
22820        }
22821      } else if (type === SCE_CONTEXTS.HTML) {
22822        return htmlSanitizer(maybeTrusted);
22823      }
22824      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
22825    }
22826
22827    return { trustAs: trustAs,
22828             getTrusted: getTrusted,
22829             valueOf: valueOf };
22830  }];
22831}
22832
22833
22834/**
22835 * @ngdoc provider
22836 * @name $sceProvider
22837 * @description
22838 *
22839 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
22840 * -   enable/disable Strict Contextual Escaping (SCE) in a module
22841 * -   override the default implementation with a custom delegate
22842 *
22843 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
22844 */
22845
22846/* jshint maxlen: false*/
22847
22848/**
22849 * @ngdoc service
22850 * @name $sce
22851 * @kind function
22852 *
22853 * @description
22854 *
22855 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
22856 *
22857 * # Strict Contextual Escaping
22858 *
22859 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
22860 * contexts to result in a value that is marked as safe to use for that context.  One example of
22861 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
22862 * to these contexts as privileged or SCE contexts.
22863 *
22864 * As of version 1.2, Angular ships with SCE enabled by default.
22865 *
22866 * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
22867 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
22868 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
22869 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
22870 * to the top of your HTML document.
22871 *
22872 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
22873 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
22874 *
22875 * Here's an example of a binding in a privileged context:
22876 *
22877 * ```
22878 * <input ng-model="userHtml" aria-label="User input">
22879 * <div ng-bind-html="userHtml"></div>
22880 * ```
22881 *
22882 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
22883 * disabled, this application allows the user to render arbitrary HTML into the DIV.
22884 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
22885 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
22886 * security vulnerabilities.)
22887 *
22888 * For the case of HTML, you might use a library, either on the client side, or on the server side,
22889 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
22890 *
22891 * How would you ensure that every place that used these types of bindings was bound to a value that
22892 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
22893 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
22894 * properties/fields and forgot to update the binding to the sanitized value?
22895 *
22896 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
22897 * determine that something explicitly says it's safe to use a value for binding in that
22898 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
22899 * for those values that you can easily tell are safe - because they were received from your server,
22900 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
22901 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
22902 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
22903 *
22904 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
22905 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
22906 * obtain values that will be accepted by SCE / privileged contexts.
22907 *
22908 *
22909 * ## How does it work?
22910 *
22911 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
22912 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
22913 * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
22914 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
22915 *
22916 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
22917 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
22918 * simplified):
22919 *
22920 * ```
22921 * var ngBindHtmlDirective = ['$sce', function($sce) {
22922 *   return function(scope, element, attr) {
22923 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
22924 *       element.html(value || '');
22925 *     });
22926 *   };
22927 * }];
22928 * ```
22929 *
22930 * ## Impact on loading templates
22931 *
22932 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
22933 * `templateUrl`'s specified by {@link guide/directive directives}.
22934 *
22935 * By default, Angular only loads templates from the same domain and protocol as the application
22936 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
22937 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
22938 * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
22939 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
22940 *
22941 * *Please note*:
22942 * The browser's
22943 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
22944 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
22945 * policy apply in addition to this and may further restrict whether the template is successfully
22946 * loaded.  This means that without the right CORS policy, loading templates from a different domain
22947 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
22948 * browsers.
22949 *
22950 * ## This feels like too much overhead
22951 *
22952 * It's important to remember that SCE only applies to interpolation expressions.
22953 *
22954 * If your expressions are constant literals, they're automatically trusted and you don't need to
22955 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
22956 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
22957 *
22958 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
22959 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
22960 *
22961 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
22962 * templates in `ng-include` from your application's domain without having to even know about SCE.
22963 * It blocks loading templates from other domains or loading templates over http from an https
22964 * served document.  You can change these by setting your own custom {@link
22965 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
22966 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
22967 *
22968 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
22969 * application that's secure and can be audited to verify that with much more ease than bolting
22970 * security onto an application later.
22971 *
22972 * <a name="contexts"></a>
22973 * ## What trusted context types are supported?
22974 *
22975 * | Context             | Notes          |
22976 * |---------------------|----------------|
22977 * | `$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. |
22978 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
22979 * | `$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. |
22980 * | `$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. |
22981 * | `$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. |
22982 *
22983 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
22984 *
22985 *  Each element in these arrays must be one of the following:
22986 *
22987 *  - **'self'**
22988 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
22989 *      domain** as the application document using the **same protocol**.
22990 *  - **String** (except the special value `'self'`)
22991 *    - The string is matched against the full *normalized / absolute URL* of the resource
22992 *      being tested (substring matches are not good enough.)
22993 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
22994 *      match themselves.
22995 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
22996 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
22997 *      in a whitelist.
22998 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
22999 *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
23000 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
23001 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
23002 *      http://foo.example.com/templates/**).
23003 *  - **RegExp** (*see caveat below*)
23004 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
23005 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
23006 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
23007 *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
23008 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
23009 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
23010 *      is highly recommended to use the string patterns and only fall back to regular expressions
23011 *      as a last resort.
23012 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
23013 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
23014 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
23015 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
23016 *    - If you are generating your JavaScript from some other templating engine (not
23017 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
23018 *      remember to escape your regular expression (and be aware that you might need more than
23019 *      one level of escaping depending on your templating engine and the way you interpolated
23020 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
23021 *      enough before coding your own.  E.g. Ruby has
23022 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
23023 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
23024 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
23025 *      Closure library's [goog.string.regExpEscape(s)](
23026 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
23027 *
23028 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
23029 *
23030 * ## Show me an example using SCE.
23031 *
23032 * <example module="mySceApp" deps="angular-sanitize.js">
23033 * <file name="index.html">
23034 *   <div ng-controller="AppController as myCtrl">
23035 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
23036 *     <b>User comments</b><br>
23037 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
23038 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
23039 *     exploit.
23040 *     <div class="well">
23041 *       <div ng-repeat="userComment in myCtrl.userComments">
23042 *         <b>{{userComment.name}}</b>:
23043 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
23044 *         <br>
23045 *       </div>
23046 *     </div>
23047 *   </div>
23048 * </file>
23049 *
23050 * <file name="script.js">
23051 *   angular.module('mySceApp', ['ngSanitize'])
23052 *     .controller('AppController', ['$http', '$templateCache', '$sce',
23053 *       function($http, $templateCache, $sce) {
23054 *         var self = this;
23055 *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
23056 *           self.userComments = userComments;
23057 *         });
23058 *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
23059 *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
23060 *             'sanitization.&quot;">Hover over this text.</span>');
23061 *       }]);
23062 * </file>
23063 *
23064 * <file name="test_data.json">
23065 * [
23066 *   { "name": "Alice",
23067 *     "htmlComment":
23068 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
23069 *   },
23070 *   { "name": "Bob",
23071 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
23072 *   }
23073 * ]
23074 * </file>
23075 *
23076 * <file name="protractor.js" type="protractor">
23077 *   describe('SCE doc demo', function() {
23078 *     it('should sanitize untrusted values', function() {
23079 *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
23080 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
23081 *     });
23082 *
23083 *     it('should NOT sanitize explicitly trusted values', function() {
23084 *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
23085 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
23086 *           'sanitization.&quot;">Hover over this text.</span>');
23087 *     });
23088 *   });
23089 * </file>
23090 * </example>
23091 *
23092 *
23093 *
23094 * ## Can I disable SCE completely?
23095 *
23096 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
23097 * for little coding overhead.  It will be much harder to take an SCE disabled application and
23098 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
23099 * for cases where you have a lot of existing code that was written before SCE was introduced and
23100 * you're migrating them a module at a time.
23101 *
23102 * That said, here's how you can completely disable SCE:
23103 *
23104 * ```
23105 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
23106 *   // Completely disable SCE.  For demonstration purposes only!
23107 *   // Do not use in new projects.
23108 *   $sceProvider.enabled(false);
23109 * });
23110 * ```
23111 *
23112 */
23113/* jshint maxlen: 100 */
23114
23115function $SceProvider() {
23116  var enabled = true;
23117
23118  /**
23119   * @ngdoc method
23120   * @name $sceProvider#enabled
23121   * @kind function
23122   *
23123   * @param {boolean=} value If provided, then enables/disables SCE.
23124   * @return {boolean} true if SCE is enabled, false otherwise.
23125   *
23126   * @description
23127   * Enables/disables SCE and returns the current value.
23128   */
23129  this.enabled = function(value) {
23130    if (arguments.length) {
23131      enabled = !!value;
23132    }
23133    return enabled;
23134  };
23135
23136
23137  /* Design notes on the default implementation for SCE.
23138   *
23139   * The API contract for the SCE delegate
23140   * -------------------------------------
23141   * The SCE delegate object must provide the following 3 methods:
23142   *
23143   * - trustAs(contextEnum, value)
23144   *     This method is used to tell the SCE service that the provided value is OK to use in the
23145   *     contexts specified by contextEnum.  It must return an object that will be accepted by
23146   *     getTrusted() for a compatible contextEnum and return this value.
23147   *
23148   * - valueOf(value)
23149   *     For values that were not produced by trustAs(), return them as is.  For values that were
23150   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
23151   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
23152   *     such a value.
23153   *
23154   * - getTrusted(contextEnum, value)
23155   *     This function should return the a value that is safe to use in the context specified by
23156   *     contextEnum or throw and exception otherwise.
23157   *
23158   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
23159   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
23160   * instance, an implementation could maintain a registry of all trusted objects by context.  In
23161   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
23162   * return the same object passed in if it was found in the registry under a compatible context or
23163   * throw an exception otherwise.  An implementation might only wrap values some of the time based
23164   * on some criteria.  getTrusted() might return a value and not throw an exception for special
23165   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
23166   *
23167   *
23168   * A note on the inheritance model for SCE contexts
23169   * ------------------------------------------------
23170   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
23171   * is purely an implementation details.
23172   *
23173   * The contract is simply this:
23174   *
23175   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
23176   *     will also succeed.
23177   *
23178   * Inheritance happens to capture this in a natural way.  In some future, we
23179   * may not use inheritance anymore.  That is OK because no code outside of
23180   * sce.js and sceSpecs.js would need to be aware of this detail.
23181   */
23182
23183  this.$get = ['$parse', '$sceDelegate', function(
23184                $parse,   $sceDelegate) {
23185    // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
23186    // the "expression(javascript expression)" syntax which is insecure.
23187    if (enabled && msie < 8) {
23188      throw $sceMinErr('iequirks',
23189        'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
23190        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
23191        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
23192    }
23193
23194    var sce = shallowCopy(SCE_CONTEXTS);
23195
23196    /**
23197     * @ngdoc method
23198     * @name $sce#isEnabled
23199     * @kind function
23200     *
23201     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
23202     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
23203     *
23204     * @description
23205     * Returns a boolean indicating if SCE is enabled.
23206     */
23207    sce.isEnabled = function() {
23208      return enabled;
23209    };
23210    sce.trustAs = $sceDelegate.trustAs;
23211    sce.getTrusted = $sceDelegate.getTrusted;
23212    sce.valueOf = $sceDelegate.valueOf;
23213
23214    if (!enabled) {
23215      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
23216      sce.valueOf = identity;
23217    }
23218
23219    /**
23220     * @ngdoc method
23221     * @name $sce#parseAs
23222     *
23223     * @description
23224     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
23225     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
23226     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
23227     * *result*)}
23228     *
23229     * @param {string} type The kind of SCE context in which this result will be used.
23230     * @param {string} expression String expression to compile.
23231     * @returns {function(context, locals)} a function which represents the compiled expression:
23232     *
23233     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23234     *      are evaluated against (typically a scope object).
23235     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23236     *      `context`.
23237     */
23238    sce.parseAs = function sceParseAs(type, expr) {
23239      var parsed = $parse(expr);
23240      if (parsed.literal && parsed.constant) {
23241        return parsed;
23242      } else {
23243        return $parse(expr, function(value) {
23244          return sce.getTrusted(type, value);
23245        });
23246      }
23247    };
23248
23249    /**
23250     * @ngdoc method
23251     * @name $sce#trustAs
23252     *
23253     * @description
23254     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
23255     * returns an object that is trusted by angular for use in specified strict contextual
23256     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
23257     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
23258     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
23259     * escaping.
23260     *
23261     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
23262     *   resourceUrl, html, js and css.
23263     * @param {*} value The value that that should be considered trusted/safe.
23264     * @returns {*} A value that can be used to stand in for the provided `value` in places
23265     * where Angular expects a $sce.trustAs() return value.
23266     */
23267
23268    /**
23269     * @ngdoc method
23270     * @name $sce#trustAsHtml
23271     *
23272     * @description
23273     * Shorthand method.  `$sce.trustAsHtml(value)` →
23274     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
23275     *
23276     * @param {*} value The value to trustAs.
23277     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
23278     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
23279     *     only accept expressions that are either literal constants or are the
23280     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
23281     */
23282
23283    /**
23284     * @ngdoc method
23285     * @name $sce#trustAsUrl
23286     *
23287     * @description
23288     * Shorthand method.  `$sce.trustAsUrl(value)` →
23289     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
23290     *
23291     * @param {*} value The value to trustAs.
23292     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
23293     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
23294     *     only accept expressions that are either literal constants or are the
23295     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
23296     */
23297
23298    /**
23299     * @ngdoc method
23300     * @name $sce#trustAsResourceUrl
23301     *
23302     * @description
23303     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
23304     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
23305     *
23306     * @param {*} value The value to trustAs.
23307     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
23308     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
23309     *     only accept expressions that are either literal constants or are the return
23310     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
23311     */
23312
23313    /**
23314     * @ngdoc method
23315     * @name $sce#trustAsJs
23316     *
23317     * @description
23318     * Shorthand method.  `$sce.trustAsJs(value)` →
23319     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
23320     *
23321     * @param {*} value The value to trustAs.
23322     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
23323     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
23324     *     only accept expressions that are either literal constants or are the
23325     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
23326     */
23327
23328    /**
23329     * @ngdoc method
23330     * @name $sce#getTrusted
23331     *
23332     * @description
23333     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
23334     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
23335     * originally supplied value if the queried context type is a supertype of the created type.
23336     * If this condition isn't satisfied, throws an exception.
23337     *
23338     * @param {string} type The kind of context in which this value is to be used.
23339     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
23340     *                         call.
23341     * @returns {*} The value the was originally provided to
23342     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
23343     *              Otherwise, throws an exception.
23344     */
23345
23346    /**
23347     * @ngdoc method
23348     * @name $sce#getTrustedHtml
23349     *
23350     * @description
23351     * Shorthand method.  `$sce.getTrustedHtml(value)` →
23352     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
23353     *
23354     * @param {*} value The value to pass to `$sce.getTrusted`.
23355     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
23356     */
23357
23358    /**
23359     * @ngdoc method
23360     * @name $sce#getTrustedCss
23361     *
23362     * @description
23363     * Shorthand method.  `$sce.getTrustedCss(value)` →
23364     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
23365     *
23366     * @param {*} value The value to pass to `$sce.getTrusted`.
23367     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
23368     */
23369
23370    /**
23371     * @ngdoc method
23372     * @name $sce#getTrustedUrl
23373     *
23374     * @description
23375     * Shorthand method.  `$sce.getTrustedUrl(value)` →
23376     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
23377     *
23378     * @param {*} value The value to pass to `$sce.getTrusted`.
23379     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
23380     */
23381
23382    /**
23383     * @ngdoc method
23384     * @name $sce#getTrustedResourceUrl
23385     *
23386     * @description
23387     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
23388     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
23389     *
23390     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
23391     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
23392     */
23393
23394    /**
23395     * @ngdoc method
23396     * @name $sce#getTrustedJs
23397     *
23398     * @description
23399     * Shorthand method.  `$sce.getTrustedJs(value)` →
23400     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
23401     *
23402     * @param {*} value The value to pass to `$sce.getTrusted`.
23403     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
23404     */
23405
23406    /**
23407     * @ngdoc method
23408     * @name $sce#parseAsHtml
23409     *
23410     * @description
23411     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
23412     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
23413     *
23414     * @param {string} expression String expression to compile.
23415     * @returns {function(context, locals)} a function which represents the compiled expression:
23416     *
23417     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23418     *      are evaluated against (typically a scope object).
23419     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23420     *      `context`.
23421     */
23422
23423    /**
23424     * @ngdoc method
23425     * @name $sce#parseAsCss
23426     *
23427     * @description
23428     * Shorthand method.  `$sce.parseAsCss(value)` →
23429     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
23430     *
23431     * @param {string} expression String expression to compile.
23432     * @returns {function(context, locals)} a function which represents the compiled expression:
23433     *
23434     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23435     *      are evaluated against (typically a scope object).
23436     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23437     *      `context`.
23438     */
23439
23440    /**
23441     * @ngdoc method
23442     * @name $sce#parseAsUrl
23443     *
23444     * @description
23445     * Shorthand method.  `$sce.parseAsUrl(value)` →
23446     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
23447     *
23448     * @param {string} expression String expression to compile.
23449     * @returns {function(context, locals)} a function which represents the compiled expression:
23450     *
23451     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23452     *      are evaluated against (typically a scope object).
23453     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23454     *      `context`.
23455     */
23456
23457    /**
23458     * @ngdoc method
23459     * @name $sce#parseAsResourceUrl
23460     *
23461     * @description
23462     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
23463     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
23464     *
23465     * @param {string} expression String expression to compile.
23466     * @returns {function(context, locals)} a function which represents the compiled expression:
23467     *
23468     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23469     *      are evaluated against (typically a scope object).
23470     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23471     *      `context`.
23472     */
23473
23474    /**
23475     * @ngdoc method
23476     * @name $sce#parseAsJs
23477     *
23478     * @description
23479     * Shorthand method.  `$sce.parseAsJs(value)` →
23480     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
23481     *
23482     * @param {string} expression String expression to compile.
23483     * @returns {function(context, locals)} a function which represents the compiled expression:
23484     *
23485     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23486     *      are evaluated against (typically a scope object).
23487     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23488     *      `context`.
23489     */
23490
23491    // Shorthand delegations.
23492    var parse = sce.parseAs,
23493        getTrusted = sce.getTrusted,
23494        trustAs = sce.trustAs;
23495
23496    forEach(SCE_CONTEXTS, function(enumValue, name) {
23497      var lName = lowercase(name);
23498      sce[camelCase("parse_as_" + lName)] = function(expr) {
23499        return parse(enumValue, expr);
23500      };
23501      sce[camelCase("get_trusted_" + lName)] = function(value) {
23502        return getTrusted(enumValue, value);
23503      };
23504      sce[camelCase("trust_as_" + lName)] = function(value) {
23505        return trustAs(enumValue, value);
23506      };
23507    });
23508
23509    return sce;
23510  }];
23511}
23512
23513/**
23514 * !!! This is an undocumented "private" service !!!
23515 *
23516 * @name $sniffer
23517 * @requires $window
23518 * @requires $document
23519 *
23520 * @property {boolean} history Does the browser support html5 history api ?
23521 * @property {boolean} transitions Does the browser support CSS transition events ?
23522 * @property {boolean} animations Does the browser support CSS animation events ?
23523 *
23524 * @description
23525 * This is very simple implementation of testing browser's features.
23526 */
23527function $SnifferProvider() {
23528  this.$get = ['$window', '$document', function($window, $document) {
23529    var eventSupport = {},
23530        android =
23531          toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
23532        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
23533        document = $document[0] || {},
23534        vendorPrefix,
23535        vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
23536        bodyStyle = document.body && document.body.style,
23537        transitions = false,
23538        animations = false,
23539        match;
23540
23541    if (bodyStyle) {
23542      for (var prop in bodyStyle) {
23543        if (match = vendorRegex.exec(prop)) {
23544          vendorPrefix = match[0];
23545          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
23546          break;
23547        }
23548      }
23549
23550      if (!vendorPrefix) {
23551        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
23552      }
23553
23554      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
23555      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
23556
23557      if (android && (!transitions ||  !animations)) {
23558        transitions = isString(bodyStyle.webkitTransition);
23559        animations = isString(bodyStyle.webkitAnimation);
23560      }
23561    }
23562
23563
23564    return {
23565      // Android has history.pushState, but it does not update location correctly
23566      // so let's not use the history API at all.
23567      // http://code.google.com/p/android/issues/detail?id=17471
23568      // https://github.com/angular/angular.js/issues/904
23569
23570      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
23571      // so let's not use the history API also
23572      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
23573      // jshint -W018
23574      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
23575      // jshint +W018
23576      hasEvent: function(event) {
23577        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
23578        // it. In particular the event is not fired when backspace or delete key are pressed or
23579        // when cut operation is performed.
23580        // IE10+ implements 'input' event but it erroneously fires under various situations,
23581        // e.g. when placeholder changes, or a form is focused.
23582        if (event === 'input' && msie <= 11) return false;
23583
23584        if (isUndefined(eventSupport[event])) {
23585          var divElm = document.createElement('div');
23586          eventSupport[event] = 'on' + event in divElm;
23587        }
23588
23589        return eventSupport[event];
23590      },
23591      csp: csp(),
23592      vendorPrefix: vendorPrefix,
23593      transitions: transitions,
23594      animations: animations,
23595      android: android
23596    };
23597  }];
23598}
23599
23600var $compileMinErr = minErr('$compile');
23601
23602/**
23603 * @ngdoc provider
23604 * @name $templateRequestProvider
23605 * @description
23606 * Used to configure the options passed to the {@link $http} service when making a template request.
23607 *
23608 * For example, it can be used for specifying the "Accept" header that is sent to the server, when
23609 * requesting a template.
23610 */
23611function $TemplateRequestProvider() {
23612
23613  var httpOptions;
23614
23615  /**
23616   * @ngdoc method
23617   * @name $templateRequestProvider#httpOptions
23618   * @description
23619   * The options to be passed to the {@link $http} service when making the request.
23620   * You can use this to override options such as the "Accept" header for template requests.
23621   *
23622   * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
23623   * options if not overridden here.
23624   *
23625   * @param {string=} value new value for the {@link $http} options.
23626   * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
23627   */
23628  this.httpOptions = function(val) {
23629    if (val) {
23630      httpOptions = val;
23631      return this;
23632    }
23633    return httpOptions;
23634  };
23635
23636  /**
23637   * @ngdoc service
23638   * @name $templateRequest
23639   *
23640   * @description
23641   * The `$templateRequest` service runs security checks then downloads the provided template using
23642   * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
23643   * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
23644   * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
23645   * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
23646   * when `tpl` is of type string and `$templateCache` has the matching entry.
23647   *
23648   * If you want to pass custom options to the `$http` service, such as setting the Accept header you
23649   * can configure this via {@link $templateRequestProvider#httpOptions}.
23650   *
23651   * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
23652   * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
23653   *
23654   * @return {Promise} a promise for the HTTP response data of the given URL.
23655   *
23656   * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
23657   */
23658  this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
23659
23660    function handleRequestFn(tpl, ignoreRequestError) {
23661      handleRequestFn.totalPendingRequests++;
23662
23663      // We consider the template cache holds only trusted templates, so
23664      // there's no need to go through whitelisting again for keys that already
23665      // are included in there. This also makes Angular accept any script
23666      // directive, no matter its name. However, we still need to unwrap trusted
23667      // types.
23668      if (!isString(tpl) || !$templateCache.get(tpl)) {
23669        tpl = $sce.getTrustedResourceUrl(tpl);
23670      }
23671
23672      var transformResponse = $http.defaults && $http.defaults.transformResponse;
23673
23674      if (isArray(transformResponse)) {
23675        transformResponse = transformResponse.filter(function(transformer) {
23676          return transformer !== defaultHttpResponseTransform;
23677        });
23678      } else if (transformResponse === defaultHttpResponseTransform) {
23679        transformResponse = null;
23680      }
23681
23682      return $http.get(tpl, extend({
23683          cache: $templateCache,
23684          transformResponse: transformResponse
23685        }, httpOptions))
23686        ['finally'](function() {
23687          handleRequestFn.totalPendingRequests--;
23688        })
23689        .then(function(response) {
23690          $templateCache.put(tpl, response.data);
23691          return response.data;
23692        }, handleError);
23693
23694      function handleError(resp) {
23695        if (!ignoreRequestError) {
23696          throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
23697            tpl, resp.status, resp.statusText);
23698        }
23699        return $q.reject(resp);
23700      }
23701    }
23702
23703    handleRequestFn.totalPendingRequests = 0;
23704
23705    return handleRequestFn;
23706  }];
23707}
23708
23709function $$TestabilityProvider() {
23710  this.$get = ['$rootScope', '$browser', '$location',
23711       function($rootScope,   $browser,   $location) {
23712
23713    /**
23714     * @name $testability
23715     *
23716     * @description
23717     * The private $$testability service provides a collection of methods for use when debugging
23718     * or by automated test and debugging tools.
23719     */
23720    var testability = {};
23721
23722    /**
23723     * @name $$testability#findBindings
23724     *
23725     * @description
23726     * Returns an array of elements that are bound (via ng-bind or {{}})
23727     * to expressions matching the input.
23728     *
23729     * @param {Element} element The element root to search from.
23730     * @param {string} expression The binding expression to match.
23731     * @param {boolean} opt_exactMatch If true, only returns exact matches
23732     *     for the expression. Filters and whitespace are ignored.
23733     */
23734    testability.findBindings = function(element, expression, opt_exactMatch) {
23735      var bindings = element.getElementsByClassName('ng-binding');
23736      var matches = [];
23737      forEach(bindings, function(binding) {
23738        var dataBinding = angular.element(binding).data('$binding');
23739        if (dataBinding) {
23740          forEach(dataBinding, function(bindingName) {
23741            if (opt_exactMatch) {
23742              var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
23743              if (matcher.test(bindingName)) {
23744                matches.push(binding);
23745              }
23746            } else {
23747              if (bindingName.indexOf(expression) != -1) {
23748                matches.push(binding);
23749              }
23750            }
23751          });
23752        }
23753      });
23754      return matches;
23755    };
23756
23757    /**
23758     * @name $$testability#findModels
23759     *
23760     * @description
23761     * Returns an array of elements that are two-way found via ng-model to
23762     * expressions matching the input.
23763     *
23764     * @param {Element} element The element root to search from.
23765     * @param {string} expression The model expression to match.
23766     * @param {boolean} opt_exactMatch If true, only returns exact matches
23767     *     for the expression.
23768     */
23769    testability.findModels = function(element, expression, opt_exactMatch) {
23770      var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
23771      for (var p = 0; p < prefixes.length; ++p) {
23772        var attributeEquals = opt_exactMatch ? '=' : '*=';
23773        var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
23774        var elements = element.querySelectorAll(selector);
23775        if (elements.length) {
23776          return elements;
23777        }
23778      }
23779    };
23780
23781    /**
23782     * @name $$testability#getLocation
23783     *
23784     * @description
23785     * Shortcut for getting the location in a browser agnostic way. Returns
23786     *     the path, search, and hash. (e.g. /path?a=b#hash)
23787     */
23788    testability.getLocation = function() {
23789      return $location.url();
23790    };
23791
23792    /**
23793     * @name $$testability#setLocation
23794     *
23795     * @description
23796     * Shortcut for navigating to a location without doing a full page reload.
23797     *
23798     * @param {string} url The location url (path, search and hash,
23799     *     e.g. /path?a=b#hash) to go to.
23800     */
23801    testability.setLocation = function(url) {
23802      if (url !== $location.url()) {
23803        $location.url(url);
23804        $rootScope.$digest();
23805      }
23806    };
23807
23808    /**
23809     * @name $$testability#whenStable
23810     *
23811     * @description
23812     * Calls the callback when $timeout and $http requests are completed.
23813     *
23814     * @param {function} callback
23815     */
23816    testability.whenStable = function(callback) {
23817      $browser.notifyWhenNoOutstandingRequests(callback);
23818    };
23819
23820    return testability;
23821  }];
23822}
23823
23824function $TimeoutProvider() {
23825  this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
23826       function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
23827
23828    var deferreds = {};
23829
23830
23831     /**
23832      * @ngdoc service
23833      * @name $timeout
23834      *
23835      * @description
23836      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
23837      * block and delegates any exceptions to
23838      * {@link ng.$exceptionHandler $exceptionHandler} service.
23839      *
23840      * The return value of calling `$timeout` is a promise, which will be resolved when
23841      * the delay has passed and the timeout function, if provided, is executed.
23842      *
23843      * To cancel a timeout request, call `$timeout.cancel(promise)`.
23844      *
23845      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
23846      * synchronously flush the queue of deferred functions.
23847      *
23848      * If you only want a promise that will be resolved after some specified delay
23849      * then you can call `$timeout` without the `fn` function.
23850      *
23851      * @param {function()=} fn A function, whose execution should be delayed.
23852      * @param {number=} [delay=0] Delay in milliseconds.
23853      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
23854      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
23855      * @param {...*=} Pass additional parameters to the executed function.
23856      * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
23857      *   will be resolved with the return value of the `fn` function.
23858      *
23859      */
23860    function timeout(fn, delay, invokeApply) {
23861      if (!isFunction(fn)) {
23862        invokeApply = delay;
23863        delay = fn;
23864        fn = noop;
23865      }
23866
23867      var args = sliceArgs(arguments, 3),
23868          skipApply = (isDefined(invokeApply) && !invokeApply),
23869          deferred = (skipApply ? $$q : $q).defer(),
23870          promise = deferred.promise,
23871          timeoutId;
23872
23873      timeoutId = $browser.defer(function() {
23874        try {
23875          deferred.resolve(fn.apply(null, args));
23876        } catch (e) {
23877          deferred.reject(e);
23878          $exceptionHandler(e);
23879        }
23880        finally {
23881          delete deferreds[promise.$$timeoutId];
23882        }
23883
23884        if (!skipApply) $rootScope.$apply();
23885      }, delay);
23886
23887      promise.$$timeoutId = timeoutId;
23888      deferreds[timeoutId] = deferred;
23889
23890      return promise;
23891    }
23892
23893
23894     /**
23895      * @ngdoc method
23896      * @name $timeout#cancel
23897      *
23898      * @description
23899      * Cancels a task associated with the `promise`. As a result of this, the promise will be
23900      * resolved with a rejection.
23901      *
23902      * @param {Promise=} promise Promise returned by the `$timeout` function.
23903      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
23904      *   canceled.
23905      */
23906    timeout.cancel = function(promise) {
23907      if (promise && promise.$$timeoutId in deferreds) {
23908        deferreds[promise.$$timeoutId].reject('canceled');
23909        delete deferreds[promise.$$timeoutId];
23910        return $browser.defer.cancel(promise.$$timeoutId);
23911      }
23912      return false;
vendor: 5,335 bytes, lines 23913-24034
23913    };
23914
23915    return timeout;
23916  }];
23917}
23918
23919// NOTE:  The usage of window and document instead of $window and $document here is
23920// deliberate.  This service depends on the specific behavior of anchor nodes created by the
23921// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
23922// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
23923// doesn't know about mocked locations and resolves URLs to the real document - which is
23924// exactly the behavior needed here.  There is little value is mocking these out for this
23925// service.
23926var urlParsingNode = document.createElement("a");
23927var originUrl = urlResolve(window.location.href);
23928
23929
23930/**
23931 *
23932 * Implementation Notes for non-IE browsers
23933 * ----------------------------------------
23934 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
23935 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
23936 * URL will be resolved into an absolute URL in the context of the application document.
23937 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
23938 * properties are all populated to reflect the normalized URL.  This approach has wide
23939 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
23940 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
23941 *
23942 * Implementation Notes for IE
23943 * ---------------------------
23944 * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
23945 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
23946 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
23947 * work around that by performing the parsing in a 2nd step by taking a previously normalized
23948 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
23949 * properties such as protocol, hostname, port, etc.
23950 *
23951 * References:
23952 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
23953 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
23954 *   http://url.spec.whatwg.org/#urlutils
23955 *   https://github.com/angular/angular.js/pull/2902
23956 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
23957 *
23958 * @kind function
23959 * @param {string} url The URL to be parsed.
23960 * @description Normalizes and parses a URL.
23961 * @returns {object} Returns the normalized URL as a dictionary.
23962 *
23963 *   | member name   | Description    |
23964 *   |---------------|----------------|
23965 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
23966 *   | protocol      | The protocol including the trailing colon                              |
23967 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
23968 *   | search        | The search params, minus the question mark                             |
23969 *   | hash          | The hash string, minus the hash symbol
23970 *   | hostname      | The hostname
23971 *   | port          | The port, without ":"
23972 *   | pathname      | The pathname, beginning with "/"
23973 *
23974 */
23975function urlResolve(url) {
23976  var href = url;
23977
23978  if (msie) {
23979    // Normalize before parse.  Refer Implementation Notes on why this is
23980    // done in two steps on IE.
23981    urlParsingNode.setAttribute("href", href);
23982    href = urlParsingNode.href;
23983  }
23984
23985  urlParsingNode.setAttribute('href', href);
23986
23987  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
23988  return {
23989    href: urlParsingNode.href,
23990    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
23991    host: urlParsingNode.host,
23992    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
23993    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
23994    hostname: urlParsingNode.hostname,
23995    port: urlParsingNode.port,
23996    pathname: (urlParsingNode.pathname.charAt(0) === '/')
23997      ? urlParsingNode.pathname
23998      : '/' + urlParsingNode.pathname
23999  };
24000}
24001
24002/**
24003 * Parse a request URL and determine whether this is a same-origin request as the application document.
24004 *
24005 * @param {string|object} requestUrl The url of the request as a string that will be resolved
24006 * or a parsed URL object.
24007 * @returns {boolean} Whether the request is for the same origin as the application document.
24008 */
24009function urlIsSameOrigin(requestUrl) {
24010  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
24011  return (parsed.protocol === originUrl.protocol &&
24012          parsed.host === originUrl.host);
24013}
24014
24015/**
24016 * @ngdoc service
24017 * @name $window
24018 *
24019 * @description
24020 * A reference to the browser's `window` object. While `window`
24021 * is globally available in JavaScript, it causes testability problems, because
24022 * it is a global variable. In angular we always refer to it through the
24023 * `$window` service, so it may be overridden, removed or mocked for testing.
24024 *
24025 * Expressions, like the one defined for the `ngClick` directive in the example
24026 * below, are evaluated with respect to the current scope.  Therefore, there is
24027 * no risk of inadvertently coding in a dependency on a global value in such an
24028 * expression.
24029 *
24030 * @example
24031   <example module="windowExample">
24032     <file name="index.html">
24033       <script>
24034         angular.module('windowExample', [])
24035           .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
24036             $scope.greeting = 'Hello, World!';
24037             $scope.doGreeting = function(greeting) {
24038               $window.alert(greeting);
24039             };
24040           }]);
24041       </script>
24042       <div ng-controller="ExampleController">
24043         <input type="text" ng-model="greeting" aria-label="greeting" />
24044         <button ng-click="doGreeting(greeting)">ALERT</button>
24045       </div>
24046     </file>
24047     <file name="protractor.js" type="protractor">
24048      it('should display the greeting in the input box', function() {
24049       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
24050       // If we click the button it will block the test runner
24051       // element(':button').click();
24052      });
24053     </file>
24054   </example>
24055 */
24056function $WindowProvider() {
24057  this.$get = valueFn(window);
24058}
24059
24060/**
24061 * @name $$cookieReader
24062 * @requires $document
24063 *
24064 * @description
24065 * This is a private service for reading cookies used by $http and ngCookies
24066 *
24067 * @return {Object} a key/value map of the current cookies
24068 */
24069function $$CookieReader($document) {
24070  var rawDocument = $document[0] || {};
24071  var lastCookies = {};
24072  var lastCookieString = '';
24073
24074  function safeDecodeURIComponent(str) {
24075    try {
24076      return decodeURIComponent(str);
24077    } catch (e) {
24078      return str;
24079    }
24080  }
24081
24082  return function() {
24083    var cookieArray, cookie, i, index, name;
24084    var currentCookieString = rawDocument.cookie || '';
24085
24086    if (currentCookieString !== lastCookieString) {
24087      lastCookieString = currentCookieString;
24088      cookieArray = lastCookieString.split('; ');
24089      lastCookies = {};
24090
24091      for (i = 0; i < cookieArray.length; i++) {
24092        cookie = cookieArray[i];
24093        index = cookie.indexOf('=');
24094        if (index > 0) { //ignore nameless cookies
24095          name = safeDecodeURIComponent(cookie.substring(0, index));
24096          // the first value that is seen for a cookie is the most
24097          // specific one.  values for the same cookie name that
24098          // follow are for less specific paths.
24099          if (isUndefined(lastCookies[name])) {
24100            lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
24101          }
24102        }
24103      }
24104    }
24105    return lastCookies;
24106  };
24107}
24108
24109$$CookieReader.$inject = ['$document'];
24110
24111function $$CookieReaderProvider() {
24112  this.$get = $$CookieReader;
24113}
24114
24115/* global currencyFilter: true,
24116 dateFilter: true,
24117 filterFilter: true,
24118 jsonFilter: true,
24119 limitToFilter: true,
24120 lowercaseFilter: true,
24121 numberFilter: true,
24122 orderByFilter: true,
24123 uppercaseFilter: true,
24124 */
24125
24126/**
24127 * @ngdoc provider
24128 * @name $filterProvider
24129 * @description
24130 *
24131 * Filters are just functions which transform input to an output. However filters need to be
24132 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
24133 * annotated with dependencies and is responsible for creating a filter function.
24134 *
24135 * <div class="alert alert-warning">
24136 * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
24137 * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
24138 * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
24139 * (`myapp_subsection_filterx`).
24140 * </div>
24141 *
24142 * ```js
24143 *   // Filter registration
24144 *   function MyModule($provide, $filterProvider) {
24145 *     // create a service to demonstrate injection (not always needed)
24146 *     $provide.value('greet', function(name){
24147 *       return 'Hello ' + name + '!';
24148 *     });
24149 *
24150 *     // register a filter factory which uses the
24151 *     // greet service to demonstrate DI.
24152 *     $filterProvider.register('greet', function(greet){
24153 *       // return the filter function which uses the greet service
24154 *       // to generate salutation
24155 *       return function(text) {
24156 *         // filters need to be forgiving so check input validity
24157 *         return text && greet(text) || text;
24158 *       };
24159 *     });
24160 *   }
24161 * ```
24162 *
24163 * The filter function is registered with the `$injector` under the filter name suffix with
24164 * `Filter`.
24165 *
24166 * ```js
24167 *   it('should be the same instance', inject(
24168 *     function($filterProvider) {
24169 *       $filterProvider.register('reverse', function(){
24170 *         return ...;
24171 *       });
24172 *     },
24173 *     function($filter, reverseFilter) {
24174 *       expect($filter('reverse')).toBe(reverseFilter);
24175 *     });
24176 * ```
24177 *
24178 *
24179 * For more information about how angular filters work, and how to create your own filters, see
24180 * {@link guide/filter Filters} in the Angular Developer Guide.
24181 */
24182
24183/**
24184 * @ngdoc service
24185 * @name $filter
24186 * @kind function
24187 * @description
24188 * Filters are used for formatting data displayed to the user.
24189 *
24190 * The general syntax in templates is as follows:
24191 *
24192 *         {{ expression [| filter_name[:parameter_value] ... ] }}
24193 *
24194 * @param {String} name Name of the filter function to retrieve
24195 * @return {Function} the filter function
24196 * @example
24197   <example name="$filter" module="filterExample">
24198     <file name="index.html">
24199       <div ng-controller="MainCtrl">
24200        <h3>{{ originalText }}</h3>
24201        <h3>{{ filteredText }}</h3>
24202       </div>
24203     </file>
24204
24205     <file name="script.js">
24206      angular.module('filterExample', [])
24207      .controller('MainCtrl', function($scope, $filter) {
24208        $scope.originalText = 'hello';
24209        $scope.filteredText = $filter('uppercase')($scope.originalText);
24210      });
24211     </file>
24212   </example>
24213  */
24214$FilterProvider.$inject = ['$provide'];
24215function $FilterProvider($provide) {
24216  var suffix = 'Filter';
24217
24218  /**
24219   * @ngdoc method
24220   * @name $filterProvider#register
24221   * @param {string|Object} name Name of the filter function, or an object map of filters where
24222   *    the keys are the filter names and the values are the filter factories.
24223   *
24224   *    <div class="alert alert-warning">
24225   *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
24226   *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
24227   *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
24228   *    (`myapp_subsection_filterx`).
24229   *    </div>
24230    * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
24231   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
24232   *    of the registered filter instances.
24233   */
24234  function register(name, factory) {
24235    if (isObject(name)) {
24236      var filters = {};
24237      forEach(name, function(filter, key) {
24238        filters[key] = register(key, filter);
24239      });
24240      return filters;
24241    } else {
24242      return $provide.factory(name + suffix, factory);
24243    }
24244  }
24245  this.register = register;
24246
24247  this.$get = ['$injector', function($injector) {
24248    return function(name) {
24249      return $injector.get(name + suffix);
24250    };
24251  }];
24252
24253  ////////////////////////////////////////
24254
24255  /* global
24256    currencyFilter: false,
24257    dateFilter: false,
24258    filterFilter: false,
24259    jsonFilter: false,
24260    limitToFilter: false,
24261    lowercaseFilter: false,
24262    numberFilter: false,
24263    orderByFilter: false,
24264    uppercaseFilter: false,
24265  */
24266
24267  register('currency', currencyFilter);
24268  register('date', dateFilter);
24269  register('filter', filterFilter);
24270  register('json', jsonFilter);
24271  register('limitTo', limitToFilter);
24272  register('lowercase', lowercaseFilter);
24273  register('number', numberFilter);
24274  register('orderBy', orderByFilter);
24275  register('uppercase', uppercaseFilter);
24276}
24277
24278/**
24279 * @ngdoc filter
24280 * @name filter
24281 * @kind function
24282 *
24283 * @description
24284 * Selects a subset of items from `array` and returns it as a new array.
24285 *
24286 * @param {Array} array The source array.
24287 * @param {string|Object|function()} expression The predicate to be used for selecting items from
24288 *   `array`.
24289 *
24290 *   Can be one of:
24291 *
24292 *   - `string`: The string is used for matching against the contents of the `array`. All strings or
24293 *     objects with string properties in `array` that match this string will be returned. This also
24294 *     applies to nested object properties.
24295 *     The predicate can be negated by prefixing the string with `!`.
24296 *
24297 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
24298 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
24299 *     which have property `name` containing "M" and property `phone` containing "1". A special
24300 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
24301 *     property of the object or its nested object properties. That's equivalent to the simple
24302 *     substring match with a `string` as described above. The predicate can be negated by prefixing
24303 *     the string with `!`.
24304 *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
24305 *     not containing "M".
24306 *
24307 *     Note that a named property will match properties on the same level only, while the special
24308 *     `$` property will match properties on the same level or deeper. E.g. an array item like
24309 *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
24310 *     **will** be matched by `{$: 'John'}`.
24311 *
24312 *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
24313 *     The function is called for each element of the array, with the element, its index, and
24314 *     the entire array itself as arguments.
24315 *
24316 *     The final result is an array of those elements that the predicate returned true for.
24317 *
24318 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
24319 *     determining if the expected value (from the filter expression) and actual value (from
24320 *     the object in the array) should be considered a match.
24321 *
24322 *   Can be one of:
24323 *
24324 *   - `function(actual, expected)`:
24325 *     The function will be given the object value and the predicate value to compare and
24326 *     should return true if both values should be considered equal.
24327 *
24328 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
24329 *     This is essentially strict comparison of expected and actual.
24330 *
24331 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
24332 *     insensitive way.
24333 *
24334 *     Primitive values are converted to strings. Objects are not compared against primitives,
24335 *     unless they have a custom `toString` method (e.g. `Date` objects).
24336 *
24337 * @example
24338   <example>
24339     <file name="index.html">
24340       <div ng-init="friends = [{name:'John', phone:'555-1276'},
24341                                {name:'Mary', phone:'800-BIG-MARY'},
24342                                {name:'Mike', phone:'555-4321'},
24343                                {name:'Adam', phone:'555-5678'},
24344                                {name:'Julie', phone:'555-8765'},
24345                                {name:'Juliette', phone:'555-5678'}]"></div>
24346
24347       <label>Search: <input ng-model="searchText"></label>
24348       <table id="searchTextResults">
24349         <tr><th>
24349Name</th><th>Phone</th></tr>
24350         <tr ng-repeat="friend in friends | filter:searchText">
24351           <td>{{friend.name}}</td>
24352           <td>{{friend.phone}}</td>
24353         </tr>
24354       </table>
24355       <hr>
24356       <label>Any: <input ng-model="search.$"></label> <br>
24357       <label>Name only <input ng-model="search.name"></label><br>
24358       <label>Phone only <input ng-model="search.phone"></label><br>
24359       <label>Equality <input type="checkbox" ng-model="strict"></label><br>
24360       <table id="searchObjResults">
24361         <tr><th>Name</th><th>Phone</th></tr>
24362         <tr ng-repeat="friendObj in friends | filter:search:strict">
24363           <td>{{friendObj.name}}</td>
24364           <td>{{friendObj.phone}}</td>
24365         </tr>
24366       </table>
24367     </file>
24368     <file name="protractor.js" type="protractor">
24369       var expectFriendNames = function(expectedNames, key) {
24370         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
24371           arr.forEach(function(wd, i) {
24372             expect(wd.getText()).toMatch(expectedNames[i]);
24373           });
24374         });
24375       };
24376
24377       it('should search across all fields when filtering with a string', function() {
24378         var searchText = element(by.model('searchText'));
24379         searchText.clear();
24380         searchText.sendKeys('m');
24381         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
24382
24383         searchText.clear();
24384         searchText.sendKeys('76');
24385         expectFriendNames(['John', 'Julie'], 'friend');
24386       });
24387
24388       it('should search in specific fields when filtering with a predicate object', function() {
24389         var searchAny = element(by.model('search.$'));
24390         searchAny.clear();
24391         searchAny.sendKeys('i');
24392         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
24393       });
24394       it('should use a equal comparison when comparator is true', function() {
24395         var searchName = element(by.model('search.name'));
24396         var strict = element(by.model('strict'));
24397         searchName.clear();
24398         searchName.sendKeys('Julie');
24399         strict.click();
24400         expectFriendNames(['Julie'], 'friendObj');
24401       });
24402     </file>
24403   </example>
24404 */
24405function filterFilter() {
24406  return function(array, expression, comparator) {
24407    if (!isArrayLike(array)) {
24408      if (array == null) {
24409        return array;
24410      } else {
24411        throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
24412      }
24413    }
24414
24415    var expressionType = getTypeForFilter(expression);
24416    var predicateFn;
24417    var matchAgainstAnyProp;
24418
24419    switch (expressionType) {
24420      case 'function':
24421        predicateFn = expression;
24422        break;
24423      case 'boolean':
24424      case 'null':
24425      case 'number':
24426      case 'string':
24427        matchAgainstAnyProp = true;
24428        //jshint -W086
24429      case 'object':
24430        //jshint +W086
24431        predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
24432        break;
24433      default:
24434        return array;
24435    }
24436
24437    return Array.prototype.filter.call(array, predicateFn);
24438  };
24439}
24440
24441// Helper functions for `filterFilter`
24442function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
24443  var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
24444  var predicateFn;
24445
24446  if (comparator === true) {
24447    comparator = equals;
24448  } else if (!isFunction(comparator)) {
24449    comparator = function(actual, expected) {
24450      if (isUndefined(actual)) {
24451        // No substring matching against `undefined`
24452        return false;
24453      }
24454      if ((actual === null) || (expected === null)) {
24455        // No substring matching against `null`; only match against `null`
24456        return actual === expected;
24457      }
24458      if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
24459        // Should not compare primitives against objects, unless they have custom `toString` method
24460        return false;
24461      }
24462
24463      actual = lowercase('' + actual);
24464      expected = lowercase('' + expected);
24465      return actual.indexOf(expected) !== -1;
24466    };
24467  }
24468
24469  predicateFn = function(item) {
24470    if (shouldMatchPrimitives && !isObject(item)) {
24471      return deepCompare(item, expression.$, comparator, false);
24472    }
24473    return deepCompare(item, expression, comparator, matchAgainstAnyProp);
24474  };
24475
24476  return predicateFn;
24477}
24478
24479function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
24480  var actualType = getTypeForFilter(actual);
24481  var expectedType = getTypeForFilter(expected);
24482
24483  if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
24484    return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
24485  } else if (isArray(actual)) {
24486    // In case `actual` is an array, consider it a match
24487    // if ANY of it's items matches `expected`
24488    return actual.some(function(item) {
24489      return deepCompare(item, expected, comparator, matchAgainstAnyProp);
24490    });
24491  }
24492
24493  switch (actualType) {
24494    case 'object':
24495      var key;
24496      if (matchAgainstAnyProp) {
24497        for (key in actual) {
24498          if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
24499            return true;
24500          }
24501        }
24502        return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
24503      } else if (expectedType === 'object') {
24504        for (key in expected) {
24505          var expectedVal = expected[key];
24506          if (isFunction(expectedVal) || isUndefined(expectedVal)) {
24507            continue;
24508          }
24509
24510          var matchAnyProperty = key === '$';
24511          var actualVal = matchAnyProperty ? actual : actual[key];
24512          if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
24513            return false;
24514          }
24515        }
24516        return true;
24517      } else {
24518        return comparator(actual, expected);
24519      }
24520      break;
24521    case 'function':
24522      return false;
24523    default:
24524      return comparator(actual, expected);
24525  }
24526}
24527
24528// Used for easily differentiating between `null` and actual `object`
24529function getTypeForFilter(val) {
24530  return (val === null) ? 'null' : typeof val;
24531}
24532
24533var MAX_DIGITS = 22;
24534var DECIMAL_SEP = '.';
24535var ZERO_CHAR = '0';
24536
24537/**
24538 * @ngdoc filter
24539 * @name currency
24540 * @kind function
24541 *
24542 * @description
24543 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
24544 * symbol for current locale is used.
24545 *
24546 * @param {number} amount Input to filter.
24547 * @param {string=} symbol Currency symbol or identifier to be displayed.
24548 * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
24549 * @returns {string} Formatted number.
24550 *
24551 *
24552 * @example
24553   <example module="currencyExample">
24554     <file name="index.html">
24555       <script>
24556         angular.module('currencyExample', [])
24557           .controller('ExampleController', ['$scope', function($scope) {
24558             $scope.amount = 1234.56;
24559           }]);
24560       </script>
24561       <div ng-controller="ExampleController">
24562         <input type="number" ng-model="amount" aria-label="amount"> <br>
24563         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
24564         custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
24565         no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
24566       </div>
24567     </file>
24568     <file name="protractor.js" type="protractor">
24569       it('should init with 1234.56', function() {
24570         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
24571         expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
24572         expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
24573       });
24574       it('should update', function() {
24575         if (browser.params.browser == 'safari') {
24576           // Safari does not understand the minus key. See
24577           // https://github.com/angular/protractor/issues/481
24578           return;
24579         }
24580         element(by.model('amount')).clear();
24581         element(by.model('amount')).sendKeys('-1234');
24582         expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
24583         expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
24584         expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
24585       });
24586     </file>
24587   </example>
24588 */
24589currencyFilter.$inject = ['$locale'];
24590function currencyFilter($locale) {
24591  var formats = $locale.NUMBER_FORMATS;
24592  return function(amount, currencySymbol, fractionSize) {
24593    if (isUndefined(currencySymbol)) {
24594      currencySymbol = formats.CURRENCY_SYM;
24595    }
24596
24597    if (isUndefined(fractionSize)) {
24598      fractionSize = formats.PATTERNS[1].maxFrac;
24599    }
24600
24601    // if null or undefined pass it through
24602    return (amount == null)
24603        ? amount
24604        : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
24605            replace(/\u00A4/g, currencySymbol);
24606  };
24607}
24608
24609/**
24610 * @ngdoc filter
24611 * @name number
24612 * @kind function
24613 *
24614 * @description
24615 * Formats a number as text.
24616 *
24617 * If the input is null or undefined, it will just be returned.
24618 * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.
24619 * If the input is not a number an empty string is returned.
24620 *
24621 *
24622 * @param {number|string} number Number to format.
24623 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
24624 * If this is not provided then the fraction size is computed from the current locale's number
24625 * formatting pattern. In the case of the default locale, it will be 3.
24626 * @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
24627 *
24628 * @example
24629   <example module="numberFilterExample
vendor: 3,034 bytes, lines 24629-24708
24629">
24630     <file name="index.html">
24631       <script>
24632         angular.module('numberFilterExample', [])
24633           .controller('ExampleController', ['$scope', function($scope) {
24634             $scope.val = 1234.56789;
24635           }]);
24636       </script>
24637       <div ng-controller="ExampleController">
24638         <label>Enter number: <input ng-model='val'></label><br>
24639         Default formatting: <span id='number-default'>{{val | number}}</span><br>
24640         No fractions: <span>{{val | number:0}}</span><br>
24641         Negative number: <span>{{-val | number:4}}</span>
24642       </div>
24643     </file>
24644     <file name="protractor.js" type="protractor">
24645       it('should format numbers', function() {
24646         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
24647         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
24648         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
24649       });
24650
24651       it('should update', function() {
24652         element(by.model('val')).clear();
24653         element(by.model('val')).sendKeys('3374.333');
24654         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
24655         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
24656         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
24657      });
24658     </file>
24659   </example>
24660 */
24661numberFilter.$inject = ['$locale'];
24662function numberFilter($locale) {
24663  var formats = $locale.NUMBER_FORMATS;
24664  return function(number, fractionSize) {
24665
24666    // if null or undefined pass it through
24667    return (number == null)
24668        ? number
24669        : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
24670                       fractionSize);
24671  };
24672}
24673
24674/**
24675 * Parse a number (as a string) into three components that can be used
24676 * for formatting the number.
24677 *
24678 * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
24679 *
24680 * @param  {string} numStr The number to parse
24681 * @return {object} An object describing this number, containing the following keys:
24682 *  - d : an array of digits containing leading zeros as necessary
24683 *  - i : the number of the digits in `d` that are to the left of the decimal point
24684 *  - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
24685 *
24686 */
24687function parse(numStr) {
24688  var exponent = 0, digits, numberOfIntegerDigits;
24689  var i, j, zeros;
24690
24691  // Decimal point?
24692  if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
24693    numStr = numStr.replace(DECIMAL_SEP, '');
24694  }
24695
24696  // Exponential form?
24697  if ((i = numStr.search(/e/i)) > 0) {
24698    // Work out the exponent.
24699    if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
24700    numberOfIntegerDigits += +numStr.slice(i + 1);
24701    numStr = numStr.substring(0, i);
24702  } else if (numberOfIntegerDigits < 0) {
24703    // There was no decimal point or exponent so it is an integer.
24704    numberOfIntegerDigits = numStr.length;
24705  }
24706
24707  // Count the number of leading zeros.
24708  for (i = 0; numStr.charAt(i) ==
vendor: 13,215 bytes, lines 24708-25079
24708 ZERO_CHAR; i++) {/* jshint noempty: false */}
24709
24710  if (i == (zeros = numStr.length)) {
24711    // The digits are all zero.
24712    digits = [0];
24713    numberOfIntegerDigits = 1;
24714  } else {
24715    // Count the number of trailing zeros
24716    zeros--;
24717    while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;
24718
24719    // Trailing zeros are insignificant so ignore them
24720    numberOfIntegerDigits -= i;
24721    digits = [];
24722    // Convert string to array of digits without leading/trailing zeros.
24723    for (j = 0; i <= zeros; i++, j++) {
24724      digits[j] = +numStr.charAt(i);
24725    }
24726  }
24727
24728  // If the number overflows the maximum allowed digits then use an exponent.
24729  if (numberOfIntegerDigits > MAX_DIGITS) {
24730    digits = digits.splice(0, MAX_DIGITS - 1);
24731    exponent = numberOfIntegerDigits - 1;
24732    numberOfIntegerDigits = 1;
24733  }
24734
24735  return { d: digits, e: exponent, i: numberOfIntegerDigits };
24736}
24737
24738/**
24739 * Round the parsed number to the specified number of decimal places
24740 * This function changed the parsedNumber in-place
24741 */
24742function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
24743    var digits = parsedNumber.d;
24744    var fractionLen = digits.length - parsedNumber.i;
24745
24746    // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
24747    fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
24748
24749    // The index of the digit to where rounding is to occur
24750    var roundAt = fractionSize + parsedNumber.i;
24751    var digit = digits[roundAt];
24752
24753    if (roundAt > 0) {
24754      // Drop fractional digits beyond `roundAt`
24755      digits.splice(Math.max(parsedNumber.i, roundAt));
24756
24757      // Set non-fractional digits beyond `roundAt` to 0
24758      for (var j = roundAt; j < digits.length; j++) {
24759        digits[j] = 0;
24760      }
24761    } else {
24762      // We rounded to zero so reset the parsedNumber
24763      fractionLen = Math.max(0, fractionLen);
24764      parsedNumber.i = 1;
24765      digits.length = Math.max(1, roundAt = fractionSize + 1);
24766      digits[0] = 0;
24767      for (var i = 1; i < roundAt; i++) digits[i] = 0;
24768    }
24769
24770    if (digit >= 5) {
24771      if (roundAt - 1 < 0) {
24772        for (var k = 0; k > roundAt; k--) {
24773          digits.unshift(0);
24774          parsedNumber.i++;
24775        }
24776        digits.unshift(1);
24777        parsedNumber.i++;
24778      } else {
24779        digits[roundAt - 1]++;
24780      }
24781    }
24782
24783    // Pad out with zeros to get the required fraction length
24784    for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
24785
24786
24787    // Do any carrying, e.g. a digit was rounded up to 10
24788    var carry = digits.reduceRight(function(carry, d, i, digits) {
24789      d = d + carry;
24790      digits[i] = d % 10;
24791      return Math.floor(d / 10);
24792    }, 0);
24793    if (carry) {
24794      digits.unshift(carry);
24795      parsedNumber.i++;
24796    }
24797}
24798
24799/**
24800 * Format a number into a string
24801 * @param  {number} number       The number to format
24802 * @param  {{
24803 *           minFrac, // the minimum number of digits required in the fraction part of the number
24804 *           maxFrac, // the maximum number of digits required in the fraction part of the number
24805 *           gSize,   // number of digits in each group of separated digits
24806 *           lgSize,  // number of digits in the last group of digits before the decimal separator
24807 *           negPre,  // the string to go in front of a negative number (e.g. `-` or `(`))
24808 *           posPre,  // the string to go in front of a positive number
24809 *           negSuf,  // the string to go after a negative number (e.g. `)`)
24810 *           posSuf   // the string to go after a positive number
24811 *         }} pattern
24812 * @param  {string} groupSep     The string to separate groups of number (e.g. `,`)
24813 * @param  {string} decimalSep   The string to act as the decimal separator (e.g. `.`)
24814 * @param  {[type]} fractionSize The size of the fractional part of the number
24815 * @return {string}              The number formatted as a string
24816 */
24817function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
24818
24819  if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
24820
24821  var isInfinity = !isFinite(number);
24822  var isZero = false;
24823  var numStr = Math.abs(number) + '',
24824      formattedText = '',
24825      parsedNumber;
24826
24827  if (isInfinity) {
24828    formattedText = '\u221e';
24829  } else {
24830    parsedNumber = parse(numStr);
24831
24832    roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
24833
24834    var digits = parsedNumber.d;
24835    var integerLen = parsedNumber.i;
24836    var exponent = parsedNumber.e;
24837    var decimals = [];
24838    isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
24839
24840    // pad zeros for small numbers
24841    while (integerLen < 0) {
24842      digits.unshift(0);
24843      integerLen++;
24844    }
24845
24846    // extract decimals digits
24847    if (integerLen > 0) {
24848      decimals = digits.splice(integerLen);
24849    } else {
24850      decimals = digits;
24851      digits = [0];
24852    }
24853
24854    // format the integer digits with grouping separators
24855    var groups = [];
24856    if (digits.length > pattern.lgSize) {
24857      groups.unshift(digits.splice(-pattern.lgSize).join(''));
24858    }
24859    while (digits.length > pattern.gSize) {
24860      groups.unshift(digits.splice(-pattern.gSize).join(''));
24861    }
24862    if (digits.length) {
24863      groups.unshift(digits.join(''));
24864    }
24865    formattedText = groups.join(groupSep);
24866
24867    // append the decimal digits
24868    if (decimals.length) {
24869      formattedText += decimalSep + decimals.join('');
24870    }
24871
24872    if (exponent) {
24873      formattedText += 'e+' + exponent;
24874    }
24875  }
24876  if (number < 0 && !isZero) {
24877    return pattern.negPre + formattedText + pattern.negSuf;
24878  } else {
24879    return pattern.posPre + formattedText + pattern.posSuf;
24880  }
24881}
24882
24883function padNumber(num, digits, trim, negWrap) {
24884  var neg = '';
24885  if (num < 0 || (negWrap && num <= 0)) {
24886    if (negWrap) {
24887      num = -num + 1;
24888    } else {
24889      num = -num;
24890      neg = '-';
24891    }
24892  }
24893  num = '' + num;
24894  while (num.length < digits) num = ZERO_CHAR + num;
24895  if (trim) {
24896    num = num.substr(num.length - digits);
24897  }
24898  return neg + num;
24899}
24900
24901
24902function dateGetter(name, size, offset, trim, negWrap) {
24903  offset = offset || 0;
24904  return function(date) {
24905    var value = date['get' + name]();
24906    if (offset > 0 || value > -offset) {
24907      value += offset;
24908    }
24909    if (value === 0 && offset == -12) value = 12;
24910    return padNumber(value, size, trim, negWrap);
24911  };
24912}
24913
24914function dateStrGetter(name, shortForm, standAlone) {
24915  return function(date, formats) {
24916    var value = date['get' + name]();
24917    var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
24918    var get = uppercase(propPrefix + name);
24919
24920    return formats[get][value];
24921  };
24922}
24923
24924function timeZoneGetter(date, formats, offset) {
24925  var zone = -1 * offset;
24926  var paddedZone = (zone >= 0) ? "+" : "";
24927
24928  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
24929                padNumber(Math.abs(zone % 60), 2);
24930
24931  return paddedZone;
24932}
24933
24934function getFirstThursdayOfYear(year) {
24935    // 0 = index of January
24936    var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
24937    // 4 = index of Thursday (+1 to account for 1st = 5)
24938    // 11 = index of *next* Thursday (+1 account for 1st = 12)
24939    return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
24940}
24941
24942function getThursdayThisWeek(datetime) {
24943    return new Date(datetime.getFullYear(), datetime.getMonth(),
24944      // 4 = index of Thursday
24945      datetime.getDate() + (4 - datetime.getDay()));
24946}
24947
24948function weekGetter(size) {
24949   return function(date) {
24950      var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
24951         thisThurs = getThursdayThisWeek(date);
24952
24953      var diff = +thisThurs - +firstThurs,
24954         result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
24955
24956      return padNumber(result, size);
24957   };
24958}
24959
24960function ampmGetter(date, formats) {
24961  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
24962}
24963
24964function eraGetter(date, formats) {
24965  return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
24966}
24967
24968function longEraGetter(date, formats) {
24969  return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
24970}
24971
24972var DATE_FORMATS = {
24973  yyyy: dateGetter('FullYear', 4, 0, false, true),
24974    yy: dateGetter('FullYear', 2, 0, true, true),
24975     y: dateGetter('FullYear', 1, 0, false, true),
24976  MMMM: dateStrGetter('Month'),
24977   MMM: dateStrGetter('Month', true),
24978    MM: dateGetter('Month', 2, 1),
24979     M: dateGetter('Month', 1, 1),
24980  LLLL: dateStrGetter('Month', false, true),
24981    dd: dateGetter('Date', 2),
24982     d: dateGetter('Date', 1),
24983    HH: dateGetter('Hours', 2),
24984     H: dateGetter('Hours', 1),
24985    hh: dateGetter('Hours', 2, -12),
24986     h: dateGetter('Hours', 1, -12),
24987    mm: dateGetter('Minutes', 2),
24988     m: dateGetter('Minutes', 1),
24989    ss: dateGetter('Seconds', 2),
24990     s: dateGetter('Seconds', 1),
24991     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
24992     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
24993   sss: dateGetter('Milliseconds', 3),
24994  EEEE: dateStrGetter('Day'),
24995   EEE: dateStrGetter('Day', true),
24996     a: ampmGetter,
24997     Z: timeZoneGetter,
24998    ww: weekGetter(2),
24999     w: weekGetter(1),
25000     G: eraGetter,
25001     GG: eraGetter,
25002     GGG: eraGetter,
25003     GGGG: longEraGetter
25004};
25005
25006var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
25007    NUMBER_STRING = /^\-?\d+$/;
25008
25009/**
25010 * @ngdoc filter
25011 * @name date
25012 * @kind function
25013 *
25014 * @description
25015 *   Formats `date` to a string based on the requested `format`.
25016 *
25017 *   `format` string can be composed of the following elements:
25018 *
25019 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
25020 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
25021 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
25022 *   * `'MMMM'`: Month in year (January-December)
25023 *   * `'MMM'`: Month in year (Jan-Dec)
25024 *   * `'MM'`: Month in year, padded (01-12)
25025 *   * `'M'`: Month in year (1-12)
25026 *   * `'LLLL'`: Stand-alone month in year (January-December)
25027 *   * `'dd'`: Day in month, padded (01-31)
25028 *   * `'d'`: Day in month (1-31)
25029 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
25030 *   * `'EEE'`: Day in Week, (Sun-Sat)
25031 *   * `'HH'`: Hour in day, padded (00-23)
25032 *   * `'H'`: Hour in day (0-23)
25033 *   * `'hh'`: Hour in AM/PM, padded (01-12)
25034 *   * `'h'`: Hour in AM/PM, (1-12)
25035 *   * `'mm'`: Minute in hour, padded (00-59)
25036 *   * `'m'`: Minute in hour (0-59)
25037 *   * `'ss'`: Second in minute, padded (00-59)
25038 *   * `'s'`: Second in minute (0-59)
25039 *   * `'sss'`: Millisecond in second, padded (000-999)
25040 *   * `'a'`: AM/PM marker
25041 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
25042 *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
25043 *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
25044 *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
25045 *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
25046 *
25047 *   `format` string can also be one of the following predefined
25048 *   {@link guide/i18n localizable formats}:
25049 *
25050 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
25051 *     (e.g. Sep 3, 2010 12:05:08 PM)
25052 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
25053 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
25054 *     (e.g. Friday, September 3, 2010)
25055 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
25056 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
25057 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
25058 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
25059 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
25060 *
25061 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
25062 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
25063 *   (e.g. `"h 'o''clock'"`).
25064 *
25065 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
25066 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
25067 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
25068 *    specified in the string input, the time is considered to be in the local timezone.
25069 * @param {string=} format Formatting rules (see Description). If not specified,
25070 *    `mediumDate` is used.
25071 * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
25072 *    continental US time zone abbreviations, but for general use, use a time zone offset, for
25073 *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
25074 *    If not specified, the timezone of the browser will be used.
25075 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
25076 *
25077 * @example
25078   <example>
25079     <file name="index.html">
25080       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
25081           <span>{{1288323623006 | date:'medium'}}</span><br>
25082       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
25083          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
25084       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
25085          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
25086       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
25087          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
25088     </file>
25089     <file name="protractor.js" type="protractor">
25090       it('should format date', function() {
25091         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
25092            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
25093         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
25094            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
25095         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
25096            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
25097         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
25098            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
25099       });
25100     </file>
25101   </example>
25102 */
25103dateFilter.$inject = ['$locale'];
25104function dateFilter($locale) {
25105
25106
25107  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
25108                     // 1        2       3         4          5          6          7          8  9     10      11
25109  function jsonStringToDate(string) {
25110    var match;
25111    if (match = string.match(R_ISO8601_STR)) {
25112      var date = new Date(0),
25113          tzHour = 0,
25114          tzMin  = 0,
25115          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
25116          timeSetter = match[8] ? date.setUTCHours : date.setHours;
25117
25118      if (match[9]) {
25119        tzHour = toInt(match[9] + match[10]);
25120        tzMin = toInt(match[9] + match[11]);
25121      }
25122      dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
25123      var h = toInt(match[4] || 0) - tzHour;
25124      var m = toInt(match[5] || 0) - tzMin;
25125      var s = toInt(match[6] || 0);
25126      var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
25127      timeSetter.call(date, h, m, s, ms);
25128      return date;
25129    }
25130    return string;
25131  }
25132
25133
25134  return function(date, format, timezone) {
25135    var text = '',
25136        parts = [],
25137        fn, match;
25138
25139    format = format || 'mediumDate';
25140    format = $locale.DATETIME_FORMATS[format] || format;
25141    if (isString(date)) {
25142      date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
25143    }
25144
25145    if (isNumber(date)) {
25146      date = new Date(date);
25147    }
25148
25149    if (!isDate(date) || !isFinite(date.getTime())) {
25150      return date;
25151    }
25152
25153    while (format) {
25154      match = DATE_FORMATS_SPLIT.exec(format);
25155      if (match) {
25156        parts = concat(parts, match, 1);
25157        format = parts.pop();
25158      } else {
25159        parts.push(format);
25160        format = null;
25161      }
25162    }
25163
25164    var dateTimezoneOffset = date.getTimezoneOffset();
25165    if (timezone) {
25166      dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
25167      date = convertTimezoneToLocal(date, timezone, true);
25168    }
25169    forEach(parts, function(value) {
25170      fn = DATE_FORMATS[value];
25171      text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
25172                 : value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
25173    });
25174
25175    return text;
25176  };
25177}
25178
25179
25180/**
25181 * @ngdoc filter
25182 * @name json
25183 * @kind function
25184 *
25185 * @description
25186 *   Allows you to convert a JavaScript object into JSON string.
25187 *
25188 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
25189 *   the binding is automatically converted to JSON.
25190 *
25191 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
25192 * @param {number=}
25192 spacing The number of spaces to use per indentation, defaults to 2.
25193 * @returns {string} JSON string.
25194 *
25195 *
25196 * @example
25197   <example>
25198     <file name="index.html">
25199       <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
25200       <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
25201     </file>
25202     <file name="protractor.js" type="protractor">
25203       it('should jsonify filtered objects', function() {
25204         expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
25205         expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
25206       });
25207     </file>
25208   </example>
25209 *
25210 */
25211function jsonFilter() {
25212  return function(object, spacing) {
25213    if (isUndefined(spacing)) {
25214        spacing = 2;
25215    }
25216    return toJson(object, spacing);
25217  };
25218}
25219
25220
25221/**
25222 * @ngdoc filter
25223 * @name lowercase
25224 * @kind function
25225 * @description
25226 * Converts string to lowercase.
25227 * @see angular.lowercase
25228 */
25229var lowercaseFilter = valueFn(lowercase);
25230
25231
25232/**
25233 * @ngdoc filter
25234 * @name uppercase
25235 * @kind function
25236 * @description
25237 * Converts string to uppercase.
25238 * @see angular.uppercase
25239 */
25240var uppercaseFilter = valueFn(uppercase);
25241
25242/**
25243 * @ngdoc filter
25244 * @name limitTo
25245 * @kind function
25246 *
25247 * @description
25248 * Creates a new array or string containing only a specified number of elements. The elements
25249 * are taken from either the beginning or the end of the source array, string or number, as specified by
25250 * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
25251 * converted to a string.
25252 *
25253 * @param {Array|string|number} input Source array, string or number to be limited.
25254 * @param {string|number} limit The length of the returned array or string. If the `limit` number
25255 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
25256 *     If the number is negative, `limit` number  of items from the end of the source array/string
25257 *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
25258 *     the input will be returned unchanged.
25259 * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
25260 *     indicates an offset from the end of `input`. Defaults to `0`.
25261 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
25262 *     had less than `limit` elements.
25263 *
25264 * @example
25265   <example module="limitToExample">
25266     <file name="index.html">
25267       <script>
25268         angular.module('limitToExample', [])
25269           .controller('ExampleController', ['$scope', function($scope) {
25270             $scope.numbers = [1,2,3,4,5,6,7,8,9];
25271             $scope.letters = "abcdefghi";
25272             $scope.longNumber = 2345432342;
25273             $scope.numLimit = 3;
25274             $scope.letterLimit = 3;
25275             $scope.longNumberLimit = 3;
25276           }]);
25277       </script>
25278       <div ng-controller="ExampleController">
25279         <label>
25280            Limit {{numbers}} to:
25281            <input type="number" step="1" ng-model="numLimit">
25282         </label>
25283         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
25284         <label>
25285            Limit {{letters}} to:
25286            <input type="number" step="1" ng-model="letterLimit">
25287         </label>
25288         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
25289         <label>
25290            Limit {{longNumber}} to:
25291            <input type="number" step="1" ng-model="longNumberLimit">
25292         </label>
25293         <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
25294       </div>
25295     </file>
25296     <file name="protractor.js" type="protractor">
25297       var numLimitInput = element(by.model('numLimit'));
25298       var letterLimitInput = element(by.model('letterLimit'));
25299       var longNumberLimitInput = element(by.model('longNumberLimit'));
25300       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
25301       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
25302       var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
25303
25304       it('should limit the number array to first three items', function() {
25305         expect(numLimitInput.getAttribute('value')).toBe('3');
25306         expect(letterLimitInput.getAttribute('value')).toBe('3');
25307         expect(longNumberLimitInput.getAttribute('value')).toBe('3');
25308         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
25309         expect(limitedLetters.getText()).toEqual('Output letters: abc');
25310         expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
25311       });
25312
25313       // There is a bug in safari and protractor that doesn't like the minus key
25314       // it('should update the output when -3 is entered', function() {
25315       //   numLimitInput.clear();
25316       //   numLimitInput.sendKeys('-3');
25317       //   letterLimitInput.clear();
25318       //   letterLimitInput.sendKeys('-3');
25319       //   longNumberLimitInput.clear();
25320       //   longNumberLimitInput.sendKeys('-3');
25321       //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
25322       //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
25323       //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
25324       // });
25325
25326       it('should not exceed the maximum size of input array', function() {
25327         numLimitInput.clear();
25328         numLimitInput.sendKeys('100');
25329         letterLimitInput.clear();
25330         letterLimitInput.sendKeys('100');
25331         longNumberLimitInput.clear();
25332         longNumberLimitInput.sendKeys('100');
25333         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
25334         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
25335         expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
25336       });
25337     </file>
25338   </example>
25339*/
25340function limitToFilter() {
25341  return function(input, limit, begin) {
25342    if (Math.abs(Number(limit)) === Infinity) {
25343      limit = Number(limit);
25344    } else {
25345      limit = toInt(limit);
25346    }
25347    if (isNaN(limit)) return input;
25348
25349    if (isNumber(input)) input = input.toString();
25350    if (!isArray(input) && !isString(input)) return input;
25351
25352    begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
25353    begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
25354
25355    if (limit >= 0) {
25356      return input.slice(begin, begin + limit);
25357    } else {
25358      if (begin === 0) {
25359        return input.slice(limit, input.length);
25360      } else {
25361        return input.slice(Math.max(0, begin + limit), begin);
25362      }
25363    }
25364  };
25365}
25366
25367/**
25368 * @ngdoc filter
25369 * @name orderBy
25370 * @kind function
25371 *
25372 * @description
25373 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
25374 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
25375 * as expected, make sure they are actually being saved as numbers and not strings.
25376 * Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
25377 *
25378 * @param {Array} array The array (or array-like object) to sort.
25379 * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
25380 *    used by the comparator to determine the order of elements.
25381 *
25382 *    Can be one of:
25383 *
25384 *    - `function`: Getter function. The result of this function will be sorted using the
25385 *      `<`, `===`, `>` operator.
25386 *    - `string`: An Angular expression. The result of this expression is used to compare elements
25387 *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
25388 *      3 first characters of a property called `name`). The result of a constant expression
25389 *      is interpreted as a property name to be used in comparisons (for example `"special name"`
25390 *      to sort object by the value of their `special name` property). An expression can be
25391 *      optionally prefixed with `+` or `-` to control ascending or descending sort order
25392 *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
25393 *      element itself is used to compare where sorting.
25394 *    - `Array`: An array of function or string predicates. The first predicate in the array
25395 *      is used for sorting, but when two items are equivalent, the next predicate is used.
25396 *
25397 *    If the predicate is missing or empty then it defaults to `'+'`.
25398 *
25399 * @param {boolean=} reverse Reverse the order of the array.
25400 * @returns {Array} Sorted copy of the source array.
25401 *
25402 *
25403 * @example
25404 * The example below demonstrates a simple ngRepeat, where the data is sorted
25405 * by age in descending order (predicate is set to `'-age'`).
25406 * `reverse` is not set, which means it defaults to `false`.
25407   <example module="orderByExample">
25408     <file name="index.html">
25409       <div ng-controller="ExampleController">
25410         <table class="friend">
25411           <tr>
25412             <th>Name</th>
25413             <th>Phone Number</th>
25414             <th>Age</th>
25415           </tr>
25416           <tr ng-repeat="friend in friends | orderBy:'-age'">
25417             <td>{{friend.name}}</td>
25418             <td>{{friend.phone}}</td>
25419             <td>{{friend.age}}</td>
25420           </tr>
25421         </table>
25422       </div>
25423     </file>
25424     <file name="script.js">
25425       angular.module('orderByExample', [])
25426         .controller('ExampleController', ['$scope', function($scope) {
25427           $scope.friends =
25428               [{name:'John', phone:'555-1212', age:10},
25429                {name:'Mary', phone:'555-9876', age:19},
25430                {name:'Mike', phone:'555-4321', age:21},
25431                {name:'Adam', phone:'555-5678', age:35},
25432                {name:'Julie', phone:'555-8765', age:29}];
25433         }]);
25434     </file>
25435   </example>
25436 *
25437 * The predicate and reverse parameters can be controlled dynamically through scope properties,
25438 * as shown in the next example.
25439 * @example
25440   <example module="orderByExample">
25441     <file name="index.html">
25442       <div ng-controller="ExampleController">
25443         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
25444         <hr/>
25445         <button ng-click="predicate=''">Set to unsorted</button>
25446         <table class="friend">
25447           <tr>
25448            <th>
25449                <button ng-click="order('name')">Name</button>
25450                <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
25451            </th>
25452            <th>
25453                <button ng-click="order('phone')">Phone Number</button>
25454                <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
25455            </th>
25456            <th>
25457                <button ng-click="order('age')">Age</button>
25458                <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
25459            </th>
25460           </tr>
25461           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
25462             <td>{{friend.name}}</td>
25463             <td>{{friend.phone}}</td>
25464             <td>{{friend.age}}</td>
25465           </tr>
25466         </table>
25467       </div>
25468     </file>
25469     <file name="script.js">
25470       angular.module('orderByExample', [])
25471         .controller('ExampleController', ['$scope', function($scope) {
25472           $scope.friends =
25473               [{name:'John', phone:'555-1212', age:10},
25474                {name:'Mary', phone:'555-9876', age:19},
25475                {name:'Mike', phone:'555-4321', age:21},
25476                {name:'Adam', phone:'555-5678', age:35},
25477                {name:'Julie', phone:'555-8765', age:29}];
25478           $scope.predicate = 'age';
25479           $scope.reverse = true;
25480           $scope.order = function(predicate) {
25481             $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
25482             $scope.predicate = predicate;
25483           };
25484         }]);
25485      </file>
25486     <file name="style.css">
25487       .sortorder:after {
25488         content: '\25b2';
25489       }
25490       .sortorder.reverse:after {
25491         content: '\25bc';
25492       }
25493     </file>
25494   </example>
25495 *
25496 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
25497 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
25498 * desired parameters.
25499 *
25500 * Example:
25501 *
25502 * @example
25503  <example module="orderByExample">
25504    <file name="index.html">
25505    <div ng-controller="ExampleController">
25506      <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
25507      <table class="friend">
25508        <tr>
25509          <th>
25510              <button ng-click="order('name')">Name</button>
25511              <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
25512          </th>
25513          <th>
25514              <button ng-click="order('phone')">Phone Number</button>
25515              <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
25516          </th>
25517          <th>
25518              <button ng-click="order('age')">Age</button>
25519              <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
25520          </th>
25521        </tr>
25522        <tr ng-repeat="friend in friends">
25523          <td>{{friend.name}}</td>
25524          <td>{{friend.phone}}</td>
25525          <td>{{friend.age}}</td>
25526        </tr>
25527      </table>
25528    </div>
25529    </file>
25530
25531    <file name="script.js">
25532      angular.module('orderByExample', [])
25533        .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
25534          var orderBy = $filter('orderBy');
25535          $scope.friends = [
25536            { name: 'John',    phone: '555-1212',    age: 10 },
25537            { name: 'Mary',    phone: '555-9876',    age: 19 },
25538            { name: 'Mike',    phone: '555-4321',    age: 21 },
25539            { name: 'Adam',    phone: '555-5678',    age: 35 },
25540            { name: 'Julie',   phone: '555-8765',    age: 29 }
25541          ];
25542          $scope.order = function(predicate) {
25543            $scope.predicate = predicate;
25544            $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
25545            $scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
25546          };
25547          $scope.order('age', true);
25548        }]);
25549    </file>
25550
25551    <file name="style.css">
25552       .sortorder:after {
25553         content: '\25b2';
25554       }
25555       .sortorder.reverse:after {
25556         content: '\25bc';
25557       }
25558    </file>
25559</example>
25560 */
25561orderByFilter.$inject = ['$parse'];
25562function orderByFilter($parse) {
25563  return function(array, sortPredicate, reverseOrder) {
25564
25565    if (array == null) return array;
25566    if (!isArrayLike(array)) {
25567      throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
25568    }
25569
25570    if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
25571    if (sortPredicate.length === 0) { sortPredicate = ['+']; }
25572
25573    var predicates = processPredicates(sortPredicate, reverseOrder);
25574    // Add a predicate at the end that evaluates to the element index. This makes the
25575    // sort stable as it works as a tie-breaker when all the input predicates cannot
25576    // distinguish between two elements.
25577    predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
25578
25579    // The next three lines are a version of a Swartzian Transform idiom from Perl
25580    // (sometimes called the Decorate-Sort-Undecorate idiom)
25581    // See https://en.wikipedia.org/wiki/Schwartzian_transform
25582    var compareValues = Array.prototype.map.call(array, getComparisonObject);
25583    compareValues.sort(doComparison);
25584    array = compareValues.map(function(item) { return item.value; });
25585
25586    return array;
25587
25588    function getComparisonObject(value, index) {
25589      return {
25590        value: value,
25591        predicateValues: predicates.map(function(predicate) {
25592          return getPredicateValue(predicate.get(value), index);
25593        })
25594      };
25595    }
25596
25597    function doComparison(v1, v2) {
25598      var result = 0;
25599      for (var index=0, length = predicates.length; index < length; ++index) {
25600        result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
25601        if (result) break;
25602      }
25603      return result;
25604    }
25605  };
25606
25607  function processPredicates(sortPredicate, reverseOrder) {
25608    reverseOrder = reverseOrder ? -1 : 1;
25609    return sortPredicate.map(function(predicate) {
25610      var descending = 1, get = identity;
25611
25612      if (isFunction(predicate)) {
25613        get = predicate;
25614      } else if (isString(predicate)) {
25615        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
25616          descending = predicate.charAt(0) == '-' ? -1 : 1;
25617          predicate = predicate.substring(1);
25618        }
25619        if (predicate !== '') {
25620          get = $parse(predicate);
25621          if (get.constant) {
25622            var key = get();
25623            get = function(value) { return value[key]; };
25624          }
25625        }
25626      }
25627      return { get: get, descending: descending * reverseOrder };
25628    });
25629  }
25630
25631  function isPrimitive(value) {
25632    switch (typeof value) {
25633      case 'number': /* falls through */
25634      case 'boolean': /* falls through */
25635      case 'string':
25636        return true;
25637      default:
25638        return false;
25639    }
25640  }
25641
25642  function objectValue(value, index) {
25643    // If `valueOf` is a valid function use that
25644    if (typeof value.valueOf === 'function') {
25645      value = value.valueOf();
25646      if (isPrimitive(value)) return value;
25647    }
25648    // If `toString` is a valid function and not the one from `Object.prototype` use that
25649    if (hasCustomToString(value)) {
25650      value = value.toString();
25651      if (isPrimitive(value)) return value;
25652    }
25653    // We have a basic object so we use the position of the object in the collection
25654    return index;
25655  }
25656
25657  function getPredicateValue(value, index) {
25658    var type = typeof value;
25659    if (value === null) {
25660      type = 'string';
25661      value = 'null';
25662    } else if (type === 'string') {
25663      value = value.toLowerCase();
25664    } else if (type === 'object') {
25665      value = objectValue(value, index);
25666    }
25667    return { value: value, type: type };
25668  }
25669
25670  function compare(v1, v2) {
25671    var result = 0;
25672    if (v1.type === v2.type) {
25673      if (v1.value !== v2.value) {
25674        result = v1.value < v2.value ? -1 : 1;
25675      }
25676    } else {
25677      result = v1.type < v2.type ? -1 : 1;
25678    }
25679    return result;
25680  }
25681}
25682
25683function ngDirective(directive) {
25684  if (isFunction(directive)) {
25685    directive = {
25686      link: directive
25687    };
25688  }
25689  directive.restrict = directive.restrict || 'AC';
25690  return valueFn(directive);
25691}
25692
25693/**
25694 * @ngdoc directive
25695 * @name a
25696 * @restrict E
25697 *
25698 * @description
25699 * Modifies the default behavior of the html A tag so that the default action is prevented when
25700 * the href attribute is empty.
25701 *
25702 * This change permits the easy creation of action links with the `ngClick` directive
25703 * without changing the location or causing page reloads, e.g.:
25704 * `<a href="" ng-click="list.addItem()">Add Item</a>`
25705 */
25706var htmlAnchorDirective = valueFn({
25707  restrict: 'E',
25708  compile: function(element, attr) {
25709    if (!attr.href && !attr.xlinkHref) {
25710      return function(scope, element) {
25711        // If the linked element is not an anchor tag anymore, do nothing
25712        if (element[0].nodeName.toLowerCase() !== 'a') return;
25713
25714        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
25715        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
25716                   'xlink:href' : 'href';
25717        element.on('click', function(event) {
25718          // if we have no href url, then don't navigate anywhere.
25719          if (!element.attr(href)) {
25720            event.preventDefault();
25721          }
25722        });
25723      };
25724    }
25725  }
25726});
25727
25728/**
25729 * @ngdoc directive
25730 * @name ngHref
25731 * @restrict A
25732 * @priority 99
25733 *
25734 * @description
25735 * Using Angular markup like `{{hash}}` in an href attribute will
25736 * make the link go to the wrong URL if the user clicks it before
25737 * Angular has a chance to replace the `{{hash}}` markup with its
25738 * value. Until Angular replaces the markup the link will be broken
25739 * and will most likely return a 404 error. The `ngHref` directive
25740 * solves this problem.
25741 *
25742 * The wrong way to write it:
25743 * ```html
25744 * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
25745 * ```
25746 *
25747 * The correct way to write it:
25748 * ```html
25749 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
25750 * ```
25751 *
25752 * @element A
25753 * @param {template} ngHref any string which can contain `{{}}` markup.
25754 *
25755 * @example
25756 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
25757 * in links and their different behaviors:
25758    <example>
25759      <file name="index.html">
25760        <input ng-model="value" /><br />
25761        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
25762        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
25763        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
25764        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
25765        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
25766        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
25767      </file>
25768      <file name="protractor.js" type="protractor">
25769        it('should execute ng-click but not reload when href without value', function() {
25770          element(by.id('link-1')).click();
25771          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
25772          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
25773        });
25774
25775        it('should execute ng-click but not reload when href empty string', function() {
25776          element(by.id('link-2')).click();
25777          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
25778          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
25779        });
25780
25781        it('should execute ng-click and change url when ng-href specified', function() {
25782          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
25783
25784          element(by.id('link-3')).click();
25785
25786          // At this point, we navigate away from an Angular page, so we need
25787          // to use browser.driver to get the base webdriver.
25788
25789          browser.wait(function() {
25790            return browser.driver.getCurrentUrl().then(function(url) {
25791              return url.match(/\/123$/);
25792            });
25793          }, 5000, 'page should navigate to /123');
25794        });
25795
25796        it('should execute ng-click but not reload when href empty string and name specified', function() {
25797          element(by.id('link-4')).click();
25798          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
25799          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
25800        });
25801
25802        it('should execute ng-click but not reload when no href but name specified', function() {
25803          element(by.id('link-5')).click();
25804          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
25805          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
25806        });
25807
25808        it('should only change url when only ng-href', function() {
25809          element(by.model('value')).clear();
25810          element(by.model('value')).sendKeys('6');
25811          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
25812
25813          element(by.id('link-6')).click();
25814
25815          // At this point, we navigate away from an Angular page, so we need
25816          // to use browser.driver to get the base webdriver.
25817          browser.wait(function() {
25818            return browser.driver.getCurrentUrl().then(function(url) {
25819              return url.match(/\/6$/);
25820            });
25821          }, 5000, 'page should navigate to /6');
25822        });
25823      </file>
25824    </example>
25825 */
25826
25827/**
25828 * @ngdoc directive
25829 * @name ngSrc
25830 * @restrict A
25831 * @priority 99
25832 *
25833 * @description
25834 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
25835 * work right: The browser will fetch from the URL with the literal
25836 * text `{{hash}}` until Angular replaces the expression inside
25837 * `{{hash}}`. The `ngSrc` directive solves this problem.
25838 *
25839 * The buggy way to write it:
25840 * ```html
25841 * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
25842 * ```
25843 *
25844 * The correct way to write it:
25845 * ```html
25846 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
25847 * ```
25848 *
25849 * @element IMG
25850 * @param {template} ngSrc any string which can contain `{{}}` markup.
25851 */
25852
25853/**
25854 * @ngdoc directive
25855 * @name ngSrcset
25856 * @restrict A
25857 * @priority 99
25858 *
25859 * @description
25860 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
25861 * work right: The browser will fetch from the URL with the literal
25862 * text `{{hash}}` until Angular replaces the expression inside
25863 * `{{hash}}`. The `ngSrcset` directive solves this problem.
25864 *
25865 * The buggy way to write it:
25866 * ```html
25867 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
25868 * ```
25869 *
25870 * The correct way to write it:
25871 * ```html
25872 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
25873 * ```
25874 *
25875 * @element IMG
25876 * @param {template} ngSrcset any string which can contain `{{}}` markup.
25877 */
25878
25879/**
25880 * @ngdoc directive
25881 * @name ngDisabled
25882 * @restrict A
25883 * @priority 100
25884 *
25885 * @description
25886 *
25887 * This directive sets the `disabled` attribute on the element if the
25888 * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
25889 *
25890 * A special directive is necessary because we cannot use interpolation inside the `disabled`
25891 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
25892 *
25893 * @example
25894    <example>
25895      <file name="index.html">
25896        <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
25897        <button ng-model="button" ng-disabled="checked">Button</button>
25898      </file>
25899      <file name="protractor.js" type="protractor">
25900        it('should toggle button', function() {
25901          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
25902          element(by.model('checked')).click();
25903          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
25904        });
25905      </file>
25906    </example>
25907 *
25908 * @element INPUT
25909 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
25910 *     then the `disabled` attribute will be set on the element
25911 */
25912
25913
25914/**
25915 * @ngdoc directive
25916 * @name ngChecked
25917 * @restrict A
25918 * @priority 100
25919 *
25920 * @description
25921 * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
25922 *
25923 * Note that this directive should not be used together with {@link ngModel `ngModel`},
25924 * as this can lead to unexpected behavior.
25925 *
25926 * A special directive is necessary because we cannot use interpolation inside the `checked`
25927 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
25928 *
25929 * @example
25930    <example>
25931      <file name="index.html">
25932        <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
25933        <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
25934      </file>
25935      <file name="protractor.js" type="protractor">
25936        it('should check both checkBoxes', function() {
25937          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
25938          element(by.model('master')).click();
25939          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
25940        });
25941      </file>
25942    </example>
25943 *
25944 * @element INPUT
25945 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
25946 *     then the `checked` attribute will be set on the element
25947 */
25948
25949
25950/**
25951 * @ngdoc directive
25952 * @name ngReadonly
25953 * @restrict A
25954 * @priority 100
25955 *
25956 * @description
25957 *
25958 * Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
25959 *
25960 * A special directive is necessary because we cannot use interpolation inside the `readOnly`
25961 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
25962 *
25963 * @example
25964    <example>
25965      <file name="index.html">
25966        <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
25967        <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
25968      </file>
25969      <file name="protractor.js" type="protractor">
25970        it('should toggle readonly attr', function() {
25971          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
25972          element(by.model('checked')).click();
25973          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
25974        });
25975      </file>
25976    </example>
25977 *
25978 * @element INPUT
25979 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
25980 *     then special attribute "readonly" will be set on the element
25981 */
25982
25983
25984/**
25985 * @ngdoc directive
25986 * @name ngSelected
25987 * @restrict A
25988 * @priority 100
25989 *
25990 * @description
25991 *
25992 * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
25993 *
25994 * A special directive is necessary because we cannot use interpolation inside the `selected`
25995 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
25996 *
25997 * @example
25998    <example>
25999      <file name="index.html">
26000        <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
26001        <select aria-label="ngSelected demo">
26002          <option>Hello!</option>
26003          <option id="greet" ng-selected="selected">Greetings!</option>
26004        </select>
26005      </file>
26006      <file name="protractor.js" type="protractor">
26007        it('should select Greetings!', function() {
26008          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
26009          element(by.model('selected')).click();
26010          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
26011        });
26012      </file>
26013    </example>
26014 *
26015 * @element OPTION
26016 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
26017 *     then special attribute "selected" will be set on the element
26018 */
26019
26020/**
26021 * @ngdoc directive
26022 * @name ngOpen
26023 * @restrict A
26024 * @priority 100
26025 *
26026 * @description
26027 *
26028 * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
26029 *
26030 * A special directive is necessary because we cannot use interpolation inside the `open`
26031 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
26032 *
26033 * @example
26034     <example>
26035       <file name="index.html">
26036         <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
26037         <details id="details" ng-open="open">
26038            <summary>Show/Hide me</summary>
26039         </details>
26040       </file>
26041       <file name="protractor.js" type="protractor">
26042         it('should toggle open', function() {
26043           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
26044           element(by.model('open')).click();
26045           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
26046         });
26047       </file>
26048     </example>
26049 *
26050 * @element DETAILS
26051 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
26052 *     then special attribute "open" will be set on the element
26053 */
26054
26055var ngAttributeAliasDirectives = {};
26056
26057// boolean attrs are evaluated
26058forEach(BOOLEAN_ATTR, function(propName, attrName) {
26059  // binding to multiple is not supported
26060  if (propName == "multiple") return;
26061
26062  function defaultLinkFn(scope, element, attr) {
26063    scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
26064      attr.$set(attrName, !!value);
26065    });
26066  }
26067
26068  var normalized = directiveNormalize('ng-' + attrName);
26069  var linkFn = defaultLinkFn;
26070
26071  if (propName === 'checked') {
26072    linkFn = function(scope, element, attr) {
26073      // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
26074      if (attr.ngModel !== attr[normalized]) {
26075        defaultLinkFn(scope, element, attr);
26076      }
26077    };
26078  }
26079
26080  ngAttributeAliasDirectives[normalized] = function() {
26081    return {
26082      restrict: 'A',
26083      priority: 100,
26084      link: linkFn
26085    };
26086  };
26087});
26088
26089// aliased input attrs are evaluated
26090forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
26091  ngAttributeAliasDirectives[ngAttr] = function() {
26092    return {
26093      priority: 100,
26094      link: function(scope, element, attr) {
26095        //special case ngPattern when a literal regular expression value
26096        //is used as the expression (this way we don't have to watch anything).
26097        if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
26098          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
26099          if (match) {
26100            attr.$set("ngPattern", new RegExp(match[1], match[2]));
26101            return;
26102          }
26103        }
26104
26105        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
26106          attr.$set(ngAttr, value);
26107        });
26108      }
26109    };
26110  };
26111});
26112
26113// ng-src, ng-srcset, ng-href are interpolated
26114forEach(['src', 'srcset', 'href'], function(attrName) {
26115  var normalized = directiveNormalize('ng-' + attrName);
26116  ngAttributeAliasDirectives[normalized] = function() {
26117    return {
26118      priority: 99, // it needs to run after the attributes are interpolated
26119      link: function(scope, element, attr) {
26120        var propName = attrName,
26121            name = attrName;
26122
26123        if (attrName === 'href' &&
26124            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
26125          name = 'xlinkHref';
26126          attr.$attr[name] = 'xlink:href';
26127          propName = null;
26128        }
26129
26130        attr.$observe(normalized, function(value) {
26131          if (!value) {
26132            if (attrName === 'href') {
26133              attr.$set(name, null);
26134            }
26135            return;
26136          }
26137
26138          attr.$set(name, value);
26139
26140          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
26141          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
26142          // to set the property as well to achieve the desired effect.
26143          // we use attr[attrName] value since $set can sanitize the url.
26144          if (msie && propName) element.prop(propName, attr[name]);
26145        });
26146      }
26147    };
26148  };
26149});
26150
26151/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
26152 */
26153var nullFormCtrl = {
26154  $addControl: noop,
26155  $$renameControl: nullFormRenameControl,
26156  $removeControl: noop,
26157  $setValidity: noop,
26158  $setDirty: noop,
26159  $setPristine: noop,
26160  $setSubmitted: noop
26161},
26162SUBMITTED_CLASS = 'ng-submitted';
26163
26164function nullFormRenameControl(control, name) {
26165  control.$name = name;
26166}
26167
26168/**
26169 * @ngdoc type
26170 * @name form.FormController
26171 *
26172 * @property {boolean} $pristine True if user has not interacted with the form yet.
26173 * @property {boolean} $dirty True if user has already interacted with the form.
26174 * @property {boolean} $valid True if all of the containing forms and controls are valid.
26175 * @property {boolean} $invalid True if at least one containing control or form is invali
26175d.
26176 * @property {boolean} $pending True if at least one containing control or form is pending.
26177 * @property {boolean} $submitted True if user has submitted the form even if its invalid.
26178 *
26179 * @property {Object} $error Is an object hash, containing references to controls or
26180 *  forms with failing validators, where:
26181 *
26182 *  - keys are validation tokens (error names),
26183 *  - values are arrays of controls or forms that have a failing validator for given error name.
26184 *
26185 *  Built-in validation tokens:
26186 *
26187 *  - `email`
26188 *  - `max`
26189 *  - `maxlength`
26190 *  - `min`
26191 *  - `minlength`
26192 *  - `number`
26193 *  - `pattern`
26194 *  - `required`
26195 *  - `url`
26196 *  - `date`
26197 *  - `datetimelocal`
26198 *  - `time`
26199 *  - `week`
26200 *  - `month`
26201 *
26202 * @description
26203 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
26204 * such as being valid/invalid or dirty/pristine.
26205 *
26206 * Each {@link ng.directive:form form} directive creates an instance
26207 * of `FormController`.
26208 *
26209 */
26210//asks for $scope to fool the BC controller module
26211FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
26212function FormController(element, attrs, $scope, $animate, $interpolate) {
26213  var form = this,
26214      controls = [];
26215
26216  // init state
26217  form.$error = {};
26218  form.$$success = {};
26219  form.$pending = undefined;
26220  form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
26221  form.$dirty = false;
26222  form.$pristine = true;
26223  form.$valid = true;
26224  form.$invalid = false;
26225  form.$submitted = false;
26226  form.$$parentForm = nullFormCtrl;
26227
26228  /**
26229   * @ngdoc method
26230   * @name form.FormController#$rollbackViewValue
26231   *
26232   * @description
26233   * Rollback all form controls pending updates to the `$modelValue`.
26234   *
26235   * Updates may be pending by a debounced event or because the input is waiting for a some future
26236   * event defined in `ng-model-options`. This method is typically needed by the reset button of
26237   * a form that uses `ng-model-options` to pend updates.
26238   */
26239  form.$rollbackViewValue = function() {
26240    forEach(controls, function(control) {
26241      control.$rollbackViewValue();
26242    });
26243  };
26244
26245  /**
26246   * @ngdoc method
26247   * @name form.FormController#$commitViewValue
26248   *
26249   * @description
26250   * Commit all form controls pending updates to the `$modelValue`.
26251   *
26252   * Updates may be pending by a debounced event or because the input is waiting for a some future
26253   * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
26254   * usually handles calling this in response to input events.
26255   */
26256  form.$commitViewValue = function() {
26257    forEach(controls, function(control) {
26258      control.$commitViewValue();
26259    });
26260  };
26261
26262  /**
26263   * @ngdoc method
26264   * @name form.FormController#$addControl
26265   * @param {object} control control object, either a {@link form.FormController} or an
26266   * {@link ngModel.NgModelController}
26267   *
26268   * @description
26269   * Register a control with the form. Input elements using ngModelController do this automatically
26270   * when they are linked.
26271   *
26272   * Note that the current state of the control will not be reflected on the new parent form. This
26273   * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
26274   * state.
26275   *
26276   * However, if the method is used programmatically, for example by adding dynamically created controls,
26277   * or controls that have been previously removed without destroying their corresponding DOM element,
26278   * it's the developers responsibility to make sure the current state propagates to the parent form.
26279   *
26280   * For example, if an input control is added that is already `$dirty` and has `$error` properties,
26281   * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
26282   */
26283  form.$addControl = function(control) {
26284    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
26285    // and not added to the scope.  Now we throw an error.
26286    assertNotHasOwnProperty(control.$name, 'input');
26287    controls.push(control);
26288
26289    if (control.$name) {
26290      form[control.$name] = control;
26291    }
26292
26293    control.$$parentForm = form;
26294  };
26295
26296  // Private API: rename a form control
26297  form.$$renameControl = function(control, newName) {
26298    var oldName = control.$name;
26299
26300    if (form[oldName] === control) {
26301      delete form[oldName];
26302    }
26303    form[newName] = control;
26304    control.$name = newName;
26305  };
26306
26307  /**
26308   * @ngdoc method
26309   * @name form.FormController#$removeControl
26310   * @param {object} control control object, either a {@link form.FormController} or an
26311   * {@link ngModel.NgModelController}
26312   *
26313   * @description
26314   * Deregister a control from the form.
26315   *
26316   * Input elements using ngModelController do this automatically when they are destroyed.
26317   *
26318   * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
26319   * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
26320   * different from case to case. For example, removing the only `$dirty` control from a form may or
26321   * may not mean that the form is still `$dirty`.
26322   */
26323  form.$removeControl = function(control) {
26324    if (control.$name && form[control.$name] === control) {
26325      delete form[control.$name];
26326    }
26327    forEach(form.$pending, function(value, name) {
26328      form.$setValidity(name, null, control);
26329    });
26330    forEach(form.$error, function(value, name) {
26331      form.$setValidity(name, null, control);
26332    });
26333    forEach(form.$$success, function(value, name) {
26334      form.$setValidity(name, null, control);
26335    });
26336
26337    arrayRemove(controls, control);
26338    control.$$parentForm = nullFormCtrl;
26339  };
26340
26341
26342  /**
26343   * @ngdoc method
26344   * @name form.FormController#$setValidity
26345   *
26346   * @description
26347   * Sets the validity of a form control.
26348   *
26349   * This method will also propagate to parent forms.
26350   */
26351  addSetValidityMethod({
26352    ctrl: this,
26353    $element: element,
26354    set: function(object, property, controller) {
26355      var list = object[property];
26356      if (!list) {
26357        object[property] = [controller];
26358      } else {
26359        var index = list.indexOf(controller);
26360        if (index === -1) {
26361          list.push(controller);
26362        }
26363      }
26364    },
26365    unset: function(object, property, controller) {
26366      var list = object[property];
26367      if (!list) {
26368        return;
26369      }
26370      arrayRemove(list, controller);
26371      if (list.length === 0) {
26372        delete object[property];
26373      }
26374    },
26375    $animate: $animate
26376  });
26377
26378  /**
26379   * @ngdoc method
26380   * @name form.FormController#$setDirty
26381   *
26382   * @description
26383   * Sets the form to a dirty state.
26384   *
26385   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
26386   * state (ng-dirty class). This method will also propagate to parent forms.
26387   */
26388  form.$setDirty = function() {
26389    $animate.removeClass(element, PRISTINE_CLASS);
26390    $animate.addClass(element, DIRTY_CLASS);
26391    form.$dirty = true;
26392    form.$pristine = false;
26393    form.$$parentForm.$setDirty();
26394  };
26395
26396  /**
26397   * @ngdoc method
26398   * @name form.FormController#$setPristine
26399   *
26400   * @description
26401   * Sets the form to its pristine state.
26402   *
26403   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
26404   * state (ng-pristine class). This method will also propagate to all the controls contained
26405   * in this form.
26406   *
26407   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
26408   * saving or resetting it.
26409   */
26410  form.$setPristine = function() {
26411    $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
26412    form.$dirty = false;
26413    form.$pristine = true;
26414    form.$submitted = false;
26415    forEach(controls, function(control) {
26416      control.$setPristine();
26417    });
26418  };
26419
26420  /**
26421   * @ngdoc method
26422   * @name form.FormController#$setUntouched
26423   *
26424   * @description
26425   * Sets the form to its untouched state.
26426   *
26427   * This method can be called to remove the 'ng-touched' class and set the form controls to their
26428   * untouched state (ng-untouched class).
26429   *
26430   * Setting a form controls back to their untouched state is often useful when setting the form
26431   * back to its pristine state.
26432   */
26433  form.$setUntouched = function() {
26434    forEach(controls, function(control) {
26435      control.$setUntouched();
26436    });
26437  };
26438
26439  /**
26440   * @ngdoc method
26441   * @name form.FormController#$setSubmitted
26442   *
26443   * @description
26444   * Sets the form to its submitted state.
26445   */
26446  form.$setSubmitted = function() {
26447    $animate.addClass(element, SUBMITTED_CLASS);
26448    form.$submitted = true;
26449    form.$$parentForm.$setSubmitted();
26450  };
26451}
26452
26453/**
26454 * @ngdoc directive
26455 * @name ngForm
26456 * @restrict EAC
26457 *
26458 * @description
26459 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
26460 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
26461 * sub-group of controls needs to be determined.
26462 *
26463 * Note: the purpose of `ngForm` is to group controls,
26464 * but not to be a replacement for the `<form>` tag with all of its capabilities
26465 * (e.g. posting to the server, ...).
26466 *
26467 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
26468 *                       related scope, under this name.
26469 *
26470 */
26471
26472 /**
26473 * @ngdoc directive
26474 * @name form
26475 * @restrict E
26476 *
26477 * @description
26478 * Directive that instantiates
26479 * {@link form.FormController FormController}.
26480 *
26481 * If the `name` attribute is specified, the form controller is published onto the current scope under
26482 * this name.
26483 *
26484 * # Alias: {@link ng.directive:ngForm `ngForm`}
26485 *
26486 * In Angular, forms can be nested. This means that the outer form is valid when all of the child
26487 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
26488 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
26489 * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
26490 * of controls needs to be determined.
26491 *
26492 * # CSS classes
26493 *  - `ng-valid` is set if the form is valid.
26494 *  - `ng-invalid` is set if the form is invalid.
26495 *  - `ng-pending` is set if the form is pending.
26496 *  - `ng-pristine` is set if the form is pristine.
26497 *  - `ng-dirty` is set if the form is dirty.
26498 *  - `ng-submitted` is set if the form was submitted.
26499 *
26500 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
26501 *
26502 *
26503 * # Submitting a form and preventing the default action
26504 *
26505 * Since the role of forms in client-side Angular applications is different than in classical
26506 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
26507 * page reload that sends the data to the server. Instead some javascript logic should be triggered
26508 * to handle the form submission in an application-specific way.
26509 *
26510 * For this reason, Angular prevents the default action (form submission to the server) unless the
26511 * `<form>` element has an `action` attribute specified.
26512 *
26513 * You can use one of the following two ways to specify what javascript method should be called when
26514 * a form is submitted:
26515 *
26516 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
26517 * - {@link ng.directive:ngClick ngClick} directive on the first
26518  *  button or input field of type submit (input[type=submit])
26519 *
26520 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
26521 * or {@link ng.directive:ngClick ngClick} directives.
26522 * This is because of the following form submission rules in the HTML specification:
26523 *
26524 * - If a form has only one input field then hitting enter in this field triggers form submit
26525 * (`ngSubmit`)
26526 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
26527 * doesn't trigger submit
26528 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
26529 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
26530 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
26531 *
26532 * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
26533 * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
26534 * to have access to the updated model.
26535 *
26536 * ## Animation Hooks
26537 *
26538 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
26539 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
26540 * other validations that are performed within the form. Animations in ngForm are similar to how
26541 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
26542 * as JS animations.
26543 *
26544 * The following example shows a simple way to utilize CSS transitions to style a form element
26545 * that has been rendered as invalid after it has been validated:
26546 *
26547 * <pre>
26548 * //be sure to include ngAnimate as a module to hook into more
26549 * //advanced animations
26550 * .my-form {
26551 *   transition:0.5s linear all;
26552 *   background: white;
26553 * }
26554 * .my-form.ng-invalid {
26555 *   background: red;
26556 *   color:white;
26557 * }
26558 * </pre>
26559 *
26560 * @example
26561    <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
26562      <file name="index.html">
26563       <script>
26564         angular.module('formExample', [])
26565           .controller('FormController', ['$scope', function($scope) {
26566             $scope.userType = 'guest';
26567           }]);
26568       </script>
26569       <style>
26570        .my-form {
26571          transition:all linear 0.5s;
26572          background: transparent;
26573        }
26574        .my-form.ng-invalid {
26575          background: red;
26576        }
26577       </style>
26578       <form name="myForm" ng-controller="FormController" class="my-form">
26579         userType: <input name="input" ng-model="userType" required>
26580         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
26581         <code>userType = {{userType}}</code><br>
26582         <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
26583         <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
26584         <code>myForm.$valid = {{myForm.$valid}}</code><br>
26585         <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
26586        </form>
26587      </file>
26588      <file name="protractor.js" type="protractor">
26589        it('should initialize to model', function() {
26590          var userType = element(by.binding('userType'));
26591          var valid = element(by.binding('myForm.input.$valid'));
26592
26593          expect(userType.getText()).toContain('guest');
26594          expect(valid.getText()).toContain('true');
26595        });
26596
26597        it('should be invalid if empty', function() {
26598          var userType = element(by.binding('userType'));
26599          var valid = element(by.binding('myForm.input.$valid'));
26600          var userInput = element(by.model('userType'));
26601
26602          userInput.clear();
26603          userInput.sendKeys('');
26604
26605          expect(userType.getText()).toEqual('userType =');
26606          expect(valid.getText()).toContain('false');
26607        });
26608      </file>
26609    </example>
26610 *
26611 * @param {string=} name Name of the form. If specified, the form controller will be published into
26612 *                       related scope, under this name.
26613 */
26614var formDirectiveFactory = function(isNgForm) {
26615  return ['$timeout', '$parse', function($timeout, $parse) {
26616    var formDirective = {
26617      name: 'form',
26618      restrict: isNgForm ? 'EAC' : 'E',
26619      require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
26620      controller: FormController,
26621      compile: function ngFormCompile(formElement, attr) {
26622        // Setup initial state of the control
26623        formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
26624
26625        var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
26626
26627        return {
26628          pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
26629            var controller = ctrls[0];
26630
26631            // if `action` attr is not present on the form, prevent the default action (submission)
26632            if (!('action' in attr)) {
26633              // we can't use jq events because if a form is destroyed during submission the default
26634              // action is not prevented. see #1238
26635              //
26636              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
26637              // page reload if the form was destroyed by submission of the form via a click handler
26638              // on a button in the form. Looks like an IE9 specific bug.
26639              var handleFormSubmission = function(event) {
26640                scope.$apply(function() {
26641                  controller.$commitViewValue();
26642                  controller.$setSubmitted();
26643                });
26644
26645                event.preventDefault();
26646              };
26647
26648              addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
26649
26650              // unregister the preventDefault listener so that we don't not leak memory but in a
26651              // way that will achieve the prevention of the default action.
26652              formElement.on('$destroy', function() {
26653                $timeout(function() {
26654                  removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
26655                }, 0, false);
26656              });
26657            }
26658
26659            var parentFormCtrl = ctrls[1] || controller.$$parentForm;
26660            parentFormCtrl.$addControl(controller);
26661
26662            var setter = nameAttr ? getSetter(controller.$name) : noop;
26663
26664            if (nameAttr) {
26665              setter(scope, controller);
26666              attr.$observe(nameAttr, function(newValue) {
26667                if (controller.$name === newValue) return;
26668                setter(scope, undefined);
26669                controller.$$parentForm.$$renameControl(controller, newValue);
26670                setter = getSetter(controller.$name);
26671                setter(scope, controller);
26672              });
26673            }
26674            formElement.on('$destroy', function() {
26675              controller.$$parentForm.$removeControl(controller);
26676              setter(scope, undefined);
26677              extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
26678            });
26679          }
26680        };
26681      }
26682    };
26683
26684    return formDirective;
26685
26686    function getSetter(expression) {
26687      if (expression === '') {
26688        //create an assignable expression, so forms with an empty name can be renamed later
26689        return $parse('this[""]').assign;
26690      }
26691      return $parse(expression).assign || noop;
26692    }
26693  }];
26694};
26695
26696var formDirective = formDirectiveFactory();
26697var ngFormDirective = formDirectiveFactory(true);
26698
26699/* global VALID_CLASS: false,
26700  INVALID_CLASS: false,
26701  PRISTINE_CLASS: false,
26702  DIRTY_CLASS: false,
26703  UNTOUCHED_CLASS: false,
26704  TOUCHED_CLASS: false,
26705  ngModelMinErr: false,
26706*/
26707
26708// Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
26709var 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)$/;
26710// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
26711// Note: We are being more lenient, because browsers are too.
26712//   1. Scheme
26713//   2. Slashes
26714//   3. Username
26715//   4. Password
26716//   5. Hostname
26717//   6. Port
26718//   7. Path
26719//   8. Query
26720//   9. Fragment
26721//                 1111111111111111 222   333333    44444        555555555555555555555555    666     77777777     8888888     999
26722var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
26723var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
26724var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
26725var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
26726var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
26727var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
26728var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
26729var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
26730
26731var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
26732var PARTIAL_VALIDATION_TYPES = createMap();
26733forEach('date,datetime-local,month,time,week'.split(','), function(type) {
26734  PARTIAL_VALIDATION_TYPES[type] = true;
26735});
26736
26737var inputType = {
26738
26739  /**
26740   * @ngdoc input
26741   * @name input[text]
26742   *
26743   * @description
26744   * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
26745   *
26746   *
26747   * @param {string} ngModel Assignable angular expression to data-bind to.
26748   * @param {string=} name Property name of the form under which the control is published.
26749   * @param {string=} required Adds `required` validation error key if the value is not entered.
26750   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26751   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26752   *    `required` when you want to data-bind to the `required` attribute.
26753   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
26754   *    minlength.
26755   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
26756   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
26757   *    any length.
26758   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
26759   *    that contains the regular expression body that will be converted to a regular expression
26760   *    as in the ngPattern directive.
26761   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
26762   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
26763   *    If the expression evaluates to a RegExp object, then this is used directly.
26764   *    If the expression evaluates to a string, then it will be converted to a RegExp
26765   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
26766   *    `new RegExp('^abc$')`.<br />
26767   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
26768   *    start at the index of the last search's match, thus not taking the whole input value into
26769   *    account.
26770   * @param {string=} ngChange Angular expression to be executed when input changes due to user
26771   *    interaction with the input element.
26772   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
26773   *    This parameter is ignored for input[type=password] controls, which will never trim the
26774   *    input.
26775   *
26776   * @example
26777      <example name="text-input-directive" module="textInputExample">
26778        <file name="index.html">
26779         <script>
26780           angular.module('textInputExample', [])
26781             .controller('ExampleController', ['$scope', function($scope) {
26782               $scope.example = {
26783                 text: 'guest',
26784                 word: /^\s*\w*\s*$/
26785               };
26786             }]);
26787         </script>
26788         <form name="myForm" ng-controller="ExampleController">
26789           <label>Single word:
26790             <input type="text" name="input" ng-model="example.text"
26791                    ng-pattern="example.word" required ng-trim="false">
26792           </label>
26793           <div role="alert">
26794             <span class="error" ng-show="myForm.input.$error.required">
26795               Required!</span>
26796             <span class="error" ng-show="myForm.input.$error.pattern">
26797               Single word only!</span>
26798           </div>
26799           <tt>text = {{example.text}}</tt><br/>
26800           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
26801           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
26802           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
26803           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
26804          </form>
26805        </file>
26806        <file name="protractor.js" type="protractor">
26807          var text = element(by.binding('example.text'));
26808          var valid = element(by.binding('myForm.input.$valid'));
26809          var input = element(by.model('example.text'));
26810
26811          it('should initialize to model', function() {
26812            expect(text.getText()).toContain('guest');
26813            expect(valid.getText()).toContain('true');
26814          });
26815
26816          it('should be invalid if empty', function() {
26817            input.clear();
26818            input.sendKeys('');
26819
26820            expect(text.getText()).toEqual('text =');
26821            expect(valid.getText()).toContain('false');
26822          });
26823
26824          it('should be invalid if multi word', function() {
26825            input.clear();
26826            input.sendKeys('hello world');
26827
26828            expect(valid.getText()).toContain('false');
26829          });
26830        </file>
26831      </example>
26832   */
26833  'text': textInputType,
26834
26835    /**
26836     * @ngdoc input
26837     * @name input[date]
26838     *
26839     * @description
26840     * Input with date validation and transformation. In browsers that do not yet support
26841     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
26842     * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
26843     * modern browsers do not yet support this input type, it is important to provide cues to users on the
26844     * expected input format via a placeholder or label.
26845     *
26846     * The model must always be a Date object, otherwise Angular will throw an error.
26847     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
26848     *
26849     * The timezone to be used to read/write the `Date` instance in the model can be defined using
26850     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
26851     *
26852     * @param {string} ngModel Assignable angular expression to data-bind to.
26853     * @param {string=} name Property name of the form under which the control is published.
26854     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
26855     *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
26856     *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
26857     *   constraint validation.
26858     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
26859     *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
26860     *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
26861     *   constraint validation.
26862     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
26863     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
26864     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
26865     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
26866     * @param {string=} required Sets `required` validation error key if the value is not entered.
26867     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26868     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26869     *    `required` when you want to data-bind to the `required` attribute.
26870     * @param {string=} ngChange Angular expression to be executed when input changes due to user
26871     *    interaction with the input element.
26872     *
26873     * @example
26874     <example name="date-input-directive" module="dateInputExample">
26875     <file name="index.html">
26876       <script>
26877          angular.module('dateInputExample', [])
26878            .controller('DateController', ['$scope', function($scope) {
26879              $scope.example = {
26880                value: new Date(2013, 9, 22)
26881              };
26882            }]);
26883       </script>
26884       <form name="myForm" ng-controller="DateController as dateCtrl">
26885          <label for="exampleInput">Pick a date in 2013:</label>
26886          <input type="date" id="exampleInput" name="input" ng-model="example.value"
26887              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
26888          <div role="alert">
26889            <span class="error" ng-show="myForm.input.$error.required">
26890                Required!</span>
26891            <span class="error" ng-show="myForm.input.$error.date">
26892                Not a valid date!</span>
26893           </div>
26894           <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
26895           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
26896           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
26897           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
26898           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
26899       </form>
26900     </file>
26901     <file name="protractor.js" type="protractor">
26902        var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
26903        var valid = element(by.binding('myForm.input.$valid'));
26904        var input = element(by.model('example.value'));
26905
26906        // currently protractor/webdriver does not support
26907        // sending keys to all known HTML5 input controls
26908        // for various browsers (see https://github.com/angular/protractor/issues/562).
26909        function setInput(val) {
26910          // set the value of the element and force validation.
26911          var scr = "var ipt = document.getElementById('exampleInput'); " +
26912          "ipt.value = '" + val + "';" +
26913          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
26914          browser.executeScript(scr);
26915        }
26916
26917        it('should initialize to model', function() {
26918          expect(value.getText()).toContain('2013-10-22');
26919          expect(valid.getText()).toContain('myForm.input.$valid = true');
26920        });
26921
26922        it('should be invalid if empty', function() {
26923          setInput('');
26924          expect(value.getText()).toEqual('value =');
26925          expect(valid.getText()).toContain('myForm.input.$valid = false');
26926        });
26927
26928        it('should be invalid if over max', function() {
26929          setInput('2015-01-01');
26930          expect(value.getText()).toContain('');
26931          expect(valid.getText()).toContain('myForm.input.$valid = false');
26932        });
26933     </file>
26934     </example>
26935     */
26936  'date': createDateInputType('date', DATE_REGEXP,
26937         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
26938         'yyyy-MM-dd'),
26939
26940   /**
26941    * @ngdoc input
26942    * @name input[datetime-local]
26943    *
26944    * @description
26945    * Input with datetime validation and transformation. In browsers that do not yet support
26946    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
26947    * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
26948    *
26949    * The model must always be a Date object, otherwise Angular will throw an error.
26950    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
26951    *
26952    * The timezone to be used to read/write the `Date` instance in the model can be defined using
26953    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
26954    *
26955    * @param {string} ngModel Assignable angular expression to data-bind to.
26956    * @param {string=} name Property name of the form under which the control is published.
26957    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
26958    *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
26959    *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
26960    *   Note that `min` will also add native HTML5 constraint validation.
26961    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
26962    *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
26963    *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
26964    *   Note that `max` will also add native HTML5 constraint validation.
26965    * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
26966    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
26967    * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
26968    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
26969    * @param {string=} required Sets `required` validation error key if the value is not entered.
26970    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
26971    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
26972    *    `required` when you want to data-bind to the `required` attribute.
26973    * @param {string=} ngChange Angular expression to be executed when input changes due to user
26974    *    interaction with the input element.
26975    *
26976    * @example
26977    <example name="datetimelocal-input-directive" module="dateExample">
26978    <file name="index.html">
26979      <script>
26980        angular.module('dateExample', [])
26981          .controller('DateController', ['$scope', function($scope) {
26982            $scope.example = {
26983              value: new Date(2010, 11, 28, 14, 57)
26984            };
26985          }]);
26986      </script>
26987      <form name="myForm" ng-controller="DateController as dateCtrl">
26988        <label for="exampleInput">Pick a date between in 2013:</label>
26989        <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
26990            placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
26991        <div role="alert">
26992          <span class="error" ng-show="myForm.input.$error.required">
26993              Required!</span>
26994          <span class="error" ng-show="myForm.input.$error.datetimelocal">
26995              Not a valid date!</span>
26996        </div>
26997        <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
26998        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
26999        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27000        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27001        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27002      </form>
27003    </file>
27004    <file name="protractor.js" type="protractor">
27005      var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
27006      var valid = element(by.binding('myForm.input.$valid'));
27007      var input = element(by.model('example.value'));
27008
27009      // currently protractor/webdriver does not support
27010      // sending keys to all known HTML5 input controls
27011      // for various browsers (https://github.com/angular/protractor/issues/562).
27012      function setInput(val) {
27013        // set the value of the element and force validation.
27014        var scr = "var ipt = document.getElementById('exampleInput'); " +
27015        "ipt.value = '" + val + "';" +
27016        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
27017        browser.executeScript(scr);
27018      }
27019
27020      it('should initialize to model', function() {
27021        expect(value.getText()).toContain('2010-12-28T14:57:00');
27022        expect(valid.getText()).toContain('myForm.input.$valid = true');
27023      });
27024
27025      it('should be invalid if empty', function() {
27026        setInput('');
27027        expect(value.getText()).toEqual('value =');
27028        expect(valid.getText()).toContain('myForm.input.$valid = false');
27029      });
27030
27031      it('should be invalid if over max', function() {
27032        setInput('2015-01-01T23:59:00');
27033        expect(value.getText()).toContain('');
27034        expect(valid.getText()).toContain('myForm.input.$valid = false');
27035      });
27036    </file>
27037    </example>
27038    */
27039  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
27040      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
27041      'yyyy-MM-ddTHH:mm:ss.sss'),
27042
27043  /**
27044   * @ngdoc input
27045   * @name input[time]
27046   *
27047   * @description
27048   * Input with time validation and transformation. In browsers that do not yet support
27049   * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
27050   * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
27051   * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
27052   *
27053   * The model must always be a Date object, otherwise Angular will throw an error.
27054   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
27055   *
27056   * The timezone to be used to read/write the `Date` instance in the model can be defined using
27057   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
27058   *
27059   * @param {string} ngModel Assignable angular expression to data-bind to.
27060   * @param {string=} name Property name of the form under which the control is published.
27061   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
27062   *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
27063   *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
27064   *   native HTML5 constraint validation.
27065   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
27066   *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
27067   *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
27068   *   native HTML5 constraint validation.
27069   * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
27070   *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
27071   * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
27072   *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
27073   * @param {string=} required Sets `required` validation error key if the value is not entered.
27074   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27075   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27076   *    `required` when you want to data-bind to the `required` attribute.
27077   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27078   *    interaction with the input element.
27079   *
27080   * @example
27081   <example name="time-input-directive" module="timeExample">
27082   <file name="index.html">
27083     <script>
27084      angular.module('timeExample', [])
27085        .controller('DateController', ['$scope', function($scope) {
27086          $scope.example = {
27087            value: new Date(1970, 0, 1, 14, 57, 0)
27088          };
27089        }]);
27090     </script>
27091     <form name="myForm" ng-controller="DateController as dateCtrl">
27092        <label for="exampleInput">Pick a between 8am and 5pm:</label>
27093        <input type="time" id="exampleInput" name="input" ng-model="example.value"
27094            placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
27095        <div role="alert">
27096          <span class="error" ng-show="myForm.input.$error.required">
27097              Required!</span>
27098          <span class="error" ng-show="myForm.input.$error.time">
27099              Not a valid date!</span>
27100        </div>
27101        <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
27102        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
27103        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27104        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27105        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27106     </form>
27107   </file>
27108   <file name="protractor.js" type="protractor">
27109      var value = element(by.binding('example.value | date: "HH:mm:ss"'));
27110      var valid = element(by.binding('myForm.input.$valid'));
27111      var input = element(by.model('example.value'));
27112
27113      // currently protractor/webdriver does not support
27114      // sending keys to all known HTML5 input controls
27115      // for various browsers (https://github.com/angular/protractor/issues/562).
27116      function setInput(val) {
27117        // set the value of the element and force validation.
27118        var scr = "var ipt = document.getElementById('exampleInput'); " +
27119        "ipt.value = '" + val + "';" +
27120        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
27121        browser.executeScript(scr);
27122      }
27123
27124      it('should initialize to model', function() {
27125        expect(value.getText()).toContain('14:57:00');
27126        expect(valid.getText()).toContain('myForm.input.$valid = true');
27127      });
27128
27129      it('should be invalid if empty', function() {
27130        setInput('');
27131        expect(value.getText()).toEqual('value =');
27132        expect(valid.getText()).toContain('myForm.input.$valid = false');
27133      });
27134
27135      it('should be invalid if over max', function() {
27136        setInput('23:59:00');
27137        expect(value.getText()).toContain('');
27138        expect(valid.getText()).toContain('myForm.input.$valid = false');
27139      });
27140   </file>
27141   </example>
27142   */
27143  'time': createDateInputType('time', TIME_REGEXP,
27144      createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
27145     'HH:mm:ss.sss'),
27146
27147   /**
27148    * @ngdoc input
27149    * @name input[week]
27150    *
27151    * @description
27152    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
27153    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
27154    * week format (yyyy-W##), for example: `2013-W02`.
27155    *
27156    * The model must always be a Date object, otherwise Angular will throw an error.
27157    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
27158    *
27159    * The timezone to be used to read/write the `Date` instance in the model can be defined using
27160    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
27161    *
27162    * @param {string} ngModel Assignable angular expression to data-bind to.
27163    * @param {string=} name Property name of the form under which the control is published.
27164    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
27165    *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
27166    *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
27167    *   native HTML5 constraint validation.
27168    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
27169    *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
27170    *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
27171    *   native HTML5 constraint validation.
27172    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
27173    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
27174    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
27175    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
27176    * @param {string=} required Sets `required` validation error key if the value is not entered.
27177    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27178    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27179    *    `required` when you want to data-bind to the `required` attribute.
27180    * @param {string=} ngChange Angular expression to be executed when input changes due to user
27181    *    interaction with the input element.
27182    *
27183    * @example
27184    <example name="week-input-directive" module="weekExample">
27185    <file name="index.html">
27186      <script>
27187      angular.module('weekExample', [])
27188        .controller('DateController', ['$scope', function($scope) {
27189          $scope.example = {
27190            value: new Date(2013, 0, 3)
27191          };
27192        }]);
27193      </script>
27194      <form name="myForm" ng-controller="DateController as dateCtrl">
27195        <label>Pick a date between in 2013:
27196          <input id="exampleInput" type="week" name="input" ng-model="example.value"
27197                 placeholder="YYYY-W##" min="2012-W32"
27198                 max="2013-W52" required />
27199        </label>
27200        <div role="alert">
27201          <span class="error" ng-show="myForm.input.$error.required">
27202              Required!</span>
27203          <span class="error" ng-show="myForm.input.$error.week">
27204              Not a valid date!</span>
27205        </div>
27206        <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
27207        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
27208        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27209        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27210        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27211      </form>
27212    </file>
27213    <file name="protractor.js" type="protractor">
27214      var value = element(by.binding('example.value | date: "yyyy-Www"'));
27215      var valid = element(by.binding('myForm.input.$valid'));
27216      var input = element(by.model('example.value'));
27217
27218      // currently protractor/webdriver does not support
27219      // sending keys to all known HTML5 input controls
27220      // for various browsers (https://github.com/angular/protractor/issues/562).
27221      function setInput(val) {
27222        // set the value of the element and force validation.
27223        var scr = "var ipt = document.getElementById('exampleInput'); " +
27224        "ipt.value = '" + val + "';" +
27225        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
27226        browser.executeScript(scr);
27227      }
27228
27229      it('should initialize to model', function() {
27230        expect(value.getText()).toContain('2013-W01');
27231        expect(valid.getText()).toContain('myForm.input.$valid = true');
27232      });
27233
27234      it('should be invalid if empty', function() {
27235        setInput('');
27236        expect(value.getText()).toEqual('value =');
27237        expect(valid.getText()).toContain('myForm.input.$valid = false');
27238      });
27239
27240      it('should be invalid if over max', function() {
27241        setInput('2015-W01');
27242        expect(value.getText()).toContain('');
27243        expect(valid.getText()).toContain('myForm.input.$valid = false');
27244      });
27245    </file>
27246    </example>
27247    */
27248  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
27249
27250  /**
27251   * @ngdoc input
27252   * @name input[month]
27253   *
27254   * @description
27255   * Input with month validation and transformation. In browsers that do not yet support
27256   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
27257   * month format (yyyy-MM), for example: `2009-01`.
27258   *
27259   * The model must always be a Date object, otherwise Angular will throw an error.
27260   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
27261   * If the model is not set to the first of the month, the next view to model update will set it
27262   * to the first of the month.
27263   *
27264   * The timezone to be used to read/write the `Date` instance in the model can be defined using
27265   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
27266   *
27267   * @param {string} ngModel Assignable angular expression to data-bind to.
27268   * @param {string=} name Property name of the form under which the control is published.
27269   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
27270   *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
27271   *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
27272   *   native HTML5 constraint validation.
27273   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
27274   *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
27275   *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
27276   *   native HTML5 constraint validation.
27277   * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
27278   *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
27279   * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
27280   *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
27281
27282   * @param {string=} required Sets `required` validation error key if the value is not entered.
27283   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27284   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27285   *    `required` when you want to data-bind to the `required` attribute.
27286   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27287   *    interaction with the input element.
27288   *
27289   * @example
27290   <example name="month-input-directive" module="monthExample">
27291   <file name="index.html">
27292     <script>
27293      angular.module('monthExample', [])
27294        .controller('DateController', ['$scope', function($scope) {
27295          $scope.example = {
27296            value: new Date(2013, 9, 1)
27297          };
27298        }]);
27299     </script>
27300     <form name="myForm" ng-controller="DateController as dateCtrl">
27301       <label for="exampleInput">Pick a month in 2013:</label>
27302       <input id="exampleInput" type="month" name="input" ng-model="example.value"
27303          placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
27304       <div role="alert">
27305         <span class="error" ng-show="myForm.input.$error.required">
27306            Required!</span>
27307         <span class="error" ng-show="myForm.input.$error.month">
27308            Not a valid month!</span>
27309       </div>
27310       <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
27311       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
27312       <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27313       <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27314       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27315     </form>
27316   </file>
27317   <file name="protractor.js" type="protractor">
27318      var value = element(by.binding('example.value | date: "yyyy-MM"'));
27319      var valid = element(by.binding('myForm.input.$valid'));
27320      var input = element(by.model('example.value'));
27321
27322      // currently protractor/webdriver does not support
27323      // sending keys to all known HTML5 input controls
27324      // for various browsers (https://github.com/angular/protractor/issues/562).
27325      function setInput(val) {
27326        // set the value of the element and force validation.
27327        var scr = "var ipt = document.getElementById('exampleInput'); " +
27328        "ipt.value = '" + val + "';" +
27329        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
27330        browser.executeScript(scr);
27331      }
27332
27333      it('should initialize to model', function() {
27334        expect(value.getText()).toContain('2013-10');
27335        expect(valid.getText()).toContain('myForm.input.$valid = true');
27336      });
27337
27338      it('should be invalid if empty', function() {
27339        setInput('');
27340        expect(value.getText()).toEqual('value =');
27341        expect(valid.getText()).toContain('myForm.input.$valid = false');
27342      });
27343
27344      it('should be invalid if over max', function() {
27345        setInput('2015-01');
27346        expect(value.getText()).toContain('');
27347        expect(valid.getText()).toContain('myForm.input.$valid = false');
27348      });
27349   </file>
27350   </example>
27351   */
27352  'month': createDateInputType('month', MONTH_REGEXP,
27353     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
27354     'yyyy-MM'),
27355
27356  /**
27357   * @ngdoc input
27358   * @name input[number]
27359   *
27360   * @description
27361   * Text input with number validation and transformation. Sets the `number` validation
27362   * error if not a valid number.
27363   *
27364   * <div class="alert alert-warning">
27365   * The model must always be of type `number` otherwise Angular will throw an error.
27366   * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
27367   * error docs for more information and an example of how to convert your model if necessary.
27368   * </div>
27369   *
27370   * ## Issues with HTML5 constraint validation
27371   *
27372   * In browsers that follow the
27373   * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
27374   * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
27375   * If a non-number is entered in the input, the browser will report the value as an empty string,
27376   * which means the view / model values in `ngModel` and subsequently the scope value
27377   * will also be an empty string.
27378   *
27379   *
27380   * @param {string} ngModel Assignable angular expression to data-bind to.
27381   * @param {string=} name Property name of the form under which the control is published.
27382   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
27383   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
27384   * @param {string=} required Sets `required` validation error key if the value is not entered.
27385   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27386   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27387   *    `required` when you want to data-bind to the `required` attribute.
27388   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
27389   *    minlength.
27390   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
27391   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
27392   *    any length.
27393   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
27394   *    that contains the regular expression body that will be converted to a regular expression
27395   *    as in the ngPattern directive.
27396   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
27397   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
27398   *    If the expression evaluates to a RegExp object, then this is used directly.
27399   *    If the expression evaluates to a string, then it will be converted to a RegExp
27400   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
27401   *    `new RegExp('^abc$')`.<br />
27402   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
27403   *    start at the index of the last search's match, thus not taking the whole input value into
27404   *    account.
27405   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27406   *    interaction with the input element.
27407   *
27408   * @example
27409      <example name="number-input-directive" module="numberExample">
27410        <file name="index.html">
27411         <script>
27412           angular.module('numberExample', [])
27413             .controller('ExampleController', ['$scope', function($scope) {
27414               $scope.example = {
27415                 value: 12
27416               };
27417             }]);
27418         </script>
27419         <form name="myForm" ng-controller="ExampleController">
27420           <label>Number:
27421             <input type="number" name="input" ng-model="example.value"
27422                    min="0" max="99" required>
27423          </label>
27424           <div role="alert">
27425             <span class="error" ng-show="myForm.input.$error.required">
27426               Required!</span>
27427             <span class="error" ng-show="myForm.input.$error.number">
27428               Not valid number!</span>
27429           </div>
27430           <tt>value = {{example.value}}</tt><br/>
27431           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
27432           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27433           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27434           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27435          </form>
27436        </file>
27437        <file name="protractor.js" type="protractor">
27438          var value = element(by.binding('example.value'));
27439          var valid = element(by.binding('myForm.input.$valid'));
27440          var input = element(by.model('example.value'));
27441
27442          it('should initialize to model', function() {
27443            expect(value.getText()).toContain('12');
27444            expect(valid.getText()).toContain('true');
27445          });
27446
27447          it('should be invalid if empty', function() {
27448            input.clear();
27449            input.sendKeys('');
27450            expect(value.getText()).toEqual('value =');
27451            expect(valid.getText()).toContain('false');
27452          });
27453
27454          it('should be invalid if over max', function() {
27455            input.clear();
27456            input.sendKeys('123');
27457            expect(value.getText()).toEqual('value =');
27458            expect(valid.getText()).toContain('false');
27459          });
27460        </file>
27461      </example>
27462   */
27463  'number': numberInputType,
27464
27465
27466  /**
27467   * @ngdoc input
27468   * @name input[url]
27469   *
27470   * @description
27471   * Text input with URL validation. Sets the `url` validation error key if the content is not a
27472   * valid URL.
27473   *
27474   * <div class="alert alert-warning">
27475   * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
27476   * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
27477   * the built-in validators (see the {@link guide/forms Forms guide})
27478   * </div>
27479   *
27480   * @param {string} ngModel Assignable angular expression to data-bind to.
27481   * @param {string=} name Property name of the form under which the control is published.
27482   * @param {string=} required Sets `required` validation error key if the value is not entered.
27483   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27484   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27485   *    `required` when you want to data-bind to the `required` attribute.
27486   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
27487   *    minlength.
27488   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
27489   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
27490   *    any length.
27491   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
27492   *    that contains the regular expression body that will be converted to a regular expression
27493   *    as in the ngPattern directive.
27494   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
27495   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
27496   *    If the expression evaluates to a RegExp object, then this is used directly.
27497   *    If the expression evaluates to a string, then it will be converted to a RegExp
27498   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
27499   *    `new RegExp('^abc$')`.<br />
27500   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
27501   *    start at the index of the last search's match, thus not taking the whole input value into
27502   *    account.
27503   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27504   *    interaction with the input element.
27505   *
27506   * @example
27507      <example name="url-input-directive" module="urlExample">
27508        <file name="index.html">
27509         <script>
27510           angular.module('urlExample', [])
27511             .controller('ExampleController', ['$scope', function($scope) {
27512               $scope.url = {
27513                 text: 'http://google.com'
27514               };
27515             }]);
27516         </script>
27517         <form name="myForm" ng-controller="ExampleController">
27518           <label>URL:
27519             <input type="url" name="input" ng-model="url.text" required>
27520           <label>
27521           <div role="alert">
27522             <span class="error" ng-show="myForm.input.$error.required">
27523               Required!</span>
27524             <span class="error" ng-show="myForm.input.$error.url">
27525               Not valid url!</span>
27526           </div>
27527           <tt>text = {{url.text}}</tt><br/>
27528           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
27529           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27530           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27531           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27532           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
27533          </form>
27534        </file>
27535        <file name="protractor.js" type="protractor">
27536          var text = element(by.binding('url.text'));
27537          var valid = element(by.binding('myForm.input.$valid'));
27538          var input = element(by.model('url.text'));
27539
27540          it('should initialize to model', function() {
27541            expect(text.getText()).toContain('http://google.com');
27542            expect(valid.getText()).toContain('true');
27543          });
27544
27545          it('should be invalid if empty', function() {
27546            input.clear();
27547            input.sendKeys('');
27548
27549            expect(text.getText()).toEqual('text =');
27550            expect(valid.getText()).toContain('false');
27551          });
27552
27553          it('should be invalid if not url', function() {
27554            input.clear();
27555            input.sendKeys('box');
27556
27557            expect(valid.getText()).toContain('false');
27558          });
27559        </file>
27560      </example>
27561   */
27562  'url': urlInputType,
27563
27564
27565  /**
27566   * @ngdoc input
27567   * @name input[email]
27568   *
27569   * @description
27570   * Text input with email validation. Sets the `email` validation error key if not a valid email
27571   * address.
27572   *
27573   * <div class="alert alert-warning">
27574   * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
27575   * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
27576   * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
27577   * </div>
27578   *
27579   * @param {string} ngModel Assignable angular expression to data-bind to.
27580   * @param {string=} name Property name of the form under which the control is published.
27581   * @param {string=} required Sets `required` validation error key if the value is not entered.
27582   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
27583   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
27584   *    `required` when you want to data-bind to the `required` attribute.
27585   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
27586   *    minlength.
27587   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
27588   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
27589   *    any length.
27590   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
27591   *    that contains the regular expression body that will be converted to a regular expression
27592   *    as in the ngPattern directive.
27593   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
27594   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
27595   *    If the expression evaluates to a RegExp object, then this is used directly.
27596   *    If the expression evaluates to a string, then it will be converted to a RegExp
27597   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
27598   *    `new RegExp('^abc$')`.<br />
27599   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
27600   *    start at the index of the last search's match, thus not taking the whole input value into
27601   *    account.
27602   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27603   *    interaction with the input element.
27604   *
27605   * @example
27606      <example name="email-input-directive" module="emailExample">
27607        <file name="index.html">
27608         <script>
27609           angular.module('emailExample', [])
27610             .controller('ExampleController', ['$scope', function($scope) {
27611               $scope.email = {
27612                 text: '[email protected]'
27613               };
27614             }]);
27615         </script>
27616           <form name="myForm" ng-controller="ExampleController">
27617             <label>Email:
27618               <input type="email" name="input" ng-model="email.text" required>
27619             </label>
27620             <div role="alert">
27621               <span class="error" ng-show="myForm.input.$error.required">
27622                 Required!</span>
27623               <span class="error" ng-show="myForm.input.$error.email">
27624                 Not valid email!</span>
27625             </div>
27626             <tt>text = {{email.text}}</tt><br/>
27627             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
27628             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
27629             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
27630             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
27631             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
27632           </form>
27633         </file>
27634        <file name="protractor.js" type="protractor">
27635          var text = element(by.binding('email.text'));
27636          var valid = element(by.binding('myForm.input.$valid'));
27637          var input = element(by.model('email.text'));
27638
27639          it('should initialize to model', function() {
27640            expect(text.getText()).toContain('[email protected]');
27641            expect(valid.getText()).toContain('true');
27642          });
27643
27644          it('should be invalid if empty', function() {
27645            input.clear();
27646            input.sendKeys('');
27647            expect(text.getText()).toEqual('text =');
27648            expect(valid.getText()).toContain('false');
27649          });
27650
27651          it('should be invalid if not email', function() {
27652            input.clear();
27653            input.sendKeys('xxx');
27654
27655            expect(valid.getText()).toContain('false');
27656          });
27657        </file>
27658      </example>
27659   */
27660  'email': emailInputType,
27661
27662
27663  /**
27664   * @ngdoc input
27665   * @name input[radio]
27666   *
27667   * @description
27668   * HTML radio button.
27669   *
27670   * @param {string} ngModel Assignable angular expression to data-bind to.
27671   * @param {string} value The value to which the `ngModel` expression should be set when selected.
27672   *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
27673   *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
27674   * @param {string=} name Property name of the form under which the control is published.
27675   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27676   *    interaction with the input element.
27677   * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
27678   *    is selected. Should be used instead of the `value` attribute if you need
27679   *    a non-string `ngModel` (`boolean`, `array`, ...).
27680   *
27681   * @example
27682      <example name="radio-input-directive" module="radioExample">
27683        <file name="index.html">
27684         <script>
27685           angular.module('radioExample', [])
27686             .controller('ExampleController', ['$scope', function($scope) {
27687               $scope.color = {
27688                 name: 'blue'
27689               };
27690               $scope.specialValue = {
27691                 "id": "12345",
27692                 "value": "green"
27693               };
27694             }]);
27695         </script>
27696         <form name="myForm" ng-controller="ExampleController">
27697           <label>
27698             <input type="radio" ng-model="color.name" value="red">
27699             Red
27700           </label><br/>
27701           <label>
27702             <input type="radio" ng-model="color.name" ng-value="specialValue">
27703             Green
27704           </label><br/>
27705           <label>
27706             <input type="radio" ng-model="color.name" value="blue">
27707             Blue
27708           </label><br/>
27709           <tt>color = {{color.name | json}}</tt><br/>
27710          </form>
27711          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
27712        </file>
27713        <file name="protractor.js" type="protractor">
27714          it('should change state', function() {
27715            var color = element(by.binding('color.name'));
27716
27717            expect(color.getText()).toContain('blue');
27718
27719            element.all(by.model('color.name')).get(0).click();
27720
27721            expect(color.getText()).toContain('red');
27722          });
27723        </file>
27724      </example>
27725   */
27726  'radio': radioInputType,
27727
27728
27729  /**
27730   * @ngdoc input
27731   * @name input[checkbox]
27732   *
27733   * @description
27734   * HTML checkbox.
27735   *
27736   * @param {string} ngModel Assignable angular expression to data-bind to.
27737   * @param {string=} name Property name of the form under which the control is published.
27738   * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
27739   * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
27740   * @param {string=} ngChange Angular expression to be executed when input changes due to user
27741   *    interaction with the input element.
27742   *
27743   * @example
27744      <example name="checkbox-input-directive" module="checkboxExample">
27745        <file name="index.html">
27746         <script>
27747           angular.module('checkboxExample', [])
27748             .controller('ExampleController', ['$scope', function($scope) {
27749               $scope.checkboxModel = {
27750                value1 : true,
27751                value2 : 'YES'
27752              };
27753             }]);
27754         </script>
27755         <form name="myForm" ng-controller="ExampleController">
27756           <label>Value1:
27757             <input type="checkbox" ng-model="checkboxModel.value1">
27758           </label><br/>
27759           <label>Value2:
27760             <input type="checkbox" ng-model="checkboxModel.value2"
27761                    ng-true-value="'YES'" ng-false-value="'NO'">
27762            </label><br/>
27763           <tt>value1 = {{checkboxModel.value1}}</tt><br/>
27764           <tt>value2 = {{checkboxModel.value2}}</tt><br/>
27765          </form>
27766        </file>
27767        <file name="protractor.js" type="protractor">
27768          it('should change state', function() {
27769            var value1 = element(by.binding('checkboxModel.value1'));
27770            var value2 = element(by.binding('checkboxModel.value2'));
27771
27772            expect(value1.getText()).toContain('true');
27773            expect(value2.getText()).toContain('YES');
27774
27775            element(by.model('checkboxModel.value1')).click();
27776            element(by.model('checkboxModel.value2')).click();
27777
27778            expect(value1.getText()).toContain('false');
27779            expect(value2.getText()).toContain('NO');
27780          });
27781        </file>
27782      </example>
27783   */
27784  'checkbox': checkboxInputType,
27785
27786  'hidden': noop,
27787  'button': noop,
27788  'submit': noop,
27789  'reset': noop,
27790  'file': noop
27791};
27792
27793function stringBasedInputType(ctrl) {
27794  ctrl.$formatters.push(function(value) {
27795    return ctrl.$isEmpty(value) ? value : value.toString();
27796  });
27797}
27798
27799function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
27800  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
27801  stringBasedInputType(ctrl);
27802}
27803
27804function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
27805  var type = lowercase(element[0].type);
27806
27807  // In composition mode, users are still inputing intermediate text buffer,
27808  // hold the listener until composition is done.
27809  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
27810  if (!$sniffer.android) {
27811    var composing = false;
27812
27813    element.on('compositionstart', function(data) {
27814      composing = true;
27815    });
27816
27817    element.on('compositionend', function() {
27818      composing = false;
27819      listener();
27820    });
27821  }
27822
27823  var timeout;
27824
27825  var listener = function(ev) {
27826    if (timeout) {
27827      $browser.defer.cancel(timeout);
27828      timeout = null;
27829    }
27830    if (composing) return;
27831    var value = element.val(),
27832        event = ev && ev.type;
27833
27834    // By default we will trim the value
27835    // If the attribute ng-trim exists we will avoid trimming
27836    // If input type is 'password', the value is never trimmed
27837    if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
27838      value = trim(value);
27839    }
27840
27841    // If a control is suffering from bad input (due to native validators), browsers discard its
27842    // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
27843    // control's value is the same empty value twice in a row.
27844    if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
27845      ctrl.$setViewValue(value, event);
27846    }
27847  };
27848
27849  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
27850  // input event on backspace, delete or cut
27851  if ($sniffer.hasEvent('input')) {
27852    element.on('input', listener);
27853  } else {
27854    var deferListener = function(ev, input, origValue) {
27855      if (!timeout) {
27856        timeout = $browser.defer(function() {
27857          timeout = null;
27858          if (!input || input.value !== origValue) {
27859            listener(ev);
27860          }
27861        });
27862      }
27863    };
27864
27865    element.on('keydown', function(event) {
27866      var key = event.keyCode;
27867
27868      // ignore
27869      //    command            modifiers                   arrows
27870      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
27871
27872      deferListener(event, this, this.value);
27873    });
27874
27875    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
27876    if ($sniffer.hasEvent('paste')) {
27877      element.on('paste cut', deferListener);
27878    }
27879  }
27880
27881  // if user paste into input using mouse on older browser
27882  // or form autocomplete on newer browser, we need "change" event to catch it
27883  element.on('change', listener);
27884
27885  // Some native input types (date-family) have the ability to change validity without
27886  // firing any input/change events.
27887  // For these event types, when native validators are present and the browser supports the type,
27888  // check for validity changes on various DOM events.
27889  if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {
27890    element.on(PARTIAL_VALIDATION_EVENTS, function(ev) {
27891      if (!timeout) {
27892        var validity = this[VALIDITY_STATE_PROPERTY];
27893        var origBadInput = validity.badInput;
27894        var origTypeMismatch = validity.typeMismatch;
27895        timeout = $browser.defer(function() {
27896          timeout = null;
27897          if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {
27898            listener(ev);
27899          }
27900        });
27901      }
27902    });
27903  }
27904
27905  ctrl.$render = function() {
27906    // Workaround for Firefox validation #12102.
27907    var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
27908    if (element.val() !== value) {
27909      element.val(value);
27910    }
27911  };
27912}
27913
27914function weekParser(isoWeek, existingDate) {
27915  if (isDate(isoWeek)) {
27916    return isoWeek;
27917  }
27918
27919  if (isString(isoWeek)) {
27920    WEEK_REGEXP.lastIndex = 0;
27921    var parts = WEEK_REGEXP.exec(isoWeek);
27922    if (parts) {
27923      var year = +parts[1],
27924          week = +parts[2],
27925          hours = 0,
27926          minutes = 0,
27927          seconds = 0,
27928          milliseconds = 0,
27929          firstThurs = getFirstThursdayOfYear(year),
27930          addDays = (week - 1) * 7;
27931
27932      if (existingDate) {
27933        hours = existingDate.getHours();
27934        minutes = existingDate.getMinutes();
27935        seconds = existingDate.getSeconds();
27936        milliseconds = existingDate.getMilliseconds();
27937      }
27938
27939      return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
27940    }
27941  }
27942
27943  return NaN;
27944}
27945
27946function createDateParser(regexp, mapping) {
27947  return function(iso, date) {
27948    var parts, map;
27949
27950    if (isDate(iso)) {
27951      return iso;
27952    }
27953
27954    if (isString(iso)) {
27955      // When a date is JSON'ified to wraps itself inside of an extra
27956      // set of double quotes. This makes the date parsing code unable
27957      // to match the date string and parse it as a date.
27958      if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
27959        iso = iso.substring(1, iso.length - 1);
27960      }
27961      if (ISO_DATE_REGEXP.test(iso)) {
27962        return new Date(iso);
27963      }
27964      regexp.lastIndex = 0;
27965      parts = regexp.exec(iso);
27966
27967      if (parts) {
27968        parts.shift();
27969        if (date) {
27970          map = {
27971            yyyy: date.getFullYear(),
27972            MM: date.getMonth() + 1,
27973            dd: date.getDate(),
27974            HH: date.getHours(),
27975            mm: date.getMinutes(),
27976            ss: date.getSeconds(),
27977            sss: date.getMilliseconds() / 1000
27978          };
27979        } else {
27980          map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
27981        }
27982
27983        forEach(parts, function(part, index) {
27984          if (index < mapping.length) {
27985            map[mapping[index]] = +part;
27986          }
27987        });
27988        return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
27989      }
27990    }
27991
27992    return NaN;
27993  };
27994}
27995
27996function createDateInputType(type, regexp, parseDate, format) {
27997  return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
27998    badInputChecker(scope, element, attr, ctrl);
27999    baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
28000    var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
28001    var previousDate;
28002
28003    ctrl.$$parserName = type;
28004    ctrl.$parsers.push(function(value) {
28005      if (ctrl.$isEmpty(value)) return null;
28006      if (regexp.test(value)) {
28007        // Note: We cannot read ctrl.$modelValue, as there might be a different
28008        // parser/formatter in the processing chain so that the model
28009        // contains some different data format!
28010        var parsedDate = parseDate(value, previousDate);
28011        if (timezone) {
28012          parsedDate = convertTimezoneToLocal(parsedDate, timezone);
28013        }
28014        return parsedDate;
28015      }
28016      return undefined;
28017    });
28018
28019    ctrl.$formatters.push(function(value) {
28020      if (value && !isDate(value)) {
28021        throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
28022      }
28023      if (isValidDate(value)) {
28024        previousDate = value;
28025        if (previousDate && timezone) {
28026          previousDate = convertTimezoneToLocal(previousDate, timezone, true);
28027        }
28028        return $filter('date')(value, format, timezone);
28029      } else {
28030        previousDate = null;
28031        return '';
28032      }
28033    });
28034
28035    if (isDefined(attr.min) || attr.ngMin) {
28036      var minVal;
28037      ctrl.$validators.min = function(value) {
28038        return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
28039      };
28040      attr.$observe('min', function(val) {
28041        minVal = parseObservedDateValue(val);
28042        ctrl.$validate();
28043      });
28044    }
28045
28046    if (isDefined(attr.max) || attr.ngMax) {
28047      var maxVal;
28048      ctrl.$validators.max = function(value) {
28049        return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
28050      };
28051      attr.$observe('max', function(val) {
28052        maxVal = parseObservedDateValue(val);
28053        ctrl.$validate();
28054      });
28055    }
28056
28057    function isValidDate(value) {
28058      // Invalid Date: getTime() returns NaN
28059      return value && !(value.getTime && value.getTime() !== value.getTime());
28060    }
28061
28062    function parseObservedDateValue(val) {
28063      return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
28064    }
28065  };
28066}
28067
28068function badInputChecker(scope, element, attr, ctrl) {
28069  var node = element[0];
28070  var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
28071  if (nativeValidation) {
28072    ctrl.$parsers.push(function(value) {
28073      var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
28074      return validity.badInput || validity.typeMismatch ? undefined : value;
28075    });
28076  }
28077}
28078
28079function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
28080  badInputChecker(scope, element, attr, ctrl);
28081  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
28082
28083  ctrl.$$parserName = 'number';
28084  ctrl.$parsers.push(function(value) {
28085    if (ctrl.$isEmpty(value))      return null;
28086    if (NUMBER_REGEXP.test(value)) return parseFloat(value);
28087    return undefined;
28088  });
28089
28090  ctrl.$formatters.push(function(value) {
28091    if (!ctrl.$isEmpty(value)) {
28092      if (!isNumber(value)) {
28093        throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
28094      }
28095      value = value.toString();
28096    }
28097    return value;
28098  });
28099
28100  if (isDefined(attr.min) || attr.ngMin) {
28101    var minVal;
28102    ctrl.$validators.min = function(value) {
28103      return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
28104    };
28105
28106    attr.$observe('min', function(val) {
28107      if (isDefined(val) && !isNumber(val)) {
28108        val = parseFloat(val, 10);
28109      }
28110      minVal = isNumber(val) && !isNaN(val) ? val : undefined;
28111      // TODO(matsko): implement validateLater to reduce number of validations
28112      ctrl.$validate();
28113    });
28114  }
28115
28116  if (isDefined(attr.max) || attr.ngMax) {
28117    var maxVal;
28118    ctrl.$validators.max = function(value) {
28119      return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
28120    };
28121
28122    attr.$observe('max', function(val) {
28123      if (isDefined(val) && !isNumber(val)) {
28124        val = parseFloat(val, 10);
28125      }
28126      maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
28127      // TODO(matsko): implement validateLater to reduce number of validations
28128      ctrl.$validate();
28129    });
28130  }
28131}
28132
28133function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
28134  // Note: no badInputChecker here by purpose as `url` is only a validation
28135  // in browsers, i.e. we can always read out input.value even if it is not valid!
28136  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
28137  stringBasedInputType(ctrl);
28138
28139  ctrl.$$parserName = 'url';
28140  ctrl.$validators.url = function(modelValue, viewValue) {
28141    var value = modelValue || viewValue;
28142    return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
28143  };
28144}
28145
28146function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
28147  // Note: no badInputChecker here by purpose as `url` is only a validation
28148  // in browsers, i.e. we can always read out input.value even if it is not valid!
28149  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
28150  stringBasedInputType(ctrl);
28151
28152  ctrl.$$parserName = 'email';
28153  ctrl.$validators.email = function(modelValue, viewValue) {
28154    var value = modelValue || viewValue;
28155    return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
28156  };
28157}
28158
28159function radioInputType(scope, element, attr, ctrl) {
28160  // make the name unique, if not defined
28161  if (isUndefined(attr.name)) {
28162    element.attr('name', nextUid());
28163  }
28164
28165  var listener = function(ev) {
28166    if (element[0].checked) {
28167      ctrl.$setViewValue(attr.value, ev && ev.type);
28168    }
28169  };
28170
28171  element.on('click', listener);
28172
28173  ctrl.$render = function() {
28174    var value = attr.value;
28175    element[0].checked = (value == ctrl.$viewValue);
28176  };
28177
28178  attr.$observe('value', ctrl.$render);
28179}
28180
28181function parseConstantExpr($parse, context, name, expression, fallback) {
28182  var parseFn;
28183  if (isDefined(expression)) {
28184    parseFn = $parse(expression);
28185    if (!parseFn.constant) {
28186      throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
28187                                   '`{1}`.', name, expression);
28188    }
28189    return parseFn(context);
28190  }
28191  return fallback;
28192}
28193
28194function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
28195  var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
28196  var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
28197
28198  var listener = function(ev) {
28199    ctrl.$setViewValue(element[0].checked, ev && ev.type);
28200  };
28201
28202  element.on('click', listener);
28203
28204  ctrl.$render = function() {
28205    element[0].checked = ctrl.$viewValue;
28206  };
28207
28208  // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
28209  // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
28210  // it to a boolean.
28211  ctrl.$isEmpty = function(value) {
28212    return value === false;
28213  };
28214
28215  ctrl.$formatters.push(function(value) {
28216    return equals(value, trueValue);
28217  });
28218
28219  ctrl.$parsers.push(function(value) {
28220    return value ? trueValue : falseValue;
28221  });
28222}
28223
28224
28225/**
28226 * @ngdoc directive
28227 * @name textarea
28228 * @restrict E
28229 *
28230 * @description
28231 * HTML textarea element control with angular data-binding. The data-binding and validation
28232 * properties of this element are exactly the same as those of the
28233 * {@link ng.directive:input input element}.
28234 *
28235 * @param {string} ngModel Assignable angular expression to data-bind to.
28236 * @param {string=} name Property name of the form under which the control is published.
28237 * @param {string=} required Sets `required` validation error key if the value is not entered.
28238 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
28239 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
28240 *    `required` when you want to data-bind to the `required` attribute.
28241 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
28242 *    minlength.
28243 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
28244 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
28245 *    length.
28246 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
28247 *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
28248 *    If the expression evaluates to a RegExp object, then this is used directly.
28249 *    If the expression evaluates to a string, then it will be converted to a RegExp
28250 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
28251 *    `new RegExp('^abc$')`.<br />
28252 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
28253 *    start at the index of the last search's match, thus not taking the whole input value into
28254 *    account.
28255 * @param {string=} ngChange Angular expression to be executed when input changes due to user
28256 *    interaction with the input element.
28257 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
28258 */
28259
28260
28261/**
28262 * @ngdoc directive
28263 * @name input
28264 * @restrict E
28265 *
28266 * @description
28267 * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
28268 * input state control, and validation.
28269 * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
28270 *
28271 * <div class="alert alert-warning">
28272 * **Note:** Not every feature offered is available for all input types.
28273 * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
28274 * </div>
28275 *
28276 * @param {string} ngModel Assignable angular expression to data-bind to.
28277 * @param {string=} name Property name of the form under which the control is published.
28278 * @param {string=} required Sets `required` validation error key if the value is not entered.
28279 * @param {boolean=} ngRequired Sets `required` attribute if set to true
28280 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
28281 *    minlength.
28282 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
28283 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
28284 *    length.
28285 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
28286 *    value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
28287 *    If the expression evaluates to a RegExp object, then this is used directly.
28288 *    If the expression evaluates to a string, then it will be converted to a RegExp
28289 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
28290 *    `new RegExp('^abc$')`.<br />
28291 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
28292 *    start at the index of the last search's match, thus not taking the whole input value into
28293 *    account.
28294 * @param {string=} ngChange Angular expression to be executed when input changes due to user
28295 *    interaction with the input element.
28296 * @param {boolean=} [ngTrim=true] If set to false Angular
vendor: 4,842 bytes, lines 28296-28414
28296 will not automatically trim the input.
28297 *    This parameter is ignored for input[type=password] controls, which will never trim the
28298 *    input.
28299 *
28300 * @example
28301    <example name="input-directive" module="inputExample">
28302      <file name="index.html">
28303       <script>
28304          angular.module('inputExample', [])
28305            .controller('ExampleController', ['$scope', function($scope) {
28306              $scope.user = {name: 'guest', last: 'visitor'};
28307            }]);
28308       </script>
28309       <div ng-controller="ExampleController">
28310         <form name="myForm">
28311           <label>
28312              User name:
28313              <input type="text" name="userName" ng-model="user.name" required>
28314           </label>
28315           <div role="alert">
28316             <span class="error" ng-show="myForm.userName.$error.required">
28317              Required!</span>
28318           </div>
28319           <label>
28320              Last name:
28321              <input type="text" name="lastName" ng-model="user.last"
28322              ng-minlength="3" ng-maxlength="10">
28323           </label>
28324           <div role="alert">
28325             <span class="error" ng-show="myForm.lastName.$error.minlength">
28326               Too short!</span>
28327             <span class="error" ng-show="myForm.lastName.$error.maxlength">
28328               Too long!</span>
28329           </div>
28330         </form>
28331         <hr>
28332         <tt>user = {{user}}</tt><br/>
28333         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
28334         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
28335         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
28336         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
28337         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
28338         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
28339         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
28340         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
28341       </div>
28342      </file>
28343      <file name="protractor.js" type="protractor">
28344        var user = element(by.exactBinding('user'));
28345        var userNameValid = element(by.binding('myForm.userName.$valid'));
28346        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
28347        var lastNameError = element(by.binding('myForm.lastName.$error'));
28348        var formValid = element(by.binding('myForm.$valid'));
28349        var userNameInput = element(by.model('user.name'));
28350        var userLastInput = element(by.model('user.last'));
28351
28352        it('should initialize to model', function() {
28353          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
28354          expect(userNameValid.getText()).toContain('true');
28355          expect(formValid.getText()).toContain('true');
28356        });
28357
28358        it('should be invalid if empty when required', function() {
28359          userNameInput.clear();
28360          userNameInput.sendKeys('');
28361
28362          expect(user.getText()).toContain('{"last":"visitor"}');
28363          expect(userNameValid.getText()).toContain('false');
28364          expect(formValid.getText()).toContain('false');
28365        });
28366
28367        it('should be valid if empty when min length is set', function() {
28368          userLastInput.clear();
28369          userLastInput.sendKeys('');
28370
28371          expect(user.getText()).toContain('{"name":"guest","last":""}');
28372          expect(lastNameValid.getText()).toContain('true');
28373          expect(formValid.getText()).toContain('true');
28374        });
28375
28376        it('should be invalid if less than required min length', function() {
28377          userLastInput.clear();
28378          userLastInput.sendKeys('xx');
28379
28380          expect(user.getText()).toContain('{"name":"guest"}');
28381          expect(lastNameValid.getText()).toContain('false');
28382          expect(lastNameError.getText()).toContain('minlength');
28383          expect(formValid.getText()).toContain('false');
28384        });
28385
28386        it('should be invalid if longer than max length', function() {
28387          userLastInput.clear();
28388          userLastInput.sendKeys('some ridiculously long name');
28389
28390          expect(user.getText()).toContain('{"name":"guest"}');
28391          expect(lastNameValid.getText()).toContain('false');
28392          expect(lastNameError.getText()).toContain('maxlength');
28393          expect(formValid.getText()).toContain('false');
28394        });
28395      </file>
28396    </example>
28397 */
28398var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
28399    function($browser, $sniffer, $filter, $parse) {
28400  return {
28401    restrict: 'E',
28402    require: ['?ngModel'],
28403    link: {
28404      pre: function(scope, element, attr, ctrls) {
28405        if (ctrls[0]) {
28406          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
28407                                                              $browser, $filter, $parse);
28408        }
28409      }
28410    }
28411  };
28412}];
28413
28414
28415
28416var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
28417/**
28418 * @ngdoc directive
28419 * @name ngValue
28420 *
28421 * @description
28422 * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
28423 * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
28424 * the bound value.
28425 *
28426 * `ngValue` is useful when dynamically generating lists of radio buttons using
28427 * {@link ngRepeat `ngRepeat`}, as shown below.
28428 *
28429 * Likewise, `ngValue` can be used to generate `<option>` elements for
28430 * the {@link select `select`} element. In that case however, only strings are supported
28431 * for the `value `attribute, so the resulting `ngModel` will always be a string.
28432 * Support for `select` models with non-string values is available via `ngOptions`.
28433 *
28434 * @element input
28435 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
28436 *   of the `input` element
28437 *
28438 * @example
28439    <example name="ngValue-directive" module="valueExample">
28440      <file name="index.html">
28441       <script>
28442          angular.module('valueExample', [])
28443            .controller('ExampleController', ['$scope', function($scope) {
28444              $scope.names = ['pizza', 'unicorns', 'robots'];
28445              $scope.my = { favorite: 'unicorns' };
28446            }]);
28447       </script>
28448        <form ng-controller="ExampleController">
28449          <h2>Which is your favorite?</h2>
28450            <label ng-repeat="name in names" for="{{name}}">
28451              {{name}}
28452              <input type="radio"
28453                     ng-model="my.favorite"
28454                     ng-value="name"
28455                     id="{{name}}"
28456                     name="favorite">
28457            </label>
28458          <div>You chose {{my.favorite}}</div>
28459        </form>
28460      </file>
28461      <file name="protractor.js" type="protractor">
28462        var favorite = element(by.binding('my.favorite'));
28463
28464        it('should initialize to model', function() {
28465          expect(favorite.getText()).toContain('unicorns');
28466        });
28467        it('should bind the values to the inputs', function() {
28468          element.all(by.model('my.favorite')).get(0).click();
28469          expect(favorite.getText()).toContain('pizza');
28470        });
28471      </file>
28472    </example>
28473 */
28474var ngValueDirective = function() {
28475  return {
28476    restrict: 'A',
28477    priority: 100,
28478    compile: function(tpl, tplAttr) {
28479      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
28480        return function ngValueConstantLink(scope, elm, attr) {
28481          attr.$set('value', scope.$eval(attr.ngValue));
28482        };
28483      } else {
28484        return function ngValueLink(scope, elm, attr) {
28485          scope.$watch(attr.ngValue, function valueWatchAction(value) {
28486            attr.$set('value', value);
28487          });
28488        };
28489      }
28490    }
28491  };
28492};
28493
28494/**
28495 * @ngdoc directive
28496 * @name ngBind
28497 * @restrict AC
28498 *
28499 * @description
28500 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
28501 * with the value of a given expression, and to update the text content when the value of that
28502 * expression changes.
28503 *
28504 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
28505 * `{{ expression }}` which is similar but less verbose.
28506 *
28507 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
28508 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
28509 * element attribute, it makes the bindings invisible to the user while the page is loading.
28510 *
28511 * An alternative solution to this problem would be using the
28512 * {@link ng.directive:ngCloak ngCloak} directive.
28513 *
28514 *
28515 * @element ANY
28516 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
28517 *
28518 * @example
28519 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
28520   <example module="bindExample">
28521     <file name="index.html">
28522       <script>
28523         angular.module('bindExample', [])
28524           .controller('ExampleController', ['$scope', function($scope) {
28525             $scope.name = 'Whirled';
28526           }]);
28527       </script>
28528       <div ng-controller="ExampleController">
28529         <label>Enter name: <input type="text" ng-model="name"></label><br>
28530         Hello <span ng-bind="name"></span>!
28531       </div>
28532     </file>
28533     <file name="protractor.js" type="protractor">
28534       it('should check ng-bind', function() {
28535         var nameInput = element(by.model('name'));
28536
28537         expect(element(by.binding('name')).getText()).toBe('Whirled');
28538         nameInput.clear();
28539         nameInput.sendKeys('world');
28540         expect(element(by.binding('name')).getText()).toBe('world');
28541       });
28542     </file>
28543   </example>
28544 */
28545var ngBindDirective = ['$compile', function($compile) {
28546  return {
28547    restrict: 'AC',
28548    compile: function ngBindCompile(templateElement) {
28549      $compile.$$addBindingClass(templateElement);
28550      return function ngBindLink(scope, element, attr) {
28551        $compile.$$addBindingInfo(element, attr.ngBind);
28552        element = element[0];
28553        scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
28554          element.textContent = isUndefined(value) ? '' : value;
28555        });
28556      };
28557    }
28558  };
28559}];
28560
28561
28562/**
28563 * @ngdoc directive
28564 * @name ngBindTemplate
28565 *
28566 * @description
28567 * The `ngBindTemplate` directive specifies that the element
28568 * text content should be replaced with the interpolation of the template
28569 * in the `ngBindTemplate` attribute.
28570 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
28571 * expressions. This directive is needed since some HTML elements
28572 * (such as TITLE and OPTION) cannot contain SPAN elements.
28573 *
28574 * @element ANY
28575 * @param {string} ngBindTemplate template of form
28576 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
28577 *
28578 * @example
28579 * Try it here: enter text in text box and watch the greeting change.
28580   <example module="bindExample">
28581     <file name="index.html">
28582       <script>
28583         angular.module('bindExample', [])
28584           .controller('ExampleController', ['$scope', function($scope) {
28585             $scope.salutation = 'Hello';
28586             $scope.name = 'World';
28587           }]);
28588       </script>
28589       <div ng-controller="ExampleController">
28590        <label>Salutation: <input type="text" ng-model="salutation"></label><br>
28591        <label>Name: <input type="text" ng-model="name"></label><br>
28592        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
28593       </div>
28594     </file>
28595     <file name="protractor.js" type="protractor">
28596       it('should check ng-bind', function() {
28597         var salutationElem = element(by.binding('salutation'));
28598         var salutationInput = element(by.model('salutation'));
28599         var nameInput = element(by.model('name'));
28600
28601         expect(salutationElem.getText()).toBe('Hello World!');
28602
28603         salutationInput.clear();
28604         salutationInput.sendKeys('Greetings');
28605         nameInput.clear();
28606         nameInput.sendKeys('user');
28607
28608         expect(salutationElem.getText()).toBe('Greetings user!');
28609       });
28610     </file>
28611   </example>
28612 */
28613var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
28614  return {
28615    compile: function ngBindTemplateCompile(templateElement) {
28616      $compile.$$addBindingClass(templateElement);
28617      return function ngBindTemplateLink(scope, element, attr) {
28618        var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
28619        $compile.$$addBindingInfo(element, interpolateFn.expressions);
28620        element = element[0];
28621        attr.$observe('ngBindTemplate', function(value) {
28622          element.textContent = isUndefined(value) ? '' : value;
28623        });
28624      };
28625    }
28626  };
28627}];
28628
28629
28630/**
28631 * @ngdoc directive
28632 * @name ngBindHtml
28633 *
28634 * @description
28635 * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
28636 * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
28637 * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
28638 * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
28639 * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
28640 *
28641 * You may also bypass sanitization for values you know are safe. To do so, bind to
28642 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
28643 * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
28644 *
28645 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
28646 * will have an exception (instead of an exploit.)
28647 *
28648 * @element ANY
28649 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
28650 *
28651 * @example
28652
28653   <example module="bindHtmlExample" deps="angular-sanitize.js">
28654     <file name="index.html">
28655       <div ng-controller="ExampleController">
28656        <p ng-bind-html="myHTML"></p>
28657       </div>
28658     </file>
28659
28660     <file name="script.js">
28661       angular.module('bindHtmlExample', ['ngSanitize'])
28662         .controller('ExampleController', ['$scope', function($scope) {
28663           $scope.myHTML =
28664              'I am an <code>HTML</code>string with ' +
28665              '<a href="#">links!</a> and other <em>stuff</em>';
28666         }]);
28667     </file>
28668
28669     <file name="protractor.js" type="protractor">
28670       it('should check ng-bind-html', function() {
28671         expect(element(by.binding('myHTML')).getText()).toBe(
28672             'I am an HTMLstring with links! and other stuff');
28673       });
28674     </file>
28675   </example>
28676 */
28677var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
28678  return {
28679    restrict: 'A',
28680    compile: function ngBindHtmlCompile(tElement, tAttrs) {
28681      var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
28682      var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
28683        return (value || '').toString();
28684      });
28685      $compile.$$addBindingClass(tElement);
28686
28687      return function ngBindHtmlLink(scope, element, attr) {
28688        $compile.$$addBindingInfo(element, attr.ngBindHtml);
28689
28690        scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
28691          // we re-evaluate the expr because we want a TrustedValueHolderType
28692          // for $sce, not a string
28693          element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
28694        });
28695      };
28696    }
28697  };
28698}];
28699
28700/**
28701 * @ngdoc directive
28702 * @name ngChange
28703 *
28704 * @description
28705 * Evaluate the given expression when the user changes the input.
28706 * The expression is evaluated immediately, unlike the JavaScript onchange event
28707 * which only triggers at the end of a change (usually, when the user leaves the
28708 * form element or presses the return key).
28709 *
28710 * The `ngChange` expression is only evaluated when a change in the input value causes
28711 * a new value to be committed to the model.
28712 *
28713 * It will not be evaluated:
28714 * * if the value returned from the `$parsers` transformation pipeline has not changed
28715 * * if the input has continued to be invalid since the model will stay `null`
28716 * * if the model is changed programmatically and not by a change to the input value
28717 *
28718 *
28719 * Note, this directive requires `ngModel` to be present.
28720 *
28721 * @element input
28722 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
28723 * in input value.
28724 *
28725 * @example
28726 * <example name="ngChange-directive" module="changeExample">
28727 *   <file name="index.html">
28728 *     <script>
28729 *       angular.module('changeExample', [])
28730 *         .controller('ExampleController', ['$scope', function($scope) {
28731 *           $scope.counter = 0;
28732 *           $scope.change = function() {
28733 *             $scope.counter++;
28734 *           };
28735 *         }]);
28736 *     </script>
28737 *     <div ng-controller="ExampleController">
28738 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
28739 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
28740 *       <label for="ng-change-example2">Confirmed</label><br />
28741 *       <tt>debug = {{confirmed}}</tt><br/>
28742 *       <tt>counter = {{counter}}</tt><br/>
28743 *     </div>
28744 *   </file>
28745 *   <file name="protractor.js" type="protractor">
28746 *     var counter = element(by.binding('counter'));
28747 *     var debug = element(by.binding('confirmed'));
28748 *
28749 *     it('should evaluate the expression if changing from view', function() {
28750 *       expect(counter.getText()).toContain('0');
28751 *
28752 *       element(by.id('ng-change-example1')).click();
28753 *
28754 *       expect(counter.getText()).toContain('1');
28755 *       expect(debug.getText()).toContain('true');
28756 *     });
28757 *
28758 *     it('should not evaluate the expression if changing from model', function() {
28759 *       element(by.id('ng-change-example2')).click();
28760
28761 *       expect(counter.getText()).toContain('0');
28762 *       expect(debug.getText()).toContain('true');
28763 *     });
28764 *   </file>
28765 * </example>
28766 */
28767var ngChangeDirective = valueFn({
28768  restrict: 'A',
28769  require: 'ngModel',
28770  link: function(scope, element, attr, ctrl) {
28771    ctrl.$viewChangeListeners.push(function() {
28772      scope.$eval(attr.ngChange);
28773    });
28774  }
28775});
28776
28777function classDirective(name, selector) {
28778  name = 'ngClass' + name;
28779  return ['$animate', function($animate) {
28780    return {
28781      restrict: 'AC',
28782      link: function(scope, element, attr) {
28783        var oldVal;
28784
28785        scope.$watch(attr[name], ngClassWatchAction, true);
28786
28787        attr.$observe('class', function(value) {
28788          ngClassWatchAction(scope.$eval(attr[name]));
28789        });
28790
28791
28792        if (name !== 'ngClass') {
28793          scope.$watch('$index', function($index, old$index) {
28794            // jshint bitwise: false
28795            var mod = $index & 1;
28796            if (mod !== (old$index & 1)) {
28797              var classes = arrayClasses(scope.$eval(attr[name]));
28798              mod === selector ?
28799                addClasses(classes) :
28800                removeClasses(classes);
28801            }
28802          });
28803        }
28804
28805        function addClasses(classes) {
28806          var newClasses = digestClassCounts(classes, 1);
28807          attr.$addClass(newClasses);
28808        }
28809
28810        function removeClasses(classes) {
28811          var newClasses = digestClassCounts(classes, -1);
28812          attr.$removeClass(newClasses);
28813        }
28814
28815        function digestClassCounts(classes, count) {
28816          // Use createMap() to prevent class assumptions involving property
28817          // names in Object.prototype
28818          var classCounts = element.data('$classCounts') || createMap();
28819          var classesToUpdate = [];
28820          forEach(classes, function(className) {
28821            if (count > 0 || classCounts[className]) {
28822              classCounts[className] = (classCounts[className] || 0) + count;
28823              if (classCounts[className] === +(count > 0)) {
28824                classesToUpdate.push(className);
28825              }
28826            }
28827          });
28828          element.data('$classCounts', classCounts);
28829          return classesToUpdate.join(' ');
28830        }
28831
28832        function updateClasses(oldClasses, newClasses) {
28833          var toAdd = arrayDifference(newClasses, oldClasses);
28834          var toRemove = arrayDifference(oldClasses, newClasses);
28835          toAdd = digestClassCounts(toAdd, 1);
28836          toRemove = digestClassCounts(toRemove, -1);
28837          if (toAdd && toAdd.length) {
28838            $animate.addClass(element, toAdd);
28839          }
28840          if (toRemove && toRemove.length) {
28841            $animate.removeClass(element, toRemove);
28842          }
28843        }
28844
28845        function ngClassWatchAction(newVal) {
28846          if (selector === true || scope.$index % 2 === selector) {
28847            var newClasses = arrayClasses(newVal || []);
28848            if (!oldVal) {
28849              addClasses(newClasses);
28850            } else if (!equals(newVal,oldVal)) {
28851              var oldClasses = arrayClasses(oldVal);
28852              updateClasses(oldClasses, newClasses);
28853            }
28854          }
28855          oldVal = shallowCopy(newVal);
28856        }
28857      }
28858    };
28859
28860    function arrayDifference(tokens1, tokens2) {
28861      var values = [];
28862
28863      outer:
28864      for (var i = 0; i < tokens1.length; i++) {
28865        var token = tokens1[i];
28866        for (var j = 0; j < tokens2.length; j++) {
28867          if (token == tokens2[j]) continue outer;
28868        }
28869        values.push(token);
28870      }
28871      return values;
28872    }
28873
28874    function arrayClasses(classVal) {
28875      var classes = [];
28876      if (isArray(classVal)) {
28877        forEach(classVal, function(v) {
28878          classes = classes.concat(arrayClasses(v));
28879        });
28880        return classes;
28881      } else if (isString(classVal)) {
28882        return classVal.split(' ');
28883      } else if (isObject(classVal)) {
28884        forEach(classVal, function(v, k) {
28885          if (v) {
28886            classes = classes.concat(k.split(' '));
28887          }
28888        });
28889        return classes;
28890      }
28891      return classVal;
28892    }
28893  }];
28894}
28895
28896/**
28897 * @ngdoc directive
28898 * @name ngClass
28899 * @restrict AC
28900 *
28901 * @description
28902 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
28903 * an expression that represents all classes to be added.
28904 *
28905 * The directive operates in three different ways, depending on which of three types the expression
28906 * evaluates to:
28907 *
28908 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
28909 * names.
28910 *
28911 * 2. If the expression evaluates to an object, then for each key-value pair of the
28912 * object with a truthy value the corresponding key is used as a class name.
28913 *
28914 * 3. If the expression evaluates to an array, each element of the array should either be a string as in
28915 * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
28916 * to give you more control over what CSS classes appear. See the code below for an example of this.
28917 *
28918 *
28919 * The directive won't add duplicate classes if a particular class was already set.
28920 *
28921 * When the expression changes, the previously added classes are removed and only then are the
28922 * new classes added.
28923 *
28924 * @animations
28925 * | Animation                        | Occurs                              |
28926 * |----------------------------------|-------------------------------------|
28927 * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
28928 * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
28929 *
28930 * @element ANY
28931 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
28932 *   of the evaluation can be a string representing space delimited class
28933 *   names, an array, or a map of class names to boolean values. In the case of a map, the
28934 *   names of the properties whose values are truthy will be added as css classes to the
28935 *   element.
28936 *
28937 * @example Example that demonstrates basic bindings via ngClass directive.
28938   <example>
28939     <file name="index.html">
28940       <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
28941       <label>
28942          <input type="checkbox" ng-model="deleted">
28943          deleted (apply "strike" class)
28944       </label><br>
28945       <label>
28946          <input type="checkbox" ng-model="important">
28947          important (apply "bold" class)
28948       </label><br>
28949       <label>
28950          <input type="checkbox" ng-model="error">
28951          error (apply "has-error" class)
28952       </label>
28953       <hr>
28954       <p ng-class="style">Using String Syntax</p>
28955       <input type="text" ng-model="style"
28956              placeholder="Type: bold strike red" aria-label="Type: bold strike red">
28957       <hr>
28958       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
28959       <input ng-model="style1"
28960              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
28961       <input ng-model="style2"
28962              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
28963       <input ng-model="style3"
28964              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
28965       <hr>
28966       <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
28967       <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
28968       <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
28969     </file>
28970     <file name="style.css">
28971       .strike {
28972           text-decoration: line-through;
28973       }
28974       .bold {
28975           font-weight: bold;
28976       }
28977       .red {
28978           color: red;
28979       }
28980       .has-error {
28981           color: red;
28982           background-color: yellow;
28983       }
28984       .orange {
28985           color: orange;
28986       }
28987     </file>
28988     <file name="protractor.js" type="protractor">
28989       var ps = element.all(by.css('p'));
28990
28991       it('should let you toggle the class', function() {
28992
28993         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
28994         expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
28995
28996         element(by.model('important')).click();
28997         expect(ps.first().getAttribute('class')).toMatch(/bold/);
28998
28999         element(by.model('error')).click();
29000         expect(ps.first().getAttribute('class')).toMatch(/has-error/);
29001       });
29002
29003       it('should let you toggle string example', function() {
29004         expect(ps.get(1).getAttribute('class')).toBe('');
29005         element(by.model('style')).clear();
29006         element(by.model('style')).sendKeys('red');
29007         expect(ps.get(1).getAttribute('class')).toBe('red');
29008       });
29009
29010       it('array example should have 3 classes', function() {
29011         expect(ps.get(2).getAttribute('class')).toBe('');
29012         element(by.model('style1')).sendKeys('bold');
29013         element(by.model('style2')).sendKeys('strike');
29014         element(by.model('style3')).sendKeys('red');
29015         expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
29016       });
29017
29018       it('array with map example should have 2 classes', function() {
29019         expect(ps.last().getAttribute('class')).toBe('');
29020         element(by.model('style4')).sendKeys('bold');
29021         element(by.model('warning')).click();
29022         expect(ps.last().getAttribute('class')).toBe('bold orange');
29023       });
29024     </file>
29025   </example>
29026
29027   ## Animations
29028
29029   The example below demonstrates how to perform animations using ngClass.
29030
29031   <example module="ngAnimate" deps="angular-animate.js" animations="true">
29032     <file name="index.html">
29033      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
29034      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
29035      <br>
29036      <span class="base-class" ng-class="myVar">Sample Text</span>
29037     </file>
29038     <file name="style.css">
29039       .base-class {
29040         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
29041       }
29042
29043       .base-class.my-class {
29044         color: red;
29045         font-size:3em;
29046       }
29047     </file>
29048     <file name="protractor.js" type="protractor">
29049       it('should check ng-class', function() {
29050         expect(element(by.css('.base-class')).getAttribute('class')).not.
29051           toMatch(/my-class/);
29052
29053         element(by.id('setbtn')).click();
29054
29055         expect(element(by.css('.base-class')).getAttribute('class')).
29056           toMatch(/my-class/);
29057
29058         element(by.id('clearbtn')).click();
29059
29060         expect(element(by.css('.base-class')).getAttribute('class')).not.
29061           toMatch(/my-class/);
29062       });
29063     </file>
29064   </example>
29065
29066
29067   ## ngClass and pre-existing CSS3 Transitions/Animations
29068   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
29069   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
29070   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
29071   to view the step by step details of {@link $animate#addClass $animate.addClass} and
29072   {@link $animate#removeClass $animate.removeClass}.
29073 */
29074var ngClassDirective = classDirective('', true);
29075
29076/**
29077 * @ngdoc directive
29078 * @name ngClassOdd
29079 * @restrict AC
29080 *
29081 * @description
29082 * The `ngClassOdd` and `ngClassEven` directives work exactly as
29083 * {@link ng.directive:ngClass ngClass}, except they work in
29084 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
29085 *
29086 * This directive can be applied only within the scope of an
29087 * {@link ng.directive:ngRepeat ngRepeat}.
29088 *
29089 * @element ANY
29090 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
29091 *   of the evaluation can be a string representing space delimited class names or an array.
29092 *
29093 * @example
29094   <example>
29095     <file name="index.html">
29096        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
29097          <li ng-repeat="name in names">
29098           <span ng-class-odd="'odd'" ng-class-even="'even'">
29099             {{name}}
29100           </span>
29101          </li>
29102        </ol>
29103     </file>
29104     <file name="style.css">
29105       .odd {
29106         color: red;
29107       }
29108       .even {
29109         color: blue;
29110       }
29111     </file>
29112     <file name="protractor.js" type="protractor">
29113       it('should check ng-class-odd and ng-class-even', function() {
29114         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
29115           toMatch(/odd/);
29116         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
29117           toMatch(/even/);
29118       });
29119     </file>
29120   </example>
29121 */
29122var ngClassOddDirective = classDirective('Odd', 0);
29123
29124/**
29125 * @ngdoc directive
29126 * @name ngClassEven
29127 * @restrict AC
29128 *
29129 * @description
29130 * The `ngClassOdd` and `ngClassEven` directives work exactly as
29131 * {@link ng.directive:ngClass ngClass}, except they work in
29132 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
29133 *
29134 * This directive can be applied only within the scope of an
29135 * {@link ng.directive:ngRepeat ngRepeat}.
29136 *
29137 * @element ANY
29138 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
29139 *   result of the evaluation can be a string representing space delimited class names or an array.
29140 *
29141 * @example
29142   <example>
29143     <file name="index.html">
29144        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
29145          <li ng-repeat="name in names">
29146           <span ng-class-odd="'odd'" ng-class-even="'even'">
29147             {{name}} &nbsp; &nbsp; &nbsp;
29148           </span>
29149          </li>
29150        </ol>
29151     </file>
29152     <file name="style.css">
29153       .odd {
29154         color: red;
29155       }
29156       .even {
29157         color: blue;
29158       }
29159     </file>
29160     <file name="protractor.js" type="protractor">
29161       it('should check ng-class-odd and ng-class-even', function() {
29162         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
29163           toMatch(/odd/);
29164         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
29165           toMatch(/even/);
29166       });
29167     </file>
29168   </example>
29169 */
29170var ngClassEvenDirective = classDirective('Even', 1);
29171
29172/**
29173 * @ngdoc directive
29174 * @name ngCloak
29175 * @restrict AC
29176 *
29177 * @description
29178 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
29179 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
29180 * directive to avoid the undesirable flicker effect caused by the html template display.
29181 *
29182 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
29183 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
29184 * of the browser view.
29185 *
29186 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
29187 * `angular.min.js`.
29188 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
29189 *
29190 * ```css
29191 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
29192 *   display: none !important;
29193 * }
29194 * ```
29195 *
29196 * When this css rule is loaded by the browser, all html elements (including their children) that
29197 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
29198 * during the compilation of the template it deletes the `ngCloak` element attribute, making
29199 * the compiled element visible.
29200 *
29201 * For the best result, the `angular.js` script must be loaded in the head section of the html
29202 * document; alternatively, the css rule above must be included in the external stylesheet of the
29203 * application.
29204 *
29205 * @element ANY
29206 *
29207 * @example
29208   <example>
29209     <file name="index.html">
29210        <div id="template1" ng-cloak>{{ 'hello' }}</div>
29211        <div id="template2" class="ng-cloak">{{ 'world' }}</div>
29212     </file>
29213     <file name="protractor.js" type="protractor">
29214       it('should remove the template directive and css class', function() {
29215         expect($('#template1').getAttribute('ng-cloak')).
29216           toBeNull();
29217         expect($('#template2').getAttribute('ng-cloak')).
29218           toBeNull();
29219       });
29220     </file>
29221   </example>
29222 *
29223 */
29224var ngCloakDirective = ngDirective({
29225  compile: function(element, attr) {
29226    attr.$set('ngCloak', undefined);
29227    element.removeClass('ng-cloak');
29228  }
29229});
29230
29231/**
29232 * @ngdoc directive
29233 * @name ngController
29234 *
29235 * @description
29236 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
29237 * supports the principles behind the Model-View-Controller design pattern.
29238 *
29239 * MVC components in angular:
29240 *
29241 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
29242 *   are accessed through bindings.
29243 * * View — The template (HTML with data bindings) that is rendered into the View.
29244 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
29245 *   logic behind the application to decorate the scope with functions and values
29246 *
29247 * Note that you can also attach controllers to the DOM by declaring it in a route definition
29248 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
29249 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
29250 * and executed twice.
29251 *
29252 * @element ANY
29253 * @scope
29254 * @priority 500
29255 * @param {expression} ngController Name of a constructor function registered with the current
29256 * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
29257 * that on the current scope evaluates to a constructor function.
29258 *
29259 * The controller instance can be published into a scope property by specifying
29260 * `ng-controller="as propertyName"`.
29261 *
29262 * If the current `$controllerProvider` is configured to use globals (via
29263 * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
29264 * also be the name of a globally accessible constructor function (not recommended).
29265 *
29266 * @example
29267 * Here is a simple form for editing user contact information. Adding, remov
29267ing, clearing, and
29268 * greeting are methods declared on the controller (see source tab). These methods can
29269 * easily be called from the angular markup. Any changes to the data are automatically reflected
29270 * in the View without the need for a manual update.
29271 *
29272 * Two different declaration styles are included below:
29273 *
29274 * * one binds methods and properties directly onto the controller using `this`:
29275 * `ng-controller="SettingsController1 as settings"`
29276 * * one injects `$scope` into the controller:
29277 * `ng-controller="SettingsController2"`
29278 *
29279 * The second option is more common in the Angular community, and is generally used in boilerplates
29280 * and in this guide. However, there are advantages to binding properties directly to the controller
29281 * and avoiding scope.
29282 *
29283 * * Using `controller as` makes it obvious which controller you are accessing in the template when
29284 * multiple controllers apply to an element.
29285 * * If you are writing your controllers as classes you have easier access to the properties and
29286 * methods, which will appear on the scope, from inside the controller code.
29287 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
29288 * inheritance masking primitives.
29289 *
29290 * This example demonstrates the `controller as` syntax.
29291 *
29292 * <example name="ngControllerAs" module="controllerAsExample">
29293 *   <file name="index.html">
29294 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
29295 *      <label>Name: <input type="text" ng-model="settings.name"/></label>
29296 *      <button ng-click="settings.greet()">greet</button><br/>
29297 *      Contact:
29298 *      <ul>
29299 *        <li ng-repeat="contact in settings.contacts">
29300 *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
29301 *             <option>phone</option>
29302 *             <option>email</option>
29303 *          </select>
29304 *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
29305 *          <button ng-click="settings.clearContact(contact)">clear</button>
29306 *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
29307 *        </li>
29308 *        <li><button ng-click="settings.addContact()">add</button></li>
29309 *     </ul>
29310 *    </div>
29311 *   </file>
29312 *   <file name="app.js">
29313 *    angular.module('controllerAsExample', [])
29314 *      .controller('SettingsController1', SettingsController1);
29315 *
29316 *    function SettingsController1() {
29317 *      this.name = "John Smith";
29318 *      this.contacts = [
29319 *        {type: 'phone', value: '408 555 1212'},
29320 *        {type: 'email', value: '[email protected]'} ];
29321 *    }
29322 *
29323 *    SettingsController1.prototype.greet = function() {
29324 *      alert(this.name);
29325 *    };
29326 *
29327 *    SettingsController1.prototype.addContact = function() {
29328 *      this.contacts.push({type: 'email', value: '[email protected]'});
29329 *    };
29330 *
29331 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
29332 *     var index = this.contacts.indexOf(contactToRemove);
29333 *      this.contacts.splice(index, 1);
29334 *    };
29335 *
29336 *    SettingsController1.prototype.clearContact = function(contact) {
29337 *      contact.type = 'phone';
29338 *      contact.value = '';
29339 *    };
29340 *   </file>
29341 *   <file name="protractor.js" type="protractor">
29342 *     it('should check controller as', function() {
29343 *       var container = element(by.id('ctrl-as-exmpl'));
29344 *         expect(container.element(by.model('settings.name'))
29345 *           .getAttribute('value')).toBe('John Smith');
29346 *
29347 *       var firstRepeat =
29348 *           container.element(by.repeater('contact in settings.contacts').row(0));
29349 *       var secondRepeat =
29350 *           container.element(by.repeater('contact in settings.contacts').row(1));
29351 *
29352 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
29353 *           .toBe('408 555 1212');
29354 *
29355 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
29356 *           .toBe('[email protected]');
29357 *
29358 *       firstRepeat.element(by.buttonText('clear')).click();
29359 *
29360 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
29361 *           .toBe('');
29362 *
29363 *       container.element(by.buttonText('add')).click();
29364 *
29365 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
29366 *           .element(by.model('contact.value'))
29367 *           .getAttribute('value'))
29368 *           .toBe('[email protected]');
29369 *     });
29370 *   </file>
29371 * </example>
29372 *
29373 * This example demonstrates the "attach to `$scope`" style of controller.
29374 *
29375 * <example name="ngController" module="controllerExample">
29376 *  <file name="index.html">
29377 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
29378 *     <label>Name: <input type="text" ng-model="name"/></label>
29379 *     <button ng-click="greet()">greet</button><br/>
29380 *     Contact:
29381 *     <ul>
29382 *       <li ng-repeat="contact in contacts">
29383 *         <select ng-model="contact.type" id="select_{{$index}}">
29384 *            <option>phone</option>
29385 *            <option>email</option>
29386 *         </select>
29387 *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
29388 *         <button ng-click="clearContact(contact)">clear</button>
29389 *         <button ng-click="removeContact(contact)">X</button>
29390 *       </li>
29391 *       <li>[ <button ng-click="addContact()">add</button> ]</li>
29392 *    </ul>
29393 *   </div>
29394 *  </file>
29395 *  <file name="app.js">
29396 *   angular.module('controllerExample', [])
29397 *     .controller('SettingsController2', ['$scope', SettingsController2]);
29398 *
29399 *   function SettingsController2($scope) {
29400 *     $scope.name = "John Smith";
29401 *     $scope.contacts = [
29402 *       {type:'phone', value:'408 555 1212'},
29403 *       {type:'email', value:'[email protected]'} ];
29404 *
29405 *     $scope.greet = function() {
29406 *       alert($scope.name);
29407 *     };
29408 *
29409 *     $scope.addContact = function() {
29410 *       $scope.contacts.push({type:'email', value:'[email protected]'});
29411 *     };
29412 *
29413 *     $scope.removeContact = function(contactToRemove) {
29414 *       var index = $scope.contacts.indexOf(contactToRemove);
29415 *       $scope.contacts.splice(index, 1);
29416 *     };
29417 *
29418 *     $scope.clearContact = function(contact) {
29419 *       contact.type = 'phone';
29420 *       contact.value = '';
29421 *     };
29422 *   }
29423 *  </file>
29424 *  <file name="protractor.js" type="protractor">
29425 *    it('should check controller', function() {
29426 *      var container = element(by.id('ctrl-exmpl'));
29427 *
29428 *      expect(container.element(by.model('name'))
29429 *          .getAttribute('value')).toBe('John Smith');
29430 *
29431 *      var firstRepeat =
29432 *          container.element(by.repeater('contact in contacts').row(0));
29433 *      var secondRepeat =
29434 *          container.element(by.repeater('contact in contacts').row(1));
29435 *
29436 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
29437 *          .toBe('408 555 1212');
29438 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
29439 *          .toBe('[email protected]');
29440 *
29441 *      firstRepeat.element(by.buttonText('clear')).click();
29442 *
29443 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
29444 *          .toBe('');
29445 *
29446 *      container.element(by.buttonText('add')).click();
29447 *
29448 *      expect(container.element(by.repeater('contact in contacts').row(2))
29449 *          .element(by.model('contact.value'))
29450 *          .getAttribute('value'))
29451 *          .toBe('[email protected]');
29452 *    });
29453 *  </file>
29454 *</example>
29455
29456 */
29457var ngControllerDirective = [function() {
29458  return {
29459    restrict: 'A',
29460    scope: true,
29461    controller: '@',
29462    priority: 500
29463  };
29464}];
29465
29466/**
29467 * @ngdoc directive
29468 * @name ngCsp
29469 *
29470 * @element html
29471 * @description
29472 *
29473 * Angular has some features that can break certain
29474 * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
29475 *
29476 * If you intend to implement these rules then you must tell Angular not to use these features.
29477 *
29478 * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
29479 *
29480 *
29481 * The following rules affect Angular:
29482 *
29483 * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
29484 * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
29485 * increase in the speed of evaluating Angular expressions.
29486 *
29487 * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
29488 * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
29489 * To make these directives work when a CSP rule is blocking inline styles, you must link to the
29490 * `angular-csp.css` in your HTML manually.
29491 *
29492 * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
29493 * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
29494 * however, triggers a CSP error to be logged in the console:
29495 *
29496 * ```
29497 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
29498 * script in the following Content Security Policy directive: "default-src 'self'". Note that
29499 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
29500 * ```
29501 *
29502 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
29503 * directive on an element of the HTML document that appears before the `<script>` tag that loads
29504 * the `angular.js` file.
29505 *
29506 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
29507 *
29508 * You can specify which of the CSP related Angular features should be deactivated by providing
29509 * a value for the `ng-csp` attribute. The options are as follows:
29510 *
29511 * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
29512 *
29513 * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
29514 *
29515 * You can use these values in the following combinations:
29516 *
29517 *
29518 * * No declaration means that Angular will assume that you can do inline styles, but it will do
29519 * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
29520 * of Angular.
29521 *
29522 * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
29523 * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
29524 * of Angular.
29525 *
29526 * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
29527 * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
29528 *
29529 * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
29530 * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
29531 *
29532 * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
29533 * styles nor use eval, which is the same as an empty: ng-csp.
29534 * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
29535 *
29536 * @example
29537 * This example shows how to apply the `ngCsp` directive to the `html` tag.
29538   ```html
29539     <!doctype html>
29540     <html ng-app ng-csp>
29541     ...
29542     ...
29543     </html>
29544   ```
29545  * @example
29546      // Note: the suffix `.csp` in the example name triggers
29547      // csp mode in our http server!
29548      <example name="example.csp" module="cspExample" ng-csp="true">
29549        <file name="index.html">
29550          <div ng-controller="MainController as ctrl">
29551            <div>
29552              <button ng-click="ctrl.inc()" id="inc">Increment</button>
29553              <span id="counter">
29554                {{ctrl.counter}}
29555              </span>
29556            </div>
29557
29558            <div>
29559              <button ng-click="ctrl.evil()" id="evil">Evil</button>
29560              <span id="evilError">
29561                {{ctrl.evilError}}
29562              </span>
29563            </div>
29564          </div>
29565        </file>
29566        <file name="script.js">
29567           angular.module('cspExample', [])
29568             .controller('MainController', function() {
29569                this.counter = 0;
29570                this.inc = function() {
29571                  this.counter++;
29572                };
29573                this.evil = function() {
29574                  // jshint evil:true
29575                  try {
29576                    eval('1+2');
29577                  } catch (e) {
29578                    this.evilError = e.message;
29579                  }
29580                };
29581              });
29582        </file>
29583        <file name="protractor.js" type="protractor">
29584          var util, webdriver;
29585
29586          var incBtn = element(by.id('inc'));
29587          var counter = element(by.id('counter'));
29588          var evilBtn = element(by.id('evil'));
29589          var evilError = element(by.id('evilError'));
29590
29591          function getAndClearSevereErrors() {
29592            return browser.manage().logs().get('browser').then(function(browserLog) {
29593              return browserLog.filter(function(logEntry) {
29594                return logEntry.level.value > webdriver.logging.Level.WARNING.value;
29595              });
29596            });
29597          }
29598
29599          function clearErrors() {
29600            getAndClearSevereErrors();
29601          }
29602
29603          function expectNoErrors() {
29604            getAndClearSevereErrors().then(function(filteredLog) {
29605              expect(filteredLog.length).toEqual(0);
29606              if (filteredLog.length) {
29607                console.log('browser console errors: ' + util.inspect(filteredLog));
29608              }
29609            });
29610          }
29611
29612          function expectError(regex) {
29613            getAndClearSevereErrors().then(function(filteredLog) {
29614              var found = false;
29615              filteredLog.forEach(function(log) {
29616                if (log.message.match(regex)) {
29617                  found = true;
29618                }
29619              });
29620              if (!found) {
29621                throw new Error('expected an error that matches ' + regex);
29622              }
29623            });
29624          }
29625
29626          beforeEach(function() {
29627            util = require('util');
29628            webdriver = require('protractor/node_modules/selenium-webdriver');
29629          });
29630
29631          // For now, we only test on Chrome,
29632          // as Safari does not load the page with Protractor's injected scripts,
29633          // and Firefox webdriver always disables content security policy (#6358)
29634          if (browser.params.browser !== 'chrome') {
29635            return;
29636          }
29637
29638          it('should not report errors when the page is loaded', function() {
29639            // clear errors so we are not dependent on previous tests
29640            clearErrors();
29641            // Need to reload the page as the page is already loaded when
29642            // we come here
29643            browser.driver.getCurrentUrl().then(function(url) {
29644              browser.get(url);
29645            });
29646            expectNoErrors();
29647          });
29648
29649          it('should evaluate expressions', function() {
29650            expect(counter.getText()).toEqual('0');
29651            incBtn.click();
29652            expect(counter.getText()).toEqual('1');
29653            expectNoErrors();
29654          });
29655
29656          it('should throw and report an error when using "eval"', function() {
29657            evilBtn.click();
29658            expect(evilError.getText()).toMatch(/Content Security Policy/);
29659            expectError(/Content Security Policy/);
29660          });
29661        </file>
29662      </example>
29663  */
29664
29665// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
29666// bootstrap the system (before $parse is instantiated), for this reason we just have
29667// the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
29668
29669/**
29670 * @ngdoc directive
29671 * @name ngClick
29672 *
29673 * @description
29674 * The ngClick directive allows you to specify custom behavior when
29675 * an element is clicked.
29676 *
29677 * @element ANY
29678 * @priority 0
29679 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
29680 * click. ({@link guide/expression#-event- Event object is available as `$event`})
29681 *
29682 * @example
29683   <example>
29684     <file name="index.html">
29685      <button ng-click="count = count + 1" ng-init="count=0">
29686        Increment
29687      </button>
29688      <span>
29689        count: {{count}}
29690      </span>
29691     </file>
29692     <file name="protractor.js" type="protractor">
29693       it('should check ng-click', function() {
29694         expect(element(by.binding('count')).getText()).toMatch('0');
29695         element(by.css('button')).click();
29696         expect(element(by.binding('count')).getText()).toMatch('1');
29697       });
29698     </file>
29699   </example>
29700 */
29701/*
29702 * A collection of directives that allows creation of custom event handlers that are defined as
29703 * angular expressions and are compiled and executed within the current scope.
29704 */
29705var ngEventDirectives = {};
29706
29707// For events that might fire synchronously during DOM manipulation
29708// we need to execute their event handlers asynchronously using $evalAsync,
29709// so that they are not executed in an inconsistent state.
29710var forceAsyncEvents = {
29711  'blur': true,
29712  'focus': true
29713};
29714forEach(
29715  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
29716  function(eventName) {
29717    var directiveName = directiveNormalize('ng-' + eventName);
29718    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
29719      return {
29720        restrict: 'A',
29721        compile: function($element, attr) {
29722          // We expose the powerful $event object on the scope that provides access to the Window,
29723          // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
29724          // checks at the cost of speed since event handler expressions are not executed as
29725          // frequently as regular change detection.
29726          var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
29727          return function ngEventHandler(scope, element) {
29728            element.on(eventName, function(event) {
29729              var callback = function() {
29730                fn(scope, {$event:event});
29731              };
29732              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
29733                scope.$evalAsync(callback);
29734              } else {
29735                scope.$apply(callback);
29736              }
29737            });
29738          };
29739        }
29740      };
29741    }];
29742  }
29743);
29744
29745/**
29746 * @ngdoc directive
29747 * @name ngDblclick
29748 *
29749 * @description
29750 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
29751 *
29752 * @element ANY
29753 * @priority 0
29754 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
29755 * a dblclick. (The Event object is available as `$event`)
29756 *
29757 * @example
29758   <example>
29759     <file name="index.html">
29760      <button ng-dblclick="count = count + 1" ng-init="count=0">
29761        Increment (on double click)
29762      </button>
29763      count: {{count}}
29764     </file>
29765   </example>
29766 */
29767
29768
29769/**
29770 * @ngdoc directive
29771 * @name ngMousedown
29772 *
29773 * @description
29774 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
29775 *
29776 * @element ANY
29777 * @priority 0
29778 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
29779 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
29780 *
29781 * @example
29782   <example>
29783     <file name="index.html">
29784      <button ng-mousedown="count = count + 1" ng-init="count=0">
29785        Increment (on mouse down)
29786      </button>
29787      count: {{count}}
29788     </file>
29789   </example>
29790 */
29791
29792
29793/**
29794 * @ngdoc directive
29795 * @name ngMouseup
29796 *
29797 * @description
29798 * Specify custom behavior on mouseup event.
29799 *
29800 * @element ANY
29801 * @priority 0
29802 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
29803 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
29804 *
29805 * @example
29806   <example>
29807     <file name="index.html">
29808      <button ng-mouseup="count = count + 1" ng-init="count=0">
29809        Increment (on mouse up)
29810      </button>
29811      count: {{count}}
29812     </file>
29813   </example>
29814 */
29815
29816/**
29817 * @ngdoc directive
29818 * @name ngMouseover
29819 *
29820 * @description
29821 * Specify custom behavior on mouseover event.
29822 *
29823 * @element ANY
29824 * @priority 0
29825 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
29826 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
29827 *
29828 * @example
29829   <example>
29830     <file name="index.html">
29831      <button ng-mouseover="count = count + 1" ng-init="count=0">
29832        Increment (when mouse is over)
29833      </button>
29834      count: {{count}}
29835     </file>
29836   </example>
29837 */
29838
29839
29840/**
29841 * @ngdoc directive
29842 * @name ngMouseenter
29843 *
29844 * @description
29845 * Specify custom behavior on mouseenter event.
29846 *
29847 * @element ANY
29848 * @priority 0
29849 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
29850 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
29851 *
29852 * @example
29853   <example>
29854     <file name="index.html">
29855      <button ng-mouseenter="count = count + 1" ng-init="count=0">
29856        Increment (when mouse enters)
29857      </button>
29858      count: {{count}}
29859     </file>
29860   </example>
29861 */
29862
29863
29864/**
29865 * @ngdoc directive
29866 * @name ngMouseleave
29867 *
29868 * @description
29869 * Specify custom behavior on mouseleave event.
29870 *
29871 * @element ANY
29872 * @priority 0
29873 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
29874 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
29875 *
29876 * @example
29877   <example>
29878     <file name="index.html">
29879      <button ng-mouseleave="count = count + 1" ng-init="count=0">
29880        Increment (when mouse leaves)
29881      </button>
29882      count: {{count}}
29883     </file>
29884   </example>
29885 */
29886
29887
29888/**
29889 * @ngdoc directive
29890 * @name ngMousemove
29891 *
29892 * @description
29893 * Specify custom behavior on mousemove event.
29894 *
29895 * @element ANY
29896 * @priority 0
29897 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
29898 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
29899 *
29900 * @example
29901   <example>
29902     <file name="index.html">
29903      <button ng-mousemove="count = count + 1" ng-init="count=0">
29904        Increment (when mouse moves)
29905      </button>
29906      count: {{count}}
29907     </file>
29908   </example>
29909 */
29910
29911
29912/**
29913 * @ngdoc directive
29914 * @name ngKeydown
29915 *
29916 * @description
29917 * Specify custom behavior on keydown event.
29918 *
29919 * @element ANY
29920 * @priority 0
29921 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
29922 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
29923 *
29924 * @example
29925   <example>
29926     <file name="index.html">
29927      <input ng-keydown="count = count + 1" ng-init="count=0">
29928      key down count: {{count}}
29929     </file>
29930   </example>
29931 */
29932
29933
29934/**
29935 * @ngdoc directive
29936 * @name ngKeyup
29937 *
29938 * @description
29939 * Specify custom behavior on keyup event.
29940 *
29941 * @element ANY
29942 * @priority 0
29943 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
29944 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
29945 *
29946 * @example
29947   <example>
29948     <file name="index.html">
29949       <p>Typing in the input box below updates the key count</p>
29950       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
29951
29952       <p>Typing in the input box below updates the keycode</p>
29953       <input ng-keyup="event=$event">
29954       <p>event keyCode: {{ event.keyCode }}</p>
29955       <p>event altKey: {{ event.altKey }}</p>
29956     </file>
29957   </example>
29958 */
29959
29960
29961/**
29962 * @ngdoc directive
29963 * @name ngKeypress
29964 *
29965 * @description
29966 * Specify custom behavior on keypress event.
29967 *
29968 * @element ANY
29969 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
29970 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
29971 * and can be interrogated for keyCode, altKey, etc.)
29972 *
29973 * @example
29974   <example>
29975     <file name="index.html">
29976      <input ng-keypress="count = count + 1" ng-init="count=0">
29977      key press count: {{count}}
29978     </file>
29979   </example>
29980 */
29981
29982
29983/**
29984 * @ngdoc directive
29985 * @name ngSubmit
29986 *
29987 * @description
29988 * Enables binding angular expressions to onsubmit events.
29989 *
29990 * Additionally it prevents the default action (which for form means 
29990sending the request to the
29991 * server and reloading the current page), but only if the form does not contain `action`,
29992 * `data-action`, or `x-action` attributes.
29993 *
29994 * <div class="alert alert-warning">
29995 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
29996 * `ngSubmit` handlers together. See the
29997 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
29998 * for a detailed discussion of when `ngSubmit` may be triggered.
29999 * </div>
30000 *
30001 * @element form
30002 * @priority 0
30003 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
30004 * ({@link guide/expression#-event- Event object is available as `$event`})
30005 *
30006 * @example
30007   <example module="submitExample">
30008     <file name="index.html">
30009      <script>
30010        angular.module('submitExample', [])
30011          .controller('ExampleController', ['$scope', function($scope) {
30012            $scope.list = [];
30013            $scope.text = 'hello';
30014            $scope.submit = function() {
30015              if ($scope.text) {
30016                $scope.list.push(this.text);
30017                $scope.text = '';
30018              }
30019            };
30020          }]);
30021      </script>
30022      <form ng-submit="submit()" ng-controller="ExampleController">
30023        Enter text and hit enter:
30024        <input type="text" ng-model="text" name="text" />
30025        <input type="submit" id="submit" value="Submit" />
30026        <pre>list={{list}}</pre>
30027      </form>
30028     </file>
30029     <file name="protractor.js" type="protractor">
30030       it('should check ng-submit', function() {
30031         expect(element(by.binding('list')).getText()).toBe('list=[]');
30032         element(by.css('#submit')).click();
30033         expect(element(by.binding('list')).getText()).toContain('hello');
30034         expect(element(by.model('text')).getAttribute('value')).toBe('');
30035       });
30036       it('should ignore empty strings', function() {
30037         expect(element(by.binding('list')).getText()).toBe('list=[]');
30038         element(by.css('#submit')).click();
30039         element(by.css('#submit')).click();
30040         expect(element(by.binding('list')).getText()).toContain('hello');
30041        });
30042     </file>
30043   </example>
30044 */
30045
30046/**
30047 * @ngdoc directive
30048 * @name ngFocus
30049 *
30050 * @description
30051 * Specify custom behavior on focus event.
30052 *
30053 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
30054 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
30055 * during an `$apply` to ensure a consistent state.
30056 *
30057 * @element window, input, select, textarea, a
30058 * @priority 0
30059 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
30060 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
30061 *
30062 * @example
30063 * See {@link ng.directive:ngClick ngClick}
30064 */
30065
30066/**
30067 * @ngdoc directive
30068 * @name ngBlur
30069 *
30070 * @description
30071 * Specify custom behavior on blur event.
30072 *
30073 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
30074 * an element has lost focus.
30075 *
30076 * Note: As the `blur` event is executed synchronously also during DOM manipulations
30077 * (e.g. removing a focussed input),
30078 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
30079 * during an `$apply` to ensure a consistent state.
30080 *
30081 * @element window, input, select, textarea, a
30082 * @priority 0
30083 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
30084 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
30085 *
30086 * @example
30087 * See {@link ng.directive:ngClick ngClick}
30088 */
30089
30090/**
30091 * @ngdoc directive
30092 * @name ngCopy
30093 *
30094 * @description
30095 * Specify custom behavior on copy event.
30096 *
30097 * @element window, input, select, textarea, a
30098 * @priority 0
30099 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
30100 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
30101 *
30102 * @example
30103   <example>
30104     <file name="index.html">
30105      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
30106      copied: {{copied}}
30107     </file>
30108   </example>
30109 */
30110
30111/**
30112 * @ngdoc directive
30113 * @name ngCut
30114 *
30115 * @description
30116 * Specify custom behavior on cut event.
30117 *
30118 * @element window, input, select, textarea, a
30119 * @priority 0
30120 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
30121 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
30122 *
30123 * @example
30124   <example>
30125     <file name="index.html">
30126      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
30127      cut: {{cut}}
30128     </file>
30129   </example>
30130 */
30131
30132/**
30133 * @ngdoc directive
30134 * @name ngPaste
30135 *
30136 * @description
30137 * Specify custom behavior on paste event.
30138 *
30139 * @element window, input, select, textarea, a
30140 * @priority 0
30141 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
30142 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
30143 *
30144 * @example
30145   <example>
30146     <file name="index.html">
30147      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
30148      pasted: {{paste}}
30149     </file>
30150   </example>
30151 */
30152
30153/**
30154 * @ngdoc directive
30155 * @name ngIf
30156 * @restrict A
30157 * @multiElement
30158 *
30159 * @description
30160 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
30161 * {expression}. If the expression assigned to `ngIf` evaluates to a false
30162 * value then the element is removed from the DOM, otherwise a clone of the
30163 * element is reinserted into the DOM.
30164 *
30165 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
30166 * element in the DOM rather than changing its visibility via the `display` css property.  A common
30167 * case when this difference is significant is when using css selectors that rely on an element's
30168 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
30168s.
30169 *
30170 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
30171 * is created when the element is restored.  The scope created within `ngIf` inherits from
30172 * its parent scope using
30173 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
30174 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
30175 * a javascript primitive defined in the parent scope. In this case any modifications made to the
30176 * variable within the child scope will override (hide) the value in the parent scope.
30177 *
30178 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
30179 * is if an element's class attribute is directly modified after it's compiled, using something like
30180 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
30181 * the added class will be lost because the original compiled state is used to regenerate the element.
30182 *
30183 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
30184 * and `leave` effects.
30185 *
30186 * @animations
30187 * | Animation                        | Occurs                               |
30188 * |----------------------------------|-------------------------------------|
30189 * | {@link ng.$animate#enter enter}  | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
30190 * | {@link ng.$animate#leave leave}  | just before the `ngIf` contents are removed from the DOM |
30191 *
30192 * @element ANY
30193 * @scope
30194 * @priority 600
30195 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
30196 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
30197 *     element is added to the DOM tree.
30198 *
30199 * @example
30200  <example module="ngAnimate" deps="angular-animate.js" animations="true">
30201    <file name="index.html">
30202      <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
30203      Show when checked:
30204      <span ng-if="checked" class="animate-if">
30205        This is removed when the checkbox is unchecked.
30206      </span>
30207    </file>
30208    <file name="animations.css">
30209      .animate-if {
30210        background:white;
30211        border:1px solid black;
30212        padding:10px;
30213      }
30214
30215      .animate-if.ng-enter, .animate-if.ng-leave {
30216        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
30217      }
30218
30219      .animate-if.ng-enter,
30220      .animate-if.ng-leave.ng-leave-active {
30221        opacity:0;
30222      }
30223
30224      .animate-if.ng-leave,
30225      .animate-if.ng-enter.ng-enter-active {
30226        opacity:1;
30227      }
30228    </file>
30229  </example>
30230 */
30231var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
30232  return {
30233    multiElement: true,
30234    transclude: 'element',
30235    priority: 600,
30236    terminal: true,
30237    restrict: 'A',
30238    $$tlb: true,
30239    link: function($scope, $element, $attr, ctrl, $transclude) {
30240        var block, childScope, previousElements;
30241        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
30242
30243          if (value) {
30244            if (!childScope) {
30245              $transclude(function(clone, newScope) {
30246                childScope = newScope;
30247                clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
30248                // Note: We only need the first/last node of the cloned nodes.
30249                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
30250                // by a directive with templateUrl when its template arrives.
30251                block = {
30252                  clone: clone
30253                };
30254                $animate.enter(clone, $element.parent(), $element);
30255              });
30256            }
30257          } else {
30258            if (previousElements) {
30259              previousElements.remove();
30260              previousElements = null;
30261            }
30262            if (childScope) {
30263              childScope.$destroy();
30264              childScope = null;
30265            }
30266            if (block) {
30267              previousElements = getBlockNodes(block.clone);
30268              $animate.leave(previousElements).then(function() {
30269                previousElements = null;
30270              });
30271              block = null;
30272            }
30273          }
30274        });
30275    }
30276  };
30277}];
30278
30279/**
30280 * @ngdoc directive
30281 * @name ngInclude
30282 * @restrict ECA
30283 *
30284 * @description
30285 * Fetches, compiles and includes an external HTML fragment.
30286 *
30287 * By default, the template URL is restricted to the same domain and protocol as the
30288 * application document. This is done by calling {@link $sce#getTrustedResourceUrl
30289 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
30290 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
30291 * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
30292 * ng.$sce Strict Contextual Escaping}.
30293 *
30294 * In addition, the browser's
30295 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
30296 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
30297 * policy may further restrict whether the template is successfully loaded.
30298 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
30299 * access on some browsers.
30300 *
30301 * @animations
30302 * | Animation                        | Occurs                              |
30303 * |----------------------------------|-------------------------------------|
30304 * | {@link ng.$animate#enter enter}  | when the expression changes, on the new include |
30305 * | {@link ng.$animate#leave leave}  | when the expression changes, on the old include |
30306 *
30307 * The enter and leave animation occur concurrently.
30308 *
30309 * @scope
30310 * @priority 400
30311 *
30312 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
30313 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
30314 * @param {string=} onload Expression to evaluate when a new partial is loaded.
30315 *                  <div class="alert alert-warning">
30316 *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
30317 *                  a function with the name on the window element, which will usually throw a
30318 *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
30319 *                  different form that {@link guide/directive#normalization matches} `onload`.
30320 *                  </div>
30321   *
30322 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
30323 *                  $anchorScroll} to scroll the viewport after the content is loaded.
30324 *
30325 *                  - If the attribute is not set, disable scrolling.
30326 *                  - If the attribute is set without value, enable scrolling.
30327 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
30328 *
30329 * @example
30330  <example module="includeExample" deps="angular-animate.js" animations="true">
30331    <file name="index.html">
30332     <div ng-controller="ExampleController">
30333       <select ng-model="template" ng-options="t.name for t in templates">
30334        <option value="">(blank)</option>
30335       </select>
30336       url of the template: <code>{{template.url}}</code>
30337       <hr/>
30338       <div class="slide-animate-container">
30339         <div class="slide-animate" ng-include="template.url"></div>
30340       </div>
30341     </div>
30342    </file>
30343    <file name="script.js">
30344      angular.module('includeExample', ['ngAnimate'])
30345        .controller('ExampleController', ['$scope', function($scope) {
30346          $scope.templates =
30347            [ { name: 'template1.html', url: 'template1.html'},
30348              { name: 'template2.html', url: 'template2.html'} ];
30349          $scope.template = $scope.templates[0];
30350        }]);
30351     </file>
30352    <file name="template1.html">
30353      Content of template1.html
30354    </file>
30355    <file name="template2.html">
30356      Content of template2.html
30357    </file>
30358    <file name="animations.css">
30359      .slide-animate-container {
30360        position:relative;
30361        background:white;
30362        border:1px solid black;
30363        height:40px;
30364        overflow:hidden;
30365      }
30366
30367      .slide-animate {
30368        padding:10px;
30369      }
30370
30371      .slide-animate.ng-enter, .slide-animate.ng-leave {
30372        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
30373
30374        position:absolute;
30375        top:0;
30376        left:0;
30377        right:0;
30378        bottom:0;
30379        display:block;
30380        padding:10px;
30381      }
30382
30383      .slide-animate.ng-enter {
30384        top:-50px;
30385      }
30386      .slide-animate.ng-enter.ng-enter-active {
30387        top:0;
30388      }
30389
30390      .slide-animate.ng-leave {
30391        top:0;
30392      }
30393      .slide-animate.ng-leave.ng-leave-active {
30394        top:50px;
30395      }
30396    </file>
30397    <file name="protractor.js" type="protractor">
30398      var templateSelect = element(by.model('template'));
30399      var includeElem = element(by.css('[ng-include]'));
30400
30401      it('should load template1.html', function() {
30402        expect(includeElem.getText()).toMatch(/Content of template1.html/);
30403      });
30404
30405      it('should load template2.html', function() {
30406        if (browser.params.browser == 'firefox') {
30407          // Firefox can't handle using selects
30408          // See https://github.com/angular/protractor/issues/480
30409          return;
30410        }
30411        templateSelect.click();
30412        templateSelect.all(by.css('option')).get(2).click();
30413        expect(includeElem.getText()).toMatch(/Content of template2.html/);
30414      });
30415
30416      it('should change to blank', function() {
30417        if (browser.params.browser == 'firefox') {
30418          // Firefox can't handle using selects
30419          return;
30420        }
30421        templateSelect.click();
30422        templateSelect.all(by.css('option')).get(0).click();
30423        expect(includeElem.isPresent()).toBe(false);
30424      });
30425    </file>
30426  </example>
30427 */
30428
30429
30430/**
30431 * @ngdoc event
30432 * @name ngInclude#$includeContentRequested
30433 * @eventType emit on the scope ngInclude was declared in
30434 * @description
30435 * Emitted every time the ngInclude content is requested.
30436 *
30437 * @param {Object} angularEvent Synthetic event object.
30438 * @param {String} src URL of content to load.
30439 */
30440
30441
30442/**
30443 * @ngdoc event
30444 * @name ngInclude#$includeContentLoaded
30445 * @eventType emit on the current ngInclude scope
30446 * @description
30447 * Emitted every time the ngInclude content is reloaded.
30448 *
30449 * @param {Object} angularEvent Synthetic event object.
30450 * @param {String} src URL of content to load.
30451 */
30452
30453
30454/**
30455 * @ngdoc event
30456 * @name ngInclude#$includeContentError
30457 * @eventType emit on the scope ngInclude was declared in
30458 * @description
30459 * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
30460 *
30461 * @param {Object} angularEvent Synthetic event object.
30462 * @param {String} src URL of content to load.
30463 */
30464var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
30465                  function($templateRequest,   $anchorScroll,   $animate) {
30466  return {
30467    restrict: 'ECA',
30468    priority: 400,
30469    terminal: true,
30470    transclude: 'element',
30471    controller: angular.noop,
30472    compile: function(element, attr) {
30473      var srcExp = attr.ngInclude || attr.src,
30474          onloadExp = attr.onload || '',
30475          autoScrollExp = attr.autoscroll;
30476
30477      return function(scope, $element, $attr, ctrl, $transclude) {
30478        var changeCounter = 0,
30479            currentScope,
30480            previousElement,
30481            currentElement;
30482
30483        var cleanupLastIncludeContent = function() {
30484          if (previousElement) {
30485            previousElement.remove();
30486            previousElement = null;
30487          }
30488          if (currentScope) {
30489            currentScope.$destroy();
30490            currentScope = null;
30491          }
30492          if (currentElement) {
30493            $animate.leave(currentElement).then(function() {
30494              previousElement = null;
30495            });
30496            previousElement = currentElement;
30497            currentElement = null;
30498          }
30499        };
30500
30501        scope.$watch(srcExp, function ngIncludeWatchAction(src) {
30502          var afterAnimation = function() {
30503            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
30504              $anchorScroll();
30505            }
30506          };
30507          var thisChangeId = ++changeCounter;
30508
30509          if (src) {
30510            //set the 2nd param to true to ignore the template request error so that the inner
30511            //contents and scope can be cleaned up.
30512            $templateRequest(src, true).then(function(response) {
30513              if (scope.$$destroyed) return;
30514
30515              if (thisChangeId !== changeCounter) return;
30516              var newScope = scope.$new();
30517              ctrl.template = response;
30518
30519              // Note: This will also link all children of ng-include that were contained in the original
30520              // html. If that content contains controllers, ... they could pollute/change the scope.
30521              // However, using ng-include on an element with additional content does not make sense...
30522              // Note: We can't remove them in the cloneAttchFn of $transclude as that
30523              // function is called before linking the content, which would apply child
30524              // directives to non existing elements.
30525              var clone = $transclude(newScope, function(clone) {
30526                cleanupLastIncludeContent();
30527                $animate.enter(clone, null, $element).then(afterAnimation);
30528              });
30529
30530              currentScope = newScope;
30531              currentElement = clone;
30532
30533              currentScope.$emit('$includeContentLoaded', src);
30534              scope.$eval(onloadExp);
30535            }, function() {
30536              if (scope.$$destroyed) return;
30537
30538              if (thisChangeId === changeCounter) {
30539                cleanupLastIncludeContent();
vendor: 2,835 bytes, lines 30540-30622
30540                scope.$emit('$includeContentError', src);
30541              }
30542            });
30543            scope.$emit('$includeContentRequested', src);
30544          } else {
30545            cleanupLastIncludeContent();
30546            ctrl.template = null;
30547          }
30548        });
30549      };
30550    }
30551  };
30552}];
30553
30554// This directive is called during the $transclude call of the first `ngInclude` directive.
30555// It will replace and compile the content of the element with the loaded template.
30556// We need this directive so that the element content is already filled when
30557// the link function of another directive on the same element as ngInclude
30558// is called.
30559var ngIncludeFillContentDirective = ['$compile',
30560  function($compile) {
30561    return {
30562      restrict: 'ECA',
30563      priority: -400,
30564      require: 'ngInclude',
30565      link: function(scope, $element, $attr, ctrl) {
30566        if (toString.call($element[0]).match(/SVG/)) {
30567          // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
30568          // support innerHTML, so detect this here and try to generate the contents
30569          // specially.
30570          $element.empty();
30571          $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
30572              function namespaceAdaptedClone(clone) {
30573            $element.append(clone);
30574          }, {futureParentElement: $element});
30575          return;
30576        }
30577
30578        $element.html(ctrl.template);
30579        $compile($element.contents())(scope);
30580      }
30581    };
30582  }];
30583
30584/**
30585 * @ngdoc directive
30586 * @name ngInit
30587 * @restrict AC
30588 *
30589 * @description
30590 * The `ngInit` directive allows you to evaluate an expression in the
30591 * current scope.
30592 *
30593 * <div class="alert alert-danger">
30594 * This directive can be abused to add unnecessary amounts of logic into your templates.
30595 * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
30596 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
30597 * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
30598 * rather than `ngInit` to initialize values on a scope.
30599 * </div>
30600 *
30601 * <div class="alert alert-warning">
30602 * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
30603 * sure you have parentheses to ensure correct operator precedence:
30604 * <pre class="prettyprint">
30605 * `<div ng-init="test1 = ($index | toString)"></div>`
30606 * </pre>
30607 * </div>
30608 *
30609 * @priority 450
30610 *
30611 * @element ANY
30612 * @param {expression} ngInit {@link guide/expression Expression} to eval.
30613 *
30614 * @example
30615   <example module="initExample">
30616     <file name="index.html">
30617   <script>
30618     angular.module('initExample', [])
30619       .controller('ExampleController', ['$scope', function($scope) {
30620         $scope.list = [['a', 'b'], ['c', 'd']];
30621       }]);
30622   </script>
30623   <div ng-controller="ExampleController">
30624     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
30625       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
30626          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
30627       </div>
30628     </div>
30629   </div>
30630     </file>
30631     <file name="protractor.js" type="protractor">
30632       it('should alias index positions', function() {
30633         var elements = element.all(by.css('.example-init'));
30634         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
30635         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
30636         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
30637         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
30638       });
30639     </file>
30640   </example>
30641 */
30642var ngInitDirective = ngDirective({
30643  priority: 450,
30644  compile: function() {
30645    return {
30646      pre: function(scope, element, attrs) {
30647        scope.$eval(attrs.ngInit);
30648      }
30649    };
30650  }
30651});
30652
30653/**
30654 * @ngdoc directive
30655 * @name ngList
30656 *
30657 * @description
30658 * Text input that converts between a delimited string and an array of strings. The default
30659 * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
30660 * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
30661 *
30662 * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
30663 * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
30664 *   list item is respected. This implies that the user of the directive is responsible for
30665 *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
30666 *   tab or newline character.
30667 * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
30668 *   when joining the list items back together) and whitespace around each list item is stripped
30669 *   before it is added to the model.
30670 *
30671 * ### Example with Validation
30672 *
30673 * <example name="ngList-directive" module="listExample">
30674 *   <file name="app.js">
30675 *      angular.module('listExample', [])
30676 *        .controller('ExampleController', ['$scope', function($scope) {
30677 *          $scope.names = ['morpheus', 'neo', 'trinity'];
30678 *        }]);
30679 *   </file>
30680 *   <file name="index.html">
30681 *    <form name="myForm" ng-controller="ExampleController">
30682 *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
30683 *      <span role="alert">
30684 *        <span class="error" ng-show="myForm.namesInput.$error.required">
30685 *        Required!</span>
30686 *      </span>
30687 *      <br>
30688 *      <tt>names = {{names}}</tt><br/>
30689 *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
30690 *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
30691 *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30692 *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30693 *     </form>
30694 *   </file>
30695 *   <file name="protractor.js" type="protractor">
30696 *     var listInput = element(by.model('names'));
30697 *     var names = element(by.exactBinding('names'));
30698 *     var valid = element(by.binding('myForm.namesInput.$valid'));
30699 *     var error = element(by.css('span.error'));
30700 *
30701 *     it('should initialize to model', function() {
30702 *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
30703 *       expect(valid.getText()).toContain('true');
30704 *       expect(error.getCssValue('display')).toBe('none');
30705 *     });
30706 *
30707 *     it('should be invalid if empty', function() {
30708 *       listInput.clear();
30709 *       listInput.sendKeys('');
30710 *
30711 *       expect(names.getText()).toContain('');
30712 *       expect(valid.getText()).toContain('false');
30713 *       expect(error.getCssValue('display')).not.toBe('none');
30714 *     });
30715 *   </file>
30716 * </example>
30717 *
30718 * ### Example - splitting on newline
30719 * <example name="ngList-directive-newlines">
30720 *   <file name="index.html">
30721 *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
30722 *    <pre>{{ list | json }}</pre>
30723 *   </file>
30724 *   <file name="protractor.js" type="protractor">
30725 *     it("should split the text by newlines", function() {
30726 *       var listInput = element(by.model('list'));
30727 *       var output = element(by.binding('list | json'));
30728 *       listInput.sendKeys('abc\ndef\nghi');
30729 *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
30730 *     });
30731 *   </file>
30732 * </example>
30733 *
30734 * @element input
30735 * @param {string=} ngList optional delimiter that should be used to split the value.
30736 */
30737var ngListDirective = function() {
30738  return {
30739    restrict: 'A',
30740    priority: 100,
30741    require: 'ngModel',
30742    link: function(scope, element, attr, ctrl) {
30743      // We want to control whitespace trimming so we use this convoluted approach
30744      // to access the ngList attribute, which doesn't pre-trim the attribute
30745      var ngList = element.attr(attr.$attr.ngList) || ', ';
30746      var trimValues = attr.ngTrim !== 'false';
30747      var separator = trimValues ? trim(ngList) : ngList;
30748
30749      var parse = function(viewValue) {
30750        // If the viewValue is invalid (say required but empty) it will be `undefined`
30751        if (isUndefined(viewValue)) return;
30752
30753        var list = [];
30754
30755        if (viewValue) {
30756          forEach(viewValue.split(separator), function(value) {
30757            if (value) list.push(trimValues ? trim(value) : value);
30758          });
30759        }
30760
30761        return list;
30762      };
30763
30764      ctrl.$parsers.push(parse);
30765      ctrl.$formatters.push(function(value) {
30766        if (isArray(value)) {
30767          return value.join(ngList);
30768        }
30769
30770        return undefined;
30771      });
30772
30773      // Override the standard $isEmpty because an empty array means the input is empty.
30774      ctrl.$isEmpty = function(value) {
30775        return !value || !value.length;
30776      };
30777    }
30778  };
30779};
30780
30781/* global VALID_CLASS: true,
30782  INVALID_CLASS: true,
30783  PRISTINE_CLASS: true,
30784  DIRTY_CLASS: true,
30785  UNTOUCHED_CLASS: true,
30786  TOUCHED_CLASS: true,
30787*/
30788
30789var VALID_CLASS = 'ng-valid',
30790    INVALID_CLASS = 'ng-invalid',
30791    PRISTINE_CLASS = 'ng-pristine',
30792    DIRTY_CLASS = 'ng-dirty',
30793    UNTOUCHED_CLASS = 'ng-untouched',
30794    TOUCHED_CLASS = 'ng-touched',
30795    PENDING_CLASS = 'ng-pending',
30796    EMPTY_CLASS = 'ng-empty',
30797    NOT_EMPTY_CLASS = 'ng-not-empty';
30798
30799var ngModelMinErr = minErr('ngModel');
30800
30801/**
30802 * @ngdoc type
30803 * @name ngModel.NgModelController
30804 *
30805 * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
30806 * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
30807 * is set.
30808 * @property {*} $modelValue The value in the model that the control is bound to.
30809 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
30810       the control reads value from the DOM. The functions are called in array order, each passing
30811       its return value through to the next. The last return value is forwarded to the
30812       {@link ngModel.NgModelController#$validators `$validators`} collection.
30813
30814Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
30815`$viewValue`}.
30816
30817Returning `undefined` from a parser means a parse error occurred. In that case,
30818no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
30819will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
30820is set to `true`. The parse error is stored in `ngModel.$error.parse`.
30821
30822 *
30823 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
30824       the model value changes. The functions are called in reverse array order, each passing the value through to the
30825       next. The last return value is used as the actual DOM value.
30826       Used to format / convert values for display in the control.
30827 * ```js
30828 * function formatter(value) {
30829 *   if (value) {
30830 *     return value.toUpperCase();
30831 *   }
30832 * }
30833 * ngModel.$formatters.push(formatter);
30834 * ```
30835 *
30836 * @property {Object.<string, function>} $validators A collection of validators that are applied
30837 *      whenever the model value changes. The key value within the object refers to the name of the
30838 *      validator while the function refers to the validation operation. The validation operation is
30839 *      provided with the model value as an argument and must return a true or false value depending
30840 *      on the response of that validation.
30841 *
30842 * ```js
30843 * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
30844 *   var value = modelValue || viewValue;
30845 *   return /[0-9]+/.test(value) &&
30846 *          /[a-z]+/.test(value) &&
30847 *          /[A-Z]+/.test(value) &&
30848 *          /\W+/.test(value);
30849 * };
30850 * ```
30851 *
30852 * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
30853 *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
30854 *      is expected to return a promise when it is run during the model validation process. Once the promise
30855 *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
30856 *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
30857 *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
30858 *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
30859 *      will only run once all synchronous validators have passed.
30860 *
30861 * Please note that if $http is used then it is important that the server returns a success HTTP response code
30862 * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
30863 *
30864 * ```js
30865 * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
30866 *   var value = modelValue || viewValue;
30867 *
30868 *   // Lookup user by username
30869 *   return $http.get('/api/users/' + value).
30870 *      then(function resolved() {
30871 *        //username exists, this means validation fails
30872 *        return $q.reject('exists');
30873 *      }, function rejected() {
30874 *        //username does not exist, therefore this validation passes
30875 *        return true;
30876 *      });
30877 * };
30878 * ```
30879 *
30880 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
30881 *     view value has changed. It is called with no arguments, and its return value is ignored.
30882 *     This can be used in place of additional $watches against the model value.
30883 *
30884 * @property {Object} $error An object hash with all failing validator ids as keys.
30885 * @property {Object} $pending An object hash with all pending validator ids as keys.
30886 *
30887 * @property {boolean} $untouched True if control has not lost focus yet.
30888 * @property {boolean} $touched True if control has lost focus.
30889 * @property {boolean} $pristine True if user has not interacted with the control yet.
30890 * @property {boolean} $dirty True if user has already interacted with the control.
30891 * @property {boolean} $valid True if there is no error.
30892 * @property {boolean}
30892 $invalid True if at least one error on the control.
30893 * @property {string} $name The name attribute of the control.
30894 *
30895 * @description
30896 *
30897 * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
30898 * The controller contains services for data-binding, validation, CSS updates, and value formatting
30899 * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
30900 * listening to DOM events.
30901 * Such DOM related logic should be provided by other directives which make use of
30902 * `NgModelController` for data-binding to control elements.
30903 * Angular provides this DOM logic for most {@link input `input`} elements.
30904 * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
30905 * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
30906 *
30907 * @example
30908 * ### Custom Control Example
30909 * This example shows how to use `NgModelController` with a custom control to achieve
30910 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
30911 * collaborate together to achieve the desired result.
30912 *
30913 * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
30914 * contents be edited in place by the user.
30915 *
30916 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
30917 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
30918 * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
30919 * that content using the `$sce` service.
30920 *
30921 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
30922    <file name="style.css">
30923      [contenteditable] {
30924        border: 1px solid black;
30925        background-color: white;
30926        min-height: 20px;
30927      }
30928
30929      .ng-invalid {
30930        border: 1px solid red;
30931      }
30932
30933    </file>
30934    <file name="script.js">
30935      angular.module('customControl', ['ngSanitize']).
30936        directive('contenteditable', ['$sce', function($sce) {
30937          return {
30938            restrict: 'A', // only activate on element attribute
30939            require: '?ngModel', // get a hold of NgModelController
30940            link: function(scope, element, attrs, ngModel) {
30941              if (!ngModel) return; // do nothing if no ng-model
30942
30943              // Specify how UI should be updated
30944              ngModel.$render = function() {
30945                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
30946              };
30947
30948              // Listen for change events to enable binding
30949              element.on('blur keyup change', function() {
30950                scope.$evalAsync(read);
30951              });
30952              read(); // initialize
30953
30954              // Write data to the model
30955              function read() {
30956                var html = element.html();
30957                // When we clear the content editable the browser leaves a <br> behind
30958                // If strip-br attribute is provided then we strip this out
30959                if ( attrs.stripBr && html == '<br>' ) {
30960                  html = '';
30961                }
30962                ngModel.$setViewValue(html);
30963              }
30964            }
30965          };
30966        }]);
30967    </file>
30968    <file name="index.html">
30969      <form name="myForm">
30970       <div contenteditable
30971            name="myWidget" ng-model="userContent"
30972            strip-br="true"
30973            required>Change me!</div>
30974        <span ng-show="myForm.myWidget.$error.required">Required!</span>
30975       <hr>
30976       <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
30977      </form>
30978    </file>
30979    <file name="protractor.js" type="protractor">
30980    it('should data-bind and become invalid', function() {
30981      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
30982        // SafariDriver can't handle contenteditable
30983        // and Firefox driver can't clear contenteditables very well
30984        return;
30985      }
30986      var contentEditable = element(by.css('[contenteditable]'));
30987      var content = 'Change me!';
30988
30989      expect(contentEditable.getText()).toEqual(content);
30990
30991      contentEditable.clear();
30992      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
30993      expect(contentEditable.getText()).toEqual('');
30994      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
30995    });
30996    </file>
30997 * </example>
30998 *
30999 *
31000 */
31001var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
31002    function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
31003  this.$viewValue = Number.NaN;
31004  this.$modelValue = Number.NaN;
31005  this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
31006  this.$validators = {};
31007  this.$asyncValidators = {};
31008  this.$parsers = [];
31009  this.$formatters = [];
31010  this.$viewChangeListeners = [];
31011  this.$untouched = true;
31012  this.$touched = false;
31013  this.$pristine = true;
31014  this.$dirty = false;
31015  this.$valid = true;
31016  this.$invalid = false;
31017  this.$error = {}; // keep invalid keys here
31018  this.$$success = {}; // keep valid keys here
31019  this.$pending = undefined; // keep pending keys here
31020  this.$name = $interpolate($attr.name || '', false)($scope);
31021  this.$$parentForm = nullFormCtrl;
31022
31023  var parsedNgModel = $parse($attr.ngModel),
31024      parsedNgModelAssign = parsedNgModel.assign,
31025      ngModelGet = parsedNgModel,
31026      ngModelSet = parsedNgModelAssign,
31027      pendingDebounce = null,
31028      parserValid,
31029      ctrl = this;
31030
31031  this.$$setOptions = function(options) {
31032    ctrl.$options = options;
31033    if (options && options.getterSetter) {
31034      var invokeModelGetter = $parse($attr.ngModel + '()'),
31035          invokeModelSetter = $parse($attr.ngModel + '($$$p)');
31036
31037      ngModelGet = function($scope) {
31038        var modelValue = parsedNgModel($scope);
31039        if (isFunction(modelValue)) {
31040          modelValue = invokeModelGetter($scope);
31041        }
31042        return modelValue;
31043      };
31044      ngModelSet = function($scope, newValue) {
31045        if (isFunction(parsedNgModel($scope))) {
31046          invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
31047        } else {
31048          parsedNgModelAssign($scope, ctrl.$modelValue);
31049        }
31050      };
31051    } else if (!parsedNgModel.assign) {
31052      throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
31053          $attr.ngModel, startingTag($element));
31054    }
31055  };
31056
31057  /**
31058   * @ngdoc method
31059   * @name ngModel.NgModelController#$render
31060   *
31061   * @description
31062   * Called when the view needs to be updated. It is expected that the user of the ng-model
31063   * directive will implement this method.
31064   *
31065   * The `$render()` method is invoked in the following situations:
31066   *
31067   * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
31068   *   committed value then `$render()` is called to update the input control.
31069   * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
31070   *   the `$viewValue` are different from last time.
31071   *
31072   * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
31073   * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
31074   * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
31075   * invoked if you only change a property on the objects.
31076   */
31077  this.$render = noop;
31078
31079  /**
31080   * @ngdoc method
31081   * @name ngModel.NgModelController#$isEmpty
31082   *
31083   * @description
31084   * This is called when we need to determine if the value of an input is empty.
31085   *
31086   * For instance, the required directive does this to work out if the input has data or not.
31087   *
31088   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
31089   *
31090   * You can override this for input directives whose concept of being empty is different from the
31091   * default. The `checkboxInputType` directive does this because in its case a value of `false`
31092   * implies empty.
31093   *
31094   * @param {*} value The value of the input to check for emptiness.
31095   * @returns {boolean} True if `value` is "empty".
31096   */
31097  this.$isEmpty = function(value) {
31098    return isUndefined(value) || value === '' || value === null || value !== value;
31099  };
31100
31101  this.$$updateEmptyClasses = function(value) {
31102    if (ctrl.$isEmpty(value)) {
31103      $animate.removeClass($element, NOT_EMPTY_CLASS);
31104      $animate.addClass($element, EMPTY_CLASS);
31105    } else {
31106      $animate.removeClass($element, EMPTY_CLASS);
31107      $animate.addClass($element, NOT_EMPTY_CLASS);
31108    }
31109  };
31110
31111
31112  var currentValidationRunId = 0;
31113
31114  /**
31115   * @ngdoc method
31116   * @name ngModel.NgModelController#$setValidity
31117   *
31118   * @description
31119   * Change the validity state, and notify the form.
31120   *
31121   * This method can be called within $parsers/$formatters or a custom validation implementation.
31122   * However, in most cases it should be sufficient to use the `ngModel.$validators` and
31123   * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
31124   *
31125   * @param {string}
31125 validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
31126   *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
31127   *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
31128   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
31129   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
31130   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
31131   * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
31132   *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
31133   *                          Skipped is used by Angular when validators do not run because of parse errors and
31134   *                          when `$asyncValidators` do not run because any of the `$validators` failed.
31135   */
31136  addSetValidityMethod({
31137    ctrl: this,
31138    $element: $element,
31139    set: function(object, property) {
31140      object[property] = true;
31141    },
31142    unset: function(object, property) {
31143      delete object[property];
31144    },
31145    $animate: $animate
31146  });
31147
31148  /**
31149   * @ngdoc method
31150   * @name ngModel.NgModelController#$setPristine
31151   *
31152   * @description
31153   * Sets the control to its pristine state.
31154   *
31155   * This method can be called to remove the `ng-dirty` class and set the control to its pristine
31156   * state (`ng-pristine` class). A model is considered to be pristine when the control
31157   * has not been changed from when first compiled.
31158   */
31159  this.$setPristine = function() {
31160    ctrl.$dirty = false;
31161    ctrl.$pristine = true;
31162    $animate.removeClass($element, DIRTY_CLASS);
31163    $animate.addClass($element, PRISTINE_CLASS);
31164  };
31165
31166  /**
31167   * @ngdoc method
31168   * @name ngModel.NgModelController#$setDirty
31169   *
31170   * @description
31171   * Sets the control to its dirty state.
31172   *
31173   * This method can be called to remove the `ng-pristine` class and set the control to its dirty
31174   * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
31175   * from when first compiled.
31176   */
31177  this.$setDirty = function() {
31178    ctrl.$dirty = true;
31179    ctrl.$pristine = false;
31180    $animate.removeClass($element, PRISTINE_CLASS);
31181    $animate.addClass($element, DIRTY_CLASS);
31182    ctrl.$$parentForm.$setDirty();
31183  };
31184
31185  /**
31186   * @ngdoc method
31187   * @name ngModel.NgModelController#$setUntouched
31188   *
31189   * @description
31190   * Sets the control to its untouched state.
31191   *
31192   * This method can be called to remove the `ng-touched` class and set the control to its
31193   * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
31194   * by default, however this function can be used to restore that state if the model has
31195   * already been touched by the user.
31196   */
31197  this.$setUntouched = function() {
31198    ctrl.$touched = false;
31199    ctrl.$untouched = true;
31200    $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
31201  };
31202
31203  /**
31204   * @ngdoc method
31205   * @name ngModel.NgModelController#$setTouched
31206   *
31207   * @description
31208   * Sets the control to its touched state.
31209   *
31210   * This method can be called to remove the `ng-untouched` class and set the control to its
31211   * touched state (`ng-touched` class). A model is considered to be touched when the user has
31212   * first focused the control element and then shifted focus away from the control (blur event).
31213   */
31214  this.$setTouched = function() {
31215    ctrl.$touched = true;
31216    ctrl.$untouched = false;
31217    $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
31218  };
31219
31220  /**
31221   * @ngdoc method
31222   * @name ngModel.NgModelController#$rollbackViewValue
31223   *
31224   * @description
31225   * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
31226   * which may be caused by a pending debounced event or because the input is waiting for a some
31227   * future event.
31228   *
31229   * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
31230   * depend on special events such as blur, you can have a situation where there is a period when
31231   * the `$viewValue` is out of sync with the ngModel's `$modelValue`.
31232   *
31233   * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
31234   * and reset the input to the last committed view value.
31235   *
31236   * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
31237   * programmatically before these debounced/future events have resolved/occurred, because Angular's
31238   * dirty checking mechanism is not able to tell whether the model has actually changed or not.
31239   *
31240   * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
31241   * input which may have such events pending. This is important in order to make sure that the
31242   * input field will be updated with the new model value and any pending operations are cancelled.
31243   *
31244   * <example name="ng-model-cancel-update" module="cancel-update-example">
31245   *   <file name="app.js">
31246   *     angular.module('cancel-update-example', [])
31247   *
31248   *     .controller('CancelUpdateController', ['$scope', function($scope) {
31249   *       $scope.model = {};
31250   *
31251   *       $scope.setEmpty = function(e, value, rollback) {
31252   *         if (e.keyCode == 27) {
31253   *           e.preventDefault();
31254   *           if (rollback) {
31255   *             $scope.myForm[value].$rollbackViewValue();
31256   *           }
31257   *           $scope.model[value] = '';
31258   *         }
31259   *       };
31260   *     }]);
31261   *   </file>
31262   *   <file name="index.html">
31263   *     <div ng-controller="CancelUpdateController">
31264   *        <p>Both of these inputs are only updated if they are blurred. Hitting escape should
31265   *        empty them. Follow these steps and observe the difference:</p>
31266   *       <ol>
31267   *         <li>Type something in the input. You will see that the model is not yet updated</li>
31268   *         <li>Press the Escape key.
31269   *           <ol>
31270   *             <li> In the first example, nothing happens, because the model is already '', and no
31271   *             update is detected. If you blur the input, the model will be set to the current view.
31272   *             </li>
31273   *             <li> In the second example, the pending update is cancelled, and the input is set back
31274   *             to the last committed view value (''). Blurring the input does nothing.
31275   *             </li>
31276   *           </ol>
31277   *         </li>
31278   *       </ol>
31279   *
31280   *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
31281   *         <div>
31282   *        <p id="inputDescription1">Without $rollbackViewValue():</p>
31283   *         <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
31284   *                ng-keydown="setEmpty($event, 'value1')">
31285   *         value1: "{{ model.value1 }}"
31286   *         </div>
31287   *
31288   *         <div>
31289   *        <p id="inputDescription2">With $rollbackViewValue():</p>
31290   *         <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
31291   *                ng-keydown="setEmpty($event, 'value2', true)">
31292   *         value2: "{{ model.value2 }}"
31293   *         </div>
31294   *       </form>
31295   *     </div>
31296   *   </file>
31297       <file name="style.css">
31298          div {
31299            display: table-cell;
31300          }
31301          div:nth-child(1) {
31302            padding-right: 30px;
31303          }
31304
31305        </file>
31306   * </example>
31307   */
31308  this.$rollbackViewValue = function() {
31309    $timeout.cancel(pendingDebounce);
31310    ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
31311    ctrl.$render();
31312  };
31313
31314  /**
31315   * @ngdoc method
31316   * @name ngModel.NgModelController#$validate
31317   *
31318   * @description
31319   * Runs each of the registered validators (first synchronous validators and then
31320   * asynchronous validators).
31321   * If the validity changes to invalid, the model will be set to `undefined`,
31322   * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
31323   * If the validity changes to valid, it will set the model to the last available valid
31324   * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
31325   */
31326  this.$validate = function() {
31327    // ignore $validate before model is initialized
31328    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
31329      return;
31330    }
31331
31332    var viewValue = ctrl.$$lastCommittedViewValue;
31333    // Note: we use the $$rawModelValue as $modelValue might have been
31334    // set to undefined during a view -> model update that found validation
31335    // errors. We can't parse the view here, since that could change
31336    // the model although neither viewValue nor the model on the scope changed
31337    var modelValue = ctrl.$$rawModelValue;
31338
31339    var prevValid = ctrl.$valid;
31340    var prevModelValue = ctrl.$modelValue;
31341
31342    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
31343
31344    ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
31345      // If there was no change in validity, don't update the model
31346      // This prevents changing an invalid modelValue to undefined
31347      if (!allowInvalid && prevValid !== allValid) {
31348        // Note: Don't check ctrl.$valid here, as we could have
31349        // external validators (e.g. calculated on the server),
31350        // that just call $setValidity and need the model value
31351        // to calculate their validity.
31352        ctrl.$modelValue = allValid ? modelValue : undefined;
31353
31354        if (ctrl.$modelValue !== prevModelValue) {
31355          ctrl.$$writeModelToScope();
31356        }
31357      }
31358    });
31359
31360  };
31361
31362  this.$$runValidators = function(modelValue, viewValue, doneCallback) {
31363    currentValidationRunId++;
31364    var localValidationRunId = currentValidationRunId;
31365
31366    // check parser error
31367    if (!processParseErrors()) {
31368      validationDone(false);
31369      return;
31370    }
31371    if (!processSyncValidators()) {
31372      validationDone(false);
31373      return;
31374    }
31375    processAsyncValidators();
31376
31377    function processParseErrors() {
31378      var errorKey = ctrl.$$parserName || 'parse';
31379      if (isUndefined(parserValid)) {
31380        setValidity(errorKey, null);
31381      } else {
31382        if (!parserValid) {
31383          forEach(ctrl.$validators, function(v, name) {
31384            setValidity(name, null);
31385          });
31386          forEach(ctrl.$asyncValidators, function(v, name) {
31387            setValidity(name, null);
31388          });
31389        }
31390        // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
31391        setValidity(errorKey, parserValid);
31392        return parserValid;
31393      }
31394      return true;
31395    }
31396
31397    function processSyncValidators() {
31398      var syncValidatorsValid = true;
31399      forEach(ctrl.$validators, function(validator, name) {
31400        var result = validator(modelValue, viewValue);
31401        syncValidatorsValid = syncValidatorsValid && result;
31402        setValidity(name, result);
31403      });
31404      if (!syncValidatorsValid) {
31405        forEach(ctrl.$asyncValidators, function(v, name) {
31406          setValidity(name, null);
31407        });
31408        return false;
31409      }
31410      return true;
31411    }
31412
31413    function processAsyncValidators() {
31414      var validatorPromises = [];
31415      var allValid = true;
31416      forEach(ctrl.$asyncValidators, function(validator, name) {
31417        var promise = validator(modelValue, viewValue);
31418        if (!isPromiseLike(promise)) {
31419          throw ngModelMinErr('nopromise',
31420            "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
31421        }
31422        setValidity(name, undefined);
31423        validatorPromises.push(promise.then(function() {
31424          setValidity(name, true);
31425        }, function(error) {
31426          allValid = false;
31427          setValidity(name, false);
31428        }));
31429      });
31430      if (!validatorPromises.length) {
31431        validationDone(true);
31432      } else {
31433        $q.all(validatorPromises).then(function() {
31434          validationDone(allValid);
31435        }, noop);
31436      }
31437    }
31438
31439    function setValidity(name, isValid) {
31440      if (localValidationRunId === currentValidationRunId) {
31441        ctrl.$setValidity(name, isValid);
31442      }
31443    }
31444
31445    function validationDone(allValid) {
31446      if (localValidationRunId === currentValidationRunId) {
31447
31448        doneCallback(allValid);
31449      }
31450    }
31451  };
31452
31453  /**
31454   * @ngdoc method
31455   * @name ngModel.NgModelController#$commitViewValue
31456   *
31457   * @description
31458   * Commit a pending update to the `$modelValue`.
31459   *
31460   * Updates may be pending by a debounced event or because the input is waiting for a some future
31461   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
31462   * usually handles calling this in response to input events.
31463   */
31464  this.$commitViewValue = function() {
31465    var viewValue = ctrl.$viewValue;
31466
31467    $timeout.cancel(pendingDebounce);
31468
31469    // If the view value has not changed then we should just exit, except in the case where there is
31470    // a native validator on the element. In this case the validation state may have changed even though
31471    // the viewValue has stayed empty.
31472    if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
31473      return;
31474    }
31475    ctrl.$$updateEmptyClasses(viewValue);
31476    ctrl.$$lastCommittedViewValue = viewValue;
31477
31478    // change to dirty
31479    if (ctrl.$pristine) {
31480      this.$setDirty();
31481    }
31482    this.$$parseAndValidate();
31483  };
31484
31485  this.$$parseAndValidate = function() {
31486    var viewValue = ctrl.$$lastCommittedViewValue;
31487    var modelValue = viewValue;
31488    parserValid = isUndefined(modelValue) ? undefined : true;
31489
31490    if (parserValid) {
31491      for (var i = 0; i < ctrl.$parsers.length; i++) {
31492        modelValue = ctrl.$parsers[i](modelValue);
31493        if (isUndefined(modelValue)) {
31494          parserValid = false;
31495          break;
31496        }
31497      }
31498    }
31499    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
31500      // ctrl.$modelValue has not been touched yet...
31501      ctrl.$modelValue = ngModelGet($scope);
31502    }
31503    var prevModelValue = ctrl.$modelValue;
31504    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
31505    ctrl.$$rawModelValue = modelValue;
31506
31507    if (allowInvalid) {
31508      ctrl.$modelValue = modelValue;
31509      writeToModelIfNeeded();
31510    }
31511
31512    // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
31513    // This can happen if e.g. $setViewValue is called from inside a parser
31514    ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
31515      if (!allowInvalid) {
31516        // Note: Don't check ctrl.$valid here, as we could have
31517        // external validators (e.g. calculated on the server),
31518        // that just call $setValidity and need the model value
31519        // to calculate their validity.
31520        ctrl.$modelValue = allValid ? modelValue : undefined;
31521        writeToModelIfNeeded();
31522      }
31523    });
31524
31525    function writeToModelIfNeeded() {
31526      if (ctrl.$modelValue !== prevModelValue) {
31527        ctrl.$$writeModelToScope();
31528      }
31529    }
31530  };
31531
31532  this.$$writeModelToScope = function() {
31533    ngModelSet($scope, ctrl.$modelValue);
31534    forEach(ctrl.$viewChangeListeners, function(listener) {
31535      try {
31536        listener();
31537      } catch (e) {
31538        $exceptionHandler(e);
31539      }
31540    });
31541  };
31542
31543  /**
31544   * @ngdoc method
31545   * @name ngModel.NgModelController#$setViewValue
31546   *
31547   * @description
31548   * Update the view value.
31549   *
31550   * This method should be called when a control wants to change the view value; typically,
31551   * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
31552   * directive calls it when the value of the input changes and {@link ng.directive:select select}
31553   * calls it when an option is selected.
31554   *
31555   * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
31556   * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
31557   * value sent directly for processing, finally to be applied to `$modelValue` and then the
31558   * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
31559   * in the `$viewChangeListeners` list, are called.
31560   *
31561   * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
31562   * and the `default` trigger is not listed, all those actions will remain pending until one of the
31563   * `updateOn` events is triggered on the DOM element.
31564   * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
31565   * directive is used with a custom debounce for this particular event.
31566   * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
31567   * is specified, once the timer runs out.
31568   *
31569   * When used with standard inputs, the view value will always be a string (which is in some cases
31570   * parsed into another type, such as a `Date` object for `input[date]`.)
31571   * However, custom controls might also pass objects to this method. In this case, we should make
31572   * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
31573   * perform a deep watch of objects, it only looks for a change of identity. If you only change
31574   * the property of the object then ngModel will not realize that the object has changed and
31575   * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
31576   * not change properties of the copy once it has been passed to `$setViewValue`.
31577   * Otherwise you may cause the model value on the scope to change incorrectly.
31578   *
31579   * <div class="alert alert-info">
31580   * In any case, the value passed to the method should always reflect the current value
31581   * of the control. For example, if you are calling `$setViewValue` for an input element,
31582   * you should pass the input DOM value. Otherwise, the control and the scope model become
31583   * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
31584   * the control's DOM value in any way. If we want to change the control's DOM value
31585   * programmatically, we should update the `ngModel` scope expression. Its new value will be
31586   * picked up by the model controller, which will run it through the `$formatters`, `$render` it
31587   * to update the DOM, and finally call `$validate` on it.
31588   * </div>
31589   *
31590   * @param {*} value value from the view.
31591   * @param {string} trigger Event that triggered the update.
31592   */
31593  this.$setViewValue = function(value, trigger) {
31594    ctrl.$viewValue = value;
31595    if (!ctrl.$options || ctrl.$options.updateOnDefault) {
31596      ctrl.$$debounceViewValueCommit(trigger);
31597    }
31598  };
31599
31600  this.$$debounceViewValueCommit = function(trigger) {
31601    var debounceDelay = 0,
31602        options = ctrl.$options,
31603        debounce;
31604
31605    if (options && isDefined(options.debounce)) {
31606      debounce = options.debounce;
31607      if (isNumber(debounce)) {
31608        debounceDelay = debounce;
31609      } else if (isNumber(debounce[trigger])) {
31610        debounceDelay = debounce[trigger];
31611      } else if (isNumber(debounce['default'])) {
31612        debounceDelay = debounce['default'];
31613      }
31614    }
31615
31616    $timeout.cancel(pendingDebounce);
31617    if (debounceDelay) {
31618      pendingDebounce = $timeout(function() {
31619        ctrl.$commitViewValue();
31620      }, debounceDelay);
31621    } else if ($rootScope.$$phase) {
31622      ctrl.$commitViewValue();
31623    } else {
31624      $scope.$apply(function() {
31625        ctrl.$commitViewValue();
31626      });
31627    }
31628  };
31629
31630  // model -> value
31631  // Note: we cannot use a normal scope.$watch as we want to detect the following:
31632  // 1. scope value is 'a'
31633  // 2. user enters 'b'
31634  // 3. ng-change kicks in and reverts scope value to 'a'
31635  //    ->
31635 scope value did not change since the last digest as
31636  //       ng-change executes in apply phase
31637  // 4. view should be changed back to 'a'
31638  $scope.$watch(function ngModelWatch() {
31639    var modelValue = ngModelGet($scope);
31640
31641    // if scope model value and ngModel value are out of sync
31642    // TODO(perf): why not move this to the action fn?
31643    if (modelValue !== ctrl.$modelValue &&
31644       // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
31645       (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
31646    ) {
31647      ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
31648      parserValid = undefined;
31649
31650      var formatters = ctrl.$formatters,
31651          idx = formatters.length;
31652
31653      var viewValue = modelValue;
31654      while (idx--) {
31655        viewValue = formatters[idx](viewValue);
31656      }
31657      if (ctrl.$viewValue !== viewValue) {
31658        ctrl.$$updateEmptyClasses(viewValue);
31659        ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
31660        ctrl.$render();
31661
31662        ctrl.$$runValidators(modelValue, viewValue, noop);
31663      }
31664    }
31665
31666    return modelValue;
31667  });
31668}];
31669
31670
31671/**
31672 * @ngdoc directive
31673 * @name ngModel
31674 *
31675 * @element input
31676 * @priority 1
31677 *
31678 * @description
31679 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
31680 * property on the scope using {@link ngModel.NgModelController NgModelController},
31681 * which is created and exposed by this directive.
31682 *
31683 * `ngModel` is responsible for:
31684 *
31685 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
31686 *   require.
31687 * - Providing validation behavior (i.e. required, number, email, url).
31688 * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
31689 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
31690 *   `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
31691 * - Registering the control with its parent {@link ng.directive:form form}.
31692 *
31693 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
31694 * current scope. If the property doesn't already exist on this scope, it will be created
31695 * implicitly and added to the scope.
31696 *
31697 * For best practices on using `ngModel`, see:
31698 *
31699 *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
31700 *
31701 * For basic examples, how to use `ngModel`, see:
31702 *
31703 *  - {@link ng.directive:input input}
31704 *    - {@link input[text] text}
31705 *    - {@link input[checkbox] checkbox}
31706 *    - {@link input[radio] radio}
31707 *    - {@link input[number] number}
31708 *    - {@link input[email] email}
31709 *    - {@link input[url] url}
31710 *    - {@link input[date] date}
31711 *    - {@link input[datetime-local] datetime-local}
31712 *    - {@link input[time] time}
31713 *    - {@link input[month] month}
31714 *    - {@link input[week] week}
31715 *  - {@link ng.directive:select select}
31716 *  - {@link ng.directive:textarea textarea}
31717 *
31718 * # Complex Models (objects or collections)
31719 *
31720 * By default, `ngModel` watches the model by reference, not value. This is important to know when
31721 * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
31722 * object or collection change, `ngModel` will not be notified and so the input will not be  re-rendered.
31723 *
31724 * The model must be assigned an entirely new object or collection before a re-rendering will occur.
31725 *
31726 * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
31727 * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
31728 * if the select is given the `multiple` attribute.
31729 *
31730 * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
31731 * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
31732 * not trigger a re-rendering of the model.
31733 *
31734 * # CSS classes
31735 * The following CSS classes are added and removed on the associated input/select/textarea element
31736 * depending on the validity of the model.
31737 *
31738 *  - `ng-valid`: the model is valid
31739 *  - `ng-invalid`: the model is invalid
31740 *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
31741 *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
31742 *  - `ng-pristine`: the control hasn't been interacted with yet
31743 *  - `ng-dirty`: the control has been interacted with
31744 *  - `ng-touched`: the control has been blurred
31745 *  - `ng-untouched`: the control hasn't been blurred
31746 *  - `ng-pending`: any `$asyncValidators` are unfulfilled
31747 *  - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
31748 *     by the {@link ngModel.NgModelController#$isEmpty} method
31749 *  - `ng-not-empty`: the view contains a non-empty value
31750 *
31751 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
31752 *
31753 * ## Animation Hooks
31754 *
31755 * Animations within models are triggered when any of the associated CSS classes are added and removed
31756 * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
31757 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
31758 * The animations that are triggered within ngModel are similar to how they work in ngClass and
31759 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
31760 *
31761 * The following example shows a simple way to utilize CSS transitions to style an input element
31762 * that has been rendered as invalid after it has been validated:
31763 *
31764 * <pre>
31765 * //be sure to include ngAnimate as a module to hook into more
31766 * //advanced animations
31767 * .my-input {
31768 *   transition:0.5s linear all;
31769 *   background: white;
31770 * }
31771 * .my-input.ng-invalid {
31772 *   background: red;
31773 *   color:white;
31774 * }
31775 * </pre>
31776 *
31777 * @example
31778 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
31779     <file name="index.html">
31780       <script>
31781        angular.module('inputExample', [])
31782          .controller('ExampleController', ['$scope', function($scope) {
31783            $scope.val = '1';
31784          }]);
31785       </script>
31786       <style>
31787         .my-input {
31788           transition:all linear 0.5s;
31789           background: transparent;
31790         }
31791         .my-input.ng-invalid {
31792           color:white;
31793           background: red;
31794         }
31795       </style>
31796       <p id="inputDescription">
31797        Update input to see transitions when valid/invalid.
31798        Integer is a valid value.
31799       </p>
31800       <form name="testForm" ng-controller="ExampleController">
31801         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
31802                aria-describedby="inputDescription" />
31803       </form>
31804     </file>
31805 * </example>
31806 *
31807 * ## Binding to a getter/setter
31808 *
31809 * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
31810 * function that returns a representation of the model when called with zero arguments, and sets
31811 * the internal state of a model when called with an argument. It's sometimes useful to use this
31812 * for models that have an internal representation that's different from what the model exposes
31813 * to the view.
31814 *
31815 * <div class="alert alert-success">
31816 * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
31817 * frequently than other parts of your code.
31818 * </div>
31819 *
31820 * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
31821 * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
31822 * a `<form>`, which will enable this behavior for all `<input>`s within it. See
31823 * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
31824 *
31825 * The following example shows how to use `ngModel` with a getter/setter:
31826 *
31827 * @example
31828 * <example name="ngModel-getter-setter" module="getterSetterExample">
31829     <file name="index.html">
31830       <div ng-controller="ExampleController">
31831         <form name="userForm">
31832           <label>Name:
31833             <input type="text" name="userName"
31834                    ng-model="user.name"
31835                    ng-model-options="{ getterSetter: true }" />
31836           </label>
31837         </form>
31838         <pre>user.name = <span ng-bind="user.name()"></span></pre>
31839       </div>
31840     </file>
31841     <file name="app.js">
31842       angular.module('getterSetterExample', [])
31843         .controller('ExampleController', ['$scope', function($scope) {
31844           var _name = 'Brian';
31845           $scope.user = {
31846             name: function(newName) {
31847              // Note that newName can be undefined for two reasons:
31848              // 1. Because it is called as a getter and thus called with no arguments
31849              // 2. Because the property should actually be set to undefined. This happens e.g. if the
31850              //    input is invalid
31851              return arguments.length ? (_name = newName) : _name;
31852             }
31853           };
31854         }]);
31855     </file>
31856 * </example>
31857 */
31858var ngModelDirective = ['$rootScope', function($rootScope) {
31859  return {
31860    restrict: 'A',
31861    require: ['ngModel', '^?form', '^?ngModelOptions'],
31862    controller: NgModelController,
31863    // Prelink needs to run before any input directive
31864    // so that we can set the NgModelOptions in NgModelController
31865    // before anyone else uses it.
31866    priority: 1,
31867    compile: function ngModelCompile(element) {
31868      // Setup initial state of the control
31869      element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
31870
31871      return {
31872        pre: function ngModelPreLink(scope, element, attr, ctrls) {
31873          var modelCtrl = ctrls[0],
31874              formCtrl = ctrls[1] || modelCtrl.$$parentForm;
31875
31876          modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
31877
31878          // notify others, especially parent forms
31879          formCtrl.$addControl(modelCtrl);
31880
31881          attr.$observe('name', function(newValue) {
31882            if (modelCtrl.$name !== newValue) {
31883              modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
31884            }
31885          });
31886
31887          scope.$on('$destroy', function() {
31888            modelCtrl.$$parentForm.$removeControl(modelCtrl);
31889          });
31890        },
31891        post: function ngModelPostLink(scope, element, attr, ctrls) {
31892          var modelCtrl = ctrls[0];
31893          if (modelCtrl.$options && modelCtrl.$options.updateOn) {
31894            element.on(modelCtrl.$options.updateOn, function(ev) {
31895              modelCtrl.$$debounceViewValueCommit(ev && ev.type);
31896            });
31897          }
31898
31899          element.on('blur', function(ev) {
31900            if (modelCtrl.$touched) return;
31901
31902            if ($rootScope.$$phase) {
31903              scope.$evalAsync(modelCtrl.$setTouched);
31904            } else {
31905              scope.$apply(modelCtrl.$setTouched);
31906            }
31907          });
31908        }
31909      };
31910    }
31911  };
31912}];
31913
31914var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
31915
31916/**
31917 * @ngdoc directive
31918 * @name ngModelOptions
31919 *
31920 * @description
31921 * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
31922 * events that will trigger a model update and/or a debouncing delay so that the actual update only
31923 * takes place when a timer expires; this timer will be reset after another change takes place.
31924 *
31925 * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
31926 * be different from the value in the actual model. This means that if you update the model you
31927 * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
31928 * order to make sure it is synchronized with the model and that any debounced action is canceled.
31929 *
31930 * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
31931 * method is by making sure the input is placed inside a form that has a `name` attribute. This is
31932 * important because `form` controllers are published to the related scope under the name in their
31933 * `name` attribute.
31934 *
31935 * Any pending changes will take place immediately when an enclosing form is submitted via the
31936 * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
31937 * to have access to the updated model.
31938 *
31939 * `ngModelOptions` has an effect on the element it's declared on and its desce
31939ndants.
31940 *
31941 * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
31942 *   - `updateOn`: string specifying which event should the input be bound to. You can set several
31943 *     events using an space delimited list. There is a special event called `default` that
31944 *     matches the default events belonging of the control.
31945 *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
31946 *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
31947 *     custom value for each event. For example:
31948 *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
31949 *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
31950 *     not validate correctly instead of the default behavior of setting the model to undefined.
31951 *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
31952       `ngModel` as getters/setters.
31953 *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
31954 *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
31955 *     continental US time zone abbreviations, but for general use, use a time zone offset, for
31956 *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
31957 *     If not specified, the timezone of the browser will be used.
31958 *
31959 * @example
31960
31961  The following example shows how to override immediate updates. Changes on the inputs within the
31962  form will update the model only when the control loses focus (blur event). If `escape` key is
31963  pressed while the input field is focused, the value is reset to the value in the current model.
31964
31965  <example name="ngModelOptions-directive-blur" module="optionsExample">
31966    <file name="index.html">
31967      <div ng-controller="ExampleController">
31968        <form name="userForm">
31969          <label>Name:
31970            <input type="text" name="userName"
31971                   ng-model="user.name"
31972                   ng-model-options="{ updateOn: 'blur' }"
31973                   ng-keyup="cancel($event)" />
31974          </label><br />
31975          <label>Other data:
31976            <input type="text" ng-model="user.data" />
31977          </label><br />
31978        </form>
31979        <pre>user.name = <span ng-bind="user.name"></span></pre>
31980        <pre>user.data = <span ng-bind="user.data"></span></pre>
31981      </div>
31982    </file>
31983    <file name="app.js">
31984      angular.module('optionsExample', [])
31985        .controller('ExampleController', ['$scope', function($scope) {
31986          $scope.user = { name: 'John', data: '' };
31987
31988          $scope.cancel = function(e) {
31989            if (e.keyCode == 27) {
31990              $scope.userForm.userName.$rollbackViewValue();
31991            }
31992          };
31993        }]);
31994    </file>
31995    <file name="protractor.js" type="protractor">
31996      var model = element(by.binding('user.name'));
31997      var input = element(by.model('user.name'));
31998      var other = element(by.model('user.data'));
31999
32000      it('should allow custom events', function() {
32001        input.sendKeys(' Doe');
32002        input.click();
32003        expect(model.getText()).toEqual('John');
32004        other.click();
32005        expect(model.getText()).toEqual('John Doe');
32006      });
32007
32008      it('should $rollbackViewValue when model changes', function() {
32009        input.sendKeys(' Doe');
32010        expect(input.getAttribute('value')).toEqual('John Doe');
32011        input.sendKeys(protractor.Key.ESCAPE);
32012        expect(input.getAttribute('value')).toEqual('John');
32013        other.click();
32014        expect(model.getText()).toEqual('John');
32015      });
32016    </file>
32017  </example>
32018
32019  This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
32020  If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
32021
32022  <example name="ngModelOptions-directive-debounce" module="optionsExample">
32023    <file name="index.html">
32024      <div ng-controller="ExampleController">
32025        <form name="userForm">
32026          <label>Name:
32027            <input type="text" name="userName"
32028                   ng-model="user.name"
32029                   ng-model-options="{ debounce: 1000 }" />
32030          </label>
32031          <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
32032          <br />
32033        </form>
32034        <pre>user.name = <span ng-bind="user.name"></span></pre>
32035      </div>
32036    </file>
32037    <file name="app.js">
32038      angular.module('optionsExample', [])
32039        .controller('ExampleController', ['$scope', function($scope) {
32040          $scope.user = { name: 'Igor' };
32041        }]);
32042    </file>
32043  </example>
32044
32045  This one shows how to bind to getter/setters:
32046
32047  <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
32048    <file name="index.html">
32049      <div ng-controller="ExampleController">
32050        <form name="userForm">
32051          <label>Name:
32052            <input type="text" name="userName"
32053                   ng-model="user.name"
32054                   ng-model-options="{ getterSetter: true }" />
32055          </label>
32056        </form>
32057        <pre>user.name = <span ng-bind="user.name()"></span></pre>
32058      </div>
32059    </file>
32060    <file name="app.js">
32061      angular.module('getterSetterExample', [])
32062        .controller('ExampleController', ['$scope', function($scope) {
32063          var _name = 'Brian';
32064          $scope.user = {
32065            name: function(newName) {
32066              // Note that newName can be undefined for two reasons:
32067              // 1. Because it is called as a getter and thus called with no arguments
32068              // 2. Because the property should actually be set to undefined. This happens e.g. if the
32069              //    input is invalid
32070              return arguments.length ? (_name = newName) : _name;
32071            }
32072          };
32073        }]);
32074    </file>
32075  </example>
32076 */
32077var ngModelOptionsDirective = function() {
32078  return {
32079    restrict: 'A',
32080    controller: ['$scope', '$attrs', function($scope, $attrs) {
32081      var that = this;
32082      this.$options = copy($scope.$eval($attrs.ngModelOptions));
32083      // Allow adding/overriding bound events
32084      if (isDefined(this.$options.updateOn)) {
32085        this.$options.updateOnDefault = false;
32086        // extract "default" pseudo-event from list of events that can trigger a model update
32087        this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
32088          that.$options.updateOnDefault = true;
32089          return ' ';
32090        }));
32091      } else {
32092        this.$options.updateOnDefault = true;
32093      }
32094    }]
32095  };
32096};
32097
32098
32099
32100// helper methods
32101function addSetValidityMethod(context) {
32102  var ctrl = context.ctrl,
32103      $element = context.$element,
32104      classCache = {},
32105      set = context.set,
32106      unset = context.unset,
32107      $animate = context.$animate;
32108
32109  classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
32110
32111  ctrl.$setValidity = setValidity;
32112
32113  function setValidity(validationErrorKey, state, controller) {
32114    if (isUndefined(state)) {
32115      createAndSet('$pending', validationErrorKey, controller);
32116    } else {
32117      unsetAndCleanup('$pending', validationErrorKey, controller);
32118    }
32119    if (!isBoolean(state)) {
32120      unset(ctrl.$error, validationErrorKey, controller);
32121      unset(ctrl.$$success, validationErrorKey, controller);
32122    } else {
32123      if (state) {
32124        unset(ctrl.$error, validationErrorKey, controller);
32125        set(ctrl.$$success, validationErrorKey, controller);
32126      } else {
32127        set(ctrl.$error, validationErrorKey, controller);
32128        unset(ctrl.$$success, validationErrorKey, controller);
32129      }
32130    }
32131    if (ctrl.$pending) {
32132      cachedToggleClass(PENDING_CLASS, true);
32133      ctrl.$valid = ctrl.$invalid = undefined;
32134      toggleValidationCss('', null);
32135    } else {
32136      cachedToggleClass(PENDING_CLASS, false);
32137      ctrl.$valid = isObjectEmpty(ctrl.$error);
32138      ctrl.$invalid = !ctrl.$valid;
32139      toggleValidationCss('', ctrl.$valid);
32140    }
32141
32142    // re-read the state as the set/unset methods could have
32143    // combined state in ctrl.$error[validationError] (used for forms),
32144    // where setting/unsetting only increments/decrements the value,
32145    // and does not replace it.
32146    var combinedState;
32147    if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
32148      combinedState = undefined;
32149    } else if (ctrl.$error[validationErrorKey]) {
32150      combinedState = false;
32151    } else if (ctrl.$$success[validationErrorKey]) {
32152      combinedState = true;
32153    } else {
32154      combinedState = null;
32155    }
32156
32157    toggleValidationCss(validationErrorKey, combinedState);
32158    ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
32159  }
32160
32161  function createAndSet(name, value, controller) {
32162    if (!ctrl[name]) {
32163      ctrl[name] = {};
32164    }
32165    set(ctrl[name], value, controller);
32166  }
32167
32168  function unsetAndCleanup(name, value, controller) {
32169    if (ctrl[name]) {
32170      unset(ctrl[name], value, controller);
32171    }
32172    if (isObjectEmpty(ctrl[name])) {
32173      ctrl[name] = undefined;
32174    }
32175  }
32176
32177  function cachedToggleClass(className, switchValue) {
32178    if (switchValue && !classCache[className]) {
32179      $animate.addClass($element, className);
32180      classCache[className] = true;
32181    } else if (!switchValue && classCache[className]) {
32182      $animate.removeClass($element, className);
32183      classCache[className] = false;
32184    }
32185  }
32186
32187  function toggleValidationCss(validationErrorKey, isValid) {
32188    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
32189
32190    cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
32191    cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
32192  }
32193}
32194
32195function isObjectEmpty(obj) {
32196  if (obj) {
32197    for (var prop in obj) {
32198      if (obj.hasOwnProperty(prop)) {
32199        return false;
32200      }
32201    }
32202  }
32203  return true;
32204}
32205
32206/**
32207 * @ngdoc directive
32208 * @name ngNonBindable
32209 * @restrict AC
32210 * @priority 1000
32211 *
32212 * @description
32213 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
32214 * DOM element. This is useful if the element contains what appears to be Angular directives and
32215 * bindings but which should be ignored by Angular. This could be the case if you have a site that
32216 * displays snippets of code, for instance.
32217 *
32218 * @element ANY
32219 *
32220 * @example
32221 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
32222 * but the one wrapped in `ngNonBindable` is left alone.
32223 *
32224 * @example
32225    <example>
32226      <file name="index.html">
32227        <div>Normal: {{1 + 2}}</div>
32228        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
32229      </file>
32230      <file name="protractor.js" type="protractor">
32231       it('should check ng-non-bindable', function() {
32232         expect(element(by.binding('1 + 2')).getText()).toContain('3');
32233         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
32234       });
32235      </file>
32236    </example>
32237 */
32238var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
32239
32240/* global jqLiteRemove */
32241
32242var ngOptionsMinErr = minErr('ngOptions');
32243
32244/**
32245 * @ngdoc directive
32246 * @name ngOptions
32247 * @restrict A
32248 *
32249 * @description
32250 *
32251 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
32252 * elements for the `<select>` element using the array or object obtained by evaluating the
32253 * `ngOptions` comprehension expression.
32254 *
32255 * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
32256 * similar result. However, `ngOptions` provides some benefits such as reducing memory and
32257 * increasing speed by not creating a new scope for each repeated instance, as well as providing
32258 * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
32259 * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
32260 *  to a non-string value. This is because an option element can only be bound to string values at
32261 * present.
32262 *
32263 * When an item in the `<select>` menu is selected, the array element or object property
32264 * represented by the selected option will be bound to the model identified by the `ngModel`
32265 * directive.
32266 *
32267 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
32268 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
32269 * option. See example below for demonstration.
32270 *
32271 * ## Complex Models (objects or collections)
32272 *
32273 * By default, `ngModel` watches the model by reference, not value. This is important to know when
32274 * binding the select to a model that is an object or a collection.
32275 *
32276 * One issue occurs if you want to preselect an option. For example, if you set
32277 * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
32278 * because the objects are not identical. So by default, you should always reference the item in y
32278our collection
32279 * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
32280 *
32281 * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
32282 * of the item not by reference, but by the result of the `track by` expression. For example, if your
32283 * collection items have an id property, you would `track by item.id`.
32284 *
32285 * A different issue with objects or collections is that ngModel won't detect if an object property or
32286 * a collection item changes. For that reason, `ngOptions` additionally watches the model using
32287 * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
32288 * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
32289 * has not changed identity, but only a property on the object or an item in the collection changes.
32290 *
32291 * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
32292 * if the model is an array). This means that changing a property deeper than the first level inside the
32293 * object/collection will not trigger a re-rendering.
32294 *
32295 * ## `select` **`as`**
32296 *
32297 * Using `select` **`as`** will bind the result of the `select` expression to the model, but
32298 * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
32299 * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
32300 * is used, the result of that expression will be set as the value of the `option` and `select` elements.
32301 *
32302 *
32303 * ### `select` **`as`** and **`track by`**
32304 *
32305 * <div class="alert alert-warning">
32306 * Be careful when using `select` **`as`** and **`track by`** in the same expression.
32307 * </div>
32308 *
32309 * Given this array of items on the $scope:
32310 *
32311 * ```js
32312 * $scope.items = [{
32313 *   id: 1,
32314 *   label: 'aLabel',
32315 *   subItem: { name: 'aSubItem' }
32316 * }, {
32317 *   id: 2,
32318 *   label: 'bLabel',
32319 *   subItem: { name: 'bSubItem' }
32320 * }];
32321 * ```
32322 *
32323 * This will work:
32324 *
32325 * ```html
32326 * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
32327 * ```
32328 * ```js
32329 * $scope.selected = $scope.items[0];
32330 * ```
32331 *
32332 * but this will not work:
32333 *
32334 * ```html
32335 * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
32336 * ```
32337 * ```js
32338 * $scope.selected = $scope.items[0].subItem;
32339 * ```
32340 *
32341 * In both examples, the **`track by`** expression is applied successfully to each `item` in the
32342 * `items` array. Because the selected option has been set programmatically in the controller, the
32343 * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
32344 * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
32345 * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
32346 * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
32347 * is not matched against any `<option>` and the `<select>` appears as having no selected value.
32348 *
32349 *
32350 * @param {string} ngModel Assignable angular expression to data-bind to.
32351 * @param {string=} name Property name of the form under which the control is published.
32352 * @param {string=} required The control is considered valid only if value is entered.
32353 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
32354 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
32355 *    `required` when you want to data-bind to the `required` attribute.
32356 * @param {comprehension_expression=} ngOptions in one of the following forms:
32357 *
32358 *   * for array data sources:
32359 *     * `label` **`for`** `value` **`in`** `array`
32360 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
32361 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
32362 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
32363 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
32364 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
32365 *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
32366 *        (for including a filter with `track by`)
32367 *   * for object data sources:
32368 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
32369 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
32370 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
32371 *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
32372 *     * `select` **`as`** `label` **`group by`** `group`
32373 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
32374 *     * `select` **`as`** `label` **`disable when`** `disable`
32375 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
32376 *
32377 * Where:
32378 *
32379 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
32380 *   * `value`: local variable which will refer to each item in the `array` or each property value
32381 *      of `object` during iteration.
32382 *   * `key`: local variable which will refer to a property name in `object` during iteration.
32383 *   * `label`: The result of this expression will be the label for `<option>` element. The
32384 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
32385 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
32386 *      element. If not specified, `select` expression will default to `value`.
32387 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
32388 *      DOM element.
32389 *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
32390 *      element. Return `true` to disable.
32391 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
32392 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
32393 *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
32394 *      even when the options are recreated (e.g. reloaded from the server).
32395 *
32396 * @example
32397    <example module="selectExample">
32398      <file name="index.html">
32399        <script>
32400        angular.module('selectExample', [])
32401          .controller('ExampleController', ['$scope', function($scope) {
32402            $scope.colors = [
32403              {name:'black', shade:'dark'},
32404              {name:'white', shade:'light', notAnOption: true},
32405              {name:'red', shade:'dark'},
32406              {name:'blue', shade:'dark', notAnOption: true},
32407              {name:'yellow', shade:'light', notAnOption: false}
32408            ];
32409            $scope.myColor = $scope.colors[2]; // red
32410          }]);
32411        </script>
32412        <div ng-controller="ExampleController">
32413          <ul>
32414            <li ng-repeat="color in colors">
32415              <label>Name: <input ng-model="color.name"></label>
32416              <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
32417              <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
32418            </li>
32419            <li>
32420              <button ng-click="colors.push({})">add</button>
32421            </li>
32422          </ul>
32423          <hr/>
32424          <label>Color (null not allowed):
32425            <select ng-model="myColor" ng-options="color.name for color in colors"></select>
32426          </label><br/>
32427          <label>Color (null allowed):
32428          <span  class="nullable">
32429            <select ng-model="myColor" ng-options="color.name for color in colors">
32430              <option value="">-- choose color --</option>
32431            </select>
32432          </span></label><br/>
32433
32434          <label>Color grouped by shade:
32435            <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
32436            </select>
32437          </label><br/>
32438
32439          <label>Color grouped by shade, with some disabled:
32440            <select ng-model="myColor"
32441                  ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
32442            </select>
32443          </label><br/>
32444
32445
32446
32447          Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
32448          <br/>
32449          <hr/>
32450          Currently selected: {{ {selected_color:myColor} }}
32451          <div style="border:solid 1px black; height:20px"
32452               ng-style="{'background-color':myColor.name}">
32453          </div>
32454        </div>
32455      </file>
32456      <file name="protractor.js" type="protractor">
32457         it('should check ng-options', function() {
32458           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
32459           element.all(by.model('myColor')).first().click();
32460           element.all(by.css('select[ng-model="myColor"] option')).first().click();
32461           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
32462           element(by.css('.nullable select[ng-model="myColor"]')).click();
32463           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
32464           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
32465         });
32466      </file>
32467    </example>
32468 */
32469
32470// jshint maxlen: false
32471//                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
32472var 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]+?))?$/;
32473                        // 1: value expression (valueFn)
32474                        // 2: label expression (displayFn)
32475                        // 3: group by expression (groupByFn)
32476                        // 4: disable when expression (disableWhenFn)
32477                        // 5: array item variable name
32478                        // 6: object item key variable name
32479                        // 7: object item value variable name
32480                        // 8: collection expression
32481                        // 9: track by expression
32482// jshint maxlen: 100
32483
32484
32485var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
32486
32487  function parseOptionsExpression(optionsExp, selectElement, scope) {
32488
32489    var match = optionsExp.match(NG_OPTIONS_REGEXP);
32490    if (!(match)) {
32491      throw ngOptionsMinErr('iexp',
32492        "Expected expression in form of " +
32493        "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
32494        " but got '{0}'. Element: {1}",
32495        optionsExp, startingTag(selectElement));
32496    }
32497
32498    // Extract the parts from the ngOptions expression
32499
32500    // The variable name for the value of the item in the collection
32501    var valueName = match[5] || match[7];
32502    // The variable name for the key of the item in the collection
32503    var keyName = match[6];
32504
32505    // An expression that generates the viewValue for an option if there is a label expression
32506    var selectAs = / as /.test(match[0]) && match[1];
32507    // An expression that is used to track the id of each object in the options collection
32508    var trackBy = match[9];
32509    // An expression that generates the viewValue for an option if there is no label expression
32510    var valueFn = $parse(match[2] ? match[1] : valueName);
32511    var selectAsFn = selectAs && $parse(selectAs);
32512    var viewValueFn = selectAsFn || valueFn;
32513    var trackByFn = trackBy && $parse(trackBy);
32514
32515    // Get the value by which we are going to track the option
32516    // if we have a trackFn then use that (passing scope and locals)
32517    // otherwise just hash the given viewValue
32518    var getTrackByValueFn = trackBy ?
32519                              function(value, locals) { return trackByFn(scope, locals); } :
32520                              function getHashOfValue(value) { return hashKey(value); };
32521    var getTrackByValue = function(value, key) {
vendor: 5,543 bytes, lines 32522-32675
32522      return getTrackByValueFn(value, getLocals(value, key));
32523    };
32524
32525    var displayFn = $parse(match[2] || match[1]);
32526    var groupByFn = $parse(match[3] || '');
32527    var disableWhenFn = $parse(match[4] || '');
32528    var valuesFn = $parse(match[8]);
32529
32530    var locals = {};
32531    var getLocals = keyName ? function(value, key) {
32532      locals[keyName] = key;
32533      locals[valueName] = value;
32534      return locals;
32535    } : function(value) {
32536      locals[valueName] = value;
32537      return locals;
32538    };
32539
32540
32541    function Option(selectValue, viewValue, label, group, disabled) {
32542      this.selectValue = selectValue;
32543      this.viewValue = viewValue;
32544      this.label = label;
32545      this.group = group;
32546      this.disabled = disabled;
32547    }
32548
32549    function getOptionValuesKeys(optionValues) {
32550      var optionValuesKeys;
32551
32552      if (!keyName && isArrayLike(optionValues)) {
32553        optionValuesKeys = optionValues;
32554      } else {
32555        // if object, extract keys, in enumeration order, unsorted
32556        optionValuesKeys = [];
32557        for (var itemKey in optionValues) {
32558          if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
32559            optionValuesKeys.push(itemKey);
32560          }
32561        }
32562      }
32563      return optionValuesKeys;
32564    }
32565
32566    return {
32567      trackBy: trackBy,
32568      getTrackByValue: getTrackByValue,
32569      getWatchables: $parse(valuesFn, function(optionValues) {
32570        // Create a collection of things that we would like to watch (watchedArray)
32571        // so that they can all be watched using a single $watchCollection
32572        // that only runs the handler once if anything changes
32573        var watchedArray = [];
32574        optionValues = optionValues || [];
32575
32576        var optionValuesKeys = getOptionValuesKeys(optionValues);
32577        var optionValuesLength = optionValuesKeys.length;
32578        for (var index = 0; index < optionValuesLength; index++) {
32579          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
32580          var value = optionValues[key];
32581
32582          var locals = getLocals(optionValues[key], key);
32583          var selectValue = getTrackByValueFn(optionValues[key], locals);
32584          watchedArray.push(selectValue);
32585
32586          // Only need to watch the displayFn if there is a specific label expression
32587          if (match[2] || match[1]) {
32588            var label = displayFn(scope, locals);
32589            watchedArray.push(label);
32590          }
32591
32592          // Only need to watch the disableWhenFn if there is a specific disable expression
32593          if (match[4]) {
32594            var disableWhen = disableWhenFn(scope, locals);
32595            watchedArray.push(disableWhen);
32596          }
32597        }
32598        return watchedArray;
32599      }),
32600
32601      getOptions: function() {
32602
32603        var optionItems = [];
32604        var selectValueMap = {};
32605
32606        // The option values were already computed in the `getWatchables` fn,
32607        // which must have been called to trigger `getOptions`
32608        var optionValues = valuesFn(scope) || [];
32609        var optionValuesKeys = getOptionValuesKeys(optionValues);
32610        var optionValuesLength = optionValuesKeys.length;
32611
32612        for (var index = 0; index < optionValuesLength; index++) {
32613          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
32614          var value = optionValues[key];
32615          var locals = getLocals(value, key);
32616          var viewValue = viewValueFn(scope, locals);
32617          var selectValue = getTrackByValueFn(viewValue, locals);
32618          var label = displayFn(scope, locals);
32619          var group = groupByFn(scope, locals);
32620          var disabled = disableWhenFn(scope, locals);
32621          var optionItem = new Option(selectValue, viewValue, label, group, disabled);
32622
32623          optionItems.push(optionItem);
32624          selectValueMap[selectValue] = optionItem;
32625        }
32626
32627        return {
32628          items: optionItems,
32629          selectValueMap: selectValueMap,
32630          getOptionFromViewValue: function(value) {
32631            return selectValueMap[getTrackByValue(value)];
32632          },
32633          getViewValueFromOption: function(option) {
32634            // If the viewValue could be an object that may be mutated by the application,
32635            // we need to make a copy and not return the reference to the value on the option.
32636            return trackBy ? angular.copy(option.viewValue) : option.viewValue;
32637          }
32638        };
32639      }
32640    };
32641  }
32642
32643
32644  // we can't just jqLite('<option>') since jqLite is not smart enough
32645  // to create it in <select> and IE barfs otherwise.
32646  var optionTemplate = document.createElement('option'),
32647      optGroupTemplate = document.createElement('optgroup');
32648
32649    function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
32650
32651      var selectCtrl = ctrls[0];
32652      var ngModelCtrl = ctrls[1];
32653      var multiple = attr.multiple;
32654
32655      // The emptyOption allows the application developer to provide their own custom "empty"
32656      // option when the viewValue does not match any of the option values.
32657      var emptyOption;
32658      for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
32659        if (children[i].value === '') {
32660          emptyOption = children.eq(i);
32661          break;
32662        }
32663      }
32664
32665      var providedEmptyOption = !!emptyOption;
32666
32667      var unknownOption = jqLite(optionTemplate.cloneNode(false));
32668      unknownOption.val('?');
32669
32670      var options;
32671      var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
32672
32673
32674      var renderEmptyOption = function() {
32675        if (!providedEmptyOption) {
32676          selectElement.prepend(emptyOption);
32677        }
32678        selectElement.val('');
32679        emptyOption.prop('selected', true); // needed for IE
32680        emptyOption.attr('selected', true);
32681      };
32682
32683      var removeEmptyOption = function() {
32684        if (!providedEmptyOption) {
32685          emptyOption.remove();
32686        }
32687      };
32688
32689
32690      var renderUnknownOption = function() {
32691        selectElement.prepend(unknownOption);
32692        selectElement.val('?');
32693        unknownOption.prop('selected', true); // needed for IE
32694        unknownOption.attr('selected', true);
32695      };
32696
32697      var removeUnknownOption = function() {
32698        unknownOption.remove();
32699      };
32700
32701      // Update the controller methods for multiple selectable options
32702      if (!multiple) {
32703
32704        selectCtrl.writeValue = function writeNgOptionsValue(value) {
32705          var option = options.getOptionFromViewValue(value);
32706
32707          if (option && !option.disabled) {
32708            // Don't update the option when it is already selected.
32709            // For example, the browser will select the first option by default. In that case,
32710            // most properties are set automatically - except the `selected` attribute, which we
32711            // set always
32712
32713            if (selectElement[0].value !== option.selectValue) {
32714              removeUnknownOption();
32715              removeEmptyOption();
32716
32717              selectElement[0].value = option.selectValue;
32718              option.element.selected = true;
32719            }
32720
32721            option.element.setAttribute('selected', 'selected');
32722          } else {
32723            if (value === null || providedEmptyOption) {
32724              removeUnknownOption();
32725              renderEmptyOption();
32726            } else {
32727              removeEmptyOption();
32728              renderUnknownOption();
32729            }
32730          }
32731        };
32732
32733        selectCtrl.readValue = function readNgOptionsValue() {
32734
32735          var selectedOption = options.selectValueMap[selectElement.val()];
32736
32737          if (selectedOption && !selectedOption.disabled) {
32738            removeEmptyOption();
32739            removeUnknownOption();
32740            return options.getViewValueFromOption(selectedOption);
32741          }
32742          return null;
32743        };
32744
32745        // If we are using `track by` then we must watch the tracked value on the model
32746        // since ngModel only watches for object identity change
32747        if (ngOptions.trackBy) {
32748          scope.$watch(
32749            function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
32750            function() { ngModelCtrl.$render(); }
32751          );
32752        }
32753
32754      } else {
32755
32756        ngModelCtrl.$isEmpty = function(value) {
32757          return !value || value.length === 0;
32758        };
32759
32760
32761        selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
32762          options.items.forEach(function(option) {
32763            option.element.selected = false;
32764          });
32765
32766          if (value) {
32767            value.forEach(function(item) {
32768              var option = options.getOptionFromViewValue(item);
32769              if (option && !option.disabled) option.element.selected = true;
32770            });
32771          }
32772        };
32773
32774
32775        selectCtrl.readValue = function readNgOptionsMultiple() {
32776          var selectedValues = selectElement.val() || [],
32777              selections = [];
32778
32779          forEach(selectedValues, function(value) {
32780            var option = options.selectValueMap[value];
32781            if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
32782          });
32783
32784          return selections;
32785        };
32786
32787        // If we are using `track by` then we must watch these tracked values on the model
32788        // since ngModel only watches for object identity change
32789        if (ngOptions.trackBy) {
32790
32791          scope.$watchCollection(function() {
32792            if (isArray(ngModelCtrl.$viewValue)) {
32793              return ngModelCtrl.$viewValue.map(function(value) {
32794                return ngOptions.getTrackByValue(value);
32795              });
32796            }
32797          }, function() {
32798            ngModelCtrl.$render();
32799          });
32800
32801        }
32802      }
32803
32804
32805      if (providedEmptyOption) {
32806
32807        // we need to remove it before calling selectElement.empty() because otherwise IE will
32808        // remove the label from the element. wtf?
32809        emptyOption.remove();
32810
32811        // compile the element since there might be bindings in it
32812        $compile(emptyOption)(scope);
32813
32814        // remove the class, which is added automatically because we recompile the element and it
32815        // becomes the compilation root
32816        emptyOption.removeClass('ng-scope');
32817      } else {
32818        emptyOption = jqLite(optionTemplate.cloneNode(false));
32819      }
32820
32821      // We need to do this here to ensure that the options object is defined
32822      // when we first hit it in writeNgOptionsValue
32823      updateOptions();
32824
32825      // We will re-render the option elements if the option values or labels change
32826      scope.$watchCollection(ngOptions.getWatchables, updateOptions);
32827
32828      // ------------------------------------------------------------------ //
32829
32830
32831      function updateOptionElement(option, element) {
32832        option.element = element;
32833        element.disabled = option.disabled;
32834        // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
32835        // selects in certain circumstances when multiple selects are next to each other and display
32836        // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
32837        // See https://github.com/angular/angular.js/issues/11314 for more info.
32838        // This is unfortunately untestable with unit / e2e tests
32839        if (option.label !== element.label) {
32840          element.label = option.label;
32841          element.textContent = option.label;
32842        }
32843        if (option.value !== element.value) element.value = option.selectValue;
32844      }
32845
32846      function addOrReuseElement(parent, current, type, templateElement) {
32847        var element;
32848        // Check whether we can reuse the next element
32849        if (current && lowercase(current.nodeName) === type) {
32850          // The next element is the right type so reuse it
32851          element = current;
32852        } else {
32853          // The next element is not the right type so create a new one
32854          element = templateElement.cloneNode(false);
32855          if (!current) {
32856            // There are no more elements so just append it to the select
32857            parent.appendChild(element);
32858          } else {
32859            // The next element is not a group so insert the new one
32860            parent.insertBefore(element, current);
32861          }
32862        }
32863        return element;
32864      }
32865
32866
32867      function removeExcessElements(current) {
32868        var next;
32869        while (current) {
32870          next = current.nextSibling;
32871          jqLiteRemove(current);
32872          current = next;
32873        }
32874      }
32875
32876
32877      function skipEmptyAndUnknownOptions(current) {
32878        var emptyOption_ = emptyOption && emptyOption[0];
32879        var unknownOption_ = unknownOption && unknownOption[0];
32880
32881        // We cannot rely on the extracted empty option being the same as the compiled empty option,
32882        // because the compiled empty option might have been replaced by a comment because
32883        // it had an "element" transclusion directive on it (such as ngIf)
32884        if (emptyOption_ || unknownOption_) {
32885          while (current &&
32886                (current === emptyOption_ ||
32887                current === unknownOption_ ||
32888                current.nodeType === NODE_TYPE_COMMENT ||
32889                (nodeName_(current) === 'option' && current.value === ''))) {
32890            current = current.nextSibling;
32891          }
32892        }
32893        return current;
32894      }
32895
32896
32897      function updateOptions() {
32898
32899        var previousValue = options && selectCtrl.readValue();
32900
32901        options = ngOptions.getOptions();
32902
32903        var groupMap = {};
32904        var currentElement = selectElement[0].firstChild;
32905
32906        // Ensure that the empty option is always there if it was explicitly provided
32907        if (providedEmptyOption) {
32908          selectElement.prepend(emptyOption);
32909        }
32910
32911        currentElement = skipEmptyAndUnknownOptions(currentElement);
32912
32913        options.items.forEach(function updateOption(option) {
32914          var group;
32915          var groupElement;
32916          var optionElement;
32917
32918          if (isDefined(option.group)) {
32919
32920            // This option is to live in a group
32921            // See if we have already created this group
32922            group = groupMap[option.group];
32923
32924            if (!group) {
32925
32926              // We have not already created this group
32927              groupElement = addOrReuseElement(selectElement[0],
32928                                               currentElement,
32929                                               'optgroup',
32930                                               optGroupTemplate);
32931              // Move to the next element
32932              currentElement = groupElement.nextSibling;
32933
32934              // Update the label on the group element
32935              groupElement.label = option.group;
32936
32937              // Store it for use later
32938              group = groupMap[option.group] = {
32939                groupElement: groupElement,
32940                currentOptionElement: groupElement.firstChild
32941              };
32942
32943            }
32944
32945            // So now we have a group for this option we add the option to the group
32946            optionElement = addOrReuseElement(group.groupElement,
32947                                              group.currentOptionElement,
32948                                              'option',
32949                                              optionTemplate);
32950            updateOptionElement(option, optionElement);
32951            // Move to the next element
32952            group.currentOptionElement = optionElement.nextSibling;
32953
32954          } else {
32955
32956            // This option is not in a group
32957            optionElement = addOrReuseElement(selectElement[0],
32958                                              currentElement,
32959                                              'option',
32960                                              optionTemplate);
32961            updateOptionElement(option, optionElement);
32962            // Move to the next element
32963            currentElement = optionElement.nextSibling;
32964          }
32965        });
32966
32967
32968        // Now remove all excess options and group
32969        Object.keys(groupMap).forEach(function(key) {
32970          removeExcessElements(groupMap[key].currentOptionElement);
32971        });
32972        removeExcessElements(currentElement);
32973
32974        ngModelCtrl.$render();
32975
32976        // Check to see if the value has changed due to the update to the options
32977        if (!ngModelCtrl.$isEmpty(previousValue)) {
32978          var nextValue = selectCtrl.readValue();
32979          var isNotPrimitive = ngOptions.trackBy || multiple;
32980          if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
32981            ngModelCtrl.$setViewValue(nextValue);
32982            ngModelCtrl.$render();
32983          }
32984        }
32985
32986      }
32987  }
32988
32989  return {
32990    restrict: 'A',
32991    terminal: true,
32992    require: ['select', 'ngModel'],
32993    link: {
32994      pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
32995        // Deactivate the SelectController.register method to prevent
32996        // option directives from accidentally registering themselves
32997        // (and unwanted $destroy handlers etc.)
32998        ctrls[0].registerOption = noop;
32999      },
33000      post: ngOptionsPostLink
33001    }
33002  };
33003}];
33004
33005/**
33006 * @ngdoc directive
33007 * @name ngPluralize
33008 * @restrict EA
33009 *
33010 * @description
33011 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
33012 * These rules are bundled with angular.js, but can be overridden
33013 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
33014 * by specifying the mappings between
33015 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
33016 * and the strings to be displayed.
33017 *
33018 * # Plural categories and explicit number rules
33019 * There are two
33020 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
33021 * in Angular's default en-US locale: "one" and "other".
33022 *
33023 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
33024 * any number that is not 1), an explicit number rule can only match one number. For example, the
33025 * explicit number rule for "3" matches the number 3. There are examples of plural categories
33026 * and explicit number rules throughout the rest of this documentation.
33027 *
33028 * # Configuring ngPluralize
33029 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
33030 * You can also provide an optional attribute, `offset`.
33031 *
33032 * The value of the `count` attribute can be either a string or an {@link guide/expression
33033 * Angular expression}; these are evaluated on the current scope for its bound value.
33034 *
33035 * The `when` attribute specifies the mappings between plural categories and the actual
33036 * string to be displayed. The value of the attribute should be a JSON object.
33037 *
33038 * The following example shows how to configure ngPluralize:
33039 *
33040 * ```html
33041 * <ng-pluralize count="personCount"
33042                 when="{'0': 'Nobody is viewing.',
33043 *                      'one': '1 person is viewing.',
33044 *                      'other': '{} people are viewing.'}">
33045 * </ng-pluralize>
33046 *```
33047 *
33048 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
33049 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
33050 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
33051 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
33052 * show "a dozen people are viewing".
33053 *
33054 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
33055 * into pluralized strings. In the previous example, Angular will replace `{}` with
33056 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
33057 * for <span ng-non-bindable>{{numberExpression}}</span>.
33058 *
33059 * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
33060 * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
33061 *
33062 * # Configuring ngPluralize with offset
33063 * The `offset` attribute allows further customization of pluralized text, which can result in
33064 * a better user experience. For example, instead of the message "4 people are viewing this document",
33065 * you might display "John, Kate and 2 others are viewing this document".
33066 * The offset attribute allows you to offset a number by any desired value.
33067 * Let's take a look at an example:
33068 *
33069 * ```html
33070 * <ng-pluralize count="personCount" offset=2
33071 *               when="{'0': 'Nobody is viewing.',
33072 *                      '1': '{{person1}} is viewing.',
33073 *                      '2': '{{person1}} and {{person2}} are viewing.',
33074 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
33075 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
33076 * </ng-pluralize>
33077 * ```
33078 *
33079 * Notice that we are still using two plural categories(one, other), but we added
33080 * three explicit number rules 0, 1 and 2.
33081 * When one person, perhaps John, views the document, "John is viewing" will be shown.
33082 * When three people view the document, no explicit number rule is found, so
33083 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
33084 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
33085 * is shown.
33086 *
33087 * Note that when you specify offsets, you must provide explicit number rules for
33088 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
33089 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
33090 * plural categories "one" and "other".
33091 *
33092 * @param {string|expression} count The variable to be bound to.
33093 * @param {string} when The mapping between plural category to its corresponding strings.
33094 * @param {number=} offset Offset to deduct from the total number.
33095 *
33096 * @example
33097    <example module="pluralizeExampl
vendor: 4,913 bytes, lines 33097-33211
33097e">
33098      <file name="index.html">
33099        <script>
33100          angular.module('pluralizeExample', [])
33101            .controller('ExampleController', ['$scope', function($scope) {
33102              $scope.person1 = 'Igor';
33103              $scope.person2 = 'Misko';
33104              $scope.personCount = 1;
33105            }]);
33106        </script>
33107        <div ng-controller="ExampleController">
33108          <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
33109          <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
33110          <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
33111
33112          <!--- Example with simple pluralization rules for en locale --->
33113          Without Offset:
33114          <ng-pluralize count="personCount"
33115                        when="{'0': 'Nobody is viewing.',
33116                               'one': '1 person is viewing.',
33117                               'other': '{} people are viewing.'}">
33118          </ng-pluralize><br>
33119
33120          <!--- Example with offset --->
33121          With Offset(2):
33122          <ng-pluralize count="personCount" offset=2
33123                        when="{'0': 'Nobody is viewing.',
33124                               '1': '{{person1}} is viewing.',
33125                               '2': '{{person1}} and {{person2}} are viewing.',
33126                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
33127                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
33128          </ng-pluralize>
33129        </div>
33130      </file>
33131      <file name="protractor.js" type="protractor">
33132        it('should show correct pluralized string', function() {
33133          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
33134          var withOffset = element.all(by.css('ng-pluralize')).get(1);
33135          var countInput = element(by.model('personCount'));
33136
33137          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
33138          expect(withOffset.getText()).toEqual('Igor is viewing.');
33139
33140          countInput.clear();
33141          countInput.sendKeys('0');
33142
33143          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
33144          expect(withOffset.getText()).toEqual('Nobody is viewing.');
33145
33146          countInput.clear();
33147          countInput.sendKeys('2');
33148
33149          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
33150          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
33151
33152          countInput.clear();
33153          countInput.sendKeys('3');
33154
33155          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
33156          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
33157
33158          countInput.clear();
33159          countInput.sendKeys('4');
33160
33161          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
33162          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
33163        });
33164        it('should show data-bound names', function() {
33165          var withOffset = element.all(by.css('ng-pluralize')).get(1);
33166          var personCount = element(by.model('personCount'));
33167          var person1 = element(by.model('person1'));
33168          var person2 = element(by.model('person2'));
33169          personCount.clear();
33170          personCount.sendKeys('4');
33171          person1.clear();
33172          person1.sendKeys('Di');
33173          person2.clear();
33174          person2.sendKeys('Vojta');
33175          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
33176        });
33177      </file>
33178    </example>
33179 */
33180var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
33181  var BRACE = /{}/g,
33182      IS_WHEN = /^when(Minus)?(.+)$/;
33183
33184  return {
33185    link: function(scope, element, attr) {
33186      var numberExp = attr.count,
33187          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
33188          offset = attr.offset || 0,
33189          whens = scope.$eval(whenExp) || {},
33190          whensExpFns = {},
33191          startSymbol = $interpolate.startSymbol(),
33192          endSymbol = $interpolate.endSymbol(),
33193          braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
33194          watchRemover = angular.noop,
33195          lastCount;
33196
33197      forEach(attr, function(expression, attributeName) {
33198        var tmpMatch = IS_WHEN.exec(attributeName);
33199        if (tmpMatch) {
33200          var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
33201          whens[whenKey] = element.attr(attr.$attr[attributeName]);
33202        }
33203      });
33204      forEach(whens, function(expression, key) {
33205        whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
33206
33207      });
33208
33209      scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
33210        var count = parseFloat(newVal);
33211        var countIsNaN = isN
vendor: 9,019 bytes, lines 33211-33419
33211aN(count);
33212
33213        if (!countIsNaN && !(count in whens)) {
33214          // If an explicit number rule such as 1, 2, 3... is defined, just use it.
33215          // Otherwise, check it against pluralization rules in $locale service.
33216          count = $locale.pluralCat(count - offset);
33217        }
33218
33219        // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
33220        // In JS `NaN !== NaN`, so we have to explicitly check.
33221        if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
33222          watchRemover();
33223          var whenExpFn = whensExpFns[count];
33224          if (isUndefined(whenExpFn)) {
33225            if (newVal != null) {
33226              $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
33227            }
33228            watchRemover = noop;
33229            updateElementText();
33230          } else {
33231            watchRemover = scope.$watch(whenExpFn, updateElementText);
33232          }
33233          lastCount = count;
33234        }
33235      });
33236
33237      function updateElementText(newText) {
33238        element.text(newText || '');
33239      }
33240    }
33241  };
33242}];
33243
33244/**
33245 * @ngdoc directive
33246 * @name ngRepeat
33247 * @multiElement
33248 *
33249 * @description
33250 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
33251 * instance gets its own scope, where the given loop variable is set to the current collection item,
33252 * and `$index` is set to the item index or key.
33253 *
33254 * Special properties are exposed on the local scope of each template instance, including:
33255 *
33256 * | Variable  | Type            | Details                                                                     |
33257 * |-----------|-----------------|-----------------------------------------------------------------------------|
33258 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
33259 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
33260 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
33261 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
33262 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
33263 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
33264 *
33265 * <div class="alert alert-info">
33266 *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
33267 *   This may be useful when, for instance, nesting ngRepeats.
33268 * </div>
33269 *
33270 *
33271 * # Iterating over object properties
33272 *
33273 * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
33274 * syntax:
33275 *
33276 * ```js
33277 * <div ng-repeat="(key, value) in myObj"> ... </div>
33278 * ```
33279 *
33280 * However, there are a limitations compared to array iteration:
33281 *
33282 * - The JavaScript specification does not define the order of keys
33283 *   returned for an object, so Angular relies on the order returned by the browser
33284 *   when running `for key in myObj`. Browsers generally follow the strategy of providing
33285 *   keys in the order in which they were defined, although there are exceptions when keys are deleted
33286 *   and reinstated. See the
33287 *   [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
33288 *
33289 * - `ngRepeat` will silently *ignore* object keys starting with `$`, because
33290 *   it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
33291 *
33292 * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
33293 *   objects, and will throw if used with one.
33294 *
33295 * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
33296 * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
33297 * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
33298 * or implement a `$watch` on the object yourself.
33299 *
33300 *
33301 * # Tracking and Duplicates
33302 *
33303 * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
33304 * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
33305 *
33306 * * When an item is added, a new instance of the template is added to the DOM.
33307 * * When an item is removed, its template instance is removed from the DOM.
33308 * * When items are reordered, their respective templates are reordered in the DOM.
33309 *
33310 * To minimize creation of DOM elements, `ngRepeat` uses a function
33311 * to "keep track" of all items in the collection and their corresponding DOM elements.
33312 * For example, if an item is added to the collection, ngRepeat will know that all other items
33313 * already have DOM elements, and will not re-render them.
33314 *
33315 * The default tracking function (which tracks items by their identity) does not allow
33316 * duplicate items in arrays. This is because when there are duplicates, it is not possible
33317 * to maintain a one-to-one mapping between collection items and DOM elements.
33318 *
33319 * If you do need to repeat duplicate items, you can substitute the default tracking behavior
33320 * with your own using the `track by` expression.
33321 *
33322 * For example, you may track items by the index of each item in the collection, using the
33323 * special scope property `$index`:
33324 * ```html
33325 *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
33326 *      {{n}}
33327 *    </div>
33328 * ```
33329 *
33330 * You may also use arbitrary expressions in `track by`, including references to custom functions
33331 * on the scope:
33332 * ```html
33333 *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
33334 *      {{n}}
33335 *    </div>
33336 * ```
33337 *
33338 * <div class="alert alert-success">
33339 * If you are working with objects that have an identifier property, you should track
33340 * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
33341 * will not have to rebuild the DOM elements for items it has already rendered, even if the
33342 * JavaScript objects in the collection have been substituted for new ones. For large collections,
33343 * this significantly improves rendering performance. If you don't have a unique identifier,
33344 * `track by $index` can also provide a performance boost.
33345 * </div>
33346 * ```html
33347 *    <div ng-repeat="model in collection track by model.id">
33348 *      {{model.name}}
33349 *    </div>
33350 * ```
33351 *
33352 * When no `track by` expression is provided, it is equivalent to tracking by the built-in
33353 * `$id` function, which tracks items by their identity:
33354 * ```html
33355 *    <div ng-repeat="obj in collection track by $id(obj)">
33356 *      {{obj.prop}}
33357 *    </div>
33358 * ```
33359 *
33360 * <div class="alert alert-warning">
33361 * **Note:** `track by` must always be the last expression:
33362 * </div>
33363 * ```
33364 * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
33365 *     {{model.name}}
33366 * </div>
33367 * ```
33368 *
33369 * # Special repeat start and end points
33370 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
33371 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
33372 * 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)
33373 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
33374 *
33375 * The example below makes use of this feature:
33376 * ```html
33377 *   <header ng-repeat-start="item in items">
33378 *     Header {{ item }}
33379 *   </header>
33380 *   <div class="body">
33381 *     Body {{ item }}
33382 *   </div>
33383 *   <footer ng-repeat-end>
33384 *     Footer {{ item }}
33385 *   </footer>
33386 * ```
33387 *
33388 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
33389 * ```html
33390 *   <header>
33391 *     Header A
33392 *   </header>
33393 *   <div class="body">
33394 *     Body A
33395 *   </div>
33396 *   <footer>
33397 *     Footer A
33398 *   </footer>
33399 *   <header>
33400 *     Header B
33401 *   </header>
33402 *   <div class="body">
33403 *     Body B
33404 *   </div>
33405 *   <footer>
33406 *     Footer B
33407 *   </footer>
33408 * ```
33409 *
33410 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
33411 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
33412 *
33413 * @animations
33414 * | Animation                        | Occurs                              |
33415 * |----------------------------------|-------------------------------------|
33416 * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
33417 * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
33418 * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
33419 *
33420 * See the example below for defining CSS animations with ngRepeat.
33421 *
33422 * @element ANY
33423 * @scope
33424 * @priority 1000
33425 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
33426 *   formats are currently supported:
33427 *
33428 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
33429 *     is a scope expression giving the collection to enumerate.
33430 *
33431 *     For example: `album in artist.albums`.
33432 *
33433 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
33434 *     and `expression` is the scope expression giving the collection to enumerate.
33435 *
33436 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
33437 *
33438 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
33439 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
33440 *     is specified, ng-repeat associates elements by identity. It is an error to have
33441 *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
33442 *     mapped to the same DOM element, which is not possible.)
33443 *
33444 *     Note that the tracking expression must come last, after any filters, and the alias expression.
33445 *
33446 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
33447 *     will be associated by item identity in the array.
33448 *
33449 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
33450 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
33451 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
33452 *     element in the same way in the DOM.
33453 *
33454 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
33455 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
33456 *     property is same.
33457 *
33458 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
33459 *     to items in conjunction with a tracking expression.
33460 *
33461 *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
33462 *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
33463 *     when a filter is active on the repeater, but the filtered result set is empty.
33464 *
33465 *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
33466 *     the items have been processed through the filter.
33467 *
33468 *     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
33469 *     (and not as operator, inside an expression).
33470 *
33471 *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
33472 *
33473 * @example
33474 * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
33475 * results by name. New (entering) and removed (leaving) items are animated.
33476  <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
33477    <file name="index.html">
33478      <div ng-controller="repeatController">
33479        I have {{friends.length}} friends. They are:
33480        <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
33481        <ul class="example-animate-container">
33482          <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
33483            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
33484          </li>
33485          <li class="animate-repeat" ng-if="results.length == 0">
33486            <strong>No results found...</strong>
33487          </li>
33488        </ul>
33489      </div>
33490    </file>
33491    <file name="script.js">
33492      angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
33493        $scope.friends = [
33494          {name:'John', age:25, gender:'boy'},
33495          {name:'Jessie', age:30, gender:'girl'},
33496          {name:'Johanna', age:28, gender:'girl'},
33497          {name:'Joy', age:15, gender:'girl'},
33498          {name:'Mary', age:28, gender:'girl'},
33499          {name:'Peter', age:95, gender:'boy'},
33500          {name:'Sebastian', age:50, gender:'boy'},
33501          {name:'Erika', age:27, gender:'girl'},
33502          {name:'Patrick', age:40, gender:'boy'},
33503          {name:'Samantha', age:60, gender:'girl'}
33504        ];
33505      });
33506    </file>
33507    <file name="animations.css">
33508      .example-animate-container {
33509        background:white;
33510        border:1px solid black;
33511        list-style:none;
33512        margin:0;
33513        padding:0 10px;
33514      }
33515
33516      .animate-repeat {
33517        line-height:30px;
33518        list-style:none;
33519        box-sizing:border-box;
33520      }
33521
33522      .animate-repeat.ng-move,
33523      .animate-repeat.ng-enter,
33524      .animate-repeat.ng-leave {
33525        transition:all linear 0.5s;
33526      }
33527
33528      .animate-repeat.ng-leave.ng-leave-active,
33529      .animate-repeat.ng-move,
33530      .animate-repeat.ng-enter {
33531        opacity:0;
33532        max-height:0;
33533      }
33534
33535      .animate-repeat.ng-leave,
33536      .animate-repeat.ng-move.ng-move-active,
33537      .animate-repeat.ng-enter.ng-enter-active {
33538        opacity:1;
33539        max-height:30px;
33540      }
33541    </file>
33542    <file name="protractor.js" type="protractor">
33543      var friends = element.all(by.repeater('friend in friends'));
33544
33545      it('should render initial data set', function() {
33546        expect(friends.count()).toBe(10);
33547        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
33548        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
33549        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
33550        expect(element(by.binding('friends.length')).getText())
33551            .toMatch("I have 10 friends. They are:");
33552      });
33553
33554       it('should update repeater when filter predicate changes', function() {
33555         expect(friends.count()).toBe(10);
33556
33557         element(by.model('q')).sendKeys('ma');
33558
33559         expect(friends.count()).toBe(2);
33560         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
33561         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
33562       });
33563      </file>
33564    </example>
33565 */
33566var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
33567  var NG_REMOVED = '$$NG_REMOVED';
33568  var ngRepeatMinErr = minErr('ngRepeat');
33569
33570  var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
33571    // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
33572    scope[valueIdentifier] = value;
33573    if (keyIdentifier) scope[keyIdentifier] = key;
33574    scope.$index = index;
33575    scope.$first = (index === 0);
33576    scope.$last = (index === (arrayLength - 1));
33577    scope.$middle = !(scope.$first || scope.$last);
33578    // jshint bitwise: false
33579    scope.$odd = !(scope.$even = (index&1) === 0);
33580    // jshint bitwise: true
33581  };
33582
33583  var getBlockStart = function(block) {
33584    return block.clone[0];
33585  };
33586
33587  var getBlockEnd = function(block) {
33588    return block.clone[block.clone.length - 1];
33589  };
33590
33591
33592  return {
33593    restrict: 'A',
33594    multiElement: true,
33595    transclude: 'element',
33596    priority: 1000,
33597    terminal: true,
33598    $$tlb: true,
33599    compile: function ngRepeatCompile($element, $attr) {
33600      var expression = $attr.ngRepeat;
33601      var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
33602
33603      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*$/);
33604
33605      if (!match) {
33606        throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
33607            expression);
33608      }
33609
33610      var lhs = match[1];
33611      var rhs = match[2];
33612      var aliasAs = match[3];
33613      var trackByExp = match[4];
33614
33615      match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
33616
33617      if (!match) {
33618        throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
33619            lhs);
33620      }
33621      var valueIdentifier = match[3] || match[1];
33622      var keyIdentifier = match[2];
33623
33624      if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
33625          /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
33626        throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
33627          aliasAs);
33628      }
33629
33630      var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
33631      var hashFnLocals = {$id: hashKey};
33632
33633      if (trackByExp) {
33634        trackByExpGetter = $parse(trackByExp);
33635      } else {
33636        trackByIdArrayFn = function(key, value) {
33637          return hashKey(value);
33638        };
33639        trackByIdObjFn = function(key) {
33640          return key;
33641        };
33642      }
33643
33644      return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
33645
33646        if (trackByExpGetter) {
33647          trackByIdExpFn = function(key, value, index) {
vendor: 11,339 bytes, lines 33648-33899
33648            // assign key, value, and $index to the locals so that they can be used in hash functions
33649            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
33650            hashFnLocals[valueIdentifier] = value;
33651            hashFnLocals.$index = index;
33652            return trackByExpGetter($scope, hashFnLocals);
33653          };
33654        }
33655
33656        // Store a list of elements from previous run. This is a hash where key is the item from the
33657        // iterator, and the value is objects with following properties.
33658        //   - scope: bound scope
33659        //   - element: previous element.
33660        //   - index: position
33661        //
33662        // We are using no-proto object so that we don't need to guard against inherited props via
33663        // hasOwnProperty.
33664        var lastBlockMap = createMap();
33665
33666        //watch props
33667        $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
33668          var index, length,
33669              previousNode = $element[0],     // node that cloned nodes should be inserted after
33670                                              // initialized to the comment node anchor
33671              nextNode,
33672              // Same as lastBlockMap but it has the current state. It will become the
33673              // lastBlockMap on the next iteration.
33674              nextBlockMap = createMap(),
33675              collectionLength,
33676              key, value, // key/value of iteration
33677              trackById,
33678              trackByIdFn,
33679              collectionKeys,
33680              block,       // last object information {scope, element, id}
33681              nextBlockOrder,
33682              elementsToRemove;
33683
33684          if (aliasAs) {
33685            $scope[aliasAs] = collection;
33686          }
33687
33688          if (isArrayLike(collection)) {
33689            collectionKeys = collection;
33690            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
33691          } else {
33692            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
33693            // if object, extract keys, in enumeration order, unsorted
33694            collectionKeys = [];
33695            for (var itemKey in collection) {
33696              if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
33697                collectionKeys.push(itemKey);
33698              }
33699            }
33700          }
33701
33702          collectionLength = collectionKeys.length;
33703          nextBlockOrder = new Array(collectionLength);
33704
33705          // locate existing items
33706          for (index = 0; index < collectionLength; index++) {
33707            key = (collection === collectionKeys) ? index : collectionKeys[index];
33708            value = collection[key];
33709            trackById = trackByIdFn(key, value, index);
33710            if (lastBlockMap[trackById]) {
33711              // found previously seen block
33712              block = lastBlockMap[trackById];
33713              delete lastBlockMap[trackById];
33714              nextBlockMap[trackById] = block;
33715              nextBlockOrder[index] = block;
33716            } else if (nextBlockMap[trackById]) {
33717              // if collision detected. restore lastBlockMap and throw an error
33718              forEach(nextBlockOrder, function(block) {
33719                if (block && block.scope) lastBlockMap[block.id] = block;
33720              });
33721              throw ngRepeatMinErr('dupes',
33722                  "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
33723                  expression, trackById, value);
33724            } else {
33725              // new never before seen block
33726              nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
33727              nextBlockMap[trackById] = true;
33728            }
33729          }
33730
33731          // remove leftover items
33732          for (var blockKey in lastBlockMap) {
33733            block = lastBlockMap[blockKey];
33734            elementsToRemove = getBlockNodes(block.clone);
33735            $animate.leave(elementsToRemove);
33736            if (elementsToRemove[0].parentNode) {
33737              // if the element was not removed yet because of pending animation, mark it as deleted
33738              // so that we can ignore it later
33739              for (index = 0, length = elementsToRemove.length; index < length; index++) {
33740                elementsToRemove[index][NG_REMOVED] = true;
33741              }
33742            }
33743            block.scope.$destroy();
33744          }
33745
33746          // we are not using forEach for perf reasons (trying to avoid #call)
33747          for (index = 0; index < collectionLength; index++) {
33748            key = (collection === collectionKeys) ? index : collectionKeys[index];
33749            value = collection[key];
33750            block = nextBlockOrder[index];
33751
33752            if (block.scope) {
33753              // if we have already seen this object, then we need to reuse the
33754              // associated scope/element
33755
33756              nextNode = previousNode;
33757
33758              // skip nodes that are already pending removal via leave animation
33759              do {
33760                nextNode = nextNode.nextSibling;
33761              } while (nextNode && nextNode[NG_REMOVED]);
33762
33763              if (getBlockStart(block) != nextNode) {
33764                // existing item which got moved
33765                $animate.move(getBlockNodes(block.clone), null, previousNode);
33766              }
33767              previousNode = getBlockEnd(block);
33768              updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
33769            } else {
33770              // new item which we don't know about
33771              $transclude(function ngRepeatTransclude(clone, scope) {
33772                block.scope = scope;
33773                // http://jsperf.com/clone-vs-createcomment
33774                var endNode = ngRepeatEndComment.cloneNode(false);
33775                clone[clone.length++] = endNode;
33776
33777                $animate.enter(clone, null, previousNode);
33778                previousNode = endNode;
33779                // Note: We only need the first/last node of the cloned nodes.
33780                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
33781                // by a directive with templateUrl when its template arrives.
33782                block.clone = clone;
33783                nextBlockMap[block.id] = block;
33784                updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
33785              });
33786            }
33787          }
33788          lastBlockMap = nextBlockMap;
33789        });
33790      };
33791    }
33792  };
33793}];
33794
33795var NG_HIDE_CLASS = 'ng-hide';
33796var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
33797/**
33798 * @ngdoc directive
33799 * @name ngShow
33800 * @multiElement
33801 *
33802 * @description
33803 * The `ngShow` directive shows or hides the given HTML element based on the expression
33804 * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
33805 * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
33806 * in AngularJS and sets the display style to none (using an !important flag).
33807 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
33808 *
33809 * ```html
33810 * <!-- when $scope.myValue is truthy (element is visible) -->
33811 * <div ng-show="myValue"></div>
33812 *
33813 * <!-- when $scope.myValue is falsy (element is hidden) -->
33814 * <div ng-show="myValue" class="ng-hide"></div>
33815 * ```
33816 *
33817 * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
33818 * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
33819 * from the element causing the element not to appear hidden.
33820 *
33821 * ## Why is !important used?
33822 *
33823 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
33824 * can be easily overridden by heavier selectors. For example, something as simple
33825 * as changing the display style on a HTML list item would make hidden elements appear visible.
33826 * This also becomes a bigger issue when dealing with CSS frameworks.
33827 *
33828 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
33829 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
33830 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
33831 *
33832 * ### Overriding `.ng-hide`
33833 *
33834 * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
33835 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
33836 * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
33837 * with extra animation classes that can be added.
33838 *
33839 * ```css
33840 * .ng-hide:not(.ng-hide-animate) {
33841 *   /&#42; this is just another form of hiding an element &#42;/
33842 *   display: block!important;
33843 *   position: absolute;
33844 *   top: -9999px;
33845 *   left: -9999px;
33846 * }
33847 * ```
33848 *
33849 * By default you don't need to override in CSS anything and the animations will work around the display style.
33850 *
33851 * ## A note about animations with `ngShow`
33852 *
33853 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
33854 * is true and false. This system works like the animation system present with ngClass except that
33855 * you must also include the !important flag to override the display property
33856 * so that you can perform an animation when the element is hidden during the time of the animation.
33857 *
33858 * ```css
33859 * //
33860 * //a working example can be found at the bottom of this page
33861 * //
33862 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
33863 *   /&#42; this is required as of 1.3x to properly
33864 *      apply all styling in a show/hide animation &#42;/
33865 *   transition: 0s linear all;
33866 * }
33867 *
33868 * .my-element.ng-hide-add-active,
33869 * .my-element.ng-hide-remove-active {
33870 *   /&#42; the transition is defined in the active class &#42;/
33871 *   transition: 1s linear all;
33872 * }
33873 *
33874 * .my-element.ng-hide-add { ... }
33875 * .my-element.ng-hide-add.ng-hide-add-active { ... }
33876 * .my-element.ng-hide-remove { ... }
33877 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
33878 * ```
33879 *
33880 * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
33881 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
33882 *
33883 * @animations
33884 * | Animation                        | Occurs                              |
33885 * |----------------------------------|-------------------------------------|
33886 * | {@link $animate#addClass addClass} `.ng-hide`  | after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden |
33887 * | {@link $animate#removeClass removeClass}  `.ng-hide`  | after the `ngShow` expression evaluates to a truthy value and just before contents are set to visible |
33888 *
33889 * @element ANY
33890 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
33891 *     then the element is shown or hidden respectively.
33892 *
33893 * @example
33894  <example module="ngAnimate" deps="angular-animate.js" animations="true">
33895    <file name="index.html">
33896      Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
33897      <div>
33898        Show:
33899        <div class="check-element animate-show" ng-show="checked">
33900          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
33901        </div>
33902      </div>
33903      <div>
33904        Hide:
33905        <div class="check-element animate-show" ng-hide="checked">
33906          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
33907        </div>
33908      </div>
33909    </file>
33910    <file name="glyphicons.css">
33911      @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
33912    </file>
33913    <file name="animations.css">
33914      .animate-show {
33915        line-height: 20px;
33916        opacity: 1;
33917        padding: 10px;
33918        border: 1px solid black;
33919        background: white;
33920      }
33921
33922      .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
33923        transition: all linear 0.5s;
33924      }
33925
33926      .animate-show.ng-hide {
33927        line-height: 0;
33928        opacity: 0;
33929        padding: 0 10px;
33930      }
33931
33932      .check-element {
33933        padding: 10px;
33934        border: 1px solid black;
33935        background: white;
33936      }
33937    </file>
33938    <file name="protractor.js" type="protractor">
33939      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
33940      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
33941
33942      it('should check ng-show / ng-hide', function() {
33943        expect(thumbsUp.isDisplayed()).toBeFalsy();
33944        expect(thumbsDown.isDisplayed()).toBeTruthy();
33945
33946        element(by.model('checked')).click();
33947
33948        expect(thumbsUp.isDisplayed()).toBeTruthy();
33949        expect(thumbsDown.isDisplayed()).toBeFalsy();
33950      });
33951    </file>
33952  </example>
33953 */
33954var ngShowDirective = ['$animate', function($animate) {
33955  return {
33956    restrict: 'A',
33957    multiElement: true,
33958    link: function(scope, element, attr) {
33959      scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
33960        // we're adding a temporary, animation-specific class for ng-hide since this way
33961        // we can control when the element is actually displayed on screen without having
33962        // to have a global/greedy CSS selector that breaks when other animations are run.
33963        // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
33964        $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
33965          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
33966        });
33967      });
33968    }
33969  };
33970}];
33971
33972
33973/**
33974 * @ngdoc directive
33975 * @name ngHide
33976 * @multiElement
33977 *
33978 * @description
33979 * The `ngHide` directive shows or hides the given HTML element based on the expression
33980 * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
33981 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
33982 * in AngularJS and sets the display style to none (using an !important flag).
33983 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
33984 *
33985 * ```html
33986 * <!-- when $scope.myValue is truthy (element is hidden) -->
33987 * <div ng-hide="myValue" class="ng-hide"></div>
33988 *
33989 * <!-- when $scope.myValue is falsy (element is visible) -->
33990 * <div ng-hide="myValue"></div>
33991 * ```
33992 *
33993 * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
33994 * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
33995 * from the element causing the element not to appear hidden.
33996 *
33997 * ## Why is !important used?
33998 *
33999 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
34000 * can be easily overridden by heavier selectors. For example, something as simple
34001 * as changing the display style on a HTML list item would make hidden elements appear visible.
34002 * This also becomes a bigger issue when dealing with CSS frameworks.
34003 *
34004 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
34005 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
34006 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
34007 *
34008 * ### Overriding `.ng-hide`
34009 *
34010 * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
34011 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
34012 * class in CSS:
34013 *
34014 * ```css
34015 * .ng-hide {
34016 *   /&#42; this is just another form of hiding an element &#42;/
34017 *   display: block!important;
34018 *   position: absolute;
34019 *   top: -9999px;
34020 *   left: -9999px;
34021 * }
34022 * ```
34023 *
34024 * By default you don't need to override in CSS anything and the animations will work around the display style.
34025 *
34026 * ## A note about animations with `ngHide`
34027 *
34028 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
34029 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
34030 * CSS class is added and removed for you instead of your own CSS class.
34031 *
34032 * ```css
34033 * //
34034 * //a working example can be found at the bottom of this page
34035 * //
34036 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
34037 *   transition: 0.5s linear all;
34038 * }
34039 *
34040 * .my-element.ng-hide-add { ... }
34041 * .my-element.ng-hide-add.ng-hide-add-active { ... }
34042 * .my-element.ng-hide-remove { ... }
34043 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
34044 * ```
34045 *
34046 * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
34047 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
34048 *
34049 * @animations
34050 * | Animation                        | Occurs                              |
34051 * |----------------------------------|-------------------------------------|
34052 * | {@link $animate#addClass addClass} `.ng-hide`  | after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden |
34053 * | {@link $animate#removeClass removeClass}  `.ng-hide`  | after the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible |
34054 *
34055 *
34056 * @element ANY
34057 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
34058 *     the element is shown or hidden respectively.
34059 *
34060 * @example
34061  <example module="ngAnimate" deps="angular-animate.js" animations="true">
34062    <file name="index.html">
34063      Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
34064      <div>
34065        Show:
34066        <div class="check-element animate-hide" ng-show="checked">
34067          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
34068        </div>
34069      </div>
34070      <div>
34071        Hide:
34072        <div class="check-element animate-hide" ng-hide="checked">
34073          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
34074        </div>
34075      </div>
34076    </file>
34077    <file name="glyphicons.css">
34078      @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
34079    </file>
34080    <file name="animations.css">
34081      .animate-hide {
34082        transition: all linear 0.5s;
34083        line-height: 20px;
34084        opacity: 1;
34085        padding: 10px;
34086        border: 1px solid black;
34087        background: white;
34088      }
34089
34090      .animate-hide.ng-hide {
34091        line-height: 0;
34092        opacity: 0;
34093        padding: 0 10px;
34094      }
34095
34096      .check-element {
34097        padding: 10px;
34098        border: 1px solid black;
34099        background: white;
34100      }
34101    </file>
34102    <file name="protractor.js" type="protractor">
34103      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
34104      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
34105
34106      it('should check ng-show / ng-hide', function() {
34107        expect(thumbsUp.isDisplayed()).toBeFalsy();
34108        expect(thumbsDown.isDisplayed()).toBeTruthy();
34109
34110        element(by.model('checked')).click();
34111
34112        expect(thumbsUp.isDisplayed()).toBeTruthy();
34113        expect(thumbsDown.isDisplayed()).toBeFalsy();
34114      });
34115    </file>
34116  </example>
34117 */
34118var ngHideDirective = ['$animate', function($animate) {
34119  return {
34120    restrict: 'A',
34121    multiElement: true,
34122    link: function(scope, element, attr) {
34123      scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
34124        // The comment inside of the ngShowDirective explains why we add and
34125        // remove a temporary class for the show/hide animation
34126        $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
34127          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
34128        });
34129      });
34130    }
34131  };
34132}];
34133
34134/**
34135 * @ngdoc directive
34136 * @name ngStyle
34137 * @restrict AC
34138 *
34139 * @description
34140 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
34141 *
34142 * @element ANY
34143 * @param {expression} ngStyle
34144 *
34145 * {@link guide/expression Expression} which evals to an
34146 * object whose keys are CSS style names and values are corresponding values for those CSS
34147 * keys.
34148 *
34149 * Since some CSS style names are not valid keys for an object, they must be quoted.
34150 * See the 'background-color' style in the example below.
34151 *
34152 * @example
34153   <example>
34154     <file name="index.html">
34155        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
34156        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
34157        <input type="button" value="clear" ng-click="myStyle={}">
34158        <br/>
34159        <span ng-style="myStyle">Sample Text</span>
34160        <pre>myStyle={{myStyle}}</pre>
34161     </file>
34162     <file name="style.css">
34163       span {
34164         color: black;
34165       }
34166     </file>
34167     <file name="protractor.js" type="protractor">
34168       var colorSpan = element(by.css('span'));
34169
34170       it('should check ng-style', function() {
34171         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
34172         element(by.css('input[value=\'set color\']')).click();
34173         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
34174         element(by.css('input[value=clear]')).click();
34175         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
34176       });
34177     </file>
34178   </example>
34179 */
34180var ngStyleDirective = ngDirective(function(scope, element, attr) {
34181  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
34182    if (oldStyles && (newStyles !== oldStyles)) {
34183      forEach(oldStyles, function(val, style) { element.css(style, '');});
34184    }
34185    if (newStyles) element.css(newStyles);
34186  }, true);
34187});
34188
34189/**
34190 * @ngdoc directive
34191 * @name ngSwitch
34192 * @restrict EA
34193 *
34194 * @description
34195 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
34196 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
34197 * as specified in the template.
34198 *
34199 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
34200 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
34201 * matches the value obtained from the evaluated expression. In other words, you define a container element
34202 * (where you place the directive), place an expression on the **`on="..."` attribute**
34203 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
34204 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
34205 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
34206 * attribute is displayed.
34207 *
34208 * <div class="alert alert-info">
34209 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
34210 * as literal string values to match against.
34211 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
34211omeVal"` not against the
34212 * value of the expression `$scope.someVal`.
34213 * </div>
34214
34215 * @animations
34216 * | Animation                        | Occurs                              |
34217 * |----------------------------------|-------------------------------------|
34218 * | {@link ng.$animate#enter enter}  | after the ngSwitch contents change and the matched child element is placed inside the container |
34219 * | {@link ng.$animate#leave leave}  | after the ngSwitch contents change and just before the former contents are removed from the DOM |
34220 *
34221 * @usage
34222 *
34223 * ```
34224 * <ANY ng-switch="expression">
34225 *   <ANY ng-switch-when="matchValue1">...</ANY>
34226 *   <ANY ng-switch-when="matchValue2">...</ANY>
34227 *   <ANY ng-switch-default>...</ANY>
34228 * </ANY>
34229 * ```
34230 *
34231 *
34232 * @scope
34233 * @priority 1200
34234 * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
34235 * On child elements add:
34236 *
34237 * * `ngSwitchWhen`: the case statement to match against. If match then this
34238 *   case will be displayed. If the same match appears multiple times, all the
34239 *   elements will be displayed.
34240 * * `ngSwitchDefault`: the default case when no other case match. If there
34241 *   are multiple default cases, all of them will be displayed when no other
34242 *   case match.
34243 *
34244 *
34245 * @example
34246  <example module="switchExample" deps="angular-animate.js" animations="true">
34247    <file name="index.html">
34248      <div ng-controller="ExampleController">
34249        <select ng-model="selection" ng-options="item for item in items">
34250        </select>
34251        <code>selection={{selection}}</code>
34252        <hr/>
34253        <div class="animate-switch-container"
34254          ng-switch on="selection">
34255            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
34256            <div class="animate-switch" ng-switch-when="home">Home Span</div>
34257            <div class="animate-switch" ng-switch-default>default</div>
34258        </div>
34259      </div>
34260    </file>
34261    <file name="script.js">
34262      angular.module('switchExample', ['ngAnimate'])
34263        .controller('ExampleController', ['$scope', function($scope) {
34264          $scope.items = ['settings', 'home', 'other'];
34265          $scope.selection = $scope.items[0];
34266        }]);
34267    </file>
34268    <file name="animations.css">
34269      .animate-switch-container {
34270        position:relative;
34271        background:white;
34272        border:1px solid black;
34273        height:40px;
34274        overflow:hidden;
34275      }
34276
34277      .animate-switch {
34278        padding:10px;
34279      }
34280
34281      .animate-switch.ng-animate {
34282        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
34283
34284        position:absolute;
34285        top:0;
34286        left:0;
34287        right:0;
34288        bottom:0;
34289      }
34290
34291      .animate-switch.ng-leave.ng-leave-active,
34292      .animate-switch.ng-enter {
34293        top:-50px;
34294      }
34295      .animate-switch.ng-leave,
34296      .animate-switch.ng-enter.ng-enter-active {
34297        top:0;
34298      }
34299    </file>
34300    <file name="protractor.js" type="protractor">
34301      var switchElem = element(by.css('[ng-switch]'));
34302      var select = element(by.model('selection'));
34303
34304      it('should start in settings', function() {
34305        expect(switchElem.getText()).toMatch(/Settings Div/);
34306      });
34307      it('should change to home', function() {
34308        select.all(by.css('option')).get(1).click();
34309        expect(switchElem.getText()).toMatch(/Home Span/);
34310      });
34311      it('should select default', function() {
34312        select.all(by.css('option')).get(2).click();
34313        expect(switchElem.getText()).toMatch(/default/);
34314      });
34315    </file>
34316  </example>
34317 */
34318var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
34319  return {
34320    require: 'ngSwitch',
34321
34322    // asks for $scope to fool the BC controller module
34323    controller: ['$scope', function ngSwitchController() {
34324     this.cases = {};
34325    }],
34326    link: function(scope, element, attr, ngSwitchController) {
34327      var watchExpr = attr.ngSwitch || attr.on,
34328          selectedTranscludes = [],
34329          selectedElements = [],
34330          previousLeaveAnimations = [],
34331          selectedScopes = [];
34332
34333      var spliceFactory = function(array, index) {
34334          return function() { array.splice(index, 1); };
34335      };
34336
34337      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
34338        var i, ii;
34339        for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
34340          $animate.cancel(previousLeaveAnimations[i]);
34341        }
34342        previousLeaveAnimations.length = 0;
34343
34344        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
34345          var selected = getBlockNodes(selectedElements[i].clone);
34346          selectedScopes[i].$destroy();
34347          var promise = previousLeaveAnimations[i] = $animate.leave(selected);
34348          promise.then(spliceFactory(previousLeaveAnimations, i));
34349        }
34350
34351        selectedElements.length = 0;
34352        selectedScopes.length = 0;
34353
34354        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
34355          forEach(selectedTranscludes, function(selectedTransclude) {
34356            selectedTransclude.transclude(function(caseElement, selectedScope) {
34357              selectedScopes.push(selectedScope);
34358              var anchor = selectedTransclude.element;
34359              caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
34360              var block = { clone: caseElement };
34361
34362              selectedElements.push(block);
34363              $animate.enter(caseElement, anchor.parent(), anchor);
34364            });
34365          });
34366        }
34367      });
34368    }
34369  };
34370}];
34371
34372var ngSwitchWhenDirective = ngDirective({
34373  transclude: 'element',
34374  priority: 1200,
34375  require: '^ngSwitch',
34376  multiElement: true,
34377  link: function(scope, element, attrs, ctrl, $transclude) {
34378    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
34379    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
34380  }
34381});
34382
34383var ngSwitchDefaultDirective = ngDirective({
34384  transclude: 'element',
34385  priority: 1200,
34386  require: '^ngSwitch',
34387  multiElement: true,
34388  link: function(scope, element, attr, ctrl, $transclude) {
34389    ctrl.cases['?'] = (ctrl.cases['?'] || []);
34390    ctrl.cases['?'].push({ transclude: $transclude, element: element });
34391   }
34392});
34393
34394/**
34395 * @ngdoc directive
34396 * @name ngTransclude
34397 * @restrict EAC
34398 *
34399 * @description
34400 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
34401 *
34402 * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
34403 * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
34404 *
34405 * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
34406 * content of this element will be removed before the transcluded content is inserted.
34407 * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
34408 * that no transcluded content is provided.
34409 *
34410 * @element ANY
34411 *
34412 * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
34413 *                                               or its value is the same as the name of the attribute then the default slot is used.
34414 *
34415 * @example
34416 * ### Basic transclusion
34417 * This example demonstrates basic transclusion of content into a component directive.
34418 * <example name="simpleTranscludeExample" module="transcludeExample">
34419 *   <file name="index.html">
34420 *     <script>
34421 *       angular.module('transcludeExample', [])
34422 *        .directive('pane', function(){
34423 *           return {
34424 *             restrict: 'E',
34425 *             transclude: true,
34426 *             scope: { title:'@' },
34427 *             template: '<div style="border: 1px solid black;">
34427' +
34428 *                         '<div style="background-color: gray">{{title}}</div>' +
34429 *                         '<ng-transclude></ng-transclude>' +
34430 *                       '</div>'
34431 *           };
34432 *       })
34433 *       .controller('ExampleController', ['$scope', function($scope) {
34434 *         $scope.title = 'Lorem Ipsum';
34435 *         $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
34436 *       }]);
34437 *     </script>
34438 *     <div ng-controller="ExampleController">
34439 *       <input ng-model="title" aria-label="title"> <br/>
34440 *       <textarea ng-model="text" aria-label="text"></textarea> <br/>
34441 *       <pane title="{{title}}"><span>{{text}}</span></pane>
34442 *     </div>
34443 *   </file>
34444 *   <file name="protractor.js" type="protractor">
34445 *      it('should have transcluded', function() {
34446 *        var titleElement = element(by.model('title'));
34447 *        titleElement.clear();
34448 *        titleElement.sendKeys('TITLE');
34449 *        var textElement = element(by.model('text'));
34450 *        textElement.clear();
34451 *        textElement.sendKeys('TEXT');
34452 *        expect(element(by.binding('title')).getText()).toEqual('TITLE');
34453 *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
34454 *      });
34455 *   </file>
34456 * </example>
34457 *
34458 * @example
34459 * ### Transclude fallback content
34460 * This example shows how to use `NgTransclude` with fallback content, that
34461 * is displayed if no transcluded content is provided.
34462 *
34463 * <example module="transcludeFallbackContentExample">
34464 * <file name="index.html">
34465 * <script>
34466 * angular.module('transcludeFallbackContentExample', [])
34467 * .directive('myButton', function(){
34468 *             return {
34469 *               restrict: 'E',
34470 *               transclude: true,
34471 *               scope: true,
34472 *               template: '<button style="cursor: pointer;">' +
34473 *                           '<ng-transclude>' +
34474 *                             '<b style="color: red;">Button1</b>' +
34475 *                           '</ng-transclude>' +
34476 *                         '</button>'
34477 *             };
34478 *         });
34479 * </script>
34480 * <!-- fallback button content -->
34481 * <my-button id="fallback"></my-button>
34482 * <!-- modified button content -->
34483 * <my-button id="modified">
34484 *   <i style="color: green;">Button2</i>
34485 * </my-button>
34486 * </file>
34487 * <file name="protractor.js" type="protractor">
34488 * it('should have different transclude element content', function() {
34489 *          expect(element(by.id('fallback')).getText()).toBe('Button1');
34490 *          expect(element(by.id('modified')).getText()).toBe('Button2');
34491 *        });
34492 * </file>
34493 * </example>
34494 *
34495 * @example
34496 * ### Multi-slot transclusion
34497 * This example demonstrates using multi-slot transclusion in a component directive.
34498 * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
34499 *   <file name="index.html">
34500 *    <style>
34501 *      .title, .footer {
34502 *        background-color: gray
34503 *      }
34504 *    </style>
34505 *    <div ng-controller="ExampleController">
34506 *      <input ng-model="title" aria-label="title"> <br/>
34507 *      <textarea ng-model="text" aria-label="text"></textarea> <br/>
34508 *      <pane>
34509 *        <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
34510 *        <pane-body><p>{{text}}</p></pane-body>
34511 *      </pane>
34512 *    </div>
34513 *   </file>
34514 *   <file name="app.js">
34515 *    angular.module('multiSlotTranscludeExample', [])
34516 *     .directive('pane', function(){
34517 *        return {
34518 *          restrict: 'E',
34519 *          transclude: {
34520 *            'title': '?paneTitle',
34521 *            'body': 'paneBody',
34522 *            'footer': '?paneFooter'
34523 *          },
34524 *          template: '<div style="border: 1px solid black;">' +
34525 *                      '<div class="title" ng-transclude="title">Fallback Title</div>' +
34526 *                      '<div ng-transclude="body"></div>' +
34527 *                      '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
34528 *                    '</div>'
34529 *        };
34530 *    })
34531 *    .controller('ExampleController', ['$scope', function($scope) {
34532 *      $scope.title = 'Lorem Ipsum';
34533 *      $scope.link = "https://google.com";
34534 *      $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
34535 *    }]);
34536 *   </file>
34537 *   <file name="protractor.js" type="protractor">
34538 *      it('should have transcluded the title and the body', function() {
34539 *        var titleElement = element(by.model('title'));
34540 *        titleElement.clear();
34541 *        titleElement.sendKeys('TITLE');
34542 *        var textElement = element(by.model('text'));
34543 *        textElement.clear();
34544 *        textElement.sendKeys('TEXT');
34545 *        expect(element(by.css('.title')).getText()).toEqual('TITLE');
34546 *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
34547 *        expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
34548 *      });
34549 *   </file>
34550 * </example>
34551 */
34552var ngTranscludeMinErr = minErr('ngTransclude');
34553var ngTranscludeDirective = ngDirective({
34554  restrict: 'EAC',
34555  link: function($scope, $element, $attrs, controller, $transclude) {
34556
34557    if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
34558      // If the attribute is of the form: `ng-transclude="ng-transclude"`
34559      // then treat it like the default
34560      $attrs.ngTransclude = '';
34561    }
34562
34563    function ngTranscludeCloneAttachFn(clone) {
34564      if (clone.length) {
34565        $element.empty();
34566        $element.append(clone);
34567      }
34568    }
34569
34570    if (!$transclude) {
34571      throw ngTranscludeMinErr('orphan',
34572       'Illegal use of ngTransclude directive in the template! ' +
34573       'No parent directive that requires a transclusion found. ' +
34574       'Element: {0}',
34575       startingTag($element));
34576    }
34577
34578    // If there is no slot name defined or the slot name is not optional
34579    // then transclude the slot
34580    var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
34581    $transclude(ngTranscludeCloneAttachFn, null, slotName);
34582  }
34583});
34584
34585/**
34586 * @ngdoc directive
34587 * @name script
34588 * @restrict E
34589 *
34590 * @description
34591 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
34592 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
34593 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
34594 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
34595 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
34596 *
34597 * @param {string} type Must be set to `'text/ng-template'`.
34598 * @param {string} id Cache name of the template.
34599 *
34600 * @example
34601  <example>
34602    <file name="index.html">
34603      <script type="text/ng-template" id="/tpl.html">
34604        Content of the template.
34605      </script>
34606
34607      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
34608      <div id="tpl-content" ng-include src="currentTpl"></div>
34609    </file>
34610    <file name="protractor.js" type="protractor">
34611      it('should load template defined inside script tag', function() {
34612        element(by.css('#tpl-link')).click();
34613        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
34614      });
34615    </file>
34616  </example>
34617 */
34618var scriptDirective = ['$templateCache', function($templateCache) {
34619  return {
34620    restrict: 'E',
34621    terminal: true,
34622    compile: function(element, attr) {
34623      if (attr.type == 'text/ng-template') {
34624        var templateUrl = attr.id,
34625            text = element[0].text;
34626
34627        $templateCache.put(templateUrl, text);
34628      }
34629    }
34630  };
34631}];
34632
34633var noopNgModelController = { $setViewValue: noop, $render: noop };
34634
34635function chromeHack(optionElement) {
34636  // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
34637  // Adding an <option selected="selected"> element to a <select required="required"> should
34638  // automatically select the new element
34639  if (optionElement[0].hasAttribute('selected')) {
34640    optionElement[0].selected = true;
34641  }
34642}
34643
34644/**
34645 * @ngdoc type
34646 * @name  select.SelectController
34647 * @description
34648 * The controller for the `<select>` directive. This provides support for reading
34649 * and writing the selected value(s) of the control and also coordinates dynamically
34650 * added `<option>` elements, perhaps by an `ngRepeat` directive.
34651 */
34652var SelectController =
34653        ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
34654
34655  var self = this,
34656      optionsMap = new HashMap();
34657
34658  // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
34659  self.ngModelCtrl = noopNgModelController;
34660
34661  // The "unknown" option is one that is prepended to the list if the viewValue
34662  // does not match any of the options. When it is rendered the value of the unknown
34663  // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
34664  //
34665  // We can't just jqLite('<option>') since jqLite is not smart enough
34666  // to create it in <select> and IE barfs otherwise.
34667  self.unknownOption = jqLite(document.createElement('option'));
34668  self.renderUnknownOption = function(val) {
34669    var unknownVal = '? ' + hashKey(val) + ' ?';
34670    self.unknownOption.val(unknownVal);
34671    $element.prepend(self.unknownOption);
34672    $element.val(unknownVal);
34673  };
34674
34675  $scope.$on('$destroy', function() {
34676    // disable unknown option so that we don't do work when the whole select is being destroyed
34677    self.renderUnknownOption = noop;
34678  });
34679
34680  self.removeUnknownOption = function() {
34681    if (self.unknownOption.parent()) self.unknownOption.remove();
34682  };
34683
34684
34685  // Read the value of the select control, the implementation of this changes depending
34686  // upon whether the select can have multiple values and whether ngOptions is at work.
34687  self.readValue = function readSingleValue() {
34688    self.removeUnknownOption();
34689    return $element.val();
34690  };
34691
34692
34693  // Write the value to the select control, the implementation of this changes depending
34694  // upon whether the select can have multiple values and whether ngOptions is at work.
34695  self.writeValue = function writeSingleValue(value) {
34696    if (self.hasOption(value)) {
34697      self.removeUnknownOption();
34698      $element.val(value);
34699      if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
34700    } else {
34701      if (value == null && self.emptyOption) {
34702        self.removeUnknownOption();
34703        $element.val('');
34704      } else {
34705        self.renderUnknownOption(value);
34706      }
34707    }
34708  };
34709
34710
34711  // Tell the select control that an option, with the given value, has been added
34712  self.addOption = function(value, element) {
34713    // Skip comment nodes, as they only pollute the `optionsMap`
34714    if (element[0].nodeType === NODE_TYPE_COMMENT) return;
34715
34716    assertNotHasOwnProperty(value, '"option value"');
34717    if (value === '') {
34718      self.emptyOption = element;
34719    }
34720    var count = optionsMap.get(value) || 0;
34721    optionsMap.put(value, count + 1);
34722    self.ngModelCtrl.$render();
34723    chromeHack(element);
34724  };
34725
34726  // Tell the select control that an option, with the given value, has been removed
34727  self.removeOption = function(value) {
34728    var count = optionsMap.get(value);
34729    if (count) {
34730      if (count === 1) {
34731        optionsMap.remove(value);
34732        if (value === '') {
34733          self.emptyOption = undefined;
34734        }
34735      } else {
34736        optionsMap.put(value, count - 1);
34737      }
34738    }
34739  };
34740
34741  // Check whether the select control has an option matching the given value
34742  self.hasOption = function(value) {
34743    return !!optionsMap.get(value);
34744  };
34745
34746
34747  self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
34748
34749    if (interpolateValueFn) {
34750      // The value attribute is interpolated
34751      var oldVal;
34752      optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
34753        if (isDefined(oldVal)) {
34754          self.removeOption(oldVal);
34755        }
34756        oldVal = newVal;
34757        self.addOption(newVal, optionElement);
34758      });
34759    } else if (interpolateTextFn) {
34760      // The text content is interpolated
34761      optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
34762        optionAttrs.$set('value', newVal);
34763        if (oldVal !== newVal) {
34764          self.removeOption(oldVal);
34765        }
34766        self.addOption(newVal, optionElement);
34767      });
34768    } else {
34769      // The value attribute is static
34770      self.addOption(optionAttrs.value, optionElement);
34771    }
34772
34773    optionElement.on('$destroy', function() {
34774      self.removeOption(optionAttrs.value);
34775      self.ngModelCtrl.$render();
34776    });
34777  };
34778}];
34779
34780/**
34781 * @ngdoc directive
34782 * @name select
34783 * @restrict E
34784 *
34785 * @description
34786 * HTML `SELECT` element with angular data-binding.
34787 *
34788 * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
34789 * between the scope and the `<select>` control (including setting default values).
34790 * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
34791 * {@link ngOptions `ngOptions`} directives.
34792 *
34793 * When an item in the `<select>` menu is selected, the value of the selected option will be bound
34794 * to the model identified by the `ngModel` directive. With static or repeated o
34794ptions, this is
34795 * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
34796 * If you want dynamic value attributes, you can use interpolation inside the value attribute.
34797 *
34798 * <div class="alert alert-warning">
34799 * Note that the value of a `select` directive used without `ngOptions` is always a string.
34800 * When the model needs to be bound to a non-string value, you must either explicitly convert it
34801 * using a directive (see example below) or use `ngOptions` to specify the set of options.
34802 * This is because an option element can only be bound to string values at present.
34803 * </div>
34804 *
34805 * If the viewValue of `ngModel` does not match any of the options, then the control
34806 * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
34807 *
34808 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
34809 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
34810 * option. See example below for demonstration.
34811 *
34812 * <div class="alert alert-info">
34813 * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
34814 * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
34815 * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
34816 * comprehension expression, and additionally in reducing memory and increasing speed by not creating
34817 * a new scope for each repeated instance.
34818 * </div>
34819 *
34820 *
34821 * @param {string} ngModel Assignable angular expression to data-bind to.
34822 * @param {string=} name Property name of the form under which the control is published.
34823 * @param {string=} multiple Allows multiple options to be selected. The selected values will be
34824 *     bound to the model as an array.
34825 * @param {string=} required Sets `required` validation error key if the value is not entered.
34826 * @param {string=} ngRequired Adds required attribute and required validation constraint to
34827 * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
34828 * when you want to data-bind to the required attribute.
34829 * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
34830 *    interaction with the select element.
34831 * @param {string=} ngOptions sets the options that the select is populated with and defines what is
34832 * set on the model on selection. See {@link ngOptions `ngOptions`}.
34833 *
34834 * @example
34835 * ### Simple `select` elements with static options
34836 *
34837 * <example name="static-select" module="staticSelect">
34838 * <file name="index.html">
34839 * <div ng-controller="ExampleController">
34840 *   <form name="myForm">
34841 *     <label for="singleSelect"> Single select: </label><br>
34842 *     <select name="singleSelect" ng-model="data.singleSelect">
34843 *       <option value="option-1">Option 1</option>
34844 *       <option value="option-2">Option 2</option>
34845 *     </select><br>
34846 *
34847 *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
34848 *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
34849 *       <option value="">---Please select---</option> <!-- not selected / blank option -->
34850 *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
34851 *       <option value="option-2">Option 2</option>
34852 *     </select><br>
34853 *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
34854 *     <tt>singleSelect = {{data.singleSelect}}</tt>
34855 *
34856 *     <hr>
34857 *     <label for="multipleSelect"> Multiple select: </label><br>
34858 *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
34859 *       <option value="option-1">Option 1</option>
34860 *       <option value="option-2">Option 2</option>
34861 *       <option value="option-3">Option 3</option>
34862 *     </select><br>
34863 *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
34864 *   </form>
34865 * </div>
34866 * </file>
34867 * <file name="app.js">
34868 *  angular.module('staticSelect', [])
34869 *    .controller('ExampleController', ['$scope', function($scope) {
34870 *      $scope.data = {
34871 *       singleSelect: null,
34872 *       multipleSelect: [],
34873 *       option1: 'option-1',
34874 *      };
34875 *
34876 *      $scope.forceUnknownOption = function() {
34877 *        $scope.data.singleSelect = 'nonsense';
34878 *      };
34879 *   }]);
34880 * </file>
34881 *</example>
34882 *
34883 * ### Using `ngRepeat` to generate `select` options
34884 * <example name="ngrepeat-select" module="ngrepeatSelect">
34885 * <file name="index.html">
34886 * <div ng-controller="ExampleController">
34887 *   <form name="myForm">
34888 *     <label for="repeatSelect"> Repeat select: </label>
34889 *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
34890 *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
34891 *     </select>
34892 *   </form>
34893 *   <hr>
34894 *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
34895 * </div>
34896 * </file>
34897 * <file name="app.js">
34898 *  angular.module('ngrepeatSelect', [])
34899 *    .controller('ExampleController', ['$scope', function($scope) {
34900 *      $scope.data = {
34901 *       repeatSelect: null,
34902 *       availableOptions: [
34903 *         {id: '1', name: 'Option A'},
34904 *         {id: '2', name: 'Option B'},
34905 *         {id: '3', name: 'Option C'}
34906 *       ],
34907 *      };
34908 *   }]);
34909 * </file>
34910 *</example>
34911 *
34912 *
34913 * ### Using `select` with `ngOptions` and setting a default value
34914 * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
34915 *
34916 * <example name="select-with-default-values" module="defaultValueSelect">
34917 * <file name="index.html">
34918 * <div ng-controller="ExampleController">
34919 *   <form name="myForm">
34920 *     <label for="mySelect">Make a choice:</label>
34921 *     <select name="mySelect" id="mySelect"
34922 *       ng-options="option.name for option in data.availableOptions track by option.id"
34923 *       ng-model="data.selectedOption"></select>
34924 *   </form>
34925 *   <hr>
34926 *   <tt>option = {{data.selectedOption}}</tt><br/>
34927 * </div>
34928 * </file>
34929 * <file name="app.js">
34930 *  angular.module('defaultValueSelect', [])
34931 *    .controller('ExampleController', ['$scope', function($scope) {
34932 *      $scope.data = {
34933 *       availableOptions: [
34934 *         {id: '1', name: 'Option A'},
34935 *         {id: '2', name: 'Option B'},
34936 *         {id: '3', name: 'Option C'}
34937 *       ],
34938 *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
34939 *       };
34940 *   }]);
34941 * </file>
34942 *</example>
34943 *
34944 *
34945 * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
34946 *
34947 * <example name="select-with-non-string-options" module="nonStringSelect">
34948 *   <file name="index.html">
34949 *     <select ng-model="model.id" convert-to-number>
34950 *       <option value="0">Zero</option>
34951 *       <option value="1">One</option>
34952 *       <option value="2">Two</option>
34953 *     </select>
34954 *     {{ model }}
34955 *   </file>
34956 *   <file name="app.js">
34957 *     angular.module('nonStringSelect', [])
34958 *       .run(function($rootScope) {
34959 *         $rootScope.model = { id: 2 };
34960 *       })
34961 *       .directive('convertToNumber', function() {
34962 *         return {
34963 *           require: 'ngModel',
34964 *           link: function(scope, element, attrs, ngModel) {
34965 *             ngModel.$parsers.push(function(val) {
34966 *               return parseInt(val, 10);
34967 *             });
34968 *             ngModel.$formatters.push(function(val) {
34969 *               return '' + val;
34970 *             });
34971 *           }
34972 *         };
34973 *       });
34974 *   </file>
34975 *   <file name="protractor.js" type="protractor">
34976 *     it('should initialize to model', function() {
34977 *       var select = element(by.css('select'));
34978 *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
34979 *     });
34980 *   </file>
34981 * </example>
34982 *
34983 */
34984var selectDirective = function() {
34985
34986  return {
34987    restrict: 'E',
34988    require: ['select', '?ngModel'],
34989    controller: SelectController,
34990    priority: 1,
34991    link: {
34992      pre: selectPreLink,
34993      post: selectPostLink
34994    }
34995  };
34996
34997  function selectPreLink(scope, element, attr, ctrls) {
34998
34999      // if ngModel is not defined, we don't need to do anything
35000      var ngModelCtrl = ctrls[1];
35001      if (!ngModelCtrl) return;
35002
35003      var selectCtrl = ctrls[0];
35004
35005      selectCtrl.ngModelCtrl = ngModelCtrl;
35006
35007      // When the selected item(s) changes we delegate getting the value of the select control
35008      // to the `readValue` method, which can be changed if the select can have multiple
35009      // selected values or if the options are being generated by `ngOptions`
35010      element.on('change', function() {
35011        scope.$apply(function() {
35012          ngModelCtrl.$setViewValue(selectCtrl.readValue());
35013        });
35014      });
35015
35016      // If the select allows multiple values then we need to modify how we read and write
35017      // values from and to the control; also what it means for the value to be empty and
35018      // we have to add an extra watch since ngModel doesn't work well with arrays - it
35019      // doesn't trigger rendering if only an item in the array changes.
35020      if (attr.multiple) {
35021
35022        // Read value now needs to check each option to see if it is selected
35023        selectCtrl.readValue = function readMultipleValue() {
35024          var array = [];
35025          forEach(element.find('option'), function(option) {
35026            if (option.selected) {
35027              array.push(option.value);
35028            }
35029          });
35030          return array;
35031        };
35032
35033        // Write value now needs to set the selected property of each matching option
35034        selectCtrl.writeValue = function writeMultipleValue(value) {
35035          var items = new HashMap(value);
35036          forEach(element.find('option'), function(option) {
35037            option.selected = isDefined(items.get(option.value));
35038          });
35039        };
35040
35041        // we have to do it on each watch since ngModel watches reference, but
35042        // we need to work of an array, so we need to see if anything was inserted/removed
35043        var lastView, lastViewRef = NaN;
35044        scope.$watch(function selectMultipleWatch() {
35045          if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
35046            lastView = shallowCopy(ngModelCtrl.$viewValue);
35047            ngModelCtrl.$render();
35048          }
35049          lastViewRef = ngModelCtrl.$viewValue;
35050        });
35051
35052        // If we are a multiple select then value is now a collection
35053        // so the meaning of $isEmpty changes
35054        ngModelCtrl.$isEmpty = function(value) {
35055          return !value || value.length === 0;
35056        };
35057
35058      }
35059    }
35060
35061    function selectPostLink(scope, element, attrs, ctrls) {
35062      // if ngModel is not defined, we don't need to do anything
35063      var ngModelCtrl = ctrls[1];
35064      if (!ngModelCtrl) return;
35065
35066      var selectCtrl = ctrls[0];
35067
35068      // We delegate rendering to the `writeValue` method, which can be changed
35069      // if the select can have multiple selected values or if the options are being
35070      // generated by `ngOptions`.
35071      // This must be done in the postLink fn to prevent $render to be called before
35072      // all nodes have been linked correctly.
35073      ngModelCtrl.$render = function() {
35074        selectCtrl.writeValue(ngModelCtrl.$viewValue);
35075      };
35076    }
35077};
35078
35079
35080// The option directive is purely designed to communicate the existence (or lack of)
35081// of dynamically created (and destroyed) option elements to their containing select
vendor: 2,836 bytes, lines 35082-35150
35082// directive via its controller.
35083var optionDirective = ['$interpolate', function($interpolate) {
35084  return {
35085    restrict: 'E',
35086    priority: 100,
35087    compile: function(element, attr) {
35088      if (isDefined(attr.value)) {
35089        // If the value attribute is defined, check if it contains an interpolation
35090        var interpolateValueFn = $interpolate(attr.value, true);
35091      } else {
35092        // If the value attribute is not defined then we fall back to the
35093        // text content of the option element, which may be interpolated
35094        var interpolateTextFn = $interpolate(element.text(), true);
35095        if (!interpolateTextFn) {
35096          attr.$set('value', element.text());
35097        }
35098      }
35099
35100      return function(scope, element, attr) {
35101        // This is an optimization over using ^^ since we don't want to have to search
35102        // all the way to the root of the DOM for every single option element
35103        var selectCtrlName = '$selectController',
35104            parent = element.parent(),
35105            selectCtrl = parent.data(selectCtrlName) ||
35106              parent.parent().data(selectCtrlName); // in case we are in optgroup
35107
35108        if (selectCtrl) {
35109          selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
35110        }
35111      };
35112    }
35113  };
35114}];
35115
35116var styleDirective = valueFn({
35117  restrict: 'E',
35118  terminal: false
35119});
35120
35121/**
35122 * @ngdoc directive
35123 * @name ngRequired
35124 *
35125 * @description
35126 *
35127 * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
35128 * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
35129 * applied to custom controls.
35130 *
35131 * The directive sets the `required` attribute on the element if the Angular expression inside
35132 * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
35133 * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
35134 * for more info.
35135 *
35136 * The validator will set the `required` error key to true if the `required` attribute is set and
35137 * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
35138 * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
35139 * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
35140 * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
35141 *
35142 * @example
35143 * <example name="ngRequiredDirective" module="ngRequiredExample">
35144 *   <file name="index.html">
35145 *     <script>
35146 *       angular.module('ngRequiredExample', [])
35147 *         .controller('ExampleController', ['$scope', function($scope) {
35148 *           $scope.required = true;
35149 *         }]);
35150 *     </script>
35151 *     <div ng-controller="ExampleController">
35152 *       <form name="form">
35153 *         <label for="required">Toggle required: </label>
35154 *         <input type="checkbox" ng-model="required" id="required" />
35155 *         <br>
35156 *         <label for="input">This input must be filled if `required` is true: </label>
35157 *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
35158 *         <hr>
35159 *         required error set? = <code>{{form.input.$error.required}}</code><br>
35160 *         model = <code>{{model}}</code>
35161 *       </form>
35162 *     </div>
35163 *   </file>
35164 *   <file name="protractor.js" type="protractor">
35165       var required = element(by.binding('form.input.$error.required'));
35166       var model = element(by.binding('model'));
35167       var input = element(by.id('input'));
35168
35169       it('should set the required error', function() {
35170         expect(required.getText()).toContain('true');
35171
35172         input.sendKeys('123');
35173         expect(required.getText()).not.toContain('true');
35174         expect(model.getText()).toContain('123');
35175       });
35176 *   </file>
35177 * </example>
35178 */
35179var requiredDirective = function() {
35180  return {
35181    restrict: 'A',
35182    require: '?ngModel',
35183    link: function(scope, elm, attr, ctrl) {
35184      if (!ctrl) return;
35185      attr.required = true; // force truthy in case we are on non input element
35186
35187      ctrl.$validators.required = function(modelValue, viewValue) {
35188        return !attr.required || !ctrl.$isEmpty(viewValue);
35189      };
35190
35191      attr.$observe('required', function() {
35192        ctrl.$validate();
35193      });
35194    }
35195  };
35196};
35197
35198/**
35199 * @ngdoc directive
35200 * @name ngPattern
35201 *
35202 * @description
35203 *
35204 * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
35205 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
35206 *
35207 * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
35208 * does not match a RegExp which is obtained by evaluating the Angular expression given in the
35209 * `ngPattern` attribute value:
35210 * * If the expression evaluates to a RegExp object, then this is used directly.
35211 * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
35212 * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
35213 *
35214 * <div class="alert alert-info">
35215 * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
35216 * start at the index of the last search's match, thus not taking the whole input value into
35217 * account.
35218 * </div>
35219 *
35220 * <div class="alert alert-info">
35221 * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
35222 * differences:
35223 * <ol>
35224 *   <li>
35225 *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
35226 *     not available.
35227 *   </li>
35228 *   <li>
35229 *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
35230 *     interpolated.
35231 *   </li>
35232 * </ol>
35233 * </div>
35234 *
35235 * @example
35236 * <example name="ngPatternDirective" module="ngPatternExample">
35237 *   <file name="index.html">
35238 *     <script>
35239 *       angular.module('ngPatternExample', [])
35240 *         .controller('ExampleController', ['$scope', function($scope) {
35241 *           $scope.regex = '\\d+';
35242 *         }]);
35243 *     </script>
35244 *     <div ng-controller="ExampleController">
35245 *       <form name="form">
35246 *         <label for="regex">Set a pattern (regex string): </label>
35247 *         <input type="text" ng-model="regex" id="regex" />
35248 *         <br>
35249 *         <label for="input">This input is restricted by the current pattern: </label>
35250 *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
35251 *         <hr>
35252 *         input valid? = <code>{{form.input.$valid}}</code><br>
35253 *         model = <code>{{model}}</code>
35254 *       </form>
35255 *     </div>
35256 *   </file>
35257 *   <file name="protractor.js" type="protractor">
35258       var model = element(by.binding('model'));
35259       var input = element(by.id('input'));
35260
35261       it('should validate the input with the default pattern', function() {
35262         input.sendKeys('aaa');
35263         expect(model.getText()).not.toContain('aaa');
35264
35265         input.clear().then(function() {
35266           input.sendKeys('123');
35267           expect(model.getText()).toContain('123');
35268         });
35269       });
35270 *   </file>
35271 * </example>
35272 */
35273var patternDirective = function() {
35274  return {
35275    restrict: 'A',
35276    require: '?ngModel',
35277    link: function(scope, elm, attr, ctrl) {
35278      if (!ctrl) return;
35279
35280      var regexp, patternExp = attr.ngPattern || attr.pattern;
35281      attr.$observe('pattern', function(regex) {
35282        if (isString(regex) && regex.length > 0) {
35283          regex = new RegExp('^' + regex + '$');
35284        }
35285
35286        if (regex && !regex.test) {
35287          throw minErr('ngPattern')('noregexp',
35288            'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
35289            regex, startingTag(elm));
35290        }
35291
35292        regexp = regex || undefined;
35293        ctrl.$validate();
35294      });
35295
35296      ctrl.$validators.pattern = function(modelValue, viewValue) {
35297        // HTML5 pattern constraint validates the input value, so we validate the viewValue
35298        return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
35299      };
35300    }
35301  };
35302};
35303
35304/**
35305 * @ngdoc directive
35306 * @name ngMaxlength
35307 *
35308 * @description
35309 *
35310 * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
35311 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
35312 *
35313 * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
35314 * is longer than the integer obtained by evaluating the Angular expression given in the
35315 * `ngMaxlength` attribute value.
35316 *
35317 * <div class="alert alert-info">
35318 * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
35319 * differences:
35320 * <ol>
35321 *   <li>
35322 *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
35323 *     validation is not available.
35324 *   </li>
35325 *   <li>
35326 *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
35327 *     interpolated.
35328 *   </li>
35329 * </ol>
35330 * </div>
35331 *
35332 * @example
35333 * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
35334 *   <file name="index.html">
35335 *     <script>
35336 *       angular.module('ngMaxlengthExample', [])
35337 *         .controller('ExampleController', ['$scope', function($scope) {
35338 *           $scope.maxlength = 5;
35339 *         }]);
35340 *     </script>
35341 *     <div ng-controller="ExampleController">
35342 *       <form name="form">
35343 *         <label for="maxlength">Set a maxlength: </label>
35344 *         <input type="number" ng-model="maxlength" id="maxlength" />
35345 *         <br>
35346 *         <label for="input">This input is restricted by the current maxlength: </label>
35347 *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
35348 *         <hr>
35349 *         input valid? = <code>{{form.input.$valid}}</code><br>
35350 *         model = <code>{{model}}</code>
35351 *       </form>
35352 *     </div>
35353 *   </file>
35354 *   <file name="protractor.js" type="protractor">
35355       var model = element(by.binding('model'));
35356       var input = element(by.id('input'));
35357
35358       it('should validate the input with the default maxlength', function() {
35359         input.sendKeys('abcdef');
35360         expect(model.getText()).not.toContain('abcdef');
35361
35362         input.clear().then(function() {
35363           input.sendKeys('abcde');
35364           expect(model.getText()).toContain('abcde');
35365         });
35366       });
35367 *   </file>
35368 * </example>
35369 */
35370var maxlengthDirective = function() {
35371  return {
35372    restrict: 'A',
35373    require: '?ngModel',
35374    link: function(scope, elm, attr, ctrl) {
35375      if (!ctrl) return;
35376
35377      var maxlength = -1;
35378      attr.$observe('maxlength', function(value) {
35379        var intVal = toInt(value);
35380        maxlength = isNaN(intVal) ? -1 : intVal;
35381        ctrl.$validate();
35382      });
35383      ctrl.$validators.maxlength = function(modelValue, viewValue) {
35384        return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
35385      };
35386    }
35387  };
35388};
35389
35390/**
35391 * @ngdoc directive
35392 * @name ngMinlength
35393 *
35394 * @description
35395 *
35396 * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
35397 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
35398 *
35399 * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
35400 * is shorter than the integer obtained by evaluating the Angular expression given in the
35401 * `ngMinlength` attribute value.
35402 *
35403 * <div class="alert alert-info">
35404 * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
35405 * differences:
35406 * <ol>
35407 *   <li>
35408 *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
35409 *     validation is not available.
35410 *   </li>
35411 *   <li>
35412 *     The `ngMinlength` value must be an expression, while the `minlength` value must be
35413 *     interpolated.
35414 *   </li>
35415 * </ol>
35416 * </div>
35417 *
35418 * @example
35419 * <example name="ngMinlengthDirective" module="ngMinlengthExample">
35420 *   <file name="index.html">
35421 *     <script>
35422 *       angular.module('ngMinlengthExample', [])
35423 *         .controller('ExampleController', ['$scope', function($scope) {
35424 *           $scope.minlength = 3;
35425 *         }]);
35426 *     </script>
35427 *     <div ng-controller="ExampleController">
35428 *       <form name="form">
35429 *         <label for="minlength">Set a minlength: </label>
35430 *         <input type="number" ng-model="minlength" id="minlength" />
35431 *         <br>
35432 *         <label for="input">This input is restricted by the current minlength: </label>
35433 *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
35434 *         <hr>
35435 *         input valid? = <code>{{form.input.$valid}}</code><br>
35436 *         model = <code>{{model}}</code>
35437 *       </form>
35438 *     </div>
35439 *   </file>
35440 *   <file name="protractor.js" type="protractor">
35441       var model = element(by.binding('model'));
35442       var input = element(by.id('input'));
35443
35444       it('should validate the input with the default minlength', function() {
35445         input.sendKeys('ab');
35446         expect(model.getText()).not.toContain('ab');
35447
35448         input.sendKeys('abc');
35449         expect(model.getText()).toContain('abc');
35450       });
35451 *   </file>
35452 * </example>
35453 */
35454var minlengthDirective = function() {
35455  return {
35456    restrict: 'A',
35457    require: '?ngModel',
35458    link: function(scope, elm, attr, ctrl) {
35459      if (!ctrl) return;
35460
35461      var minlength = 0;
35462      attr.$observe('minlength', function(value) {
35463        minlength = toInt(value) || 0;
35464        ctrl.$validate();
35465      });
35466      ctrl.$validators.minlength = function(modelValue, viewValue) {
35467        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
35468      };
35469    }
35470  };
35471};
35472
35473if (window.angular.bootstrap) {
35474  //AngularJS is already loaded, so we can return here...
35475  if (window.console) {
35476    console.log('WARNING: Tried to load angular more than once.');
35477  }
35478  return;
35479}
35480
35481//try to bind to jquery now so that one can write jqLite(document).ready()
35482//but we will rebind on bootstrap again.
35483bindJQuery();
35484
35485publishExternalAPI(angular);
35486
35487angular.module("ngLocale", [], ["$provide", function($provide) {
35488var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
35489function getDecimals(n) {
35490  n = n + '';
35491  var i = n.indexOf('.');
35492  return (i == -1) ? 0 : n.length - i - 1;
35493}
35494
35495function getVF(n, opt_precision) {
35496  var v = opt_precision;
35497
35498  if (undefined === v) {
35499    v = Math.min(getDecimals(n), 3);
35500  }
35501
35502  var base = Math.pow(10, v);
35503  var f = ((n * base) | 0) % base;
35504  return {v: v, f: f};
35505}
35506
35507$provide.value("$locale", {
35508  "DATETIME_FORMATS": {
35509    "AMPMS": [
35510      "AM",
35511      "PM"
35512    ],
35513    "DAY": [
35514      "Sunday",
35515      "Monday",
35516      "Tuesday",
35517      "Wednesday",
35518      "Thursday",
35519      "Friday",
35520      "Saturday"
35521    ],
35522    "ERANAMES": [
35523      "Before Christ",
35524      "Anno Domini"
35525    ],
35526    "ERAS": [
35527      "BC",
35528      "AD"
35529    ],
35530    "FIRSTDAYOFWEEK": 6,
35531    "MONTH": [
35532      "January",
35533      "February",
35534      "March",
35535      "April",
35536      "May",
35537      "June",
35538      "July",
35539      "August",
35540      "September",
35541      "October",
35542      "November",
35543      "December"
35544    ],
35545    "SHORTDAY": [
35546      "Sun",
35547      "Mon",
35548      "Tue",
35549      "Wed",
35550      "Thu",
35551      "Fri",
35552      "Sat"
35553    ],
35554    "SHORTMONTH": [
35555      "Jan",
35556      "Feb",
35557      "Mar",
35558      "Apr",
35559      "May",
35560      "Jun",
35561      "Jul",
35562      "Aug",
35563      "Sep",
35564      "Oct",
35565      "Nov",
35566      "Dec"
35567    ],
35568    "STANDALONEMONTH": [
35569      "January",
35570      "February",
35571      "March",
35572      "April",
35573      "May",
35574      "June",
35575      "July",
35576      "August",
35577      "September",
35578      "October",
35579      "November",
35580      "December"
35581    ],
35582    "WEEKENDRANGE": [
35583      5,
35584      6
35585    ],
35586    "fullDate": "EEEE, MMMM d, y",
35587    "longDate": "MMMM d, y",
35588    "medium": "MMM d, y h:mm:ss a",
35589    "mediumDate": "MMM d, y",
35590    "mediumTime": "h:mm:ss a",
35591    "short": "M/d/yy h:mm a",
35592    "shortDate": "M/d/yy",
35593    "shortTime": "h:mm a"
35594  },
35595  "NUMBER_FORMATS": {
35596    "CURRENCY_SYM": "$",
35597    "DECIMAL_SEP": ".",
35598    "GROUP_SEP": ",",
35599    "PATTERNS": [
35600      {
35601        "gSize": 3,
35602        "lgSize": 3,
35603        "maxFrac": 3,
35604        "minFrac": 0,
35605        "minInt": 1,
35606        "negPre": "-",
35607        "negSuf": "",
35608        "posPre": "",
35609        "posSuf": ""
35610      },
35611      {
35612        "gSize": 3,
35613        "lgSize": 3,
35614        "maxFrac": 2,
35615        "minFrac": 2,
35616        "minInt": 1,
35617        "negPre": "-\u00a4",
35618        "negSuf": "",
35619        "posPre": "\u00a4",
35620        "posSuf": ""
35621      }
35622    ]
35623  },
35624  "id": "en-us",
35625  "localeID": "en_US",
35626  "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;}
35627});
35628}]);
35629
35630  jqLite(document).ready(function() {
35631    angularInit(document, bootstrap);
35632  });
35633
35634})(window, document);
35635
35636!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>');
35637},{}],5:[function(require,module,exports){
35638require('./angular');
35639module.exports = angular;
35640
35641},{"./angular":4}],6:[function(require,module,exports){
35642// CodeMirror, copyright (c) by Marijn Haverbeke and others
35643// Distributed under an MIT license: http://codemirror.net/LICENSE
35644
35645// This is CodeMirror (http://codemirror.net), a code editor
vendor: 107,460 bytes, lines 35646-38413
35646// implemented in JavaScript on top of the browser's DOM.
35647//
35648// You can find some technical background for some of the code below
35649// at http://marijnhaverbeke.nl/blog/#cm-internals .
35650
35651(function (global, factory) {
35652	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
35653	typeof define === 'function' && define.amd ? define(factory) :
35654	(global.CodeMirror = factory());
35655}(this, (function () { 'use strict';
35656
35657// Kludges for bugs and behavior differences that can't be feature
35658// detected are enabled based on userAgent etc sniffing.
35659var userAgent = navigator.userAgent;
35660var platform = navigator.platform;
35661
35662var gecko = /gecko\/\d/i.test(userAgent);
35663var ie_upto10 = /MSIE \d/.test(userAgent);
35664var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
35665var edge = /Edge\/(\d+)/.exec(userAgent);
35666var ie = ie_upto10 || ie_11up || edge;
35667var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
35668var webkit = !edge && /WebKit\//.test(userAgent);
35669var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
35670var chrome = !edge && /Chrome\//.test(userAgent);
35671var presto = /Opera\//.test(userAgent);
35672var safari = /Apple Computer/.test(navigator.vendor);
35673var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
35674var phantom = /PhantomJS/.test(userAgent);
35675
35676var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
35677var android = /Android/.test(userAgent);
35678// This is woefully incomplete. Suggestions for alternative methods welcome.
35679var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
35680var mac = ios || /Mac/.test(platform);
35681var chromeOS = /\bCrOS\b/.test(userAgent);
35682var windows = /win/i.test(platform);
35683
35684var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
35685if (presto_version) { presto_version = Number(presto_version[1]); }
35686if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
35687// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
35688var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
35689var captureRightClick = gecko || (ie && ie_version >= 9);
35690
35691function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
35692
35693var rmClass = function(node, cls) {
35694  var current = node.className;
35695  var match = classTest(cls).exec(current);
35696  if (match) {
35697    var after = current.slice(match.index + match[0].length);
35698    node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
35699  }
35700};
35701
35702function removeChildren(e) {
35703  for (var count = e.childNodes.length; count > 0; --count)
35704    { e.removeChild(e.firstChild); }
35705  return e
35706}
35707
35708function removeChildrenAndAdd(parent, e) {
35709  return removeChildren(parent).appendChild(e)
35710}
35711
35712function elt(tag, content, className, style) {
35713  var e = document.createElement(tag);
35714  if (className) { e.className = className; }
35715  if (style) { e.style.cssText = style; }
35716  if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
35717  else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
35718  return e
35719}
35720// wrapper for elt, which removes the elt from the accessibility tree
35721function eltP(tag, content, className, style) {
35722  var e = elt(tag, content, className, style);
35723  e.setAttribute("role", "presentation");
35724  return e
35725}
35726
35727var range;
35728if (document.createRange) { range = function(node, start, end, endNode) {
35729  var r = document.createRange();
35730  r.setEnd(endNode || node, end);
35731  r.setStart(node, start);
35732  return r
35733}; }
35734else { range = function(node, start, end) {
35735  var r = document.body.createTextRange();
35736  try { r.moveToElementText(node.parentNode); }
35737  catch(e) { return r }
35738  r.collapse(true);
35739  r.moveEnd("character", end);
35740  r.moveStart("character", start);
35741  return r
35742}; }
35743
35744function contains(parent, child) {
35745  if (child.nodeType == 3) // Android browser always returns false when child is a textnode
35746    { child = child.parentNode; }
35747  if (parent.contains)
35748    { return parent.contains(child) }
35749  do {
35750    if (child.nodeType == 11) { child = child.host; }
35751    if (child == parent) { return true }
35752  } while (child = child.parentNode)
35753}
35754
35755function activeElt() {
35756  // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
35757  // IE < 10 will throw when accessed while the page is loading or in an iframe.
35758  // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
35759  var activeElement;
35760  try {
35761    activeElement = document.activeElement;
35762  } catch(e) {
35763    activeElement = document.body || null;
35764  }
35765  while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
35766    { activeElement = activeElement.shadowRoot.activeElement; }
35767  return activeElement
35768}
35769
35770function addClass(node, cls) {
35771  var current = node.className;
35772  if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
35773}
35774function joinClasses(a, b) {
35775  var as = a.split(" ");
35776  for (var i = 0; i < as.length; i++)
35777    { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
35778  return b
35779}
35780
35781var selectInput = function(node) { node.select(); };
35782if (ios) // Mobile Safari apparently has a bug where select() is broken.
35783  { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
35784else if (ie) // Suppress mysterious IE10 errors
35785  { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
35786
35787function bind(f) {
35788  var args = Array.prototype.slice.call(arguments, 1);
35789  return function(){return f.apply(null, args)}
35790}
35791
35792function copyObj(obj, target, overwrite) {
35793  if (!target) { target = {}; }
35794  for (var prop in obj)
35795    { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
35796      { target[prop] = obj[prop]; } }
35797  return target
35798}
35799
35800// Counts the column offset in a string, taking tabs into account.
35801// Used mostly to find indentation.
35802function countColumn(string, end, tabSize, startIndex, startValue) {
35803  if (end == null) {
35804    end = string.search(/[^\s\u00a0]/);
35805    if (end == -1) { end = string.length; }
35806  }
35807  for (var i = startIndex || 0, n = startValue || 0;;) {
35808    var nextTab = string.indexOf("\t", i);
35809    if (nextTab < 0 || nextTab >= end)
35810      { return n + (end - i) }
35811    n += nextTab - i;
35812    n += tabSize - (n % tabSize);
35813    i = nextTab + 1;
35814  }
35815}
35816
35817var Delayed = function() {this.id = null;};
35818Delayed.prototype.set = function (ms, f) {
35819  clearTimeout(this.id);
35820  this.id = setTimeout(f, ms);
35821};
35822
35823function indexOf(array, elt) {
35824  for (var i = 0; i < array.length; ++i)
35825    { if (array[i] == elt) { return i } }
35826  return -1
35827}
35828
35829// Number of pixels added to scroller and sizer to hide scrollbar
35830var scrollerGap = 30;
35831
35832// Returned or thrown by various protocols to signal 'I'm not
35833// handling this'.
35834var Pass = {toString: function(){return "CodeMirror.Pass"}};
35835
35836// Reused option objects for setSelection & friends
35837var sel_dontScroll = {scroll: false};
35838var sel_mouse = {origin: "*mouse"};
35839var sel_move = {origin: "+move"};
35840
35841// The inverse of countColumn -- find the offset that corresponds to
35842// a particular column.
35843function findColumn(string, goal, tabSize) {
35844  for (var pos = 0, col = 0;;) {
35845    var nextTab = string.indexOf("\t", pos);
35846    if (nextTab == -1) { nextTab = string.length; }
35847    var skipped = nextTab - pos;
35848    if (nextTab == string.length || col + skipped >= goal)
35849      { return pos + Math.min(skipped, goal - col) }
35850    col += nextTab - pos;
35851    col += tabSize - (col % tabSize);
35852    pos = nextTab + 1;
35853    if (col >= goal) { return pos }
35854  }
35855}
35856
35857var spaceStrs = [""];
35858function spaceStr(n) {
35859  while (spaceStrs.length <= n)
35860    { spaceStrs.push(lst(spaceStrs) + " "); }
35861  return spaceStrs[n]
35862}
35863
35864function lst(arr) { return arr[arr.length-1] }
35865
35866function map(array, f) {
35867  var out = [];
35868  for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
35869  return out
35870}
35871
35872function insertSorted(array, value, score) {
35873  var pos = 0, priority = score(value);
35874  while (pos < array.length && score(array[pos]) <= priority) { pos++; }
35875  array.splice(pos, 0, value);
35876}
35877
35878function nothing() {}
35879
35880function createObj(base, props) {
35881  var inst;
35882  if (Object.create) {
35883    inst = Object.create(base);
35884  } else {
35885    nothing.prototype = base;
35886    inst = new nothing();
35887  }
35888  if (props) { copyObj(props, inst); }
35889  return inst
35890}
35891
35892var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
35893function isWordCharBasic(ch) {
35894  return /\w/.test(ch) || ch > "\x80" &&
35895    (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
35896}
35897function isWordChar(ch, helper) {
35898  if (!helper) { return isWordCharBasic(ch) }
35899  if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
35900  return helper.test(ch)
35901}
35902
35903function isEmpty(obj) {
35904  for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
35905  return true
35906}
35907
35908// Extending unicode characters. A series of a non-extending char +
35909// any number of extending chars is treated as a single unit as far
35910// as editing and measuring is concerned. This is not fully correct,
35911// since some scripts/fonts/browsers also treat other configurations
35912// of code points as a group.
35913var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
35914function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
35915
35916// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
35917function skipExtendingChars(str, pos, dir) {
35918  while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
35919  return pos
35920}
35921
35922// Returns the value from the range [`from`; `to`] that satisfies
35923// `pred` and is closest to `from`. Assumes that at least `to`
35924// satisfies `pred`. Supports `from` being greater than `to`.
35925function findFirst(pred, from, to) {
35926  // At any point we are certain `to` satisfies `pred`, don't know
35927  // whether `from` does.
35928  var dir = from > to ? -1 : 1;
35929  for (;;) {
35930    if (from == to) { return from }
35931    var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
35932    if (mid == from) { return pred(mid) ? from : to }
35933    if (pred(mid)) { to = mid; }
35934    else { from = mid + dir; }
35935  }
35936}
35937
35938// The display handles the DOM integration, both for input reading
35939// and content drawing. It holds references to DOM nodes and
35940// display-related state.
35941
35942function Display(place, doc, input) {
35943  var d = this;
35944  this.input = input;
35945
35946  // Covers bottom-right square when both scrollbars are present.
35947  d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
35948  d.scrollbarFiller.setAttribute("cm-not-content", "true");
35949  // Covers bottom of gutter when coverGutterNextToScrollbar is on
35950  // and h scrollbar is present.
35951  d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
35952  d.gutterFiller.setAttribute("cm-not-content", "true");
35953  // Will contain the actual code, positioned to cover the viewport.
35954  d.lineDiv = eltP("div", null, "CodeMirror-code");
35955  // Elements are added to these to represent selection and cursors.
35956  d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
35957  d.cursorDiv = elt("div", null, "CodeMirror-cursors");
35958  // A visibility: hidden element used to find the size of things.
35959  d.measure = elt("div", null, "CodeMirror-measure");
35960  // When lines outside of the viewport are measured, they are drawn in this.
35961  d.lineMeasure = elt("div", null, "CodeMirror-measure");
35962  // Wraps everything that needs to exist inside the vertically-padded coordinate system
35963  d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
35964                    null, "position: relative; outline: none");
35965  var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
35966  // Moved around its parent to cover visible view.
35967  d.mover = elt("div", [lines], null, "position: relative");
35968  // Set to the height of the document, allowing scrolling.
35969  d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
35970  d.sizerWidth = null;
35971  // Behavior of elts with overflow: auto and padding is
35972  // inconsistent across browsers. This is used to ensure the
35973  // scrollable area is big enough.
35974  d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
35975  // Will contain the gutters, if any.
35976  d.gutters = elt("div", null, "CodeMirror-gutters");
35977  d.lineGutter = null;
35978  // Actual scrollable element.
35979  d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
35980  d.scroller.setAttribute("tabIndex", "-1");
35981  // The element in which the editor lives.
35982  d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
35983
35984  // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
35985  if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
35986  if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
35987
35988  if (place) {
35989    if (place.appendChild) { place.appendChild(d.wrapper); }
35990    else { place(d.wrapper); }
35991  }
35992
35993  // Current rendered range (may be bigger than the view window).
35994  d.viewFrom = d.viewTo = doc.first;
35995  d.reportedViewFrom = d.reportedViewTo = doc.first;
35996  // Information about the rendered lines.
35997  d.view = [];
35998  d.renderedView = null;
35999  // Holds info about a single rendered line when it was rendered
36000  // for measurement, while not in view.
36001  d.externalMeasured = null;
36002  // Empty space (in pixels) above the view
36003  d.viewOffset = 0;
36004  d.lastWrapHeight = d.lastWrapWidth = 0;
36005  d.updateLineNumbers = null;
36006
36007  d.nativeBarWidth = d.barHeight = d.barWidth = 0;
36008  d.scrollbarsClipped = false;
36009
36010  // Used to only resize the line number gutter when necessary (when
36011  // the amount of lines crosses a boundary that makes its width change)
36012  d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
36013  // Set to true when a non-horizontal-scrolling line widget is
36014  // added. As an optimization, line widget aligning is skipped when
36015  // this is false.
36016  d.alignWidgets = false;
36017
36018  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
36019
36020  // Tracks the maximum line length so that the horizontal scrollbar
36021  // can be kept static when scrolling.
36022  d.maxLine = null;
36023  d.maxLineLength = 0;
36024  d.maxLineChanged = false;
36025
36026  // Used for measuring wheel scrolling granularity
36027  d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
36028
36029  // True when shift is held down.
36030  d.shift = false;
36031
36032  // Used to track whether anything happened since the context menu
36033  // was opened.
36034  d.selForContextMenu = null;
36035
36036  d.activeTouch = null;
36037
36038  input.init(d);
36039}
36040
36041// Find the line object corresponding to the given line number.
36042function getLine(doc, n) {
36043  n -= doc.first;
36044  if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
36045  var chunk = doc;
36046  while (!chunk.lines) {
36047    for (var i = 0;; ++i) {
36048      var child = chunk.children[i], sz = child.chunkSize();
36049      if (n < sz) { chunk = child; break }
36050      n -= sz;
36051    }
36052  }
36053  return chunk.lines[n]
36054}
36055
36056// Get the part of a document between two positions, as an array of
36057// strings.
36058function getBetween(doc, start, end) {
36059  var out = [], n = start.line;
36060  doc.iter(start.line, end.line + 1, function (line) {
36061    var text = line.text;
36062    if (n == end.line) { text = text.slice(0, end.ch); }
36063    if (n == start.line) { text = text.slice(start.ch); }
36064    out.push(text);
36065    ++n;
36066  });
36067  return out
36068}
36069// Get the lines between from and to, as array of strings.
36070function getLines(doc, from, to) {
36071  var out = [];
36072  doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
36073  return out
36074}
36075
36076// Update the height of a line, propagating the height change
36077// upwards to parent nodes.
36078function updateLineHeight(line, height) {
36079  var diff = height - line.height;
36080  if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
36081}
36082
36083// Given a line object, find its line number by walking up through
36084// its parent links.
36085function lineNo(line) {
36086  if (line.parent == null) { return null }
36087  var cur = line.parent, no = indexOf(cur.lines, line);
36088  for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
36089    for (var i = 0;; ++i) {
36090      if (chunk.children[i] == cur) { break }
36091      no += chunk.children[i].chunkSize();
36092    }
36093  }
36094  return no + cur.first
36095}
36096
36097// Find the line at the given vertical position, using the height
36098// information in the document tree.
36099function lineAtHeight(chunk, h) {
36100  var n = chunk.first;
36101  outer: do {
36102    for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
36103      var child = chunk.children[i$1], ch = child.height;
36104      if (h < ch) { chunk = child; continue outer }
36105      h -= ch;
36106      n += child.chunkSize();
36107    }
36108    return n
36109  } while (!chunk.lines)
36110  var i = 0;
36111  for (; i < chunk.lines.length; ++i) {
36112    var line = chunk.lines[i], lh = line.height;
36113    if (h < lh) { break }
36114    h -= lh;
36115  }
36116  return n + i
36117}
36118
36119function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
36120
36121function lineNumberFor(options, i) {
36122  return String(options.lineNumberFormatter(i + options.firstLineNumber))
36123}
36124
36125// A Pos instance represents a position within the text.
36126function Pos(line, ch, sticky) {
36127  if ( sticky === void 0 ) sticky = null;
36128
36129  if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
36130  this.line = line;
36131  this.ch = ch;
36132  this.sticky = sticky;
36133}
36134
36135// Compare two positions, return 0 if they are the same, a negative
36136// number when a is less, and a positive number otherwise.
36137function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
36138
36139function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
36140
36141function copyPos(x) {return Pos(x.line, x.ch)}
36142function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
36143function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
36144
36145// Most of the external API clips given positions to make sure they
36146// actually exist within the document.
36147function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
36148function clipPos(doc, pos) {
36149  if (pos.line < doc.first) { return Pos(doc.first, 0) }
36150  var last = doc.first + doc.size - 1;
36151  if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
36152  return clipToLen(pos, getLine(doc, pos.line).text.length)
36153}
36154function clipToLen(pos, linelen) {
36155  var ch = pos.ch;
36156  if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
36157  else if (ch < 0) { return Pos(pos.line, 0) }
36158  else { return pos }
36159}
36160function clipPosArray(doc, array) {
36161  var out = [];
36162  for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
36163  return out
36164}
36165
36166// Optimize some code when these features are not used.
36167var sawReadOnlySpans = false;
36168var sawCollapsedSpans = false;
36169
36170function seeReadOnlySpans() {
36171  sawReadOnlySpans = true;
36172}
36173
36174function seeCollapsedSpans() {
36175  sawCollapsedSpans = true;
36176}
36177
36178// TEXTMARKER SPANS
36179
36180function MarkedSpan(marker, from, to) {
36181  this.marker = marker;
36182  this.from = from; this.to = to;
36183}
36184
36185// Search an array of spans for a span matching the given marker.
36186function getMarkedSpanFor(spans, marker) {
36187  if (spans) { for (var i = 0; i < spans.length; ++i) {
36188    var span = spans[i];
36189    if (span.marker == marker) { return span }
36190  } }
36191}
36192// Remove a span from an array, returning undefined if no spans are
36193// left (we don't store arrays for lines without spans).
36194function removeMarkedSpan(spans, span) {
36195  var r;
36196  for (var i = 0; i < spans.length; ++i)
36197    { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
36198  return r
36199}
36200// Add a span to a line.
36201function addMarkedSpan(line, span) {
36202  line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
36203  span.marker.attachLine(line);
36204}
36205
36206// Used for the algorithm that adjusts markers for a change in the
36207// document. These functions cut an array of spans at a given
36208// character position, returning an array of remaining chunks (or
36209// undefined if nothing remains).
36210function markedSpansBefore(old, startCh, isInsert) {
36211  var nw;
36212  if (old) { for (var i = 0; i < old.length; ++i) {
36213    var span = old[i], marker = span.marker;
36214    var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
36215    if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
36216      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
36217    }
36218  } }
36219  return nw
36220}
36221function markedSpansAfter(old, endCh, isInsert) {
36222  var nw;
36223  if (old) { for (var i = 0; i < old.length; ++i) {
36224    var span = old[i], marker = span.marker;
36225    var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
36226    if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
36227      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
36228                                            span.to == null ? null : span.to - endCh));
36229    }
36230  } }
36231  return nw
36232}
36233
36234// Given a change object, compute the new set of marker spans that
36235// cover the line in which the change took place. Removes spans
36236// entirely within the change, reconnects spans belonging to the
36237// same marker that appear on both sides of the change, and cuts off
36238// spans partially within the change. Returns an array of span
36239// arrays with one element for each line in (after) the change.
36240function stretchSpansOverChange(doc, change) {
36241  if (change.full) { return null }
36242  var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
36243  var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
36244  if (!oldFirst && !oldLast) { return null }
36245
36246  var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
36247  // Get the spans that 'stick out' on both sides
36248  var first = markedSpansBefore(oldFirst, startCh, isInsert);
36249  var last = markedSpansAfter(oldLast, endCh, isInsert);
36250
36251  // Next, merge those two ends
36252  var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
36253  if (first) {
36254    // Fix up .to properties of first
36255    for (var i = 0; i < first.length; ++i) {
36256      var span = first[i];
36257      if (span.to == null) {
36258        var found = getMarkedSpanFor(last, span.marker);
36259        if (!found) { span.to = startCh; }
36260        else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
36261      }
36262    }
36263  }
36264  if (last) {
36265    // Fix up .from in last (or move them into first in case of sameLine)
36266    for (var i$1 = 0; i$1 < last.length; ++i$1) {
36267      var span$1 = last[i$1];
36268      if (span$1.to != null) { span$1.to += offset; }
36269      if (span$1.from == null) {
36270        var found$1 = getMarkedSpanFor(first, span$1.marker);
36271        if (!found$1) {
36272          span$1.from = offset;
36273          if (sameLine) { (first || (first = [])).push(span$1); }
36274        }
36275      } else {
36276        span$1.from += offset;
36277        if (sameLine) { (first || (first = [])).push(span$1); }
36278      }
36279    }
36280  }
36281  // Make sure we didn't create any zero-length spans
36282  if (first) { first = clearEmptySpans(first); }
36283  if (last && last != first) { last = clearEmptySpans(last); }
36284
36285  var newMarkers = [first];
36286  if (!sameLine) {
36287    // Fill gap with whole-line-spans
36288    var gap = change.text.length - 2, gapMarkers;
36289    if (gap > 0 && first)
36290      { for (var i$2 = 0; i$2 < first.length; ++i$2)
36291        { if (first[i$2].to == null)
36292          { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
36293    for (var i$3 = 0; i$3 < gap; ++i$3)
36294      { newMarkers.push(gapMarkers); }
36295    newMarkers.push(last);
36296  }
36297  return newMarkers
36298}
36299
36300// Remove spans that are empty and don't have a clearWhenEmpty
36301// option of false.
36302function clearEmptySpans(spans) {
36303  for (var i = 0; i < spans.length; ++i) {
36304    var span = spans[i];
36305    if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
36306      { spans.splice(i--, 1); }
36307  }
36308  if (!spans.length) { return null }
36309  return spans
36310}
36311
36312// Used to 'clip' out readOnly ranges when making a change.
36313function removeReadOnlyRanges(doc, from, to) {
36314  var markers = null;
36315  doc.iter(from.line, to.line + 1, function (line) {
36316    if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
36317      var mark = line.markedSpans[i].marker;
36318      if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
36319        { (markers || (markers = [])).push(mark); }
36320    } }
36321  });
36322  if (!markers) { return null }
36323  var parts = [{from: from, to: to}];
36324  for (var i = 0; i < markers.length; ++i) {
36325    var mk = markers[i], m = mk.find(0);
36326    for (var j = 0; j < parts.length; ++j) {
36327      var p = parts[j];
36328      if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
36329      var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
36330      if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
36331        { newParts.push({from: p.from, to: m.from}); }
36332      if (dto > 0 || !mk.inclusiveRight && !dto)
36333        { newParts.push({from: m.to, to: p.to}); }
36334      parts.splice.apply(parts, newParts);
36335      j += newParts.length - 3;
36336    }
36337  }
36338  return parts
36339}
36340
36341// Connect or disconnect spans from a line.
36342function detachMarkedSpans(line) {
36343  var spans = line.markedSpans;
36344  if (!spans) { return }
36345  for (var i = 0; i < spans.length; ++i)
36346    { spans[i].marker.detachLine(line); }
36347  line.markedSpans = null;
36348}
36349function attachMarkedSpans(line, spans) {
36350  if (!spans) { return }
36351  for (var i = 0; i < spans.length; ++i)
36352    { spans[i].marker.attachLine(line); }
36353  line.markedSpans = spans;
36354}
36355
36356// Helpers used when computing which overlapping collapsed span
36357// counts as the larger one.
36358function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
36359function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
36360
36361// Returns a number indicating which of two overlapping collapsed
36362// spans is larger (and thus includes the other). Falls back to
36363// comparing ids when the spans cover exactly the same range.
36364function compareCollapsedMarkers(a, b) {
36365  var lenDiff = a.lines.length - b.lines.length;
36366  if (lenDiff != 0) { return lenDiff }
36367  var aPos = a.find(), bPos = b.find();
36368  var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
36369  if (fromCmp) { return -fromCmp }
36370  var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
36371  if (toCmp) { return toCmp }
36372  return b.id - a.id
36373}
36374
36375// Find out whether a line ends or starts in a collapsed span. If
36376// so, return the marker for that span.
36377function collapsedSpanAtSide(line, start) {
36378  var sps = sawCollapsedSpans && line.markedSpans, found;
36379  if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
36380    sp = sps[i];
36381    if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
36382        (!found || compareCollapsedMarkers(found, sp.marker) < 0))
36383      { found = sp.marker; }
36384  } }
36385  return found
36386}
36387function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
36388function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
36389
36390// Test whether there exists a collapsed span that partially
36391// overlaps (covers the start or end, but not both) of a new span.
36392// Such overlap is not allowed.
36393function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
36394  var line = getLine(doc, lineNo$$1);
36395  var sps = sawCollapsedSpans && line.markedSpans;
36396  if (sps) { for (var i = 0; i < sps.length; ++i) {
36397    var sp = sps[i];
36398    if (!sp.marker.collapsed) { continue }
36399    var found = sp.marker.find(0);
36400    var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
36401    var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
36402    if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
36403    if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
36404        fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
36405      { return true }
36406  } }
36407}
36408
36409// A visual line is a line as drawn on the screen. Folding, for
36410// example, can cause multiple logical lines to appear on the same
36411// visual line. This finds the start of the visual line that the
36412// given line is part of (usually that is the line itself).
36413function visualLine(line) {
36414  var merged;
36415  while (merged = collapsedSpanAtStart(line))
36416    { line = merged.find(-1, true).line; }
36417  return line
36418}
36419
36420function visualLineEnd(line) {
36421  var merged;
36422  while (merged = collapsedSpanAtEnd(line))
36423    { line = merged.find(1, true).line; }
36424  return line
36425}
36426
36427// Returns an array of logical lines that continue the visual line
36428// started by the argument, or undefined if there are no such lines.
36429function visualLineContinued(line) {
36430  var merged, lines;
36431  while (merged = collapsedSpanAtEnd(line)) {
36432    line = merged.find(1, true).line
36433    ;(lines || (lines = [])).push(line);
36434  }
36435  return lines
36436}
36437
36438// Get the line number of the start of the visual line that the
36439// given line number is part of.
36440function visualLineNo(doc, lineN) {
36441  var line = getLine(doc, lineN), vis = visualLine(line);
36442  if (line == vis) { return lineN }
36443  return lineNo(vis)
36444}
36445
36446// Get the line number of the start of the next visual line after
36447// the given line.
36448function visualLineEndNo(doc, lineN) {
36449  if (lineN > doc.lastLine()) { return lineN }
36450  var line = getLine(doc, lineN), merged;
36451  if (!lineIsHidden(doc, line)) { return lineN }
36452  while (merged = collapsedSpanAtEnd(line))
36453    { line = merged.find(1, true).line; }
36454  return lineNo(line) + 1
36455}
36456
36457// Compute whether a line is hidden. Lines count as hidden when they
36458// are part of a visual line that starts with another line, or when
36459// they are entirely covered by collapsed, non-widget span.
36460function lineIsHidden(doc, line) {
36461  var sps = sawCollapsedSpans && line.markedSpans;
36462  if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
36463    sp = sps[i];
36464    if (!sp.marker.collapsed) { continue }
36465    if (sp.from == null) { return true }
36466    if (sp.marker.widgetNode) { continue }
36467    if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
36468      { return true }
36469  } }
36470}
36471function lineIsHiddenInner(doc, line, span) {
36472  if (span.to == null) {
36473    var end = span.marker.find(1, true);
36474    return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
36475  }
36476  if (span.marker.inclusiveRight && span.to == line.text.length)
36477    { return true }
36478  for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
36479    sp = line.markedSpans[i];
36480    if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
36481        (sp.to == null || sp.to != span.from) &&
36482        (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
36483        lineIsHiddenInner(doc, line, sp)) { return true }
36484  }
36485}
36486
36487// Find the height above the given line.
36488function heightAtLine(lineObj) {
36489  lineObj = visualLine(lineObj);
36490
36491  var h = 0, chunk = lineObj.parent;
36492  for (var i = 0; i < chunk.lines.length; ++i) {
36493    var line = chunk.lines[i];
36494    if (line == lineObj) { break }
36495    else { h += line.height; }
36496  }
36497  for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
36498    for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
36499      var cur = p.children[i$1];
36500      if (cur == chunk) { break }
36501      else { h += cur.height; }
36502    }
36503  }
36504  return h
36505}
36506
36507// Compute the character length of a line, taking into account
36508// collapsed ranges (see markText) that might hide parts, and join
36509// other lines onto it.
36510function lineLength(line) {
36511  if (line.height == 0) { return 0 }
36512  var len = line.text.length, merged, cur = line;
36513  while (merged = collapsedSpanAtStart(cur)) {
36514    var found = merged.find(0, true);
36515    cur = found.from.line;
36516    len += found.from.ch - found.to.ch;
36517  }
36518  cur = line;
36519  while (merged = collapsedSpanAtEnd(cur)) {
36520    var found$1 = merged.find(0, true);
36521    len -= cur.text.length - found$1.from.ch;
36522    cur = found$1.to.line;
36523    len += cur.text.length - found$1.to.ch;
36524  }
36525  return len
36526}
36527
36528// Find the longest line in the document.
36529function findMaxLine(cm) {
36530  var d = cm.display, doc = cm.doc;
36531  d.maxLine = getLine(doc, doc.first);
36532  d.maxLineLength = lineLength(d.maxLine);
36533  d.maxLineChanged = true;
36534  doc.iter(function (line) {
36535    var len = lineLength(line);
36536    if (len > d.maxLineLength) {
36537      d.maxLineLength = len;
36538      d.maxLine = line;
36539    }
36540  });
36541}
36542
36543// BIDI HELPERS
36544
36545function iterateBidiSections(order, from, to, f) {
36546  if (!order) { return f(from, to, "ltr", 0) }
36547  var found = false;
36548  for (var i = 0; i < order.length; ++i) {
36549    var part = order[i];
36550    if (part.from < to && part.to > from || from == to && part.to == from) {
36551      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
36552      found = true;
36553    }
36554  }
36555  if (!found) { f(from, to, "ltr"); }
36556}
36557
36558var bidiOther = null;
36559function getBidiPartAt(order, ch, sticky) {
36560  var found;
36561  bidiOther = null;
36562  for (var i = 0; i < order.length; ++i) {
36563    var cur = order[i];
36564    if (cur.from < ch && cur.to > ch) { return i }
36565    if (cur.to == ch) {
36566      if (cur.from != cur.to && sticky == "before") { found = i; }
36567      else { bidiOther = i; }
36568    }
36569    if (cur.from == ch) {
36570      if (cur.from != cur.to && sticky != "before") { found = i; }
36571      else { bidiOther = i; }
36572    }
36573  }
36574  return found != null ? found : bidiOther
36575}
36576
36577// Bidirectional ordering algorithm
36578// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
36579// that this (partially) implements.
36580
36581// One-char codes used for character types:
36582// L (L):   Left-to-Right
36583// R (R):   Right-to-Left
36584// r (AL):  Right-to-Left Arabic
36585// 1 (EN):  European Number
36586// + (ES):  European Number Separator
36587// % (ET):  European Number Terminator
36588// n (AN):  Arabic Number
36589// , (CS):  Common Number Separator
36590// m (NSM): Non-Spacing Mark
36591// b (BN):  Boundary Neutral
36592// s (B):   Paragraph Separator
36593// t (S):   Segment Separator
36594// w (WS):  Whitespace
36595// N (ON):  Other Neutrals
36596
36597// Returns null if characters are ordered as they appear
36598// (left-to-right), or an array of sections ({from, to, level}
36599// objects) in the order in which they occur visually.
36600var bidiOrdering = (function() {
36601  // Character types for codepoints 0 to 0xff
36602  var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
36603  // Character types for codepoints 0x600 to 0x6f9
36604  var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
36605  function charType(code) {
36606    if (code <= 0xf7) { return lowTypes.charAt(code) }
36607    else if (0x590 <= code && code <= 0x5f4) { return "R" }
36608    else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
36609    else if (0x6ee <= code && code <= 0x8ac) { return "r" }
36610    else if (0x2000 <= code && code <= 0x200b) { return "w" }
36611    else if (code == 0x200c) { return "b" }
36612    else { return "L" }
36613  }
36614
36615  var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
36616  var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
36617
36618  function BidiSpan(level, from, to) {
36619    this.level = level;
36620    this.from = from; this.to = to;
36621  }
36622
36623  return function(str, direction) {
36624    var outerType = direction == "ltr" ? "L" : "R";
36625
36626    if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
36627    var len = str.length, types = [];
36628    for (var i = 0; i < len; ++i)
36629      { types.push(charType(str.charCodeAt(i))); }
36630
36631    // W1. Examine each non-spacing mark (NSM) in the level run, and
36632    // change the type of the NSM to the type of the previous
36633    // character. If the NSM is at the start of the level run, it will
36634    // get the type of sor.
36635    for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
36636      var type = types[i$1];
36637      if (type == "m") { types[i$1] = prev; }
36638      else { prev = type; }
36639    }
36640
36641    // W2. Search backwards from each instance of a European number
36642    // until the first strong type (R, L, AL, or sor) is found. If an
36643    // AL is found, change the type of the European number to Arabic
36644    // number.
36645    // W3. Change all ALs to R.
36646    for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
36647      var type$1 = types[i$2];
36648      if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
36649      else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
36650    }
36651
36652    // W4. A single European separator between two European numbers
36653    // changes to a European number. A single common separator between
36654    // two numbers of the same type changes to that type.
36655    for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
36656      var type$2 = types[i$3];
36657      if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
36658      else if (type$2 == "," && prev$1 == types[i$3+1] &&
36659               (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
36660      prev$1 = type$2;
36661    }
36662
36663    // W5. A sequence of European terminators adjacent to European
36664    // numbers changes to all European numbers.
36665    // W6. Otherwise, separators and terminators change to Other
36666    // Neutral.
36667    for (var i$4 = 0; i$4 < len; ++i$4) {
36668      var type$3 = types[i$4];
36669      if (type$3 == ",") { types[i$4] = "N"; }
36670      else if (type$3 == "%") {
36671        var end = (void 0);
36672        for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
36673        var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
36674        for (var j = i$4; j < end; ++j) { types[j] = replace; }
36675        i$4 = end - 1;
36676      }
36677    }
36678
36679    // W7. Search backwards from each instance of a European number
36680    // until the first strong type (R, L, or sor) is found. If an L is
36681    // found, then change the type of the European number to L.
36682    for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
36683      var type$4 = types[i$5];
36684      if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
36685      else if (isStrong.test(type$4)) { cur$1 = type$4; }
36686    }
36687
36688    // N1. A sequence of neutrals takes the direction of the
36689    // surrounding strong text if the text on both sides has the same
36690    // direction. European and Arabic numbers act as if they were R in
36691    // terms of their influence on neutrals. Start-of-level-run (sor)
36692    // and end-of-level-run (eor) are used at level run boundaries.
36693    // N2. Any remaining neutrals take the embedding direction.
36694    for (var i$6 = 0; i$6 < len; ++i$6) {
36695      if (isNeutral.test(types[i$6])) {
36696        var end$1 = (void 0);
36697        for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
36698        var before = (i$6 ? types[i$6-1] : outerType) == "L";
36699        var after = (end$1 < len ? types[end$1] : outerType) == "L";
36700        var replace$1 = before == after ? (before ? "L" : "R") : outerType;
36701        for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
36702        i$6 = end$1 - 1;
36703      }
36704    }
36705
36706    // Here we depart from the documented algorithm, in order to avoid
36707    // building up an actual levels array. Since there are only three
36708    // levels (0, 1, 2) in an implementation that doesn't take
36709    // explicit embedding into account, we can build up the order on
36710    // the fly, without following the level-based algorithm.
36711    var order = [], m;
36712    for (var i$7 = 0; i$7 < len;) {
36713      if (countsAsLeft.test(types[i$7])) {
36714        var start = i$7;
36715        for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
36716        order.push(new BidiSpan(0, start, i$7));
36717      } else {
36718        var pos = i$7, at = order.length;
36719        for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
36720        for (var j$2 = pos; j$2 < i$7;) {
36721          if (countsAsNum.test(types[j$2])) {
36722            if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
36723            var nstart = j$2;
36724            for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
36725            order.splice(at, 0, new BidiSpan(2, nstart, j$2));
36726            pos = j$2;
36727          } else { ++j$2; }
36728        }
36729        if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
36730      }
36731    }
36732    if (direction == "ltr") {
36733      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
36734        order[0].from = m[0].length;
36735        order.unshift(new BidiSpan(0, 0, m[0].length));
36736      }
36737      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
36738        lst(order).to -= m[0].length;
36739        order.push(new BidiSpan(0, len - m[0].length, len));
36740      }
36741    }
36742
36743    return direction == "rtl" ? order.reverse() : order
36744  }
36745})();
36746
36747// Get the bidi ordering for the given line (and cache it). Returns
36748// false for lines that are fully left-to-right, and an array of
36749// BidiSpan objects otherwise.
36750function getOrder(line, direction) {
36751  var order = line.order;
36752  if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
36753  return order
36754}
36755
36756// EVENT HANDLING
36757
36758// Lightweight event framework. on/off also work on DOM nodes,
36759// registering native DOM handlers.
36760
36761var noHandlers = [];
36762
36763var on = function(emitter, type, f) {
36764  if (emitter.addEventListener) {
36765    emitter.addEventListener(type, f, false);
36766  } else if (emitter.attachEvent) {
36767    emitter.attachEvent("on" + type, f);
36768  } else {
36769    var map$$1 = emitter._handlers || (emitter._handlers = {});
36770    map$$1[type] = (map$$1[type] || noHandlers).concat(f);
36771  }
36772};
36773
36774function getHandlers(emitter, type) {
36775  return emitter._handlers && emitter._handlers[type] || noHandlers
36776}
36777
36778function off(emitter, type, f) {
36779  if (emitter.removeEventListener) {
36780    emitter.removeEventListener(type, f, false);
36781  } else if (emitter.detachEvent) {
36782    emitter.detachEvent("on" + type, f);
36783  } else {
36784    var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
36785    if (arr) {
36786      var index = indexOf(arr, f);
36787      if (index > -1)
36788        { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
36789    }
36790  }
36791}
36792
36793function signal(emitter, type /*, values...*/) {
36794  var handlers = getHandlers(emitter, type);
36795  if (!handlers.length) { return }
36796  var args = Array.prototype.slice.call(arguments, 2);
36797  for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
36798}
36799
36800// The DOM events that CodeMirror handles can be overridden by
36801// registering a (non-DOM) handler on the editor for the event name,
36802// and preventDefault-ing the event in that handler.
36803function signalDOMEvent(cm, e, override) {
36804  if (typeof e == "string")
36805    { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
36806  signal(cm, override || e.type, cm, e);
36807  return e_defaultPrevented(e) || e.codemirrorIgnore
36808}
36809
36810function signalCursorActivity(cm) {
36811  var arr = cm._handlers && cm._handlers.cursorActivity;
36812  if (!arr) { return }
36813  var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
36814  for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
36815    { set.push(arr[i]); } }
36816}
36817
36818function hasHandler(emitter, type) {
36819  return getHandlers(emitter, type).length > 0
36820}
36821
36822// Add on and off methods to a constructor's prototype, to make
36823// registering events on such objects more convenient.
36824function eventMixin(ctor) {
36825  ctor.prototype.on = function(type, f) {on(this, type, f);};
36826  ctor.prototype.off = function(type, f) {off(this, type, f);};
36827}
36828
36829// Due to the fact that we still support jurassic IE versions, some
36830// compatibility wrappers are needed.
36831
36832function e_preventDefault(e) {
36833  if (e.preventDefault) { e.preventDefault(); }
36834  else { e.returnValue = false; }
36835}
36836function e_stopPropagation(e) {
36837  if (e.stopPropagation) { e.stopPropagation(); }
36838  else { e.cancelBubble = true; }
36839}
36840function e_defaultPrevented(e) {
36841  return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
36842}
36843function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
36844
36845function e_target(e) {return e.target || e.srcElement}
36846function e_button(e) {
36847  var b = e.which;
36848  if (b == null) {
36849    if (e.button & 1) { b = 1; }
36850    else if (e.button & 2) { b = 3; }
36851    else if (e.button & 4) { b = 2; }
36852  }
36853  if (mac && e.ctrlKey && b == 1) { b = 3; }
36854  return b
36855}
36856
36857// Detect drag-and-drop
36858var dragAndDrop = function() {
36859  // There is *some* kind of drag-and-drop support in IE6-8, but I
36860  // couldn't get it to work yet.
36861  if (ie && ie_version < 9) { return false }
36862  var div = elt('div');
36863  return "draggable" in div || "dragDrop" in div
36864}();
36865
36866var zwspSupported;
36867function zeroWidthElement(measure) {
36868  if (zwspSupported == null) {
36869    var test = elt("span", "\u200b");
36870    removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
36871    if (measure.firstChild.offsetHeight != 0)
36872      { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
36873  }
36874  var node = zwspSupported ? elt("span", "\u200b") :
36875    elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
36876  node.setAttribute("cm-text", "");
36877  return node
36878}
36879
36880// Feature-detect IE's crummy client rect reporting for bidi text
36881var badBidiRects;
36882function hasBadBidiRects(measure) {
36883  if (badBidiRects != null) { return badBidiRects }
36884  var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
36885  var r0 = range(txt, 0, 1).getBoundingClientRect();
36886  var r1 = range(txt, 1, 2).getBoundingClientRect();
36887  removeChildren(measure);
36888  if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
36889  return badBidiRects = (r1.right - r0.right < 3)
36890}
36891
36892// See if "".split is the broken IE version, if so, provide an
36893// alternative way to split lines.
36894var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
36895  var pos = 0, result = [], l = string.length;
36896  while (pos <= l) {
36897    var nl = string.indexOf("\n", pos);
36898    if (nl == -1) { nl = string.length; }
36899    var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
36900    var rt = line.indexOf("\r");
36901    if (rt != -1) {
36902      result.push(line.slice(0, rt));
36903      pos += rt + 1;
36904    } else {
36905      result.push(line);
36906      pos = nl + 1;
36907    }
36908  }
36909  return result
36910} : function (string) { return string.split(/\r\n?|\n/); };
36911
36912var hasSelection = window.getSelection ? function (te) {
36913  try { return te.selectionStart != te.selectionEnd }
36914  catch(e) { return false }
36915} : function (te) {
36916  var range$$1;
36917  try {range$$1 = te.ownerDocument.selection.createRange();}
36918  catch(e) {}
36919  if (!range$$1 || range$$1.parentElement() != te) { return false }
36920  return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
36921};
36922
36923var hasCopyEvent = (function () {
36924  var e = elt("div");
36925  if ("oncopy" in e) { return true }
36926  e.setAttribute("oncopy", "return;");
36927  return typeof e.oncopy == "function"
36928})();
36929
36930var badZoomedRects = null;
36931function hasBadZoomedRects(measure) {
36932  if (badZoomedRects != null) { return badZoomedRects }
36933  var node = removeChildrenAndAdd(measure, elt("span", "x"));
36934  var normal = node.getBoundingClientRect();
36935  var fromRange = range(node, 0, 1).getBoundingClientRect();
36936  return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
36937}
36938
36939// Known modes, by name and by MIME
36940var modes = {};
36941var mimeModes = {};
36942
36943// Extra arguments are stored as the mode's dependencies, which is
36944// used by (legacy) mechanisms like loadmode.js to automatically
36945// load a mode. (Preferred mechanism is the require/define calls.)
36946function defineMode(name, mode) {
36947  if (arguments.length > 2)
36948    { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
36949  modes[name] = mode;
36950}
36951
36952function defineMIME(mime, spec) {
36953  mimeModes[mime] = spec;
36954}
36955
36956// Given a MIME type, a {name, ...options} config object, or a name
36957// string, return a mode config object.
36958function resolveMode(spec) {
36959  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
36960    spec = mimeModes[spec];
36961  } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
36962    var found = mimeModes[spec.name];
36963    if (typeof found == "string") { found = {name: found}; }
36964    spec = createObj(found, spec);
36965    spec.name = found.name;
36966  } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
36967    return resolveMode("application/xml")
36968  } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
36969    return resolveMode("application/json")
36970  }
36971  if (typeof spec == "string") { return {name: spec} }
36972  else { return spec || {name: "null"} }
36973}
36974
36975// Given a mode spec (anything that resolveMode accepts), find and
36976// initialize an actual mode object.
36977function getMode(options, spec) {
36978  spec = resolveMode(spec);
36979  var mfactory = modes[spec.name];
36980  if (!mfactory) { return getMode(options, "text/plain") }
36981  var modeObj = mfactory(options, spec);
36982  if (modeExtensions.hasOwnProperty(spec.name)) {
36983    var exts = modeExtensions[spec.name];
36984    for (var prop in exts) {
36985      if (!exts.hasOwnProperty(prop)) { continue }
36986      if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
36987      modeObj[prop] = exts[prop];
36988    }
36989  }
36990  modeObj.name = spec.name;
36991  if (spec.helperType) { modeObj.helperType = spec.helperType; }
36992  if (spec.modeProps) { for (var prop$1 in spec.modeProps)
36993    { modeObj[prop$1] = spec.modeProps[prop$1]; } }
36994
36995  return modeObj
36996}
36997
36998// This can be used to attach properties to mode objects from
36999// outside the actual mode definition.
37000var modeExtensions = {};
37001function extendMode(mode, properties) {
37002  var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
37003  copyObj(properties, exts);
37004}
37005
37006function copyState(mode, state) {
37007  if (state === true) { return state }
37008  if (mode.copyState) { return mode.copyState(state) }
37009  var nstate = {};
37010  for (var n in state) {
37011    var val = state[n];
37012    if (val instanceof Array) { val = val.concat([]); }
37013    nstate[n] = val;
37014  }
37015  return nstate
37016}
37017
37018// Given a mode and a state (for that mode), find the inner mode and
37019// state at the position that the state refers to.
37020function innerMode(mode, state) {
37021  var info;
37022  while (mode.innerMode) {
37023    info = mode.innerMode(state);
37024    if (!info || info.mode == mode) { break }
37025    state = info.state;
37026    mode = info.mode;
37027  }
37028  return info || {mode: mode, state: state}
37029}
37030
37031function startState(mode, a1, a2) {
37032  return mode.startState ? mode.startState(a1, a2) : true
37033}
37034
37035// STRING STREAM
37036
37037// Fed to the mode parsers, provides helper functions to make
37038// parsers more succinct.
37039
37040var StringStream = function(string, tabSize, lineOracle) {
37041  this.pos = this.start = 0;
37042  this.string = string;
37043  this.tabSize = tabSize || 8;
37044  this.lastColumnPos = this.lastColumnValue = 0;
37045  this.lineStart = 0;
37046  this.lineOracle = lineOracle;
37047};
37048
37049StringStream.prototype.eol = function () {return this.pos >= this.string.length};
37050StringStream.prototype.sol = function () {return this.pos == this.lineStart};
37051StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
37052StringStream.prototype.next = function () {
37053  if (this.pos < this.string.length)
37054    { return this.string.charAt(this.pos++) }
37055};
37056StringStream.prototype.eat = function (match) {
37057  var ch = this.string.charAt(this.pos);
37058  var ok;
37059  if (typeof match == "string") { ok = ch == match; }
37060  else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
37061  if (ok) {++this.pos; return ch}
37062};
37063StringStream.prototype.eatWhile = function (match) {
37064  var start = this.pos;
37065  while (this.eat(match)){}
37066  return this.pos > start
37067};
37068StringStream.prototype.eatSpace = function () {
37069    var this$1 = this;
37070
37071  var start = this.pos;
37072  while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
37073  return this.pos > start
37074};
37075StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
37076StringStream.prototype.skipTo = function (ch) {
37077  var found = this.string.indexOf(ch, this.pos);
37078  if (found > -1) {this.pos = found; return true}
37079};
37080StringStream.prototype.backUp = function (n) {this.pos -= n;};
37081StringStream.prototype.column = function () {
37082  if (this.lastColumnPos < this.start) {
37083    this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
37084    this.lastColumnPos = this.start;
37085  }
37086  return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
37087};
37088StringStream.prototype.indentation = function () {
37089  return countColumn(this.string, null, this.tabSize) -
37090    (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
37091};
37092StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
37093  if (typeof pattern == "string") {
37094    var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
37095    var substr = this.string.substr(this.pos, pattern.length);
37096    if (cased(substr) == cased(pattern)) {
37097      if (consume !== false) { this.pos += pattern.length; }
37098      return true
37099    }
37100  } else {
37101    var match = this.string.slice(this.pos).match(pattern);
37102    if (match && match.index > 0) { return null }
37103    if (match && consume !== false) { this.pos += match[0].length; }
37104    return match
37105  }
37106};
37107StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
37108StringStream.prototype.hideFirstChars = function (n, inner) {
37109  this.lineStart += n;
37110  try { return inner() }
37111  finally { this.lineStart -= n; }
37112};
37113StringStream.prototype.lookAhead = function (n) {
37114  var oracle = this.lineOracle;
37115  return oracle && oracle.lookAhead(n)
37116};
37117StringStream.prototype.baseToken = function () {
37118  var oracle = this.lineOracle;
37119  return oracle && oracle.baseToken(this.pos)
37120};
37121
37122var SavedContext = function(state, lookAhead) {
37123  this.state = state;
37124  this.lookAhead = lookAhead;
37125};
37126
37127var Context = function(doc, state, line, lookAhead) {
37128  this.state = state;
37129  this.doc = doc;
37130  this.line = line;
37131  this.maxLookAhead = lookAhead || 0;
37132  this.baseTokens = null;
37133  this.baseTokenPos = 1;
37134};
37135
37136Context.prototype.lookAhead = function (n) {
37137  var line = this.doc.getLine(this.line + n);
37138  if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
37139  return line
37140};
37141
37142Context.prototype.baseToken = function (n) {
37143    var this$1 = this;
37144
37145  if (!this.baseTokens) { return null }
37146  while (this.baseTokens[this.baseTokenPos] <= n)
37147    { this$1.baseTokenPos += 2; }
37148  var type = this.baseTokens[this.baseTokenPos + 1];
37149  return {type: type && type.replace(/( |^)overlay .*/, ""),
37150          size: this.baseTokens[this.baseTokenPos] - n}
37151};
37152
37153Context.prototype.nextLine = function () {
37154  this.line++;
37155  if (this.maxLookAhead > 0) { this.maxLookAhead--; }
37156};
37157
37158Context.fromSaved = function (doc, saved, line) {
37159  if (saved instanceof SavedContext)
37160    { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
37161  else
37162    { return new Context(doc, copyState(doc.mode, saved), line) }
37163};
37164
37165Context.prototype.save = function (copy) {
37166  var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
37167  return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
37168};
37169
37170
37171// Compute a style array (an array starting with a mode generation
37172// -- for invalidation -- followed by pairs of end positions and
37173// style strings), which is used to highlight the tokens on the
37174// line.
37175function highlightLine(cm, line, context, forceToEnd) {
37176  // A styles array always starts with a number identifying the
37177  // mode/overlays that it is based on (for easy invalidation).
37178  var st = [cm.state.modeGen], lineClasses = {};
37179  // Compute the base array of styles
37180  runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
37181          lineClasses, forceToEnd);
37182  var state = context.state;
37183
37184  // Run overlays, adjust style array.
37185  var loop = function ( o ) {
37186    context.baseTokens = st;
37187    var overlay = cm.state.overlays[o], i = 1, at = 0;
37188    context.state = true;
37189    runMode(cm, line.text, overlay.mode, context, function (end, style) {
37190      var start = i;
37191      // Ensure there's a token end at the current position, and that i points at it
37192      while (at < end) {
37193        var i_end = st[i];
37194        if (i_end > end)
37195          { st.splice(i, 1, end, st[i+1], i_end); }
37196        i += 2;
37197        at = Math.min(end, i_end);
37198      }
37199      if (!style) { return }
37200      if (overlay.opaque) {
37201        st.splice(start, i - start, end, "overlay " + style);
37202        i = start + 2;
37203      } else {
37204        for (; start < i; start += 2) {
37205          var cur = st[start+1];
37206          st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
37207        }
37208      }
37209    }, lineClasses);
37210    context.state = state;
37211    context.baseTokens = null;
37212    context.baseTokenPos = 1;
37213  };
37214
37215  for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
37216
37217  return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
37218}
37219
37220function getLineStyles(cm, line, updateFrontier) {
37221  if (!line.styles || line.styles[0] != cm.state.modeGen) {
37222    var context = getContextBefore(cm, lineNo(line));
37223    var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
37224    var result = highlightLine(cm, line, context);
37225    if (resetState) { context.state = resetState; }
37226    line.stateAfter = context.save(!resetState);
37227    line.styles = result.styles;
37228    if (result.classes) { line.styleClasses = result.classes; }
37229    else if (line.styleClasses) { line.styleClasses = null; }
37230    if (updateFrontier === cm.doc.highlightFrontier)
37231      { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
37232  }
37233  return line.styles
37234}
37235
37236function getContextBefore(cm, n, precise) {
37237  var doc = cm.doc, display = cm.display;
37238  if (!doc.mode.startState) { return new Context(doc, true, n) }
37239  var start = findStartLine(cm, n, precise);
37240  var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
37241  var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
37242
37243  doc.iter(start, n, function (line) {
37244    processLine(cm, line.text, context);
37245    var pos = context.line;
37246    line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
37247    context.nextLine();
37248  });
37249  if (precise) { doc.modeFrontier = context.line; }
37250  return context
37251}
37252
37253// Lightweight form of highlight -- proceed over this line and
37254// update state, but don't save a style array. Used for lines that
37255// aren't currently visible.
37256function processLine(cm, text, context, startAt) {
37257  var mode = cm.doc.mode;
37258  var stream = new StringStream(text, cm.options.tabSize, context);
37259  stream.start = stream.pos = startAt || 0;
37260  if (text == "") { callBlankLine(mode, context.state); }
37261  while (!stream.eol()) {
37262    readToken(mode, stream, context.state);
37263    stream.start = stream.pos;
37264  }
37265}
37266
37267function callBlankLine(mode, state) {
37268  if (mode.blankLine) { return mode.blankLine(state) }
37269  if (!mode.innerMode) { return }
37270  var inner = innerMode(mode, state);
37271  if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
37272}
37273
37274function readToken(mode, stream, state, inner) {
37275  for (var i = 0; i < 10; i++) {
37276    if (inner) { inner[0] = innerMode(mode, state).mode; }
37277    var style = mode.token(stream, state);
37278    if (stream.pos > stream.start) { return style }
37279  }
37280  throw new Error("Mode " + mode.name + " failed to advance stream.")
37281}
37282
37283var Token = function(stream, type, state) {
37284  this.start = stream.start; this.end = stream.pos;
37285  this.string = stream.current();
37286  this.type = type || null;
37287  this.state = state;
37288};
37289
37290// Utility for getTokenAt and getLineTokens
37291function takeToken(cm, pos, precise, asArray) {
37292  var doc = cm.doc, mode = doc.mode, style;
37293  pos = clipPos(doc, pos);
37294  var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
37295  var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
37296  if (asArray) { tokens = []; }
37297  while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
37298    stream.start = stream.pos;
37299    style = readToken(mode, stream, context.state);
37300    if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
37301  }
37302  return asArray ? tokens : new Token(stream, style, context.state)
37303}
37304
37305function extractLineClasses(type, output) {
37306  if (type) { for (;;) {
37307    var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
37308    if (!lineClass) { break }
37309    type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
37310    var prop = lineClass[1] ? "bgClass" : "textClass";
37311    if (output[prop] == null)
37312      { output[prop] = lineClass[2]; }
37313    else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
37314      { output[prop] += " " + lineClass[2]; }
37315  } }
37316  return type
37317}
37318
37319// Run the given mode's parser over a line, calling f for each token.
37320function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
37321  var flattenSpans = mode.flattenSpans;
37322  if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
37323  var curStart = 0, curStyle = null;
37324  var stream = new StringStream(text, cm.options.tabSize, context), style;
37325  var inner = cm.options.addModeClass && [null];
37326  if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
37327  while (!stream.eol()) {
37328    if (stream.pos > cm.options.maxHighlightLength) {
37329      flattenSpans = false;
37330      if (forceToEnd) { processLine(cm, text, context, stream.pos); }
37331      stream.pos = text.length;
37332      style = null;
37333    } else {
37334      style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
37335    }
37336    if (inner) {
37337      var mName = inner[0].name;
37338      if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
37339    }
37340    if (!flattenSpans || curStyle != style) {
37341      while (curStart < stream.start) {
37342        curStart = Math.min(stream.start, curStart + 5000);
37343        f(curStart, curStyle);
37344      }
37345      curStyle = style;
37346    }
37347    stream.start = stream.pos;
37348  }
37349  while (curStart < stream.pos) {
37350    // Webkit seems to refuse to render text nodes longer than 57444
37351    // characters, and returns inaccurate measurements in nodes
37352    // starting around 5000 chars.
37353    var pos = Math.min(stream.pos, curStart + 5000);
37354    f(pos, curStyle);
37355    curStart = pos;
37356  }
37357}
37358
37359// Finds the line to start with when starting a parse. Tries to
37360// find a line with a stateAfter, so that it can start with a
37361// valid state. If that fails, it returns the line with the
37362// smallest indentation, which tends to need the least context to
37363// parse correctly.
37364function findStartLine(cm, n, precise) {
37365  var minindent, minline, doc = cm.doc;
37366  var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
37367  for (var search = n; search > lim; --search) {
37368    if (search <= doc.first) { return doc.first }
37369    var line = getLine(doc, search - 1), after = line.stateAfter;
37370    if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
37371      { return search }
37372    var indented = countColumn(line.text, null, cm.options.tabSize);
37373    if (minline == null || minindent > indented) {
37374      minline = search - 1;
37375      minindent = indented;
37376    }
37377  }
37378  return minline
37379}
37380
37381function retreatFrontier(doc, n) {
37382  doc.modeFrontier = Math.min(doc.modeFrontier, n);
37383  if (doc.highlightFrontier < n - 10) { return }
37384  var start = doc.first;
37385  for (var line = n - 1; line > start; line--) {
37386    var saved = getLine(doc, line).stateAfter;
37387    // change is on 3
37388    // state on line 1 looked ahead 2 -- so saw 3
37389    // test 1 + 2 < 3 should cover this
37390    if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
37391      start = line + 1;
37392      break
37393    }
37394  }
37395  doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
37396}
37397
37398// LINE DATA STRUCTURE
37399
37400// Line objects. These hold state related to a line, including
37401// highlighting info (the styles array).
37402var Line = function(text, markedSpans, estimateHeight) {
37403  this.text = text;
37404  attachMarkedSpans(this, markedSpans);
37405  this.height = estimateHeight ? estimateHeight(this) : 1;
37406};
37407
37408Line.prototype.lineNo = function () { return lineNo(this) };
37409eventMixin(Line);
37410
37411// Change the content (text, markers) of a line. Automatically
37412// invalidates cached information and tries to re-estimate the
37413// line's height.
37414function updateLine(line, text, markedSpans, estimateHeight) {
37415  line.text = text;
37416  if (line.stateAfter) { line.stateAfter = null; }
37417  if (line.styles) { line.styles = null; }
37418  if (line.order != null) { line.order = null; }
37419  detachMarkedSpans(line);
37420  attachMarkedSpans(line, markedSpans);
37421  var estHeight = estimateHeight ? estimateHeight(line) : 1;
37422  if (estHeight != line.height) { updateLineHeight(line, estHeight); }
37423}
37424
37425// Detach a line from the document tree and its markers.
37426function cleanUpLine(line) {
37427  line.parent = null;
37428  detachMarkedSpans(line);
37429}
37430
37431// Convert a style as returned by a mode (either null, or a string
37432// containing one or more styles) to a CSS style. This is cached,
37433// and also looks for line-wide styles.
37434var styleToClassCache = {};
37435var styleToClassCacheWithMode = {};
37436function interpretTokenStyle(style, options) {
37437  if (!style || /^\s*$/.test(style)) { return null }
37438  var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
37439  return cache[style] ||
37440    (cache[style] = style.replace(/\S+/g, "cm-$&"))
37441}
37442
37443// Render the DOM representation of the text of a line. Also builds
37444// up a 'line map', which points at the DOM nodes that represent
37445// specific stretches of text, and is used by the measuring code.
37446// The returned object contains the DOM node, this map, and
37447// information about line-wide styles that were set by the mode.
37448function buildLineContent(cm, lineView) {
37449  // The padding-right forces the element to have a 'border', which
37450  // is needed on Webkit to be able to get line-level bounding
37451  // rectangles for it (in measureChar).
37452  var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
37453  var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
37454                 col: 0, pos: 0, cm: cm,
37455                 trailingSpace: false,
37456                 splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
37457  lineView.measure = {};
37458
37459  // Iterate over the logical lines that make up this visual line.
37460  for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
37461    var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
37462    builder.pos = 0;
37463    builder.addToken = buildToken;
37464    // Optionally wire in some hacks into the token-rendering
37465    // algorithm, to deal with browser quirks.
37466    if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
37467      { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
37468    builder.map = [];
37469    var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
37470    insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
37471    if (line.styleClasses) {
37472      if (line.styleClasses.bgClass)
37473        { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
37474      if (line.styleClasses.textClass)
37475        { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
37476    }
37477
37478    // Ensure at least a single node is present, for measuring.
37479    if (builder.map.length == 0)
37480      { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
37481
37482    // Store the map and a cache object for the current logical line
37483    if (i == 0) {
37484      lineView.measure.map = builder.map;
37485      lineView.measure.cache = {};
37486    } else {
37487      (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
37488      ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
37489    }
37490  }
37491
37492  // See issue #2901
37493  if (webkit) {
37494    var last = builder.content.lastChild;
37495    if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
37496      { builder.content.className = "cm-tab-wrap-hack"; }
37497  }
37498
37499  signal(cm, "renderLine", cm, lineView.line, builder.pre);
37500  if (builder.pre.className)
37501    { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
37502
37503  return builder
37504}
37505
37506function defaultSpecialCharPlaceholder(ch) {
37507  var token = elt("span", "\u2022", "cm-invalidchar");
37508  token.title = "\\u" + ch.charCodeAt(0).toString(16);
37509  token.setAttribute("aria-label", token.title);
37510  return token
37511}
37512
37513// Build up the DOM representation for a single token, and add it to
37514// the line map. Takes care to render special characters separately.
37515function buildToken(builder, text, style, startStyle, endStyle, title, css) {
37516  if (!text) { return }
37517  var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
37518  var special = builder.cm.state.specialChars, mustWrap = false;
37519  var content;
37520  if (!special.test(text)) {
37521    builder.col += text.length;
37522    content = document.createTextNode(displayText);
37523    builder.map.push(builder.pos, builder.pos + text.length, content);
37524    if (ie && ie_version < 9) { mustWrap = true; }
37525    builder.pos += text.length;
37526  } else {
37527    content = document.createDocumentFragment();
37528    var pos = 0;
37529    while (true) {
37530      special.lastIndex = pos;
37531      var m = special.exec(text);
37532      var skipped = m ? m.index - pos : text.length - pos;
37533      if (skipped) {
37534        var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
37535        if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
37536        else { content.appendChild(txt); }
37537        builder.map.push(builder.pos, builder.pos + skipped, txt);
37538        builder.col += skipped;
37539        builder.pos += skipped;
37540      }
37541      if (!m) { break }
37542      pos += skipped + 1;
37543      var txt$1 = (void 0);
37544      if (m[0] == "\t") {
37545        var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
37546        txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
37547        txt$1.setAttribute("role", "presentation");
37548        txt$1.setAttribute("cm-text", "\t");
37549        builder.col += tabWidth;
37550      } else if (m[0] == "\r" || m[0] == "\n") {
37551        txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
37552        txt$1.setAttribute("cm-text", m[0]);
37553        builder.col += 1;
37554      } else {
37555        txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
37556        txt$1.setAttribute("cm-text", m[0]);
37557        if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
37558        else { content.appendChild(txt$1); }
37559        builder.col += 1;
37560      }
37561      builder.map.push(builder.pos, builder.pos + 1, txt$1);
37562      builder.pos++;
37563    }
37564  }
37565  builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
37566  if (style || startStyle || endStyle || mustWrap || css) {
37567    var fullStyle = style || "";
37568    if (startStyle) { fullStyle += startStyle; }
37569    if (endStyle) { fullStyle += endStyle; }
37570    var token = elt("span", [content], fullStyle, css);
37571    if (title) { token.title = title; }
37572    return builder.content.appendChild(token)
37573  }
37574  builder.content.appendChild(content);
37575}
37576
37577function splitSpaces(text, trailingBefore) {
37578  if (text.length > 1 && !/  /.test(text)) { return text }
37579  var spaceBefore = trailingBefore, result = "";
37580  for (var i = 0; i < text.length; i++) {
37581    var ch = text.charAt(i);
37582    if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
37583      { ch = "\u00a0"; }
37584    result += ch;
37585    spaceBefore = ch == " ";
37586  }
37587  return result
37588}
37589
37590// Work around nonsense dimensions being reported for stretches of
37591// right-to-left text.
37592function buildTokenBadBidi(inner, order) {
37593  return function (builder, text, style, startStyle, endStyle, title, css) {
37594    style = style ? style + " cm-force-border" : "cm-force-border";
37595    var start = builder.pos, end = start + text.length;
37596    for (;;) {
37597      // Find the part that overlaps with the start of this text
37598      var part = (void 0);
37599      for (var i = 0; i < order.length; i++) {
37600        part = order[i];
37601        if (part.to > start && part.from <= start) { break }
37602      }
37603      if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
37604      inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
37605      startStyle = null;
37606      text = text.slice(part.to - start);
37607      start = part.to;
37608    }
37609  }
37610}
37611
37612function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
37613  var widget = !ignoreWidget && marker.widgetNode;
37614  if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
37615  if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
37616    if (!widget)
37617      { widget = builder.content.appendChild(document.createElement("span")); }
37618    widget.setAttribute("cm-marker", marker.id);
37619  }
37620  if (widget) {
37621    builder.cm.display.input.setUneditable(widget);
37622    builder.content.appendChild(widget);
37623  }
37624  builder.pos += size;
37625  builder.trailingSpace = false;
37626}
37627
37628// Outputs a number of spans to make up a line, taking highlighting
37629// and marked text into account.
37630function insertLineContent(line, builder, styles) {
37631  var spans = line.markedSpans, allText = line.text, at = 0;
37632  if (!spans) {
37633    for (var i$1 = 1; i$1 < styles.length; i$1+=2)
37634      { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
37635    return
37636  }
37637
37638  var len = allText.length, pos = 0, i = 1, text = "", style, css;
37639  var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
37640  for (;;) {
37641    if (nextChange == pos) { // Update current marker set
37642      spanStyle = spanEndStyle = spanStartStyle = title = css = "";
37643      collapsed = null; nextChange = Infinity;
37644      var foundBookmarks = [], endStyles = (void 0);
37645      for (var j = 0; j < spans.length; ++j) {
37646        var sp = spans[j], m = sp.marker;
37647        if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
37648          foundBookmarks.push(m);
37649        } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
37650          if (sp.to != null && sp.to != pos && nextChange > sp.to) {
37651            nextChange = sp.to;
37652            spanEndStyle = "";
37653          }
37654          if (m.className) { spanStyle += " " + m.className; }
37655          if (m.css) { css = (css ? css + ";" : "") + m.css; }
37656          if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
37657          if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
37658          if (m.title && !title) { title = m.title; }
37659          if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
37660            { collapsed = sp; }
37661        } else if (sp.from > pos && nextChange > sp.from) {
37662          nextChange = sp.from;
37663        }
37664      }
37665      if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
37666        { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
37667
37668      if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
37669        { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
37670      if (collapsed && (collapsed.from || 0) == pos) {
37671        buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
37672                           collapsed.marker, collapsed.from == null);
37673        if (collapsed.to == null) { return }
37674        if (collapsed.to == pos) { collapsed = false; }
37675      }
37676    }
37677    if (pos >= len) { break }
37678
37679    var upto = Math.min(len, nextChange);
37680    while (true) {
37681      if (text) {
37682        var end = pos + text.length;
37683        if (!collapsed) {
37684          var tokenText = end > upto ? text.slice(0, upto - pos) : text;
37685          builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
37686                           spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
37687        }
37688        if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
37689        pos = end;
37690        spanStartStyle = "";
37691      }
37692      text = allText.slice(at, at = styles[i++]);
37693      style = interpretTokenStyle(styles[i++], builder.cm.options);
37694    }
37695  }
37696}
37697
37698
37699// These objects are used to represent the visible (currently drawn)
37700// part of the document. A LineView may correspond to multiple
37701// logical lines, if those are connected by collapsed ranges.
37702function LineView(doc, line, lineN) {
37703  // The starting line
37704  this.line = line;
37705  // Continuing lines, if any
37706  this.rest = visualLineContinued(line);
37707  // Number of logical lines in this visual line
37708  this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
37709  this.node = this.text = null;
37710  this.hidden = lineIsHidden(doc, line);
37711}
37712
37713// Create a range of LineView objects for the given lines.
37714function buildViewArray(cm, from, to) {
37715  var array = [], nextPos;
37716  for (var pos = from; pos < to; pos = nextPos) {
37717    var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
37718    nextPos = pos + view.size;
37719    array.push(view);
37720  }
37721  return array
37722}
37723
37724var operationGroup = null;
37725
37726function pushOperation(op) {
37727  if (operationGroup) {
37728    operationGroup.ops.push(op);
37729  } else {
37730    op.ownsGroup = operationGroup = {
37731      ops: [op],
37732      delayedCallbacks: []
37733    };
37734  }
37735}
37736
37737function fireCallbacksForOps(group) {
37738  // Calls delayed callbacks and cursorActivity handlers until no
37739  // new ones appear
37740  var callbacks = group.delayedCallbacks, i = 0;
37741  do {
37742    for (; i < callbacks.length; i++)
37743      { callbacks[i].call(null); }
37744    for (var j = 0; j < group.ops.length; j++) {
37745      var op = group.ops[j];
37746      if (op.cursorActivityHandlers)
37747        { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
37748          { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
37749    }
37750  } while (i < callbacks.length)
37751}
37752
37753function finishOperation(op, endCb) {
37754  var group = op.ownsGroup;
37755  if (!group) { return }
37756
37757  try { fireCallbacksForOps(group); }
37758  finally {
37759    operationGroup = null;
37760    endCb(group);
37761  }
37762}
37763
37764var orphanDelayedCallbacks = null;
37765
37766// Often, we want to signal events at a point where we are in the
37767// middle of some work, but don't want the handler to start calling
37768// other methods on the editor, which might be in an inconsistent
37769// state or simply not expect any other events to happen.
37770// signalLater looks whether there are any handlers, and schedules
37771// them to be executed when the last operation ends, or, if no
37772// operation is active, when a timeout fires.
37773function signalLater(emitter, type /*, values...*/) {
37774  var arr = getHandlers(emitter, type);
37775  if (!arr.length) { return }
37776  var args = Array.prototype.slice.call(arguments, 2), list;
37777  if (operationGroup) {
37778    list = operationGroup.delayedCallbacks;
37779  } else if (orphanDelayedCallbacks) {
37780    list = orphanDelayedCallbacks;
37781  } else {
37782    list = orphanDelayedCallbacks = [];
37783    setTimeout(fireOrphanDelayed, 0);
37784  }
37785  var loop = function ( i ) {
37786    list.push(function () { return arr[i].apply(null, args); });
37787  };
37788
37789  for (var i = 0; i < arr.length; ++i)
37790    loop( i );
37791}
37792
37793function fireOrphanDelayed() {
37794  var delayed = orphanDelayedCallbacks;
37795  orphanDelayedCallbacks = null;
37796  for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
37797}
37798
37799// When an aspect of a line changes, a string is added to
37800// lineView.changes. This updates the relevant part of the line's
37801// DOM structure.
37802function updateLineForChanges(cm, lineView, lineN, dims) {
37803  for (var j = 0; j < lineView.changes.length; j++) {
37804    var type = lineView.changes[j];
37805    if (type == "text") { updateLineText(cm, lineView); }
37806    else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
37807    else if (type == "class") { updateLineClasses(cm, lineView); }
37808    else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
37809  }
37810  lineView.changes = null;
37811}
37812
37813// Lines with gutter elements, widgets or a background class need to
37814// be wrapped, and have the extra elements added to the wrapper div
37815function ensureLineWrapped(lineView) {
37816  if (lineView.node == lineView.text) {
37817    lineView.node = elt("div", null, null, "position: relative");
37818    if (lineView.text.parentNode)
37819      { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
37820    lineView.node.appendChild(lineView.text);
37821    if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
37822  }
37823  return lineView.node
37824}
37825
37826function updateLineBackground(cm, lineView) {
37827  var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
37828  if (cls) { cls += " CodeMirror-linebackground"; }
37829  if (lineView.background) {
37830    if (cls) { lineView.background.className = cls; }
37831    else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
37832  } else if (cls) {
37833    var wrap = ensureLineWrapped(lineView);
37834    lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
37835    cm.display.input.setUneditable(lineView.background);
37836  }
37837}
37838
37839// Wrapper around buildLineContent which will reuse the structure
37840// in display.externalMeasured when possible.
37841function getLineContent(cm, lineView) {
37842  var ext = cm.display.externalMeasured;
37843  if (ext && ext.line == lineView.line) {
37844    cm.display.externalMeasured = null;
37845    lineView.measure = ext.measure;
37846    return ext.built
37847  }
37848  return buildLineContent(cm, lineView)
37849}
37850
37851// Redraw the line's text. Interacts with the background and text
37852// classes because the mode may output tokens that influence these
37853// classes.
37854function updateLineText(cm, lineView) {
37855  var cls = lineView.text.className;
37856  var built = getLineContent(cm, lineView);
37857  if (lineView.text == lineView.node) { lineView.node = built.pre; }
37858  lineView.text.parentNode.replaceChild(built.pre, lineView.text);
37859  lineView.text = built.pre;
37860  if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
37861    lineView.bgClass = built.bgClass;
37862    lineView.textClass = built.textClass;
37863    updateLineClasses(cm, lineView);
37864  } else if (cls) {
37865    lineView.text.className = cls;
37866  }
37867}
37868
37869function updateLineClasses(cm, lineView) {
37870  updateLineBackground(cm, lineView);
37871  if (lineView.line.wrapClass)
37872    { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
37873  else if (lineView.node != lineView.text)
37874    { lineView.node.className = ""; }
37875  var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
37876  lineView.text.className = textClass || "";
37877}
37878
37879function updateLineGutter(cm, lineView, lineN, dims) {
37880  if (lineView.gutter) {
37881    lineView.node.removeChild(lineView.gutter);
37882    lineView.gutter = null;
37883  }
37884  if (lineView.gutterBackground) {
37885    lineView.node.removeChild(lineView.gutterBackground);
37886    lineView.gutterBackground = null;
37887  }
37888  if (lineView.line.gutterClass) {
37889    var wrap = ensureLineWrapped(lineView);
37890    lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
37891                                    ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
37892    cm.display.input.setUneditable(lineView.gutterBackground);
37893    wrap.insertBefore(lineView.gutterBackground, lineView.text);
37894  }
37895  var markers = lineView.line.gutterMarkers;
37896  if (cm.options.lineNumbers || markers) {
37897    var wrap$1 = ensureLineWrapped(lineView);
37898    var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
37899    cm.display.input.setUneditable(gutterWrap);
37900    wrap$1.insertBefore(gutterWrap, lineView.text);
37901    if (lineView.line.gutterClass)
37902      { gutterWrap.className += " " + lineView.line.gutterClass; }
37903    if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
37904      { lineView.lineNumber = gutterWrap.appendChild(
37905        elt("div", lineNumberFor(cm.options, lineN),
37906            "CodeMirror-linenumber CodeMirror-gutter-elt",
37907            ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
37908    if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
37909      var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
37910      if (found)
37911        { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
37912                                   ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
37913    } }
37914  }
37915}
37916
37917function updateLineWidgets(cm, lineView, dims) {
37918  if (lineView.alignable) { lineView.alignable = null; }
37919  for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
37920    next = node.nextSibling;
37921    if (node.className == "CodeMirror-linewidget")
37922      { lineView.node.removeChild(node); }
37923  }
37924  insertLineWidgets(cm, lineView, dims);
37925}
37926
37927// Build a line's DOM representation from scratch
37928function buildLineElement(cm, lineView, lineN, dims) {
37929  var built = getLineContent(cm, lineView);
37930  lineView.text = lineView.node = built.pre;
37931  if (built.bgClass) { lineView.bgClass = built.bgClass; }
37932  if (built.textClass) { lineView.textClass = built.textClass; }
37933
37934  updateLineClasses(cm, lineView);
37935  updateLineGutter(cm, lineView, lineN, dims);
37936  insertLineWidgets(cm, lineView, dims);
37937  return lineView.node
37938}
37939
37940// A lineView may contain multiple logical lines (when merged by
37941// collapsed spans). The widgets for all of them need to be drawn.
37942function insertLineWidgets(cm, lineView, dims) {
37943  insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
37944  if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
37945    { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
37946}
37947
37948function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
37949  if (!line.widgets) { return }
37950  var wrap = ensureLineWrapped(lineView);
37951  for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
37952    var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
37953    if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
37954    positionLineWidget(widget, node, lineView, dims);
37955    cm.display.input.setUneditable(node);
37956    if (allowAbove && widget.above)
37957      { wrap.insertBefore(node, lineView.gutter || lineView.text); }
37958    else
37959      { wrap.appendChild(node); }
37960    signalLater(widget, "redraw");
37961  }
37962}
37963
37964function positionLineWidget(widget, node, lineView, dims) {
37965  if (widget.noHScroll) {
37966    (lineView.alignable || (lineView.alignable = [])).push(node);
37967    var width = dims.wrapperWidth;
37968    node.style.left = dims.fixedPos + "px";
37969    if (!widget.coverGutter) {
37970      width -= dims.gutterTotalWidth;
37971      node.style.paddingLeft = dims.gutterTotalWidth + "px";
37972    }
37973    node.style.width = width + "px";
37974  }
37975  if (widget.coverGutter) {
37976    node.style.zIndex = 5;
37977    node.style.position = "relative";
37978    if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
37979  }
37980}
37981
37982function widgetHeight(widget) {
37983  if (widget.height != null) { return widget.height }
37984  var cm = widget.doc.cm;
37985  if (!cm) { return 0 }
37986  if (!contains(document.body, widget.node)) {
37987    var parentStyle = "position: relative;";
37988    if (widget.coverGutter)
37989      { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
37990    if (widget.noHScroll)
37991      { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
37992    removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
37993  }
37994  return widget.height = widget.node.parentNode.offsetHeight
37995}
37996
37997// Return true when the given mouse event happened in a widget
37998function eventInWidget(display, e) {
37999  for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
38000    if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
38001        (n.parentNode == display.sizer && n != display.mover))
38002      { return true }
38003  }
38004}
38005
38006// POSITION MEASUREMENT
38007
38008function paddingTop(display) {return display.lineSpace.offsetTop}
38009function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
38010function paddingH(display) {
38011  if (display.cachedPaddingH) { return display.cachedPaddingH }
38012  var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
38013  var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
38014  var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
38015  if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
38016  return data
38017}
38018
38019function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
38020function displayWidth(cm) {
38021  return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
38022}
38023function displayHeight(cm) {
38024  return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
38025}
38026
38027// Ensure the lineView.wrapping.heights array is populated. This is
38028// an array of bottom offsets for the lines that make up a drawn
38029// line. When lineWrapping is on, there might be more than one
38030// height.
38031function ensureLineHeights(cm, lineView, rect) {
38032  var wrapping = cm.options.lineWrapping;
38033  var curWidth = wrapping && displayWidth(cm);
38034  if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
38035    var heights = lineView.measure.heights = [];
38036    if (wrapping) {
38037      lineView.measure.width = curWidth;
38038      var rects = lineView.text.firstChild.getClientRects();
38039      for (var i = 0; i < rects.length - 1; i++) {
38040        var cur = rects[i], next = rects[i + 1];
38041        if (Math.abs(cur.bottom - next.bottom) > 2)
38042          { heights.push((cur.bottom + next.top) / 2 - rect.top); }
38043      }
38044    }
38045    heights.push(rect.bottom - rect.top);
38046  }
38047}
38048
38049// Find a line map (mapping character offsets to text nodes) and a
38050// measurement cache for the given line number. (A line view might
38051// contain multiple lines when collapsed ranges are present.)
38052function mapFromLineView(lineView, line, lineN) {
38053  if (lineView.line == line)
38054    { return {map: lineView.measure.map, cache: lineView.measure.cache} }
38055  for (var i = 0; i < lineView.rest.length; i++)
38056    { if (lineView.rest[i] == line)
38057      { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
38058  for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
38059    { if (lineNo(lineView.rest[i$1]) > lineN)
38060      { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
38061}
38062
38063// Render a line into the hidden node display.externalMeasured. Used
38064// when measurement is needed for a line that's not in the viewport.
38065function updateExternalMeasurement(cm, line) {
38066  line = visualLine(line);
38067  var lineN = lineNo(line);
38068  var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
38069  view.lineN = lineN;
38070  var built = view.built = buildLineContent(cm, view);
38071  view.text = built.pre;
38072  removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
38073  return view
38074}
38075
38076// Get a {top, bottom, left, right} box (in line-local coordinates)
38077// for a given character.
38078function measureChar(cm, line, ch, bias) {
38079  return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
38080}
38081
38082// Find a line view that corresponds to the given line number.
38083function findViewForLine(cm, lineN) {
38084  if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
38085    { return cm.display.view[findViewIndex(cm, lineN)] }
38086  var ext = cm.display.externalMeasured;
38087  if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
38088    { return ext }
38089}
38090
38091// Measurement can be split in two steps, the set-up work that
38092// applies to the whole line, and the measurement of the actual
38093// character. Functions like coordsChar, that need to do a lot of
38094// measurements in a row, can thus ensure that the set-up work is
38095// only done once.
38096function prepareMeasureForLine(cm, line) {
38097  var lineN = lineNo(line);
38098  var view = findViewForLine(cm, lineN);
38099  if (view && !view.text) {
38100    view = null;
38101  } else if (view && view.changes) {
38102    updateLineForChanges(cm, view, lineN, getDimensions(cm));
38103    cm.curOp.forceUpdate = true;
38104  }
38105  if (!view)
38106    { view = updateExternalMeasurement(cm, line); }
38107
38108  var info = mapFromLineView(view, line, lineN);
38109  return {
38110    line: line, view: view, rect: null,
38111    map: info.map, cache: info.cache, before: info.before,
38112    hasHeights: false
38113  }
38114}
38115
38116// Given a prepared measurement object, measures the position of an
38117// actual character (or fetches it from the cache).
38118function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
38119  if (prepared.before) { ch = -1; }
38120  var key = ch + (bias || ""), found;
38121  if (prepared.cache.hasOwnProperty(key)) {
38122    found = prepared.cache[key];
38123  } else {
38124    if (!prepared.rect)
38125      { prepared.rect = prepared.view.text.getBoundingClientRect(); }
38126    if (!prepared.hasHeights) {
38127      ensureLineHeights(cm, prepared.view, prepared.rect);
38128      prepared.hasHeights = true;
38129    }
38130    found = measureCharInner(cm, prepared, ch, bias);
38131    if (!found.bogus) { prepared.cache[key] = found; }
38132  }
38133  return {left: found.left, right: found.right,
38134          top: varHeight ? found.rtop : found.top,
38135          bottom: varHeight ? found.rbottom : found.bottom}
38136}
38137
38138var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
38139
38140function nodeAndOffsetInLineMap(map$$1, ch, bias) {
38141  var node, start, end, collapse, mStart, mEnd;
38142  // First, search the line map for the text node corresponding to,
38143  // or closest to, the target character.
38144  for (var i = 0; i < map$$1.length; i += 3) {
38145    mStart = map$$1[i];
38146    mEnd = map$$1[i + 1];
38147    if (ch < mStart) {
38148      start = 0; end = 1;
38149      collapse = "left";
38150    } else if (ch < mEnd) {
38151      start = ch - mStart;
38152      end = start + 1;
38153    } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
38154      end = mEnd - mStart;
38155      start = end - 1;
38156      if (ch >= mEnd) { collapse = "right"; }
38157    }
38158    if (start != null) {
38159      node = map$$1[i + 2];
38160      if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
38161        { collapse = bias; }
38162      if (bias == "left" && start == 0)
38163        { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
38164          node = map$$1[(i -= 3) + 2];
38165          collapse = "left";
38166        } }
38167      if (bias == "right" && start == mEnd - mStart)
38168        { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
38169          node = map$$1[(i += 3) + 2];
38170          collapse = "right";
38171        } }
38172      break
38173    }
38174  }
38175  return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
38176}
38177
38178function getUsefulRect(rects, bias) {
38179  var rect = nullRect;
38180  if (bias == "left") { for (var i = 0; i < rects.length; i++) {
38181    if ((rect = rects[i]).left != rect.right) { break }
38182  } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
38183    if ((rect = rects[i$1]).left != rect.right) { break }
38184  } }
38185  return rect
38186}
38187
38188function measureCharInner(cm, prepared, ch, bias) {
38189  var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
38190  var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
38191
38192  var rect;
38193  if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
38194    for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
38195      while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
38196      while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
38197      if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
38198        { rect = node.parentNode.getBoundingClientRect(); }
38199      else
38200        { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
38201      if (rect.left || rect.right || start == 0) { break }
38202      end = start;
38203      start = start - 1;
38204      collapse = "right";
38205    }
38206    if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
38207  } else { // If it is a widget, simply get the box for the whole widget.
38208    if (start > 0) { collapse = bias = "right"; }
38209    var rects;
38210    if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
38211      { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
38212    else
38213      { rect = node.getBoundingClientRect(); }
38214  }
38215  if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
38216    var rSpan = node.parentNode.getClientRects()[0];
38217    if (rSpan)
38218      { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
38219    else
38220      { rect = nullRect; }
38221  }
38222
38223  var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
38224  var mid = (rtop + rbot) / 2;
38225  var heights = prepared.view.measure.heights;
38226  var i = 0;
38227  for (; i < heights.length - 1; i++)
38228    { if (mid < heights[i]) { break } }
38229  var top = i ? heights[i - 1] : 0, bot = heights[i];
38230  var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
38231                right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
38232                top: top, bottom: bot};
38233  if (!rect.left && !rect.right) { result.bogus = true; }
38234  if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
38235
38236  return result
38237}
38238
38239// Work around problem with bounding client rects on ranges being
38240// returned incorrectly when zoomed on IE10 and below.
38241function maybeUpdateRectForZooming(measure, rect) {
38242  if (!window.screen || screen.logicalXDPI == null ||
38243      screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
38244    { return rect }
38245  var scaleX = screen.logicalXDPI / screen.deviceXDPI;
38246  var scaleY = screen.logicalYDPI / screen.deviceYDPI;
38247  return {left: rect.left * scaleX, right: rect.right * scaleX,
38248          top: rect.top * scaleY, bottom: rect.bottom * scaleY}
38249}
38250
38251function clearLineMeasurementCacheFor(lineView) {
38252  if (lineView.measure) {
38253    lineView.measure.cache = {};
38254    lineView.measure.heights = null;
38255    if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
38256      { lineView.measure.caches[i] = {}; } }
38257  }
38258}
38259
38260function clearLineMeasurementCache(cm) {
38261  cm.display.externalMeasure = null;
38262  removeChildren(cm.display.lineMeasure);
38263  for (var i = 0; i < cm.display.view.length; i++)
38264    { clearLineMeasurementCacheFor(cm.display.view[i]); }
38265}
38266
38267function clearCaches(cm) {
38268  clearLineMeasurementCache(cm);
38269  cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
38270  if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
38271  cm.display.lineNumChars = null;
38272}
38273
38274function pageScrollX() {
38275  // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
38276  // which causes page_Offset and bounding client rects to use
38277  // different reference viewports and invalidate our calculations.
38278  if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
38279  return window.pageXOffset || (document.documentElement || document.body).scrollLeft
38280}
38281function pageScrollY() {
38282  if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
38283  return window.pageYOffset || (document.documentElement || document.body).scrollTop
38284}
38285
38286function widgetTopHeight(lineObj) {
38287  var height = 0;
38288  if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
38289    { height += widgetHeight(lineObj.widgets[i]); } } }
38290  return height
38291}
38292
38293// Converts a {top, bottom, left, right} box from line-local
38294// coordinates into another coordinate system. Context may be one of
38295// "line", "div" (display.lineDiv), "local"./null (editor), "window",
38296// or "page".
38297function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
38298  if (!includeWidgets) {
38299    var height = widgetTopHeight(lineObj);
38300    rect.top += height; rect.bottom += height;
38301  }
38302  if (context == "line") { return rect }
38303  if (!context) { context = "local"; }
38304  var yOff = heightAtLine(lineObj);
38305  if (context == "local") { yOff += paddingTop(cm.display); }
38306  else { yOff -= cm.display.viewOffset; }
38307  if (context == "page" || context == "window") {
38308    var lOff = cm.display.lineSpace.getBoundingClientRect();
38309    yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
38310    var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
38311    rect.left += xOff; rect.right += xOff;
38312  }
38313  rect.top += yOff; rect.bottom += yOff;
38314  return rect
38315}
38316
38317// Coverts a box from "div" coords to another coordinate system.
38318// Context may be "window", "page", "div", or "local"./null.
38319function fromCoordSystem(cm, coords, context) {
38320  if (context == "div") { return coords }
38321  var left = coords.left, top = coords.top;
38322  // First move into "page" coordinate system
38323  if (context == "page") {
38324    left -= pageScrollX();
38325    top -= pageScrollY();
38326  } else if (context == "local" || !context) {
38327    var localBox = cm.display.sizer.getBoundingClientRect();
38328    left += localBox.left;
38329    top += localBox.top;
38330  }
38331
38332  var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
38333  return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
38334}
38335
38336function charCoords(cm, pos, context, lineObj, bias) {
38337  if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
38338  return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
38339}
38340
38341// Returns a box for a given cursor position, which may have an
38342// 'other' property containing the position of the secondary cursor
38343// on a bidi boundary.
38344// A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
38345// and after `char - 1` in writing order of `char - 1`
38346// A cursor Pos(line, char, "after") is on the same visual line as `char`
38347// and before `char` in writing order of `char`
38348// Examples (upper-case letters are RTL, lower-case are LTR):
38349//     Pos(0, 1, ...)
38350//     before   after
38351// ab     a|b     a|b
38352// aB     a|B     aB|
38353// Ab     |Ab     A|b
38354// AB     B|A     B|A
38355// Every position after the last character on a line is considered to stick
38356// to the last character on the line.
38357function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
38358  lineObj = lineObj || getLine(cm.doc, pos.line);
38359  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
38360  function get(ch, right) {
38361    var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
38362    if (right) { m.left = m.right; } else { m.right = m.left; }
38363    return intoCoordSystem(cm, lineObj, m, context)
38364  }
38365  var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
38366  if (ch >= lineObj.text.length) {
38367    ch = lineObj.text.length;
38368    sticky = "before";
38369  } else if (ch <= 0) {
38370    ch = 0;
38371    sticky = "after";
38372  }
38373  if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
38374
38375  function getBidi(ch, partPos, invert) {
38376    var part = order[partPos], right = part.level == 1;
38377    return get(invert ? ch - 1 : ch, right != invert)
38378  }
38379  var partPos = getBidiPartAt(order, ch, sticky);
38380  var other = bidiOther;
38381  var val = getBidi(ch, partPos, sticky == "before");
38382  if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
38383  return val
38384}
38385
38386// Used to cheaply estimate the coordinates for a position. Used for
38387// intermediate scroll updates.
38388function estimateCoords(cm, pos) {
38389  var left = 0;
38390  pos = clipPos(cm.doc, pos);
38391  if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
38392  var lineObj = getLine(cm.doc, pos.line);
38393  var top = heightAtLine(lineObj) + paddingTop(cm.display);
38394  return {left: left, right: left, top: top, bottom: top + lineObj.height}
38395}
38396
38397// Positions returned by coordsChar contain some extra information.
38398// xRel is the relative x position of the input coordinates compared
38399// to the found position (so xRel > 0 means the coordinates are to
38400// the right of the character position, for example). When outside
38401// is true, that means the coordinates lie outside the line's
38402// vertical range.
38403function PosWithInfo(line, ch, sticky, outside, xRel) {
38404  var pos = Pos(line, ch, sticky);
38405  pos.xRel = xRel;
38406  if (outside) { pos.outside = true; }
38407  return pos
38408}
38409
38410// Compute the character position closest to the given coordinates.
38411// Input must be lineSpace-local ("div" coordinate system).
38412function coordsChar(cm, x, y) {
38413  var doc = cm.doc;
38414  y += cm.display.viewOffset;
38415  if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
38416  var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
38417  if (lineN > last)
38418    { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
38419  if (x < 0) { x = 0; }
38420
38421  var lineObj = getLine(doc, lineN);
38422  for (;;) {
38423    var found = coordsCharInner(cm, lineObj, lineN, x, y);
38424    var merged = collapsedSpanAtEnd(lineObj);
38425    var mergedPos = merged && merged.find(0, true);
38426    if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
38427      { lineN = lineNo(lineObj = mergedPos.to.line); }
38428    else
38429      { return found }
38430  }
38431}
38432
38433function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
38434  y -= widgetTopHeight(lineObj);
38435  var end = lineObj.text.length;
38436  var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
38437  end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
38438  return {begin: begin, end: end}
38439}
38440
38441function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
38442  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
38443  var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
38444  return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
38445}
38446
38447// Returns true if the given side of a box is after the given
38448// coordinates, in top-to-bottom, left-to-right order.
38449function boxIsAfter(box, x, y, left) {
38450  return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
38451}
38452
38453function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
38454  // Move y into line-local coordinate space
38455  y -= heightAtLine(lineObj);
38456  var preparedMeasure = prepareMeasureForLine(cm, lineObj);
38457  // When directly calling `measureCharPrepared`, we have to adjust
38458  // for the widgets at this line.
38459  var widgetHeight$$1 = widgetTopHeight(lineObj);
38460  var begin = 0, end = lineObj.text.length, ltr = true;
38461
38462  var order = getOrder(lineObj, cm.doc.direction);
38463  // If the line isn't plain left-to-right text, first figure out
38464  // which bidi section the coordinates fall into.
38465  if (order) {
38466    var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
38467                 (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
38468    ltr = part.level != 1;
38469    // The awkward -1 offsets are needed because findFirst (called
38470    // on these below) will treat its first bound as inclusive,
38471    // second as exclusive, but we want to actually address the
38472    // characters in the part's range
38473    begin = ltr ? part.from : part.to - 1;
38474    end = ltr ? part.to : part.from - 1;
38475  }
38476
38477  // A binary search to find the first character whose bounding box
38478  // starts after the coordinates. If we run across any whose box wrap
38479  // the coordinates, store that.
38480  var chAround = null, boxAround = null;
38481  var ch = findFirst(function (ch) {
38482    var box = measureCharPrepared(cm, preparedMeasure, ch);
38483    box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
38484    if (!boxIsAfter(box, x, y, false)) { return false }
38485    if (box.top <= y && box.left <= x) {
38486      chAround = ch;
38487      boxAround = box;
38488    }
38489    return true
38490  }, begin, end);
38491
38492  var baseX, sticky, outside = false;
vendor: 4,694 bytes, lines 38493-38599
38493  // If a box around the coordinates was found, use that
38494  if (boxAround) {
38495    // Distinguish coordinates nearer to the left or right side of the box
38496    var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
38497    ch = chAround + (atStart ? 0 : 1);
38498    sticky = atStart ? "after" : "before";
38499    baseX = atLeft ? boxAround.left : boxAround.right;
38500  } else {
38501    // (Adjust for extended bound, if necessary.)
38502    if (!ltr && (ch == end || ch == begin)) { ch++; }
38503    // To determine which side to associate with, get the box to the
38504    // left of the character and compare it's vertical position to the
38505    // coordinates
38506    sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
38507      (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
38508      "after" : "before";
38509    // Now get accurate coordinates for this place, in order to get a
38510    // base X position
38511    var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
38512    baseX = coords.left;
38513    outside = y < coords.top || y >= coords.bottom;
38514  }
38515
38516  ch = skipExtendingChars(lineObj.text, ch, 1);
38517  return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
38518}
38519
38520function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
38521  // Bidi parts are sorted left-to-right, and in a non-line-wrapping
38522  // situation, we can take this ordering to correspond to the visual
38523  // ordering. This finds the first part whose end is after the given
38524  // coordinates.
38525  var index = findFirst(function (i) {
38526    var part = order[i], ltr = part.level != 1;
38527    return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
38528                                   "line", lineObj, preparedMeasure), x, y, true)
38529  }, 0, order.length - 1);
38530  var part = order[index];
38531  // If this isn't the first part, the part's start is also after
38532  // the coordinates, and the coordinates aren't on the same line as
38533  // that start, move one part back.
38534  if (index > 0) {
38535    var ltr = part.level != 1;
38536    var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
38537                             "line", lineObj, preparedMeasure);
38538    if (boxIsAfter(start, x, y, true) && start.top > y)
38539      { part = order[index - 1]; }
38540  }
38541  return part
38542}
38543
38544function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
38545  // In a wrapped line, rtl text on wrapping boundaries can do things
38546  // that don't correspond to the ordering in our `order` array at
38547  // all, so a binary search doesn't work, and we want to return a
38548  // part that only spans one line so that the binary search in
38549  // coordsCharInner is safe. As such, we first find the extent of the
38550  // wrapped line, and then do a flat search in which we discard any
38551  // spans that aren't on the line.
38552  var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
38553  var begin = ref.begin;
38554  var end = ref.end;
38555  if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
38556  var part = null, closestDist = null;
38557  for (var i = 0; i < order.length; i++) {
38558    var p = order[i];
38559    if (p.from >= end || p.to <= begin) { continue }
38560    var ltr = p.level != 1;
38561    var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
38562    // Weigh against spans ending before this, so that they are only
38563    // picked if nothing ends after
38564    var dist = endX < x ? x - endX + 1e9 : endX - x;
38565    if (!part || closestDist > dist) {
38566      part = p;
38567      closestDist = dist;
38568    }
38569  }
38570  if (!part) { part = order[order.length - 1]; }
38571  // Clip the part to the wrapped line.
38572  if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
38573  if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
38574  return part
38575}
38576
38577var measureText;
38578// Compute the default text height.
38579function textHeight(display) {
38580  if (display.cachedTextHeight != null) { return display.cachedTextHeight }
38581  if (measureText == null) {
38582    measureText = elt("pre");
38583    // Measure a bunch of lines, for browsers that compute
38584    // fractional heights.
38585    for (var i = 0; i < 49; ++i) {
38586      measureText.appendChild(document.createTextNode("x"));
38587      measureText.appendChild(elt("br"));
38588    }
38589    measureText.appendChild(document.createTextNode("x"));
38590  }
38591  removeChildrenAndAdd(display.measure, measureText);
38592  var height = measureText.offsetHeight / 50;
38593  if (height > 3) { display.cachedTextHeight = height; }
38594  removeChildren(display.measure);
38595  return height || 1
38596}
38597
38598// Compute the default character width.
38599function charWidth(display) {
38600  if (display.cachedCharWidth != null) { return display.cachedCharWidth }
38601  var anchor = elt("span", "xxxxxxxxxx");
38602  var pre = elt("pre", [anchor]);
38603  removeChildrenAndAdd(display.measure, pre);
38604  var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
38605  if (width > 2) { display.cachedCharWidth = width; }
38606  return width || 10
38607}
38608
38609// Do a bulk-read of the DOM positions and sizes needed to draw the
38610// view, so that we don't interleave reading and writing to the DOM.
38611function getDimensions(cm) {
38612  var d = cm.display, left = {}, width = {};
38613  var gutterLeft = d.gutters.clientLeft;
38614  for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
38615    left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
38616    width[cm.options.gutters[i]] = n.clientWidth;
38617  }
38618  return {fixedPos: compensateForHScroll(d),
38619          gutterTotalWidth: d.gutters.offsetWidth,
38620          gutterLeft: left,
38621          gutterWidth: width,
38622          wrapperWidth: d.wrapper.clientWidth}
38623}
38624
38625// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
38626// but using getBoundingClientRect to get a sub-pixel-accurate
38627// result.
38628function compensateForHScroll(display) {
vendor: 95,213 bytes, lines 38629-41094
38629  return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
38630}
38631
38632// Returns a function that estimates the height of a line, to use as
38633// first approximation until the line becomes visible (and is thus
38634// properly measurable).
38635function estimateHeight(cm) {
38636  var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
38637  var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
38638  return function (line) {
38639    if (lineIsHidden(cm.doc, line)) { return 0 }
38640
38641    var widgetsHeight = 0;
38642    if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
38643      if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
38644    } }
38645
38646    if (wrapping)
38647      { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
38648    else
38649      { return widgetsHeight + th }
38650  }
38651}
38652
38653function estimateLineHeights(cm) {
38654  var doc = cm.doc, est = estimateHeight(cm);
38655  doc.iter(function (line) {
38656    var estHeight = est(line);
38657    if (estHeight != line.height) { updateLineHeight(line, estHeight); }
38658  });
38659}
38660
38661// Given a mouse event, find the corresponding position. If liberal
38662// is false, it checks whether a gutter or scrollbar was clicked,
38663// and returns null if it was. forRect is used by rectangular
38664// selections, and tries to estimate a character position even for
38665// coordinates beyond the right of the text.
38666function posFromMouse(cm, e, liberal, forRect) {
38667  var display = cm.display;
38668  if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
38669
38670  var x, y, space = display.lineSpace.getBoundingClientRect();
38671  // Fails unpredictably on IE[67] when mouse is dragged around quickly.
38672  try { x = e.clientX - space.left; y = e.clientY - space.top; }
38673  catch (e) { return null }
38674  var coords = coordsChar(cm, x, y), line;
38675  if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
38676    var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
38677    coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
38678  }
38679  return coords
38680}
38681
38682// Find the view element corresponding to a given line. Return null
38683// when the line isn't visible.
38684function findViewIndex(cm, n) {
38685  if (n >= cm.display.viewTo) { return null }
38686  n -= cm.display.viewFrom;
38687  if (n < 0) { return null }
38688  var view = cm.display.view;
38689  for (var i = 0; i < view.length; i++) {
38690    n -= view[i].size;
38691    if (n < 0) { return i }
38692  }
38693}
38694
38695function updateSelection(cm) {
38696  cm.display.input.showSelection(cm.display.input.prepareSelection());
38697}
38698
38699function prepareSelection(cm, primary) {
38700  if ( primary === void 0 ) primary = true;
38701
38702  var doc = cm.doc, result = {};
38703  var curFragment = result.cursors = document.createDocumentFragment();
38704  var selFragment = result.selection = document.createDocumentFragment();
38705
38706  for (var i = 0; i < doc.sel.ranges.length; i++) {
38707    if (!primary && i == doc.sel.primIndex) { continue }
38708    var range$$1 = doc.sel.ranges[i];
38709    if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
38710    var collapsed = range$$1.empty();
38711    if (collapsed || cm.options.showCursorWhenSelecting)
38712      { drawSelectionCursor(cm, range$$1.head, curFragment); }
38713    if (!collapsed)
38714      { drawSelectionRange(cm, range$$1, selFragment); }
38715  }
38716  return result
38717}
38718
38719// Draws a cursor for the given range
38720function drawSelectionCursor(cm, head, output) {
38721  var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
38722
38723  var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
38724  cursor.style.left = pos.left + "px";
38725  cursor.style.top = pos.top + "px";
38726  cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
38727
38728  if (pos.other) {
38729    // Secondary cursor, shown when on a 'jump' in bi-directional text
38730    var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
38731    otherCursor.style.display = "";
38732    otherCursor.style.left = pos.other.left + "px";
38733    otherCursor.style.top = pos.other.top + "px";
38734    otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
38735  }
38736}
38737
38738function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
38739
38740// Draws the given range as a highlighted selection
38741function drawSelectionRange(cm, range$$1, output) {
38742  var display = cm.display, doc = cm.doc;
38743  var fragment = document.createDocumentFragment();
38744  var padding = paddingH(cm.display), leftSide = padding.left;
38745  var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
38746  var docLTR = doc.direction == "ltr";
38747
38748  function add(left, top, width, bottom) {
38749    if (top < 0) { top = 0; }
38750    top = Math.round(top);
38751    bottom = Math.round(bottom);
38752    fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n                             top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n                             height: " + (bottom - top) + "px")));
38753  }
38754
38755  function drawForLine(line, fromArg, toArg) {
38756    var lineObj = getLine(doc, line);
38757    var lineLen = lineObj.text.length;
38758    var start, end;
38759    function coords(ch, bias) {
38760      return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
38761    }
38762
38763    function wrapX(pos, dir, side) {
38764      var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
38765      var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
38766      var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
38767      return coords(ch, prop)[prop]
38768    }
38769
38770    var order = getOrder(lineObj, doc.direction);
38771    iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
38772      var ltr = dir == "ltr";
38773      var fromPos = coords(from, ltr ? "left" : "right");
38774      var toPos = coords(to - 1, ltr ? "right" : "left");
38775
38776      var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
38777      var first = i == 0, last = !order || i == order.length - 1;
38778      if (toPos.top - fromPos.top <= 3) { // Single line
38779        var openLeft = (docLTR ? openStart : openEnd) && first;
38780        var openRight = (docLTR ? openEnd : openStart) && last;
38781        var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
38782        var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
38783        add(left, fromPos.top, right - left, fromPos.bottom);
38784      } else { // Multiple lines
38785        var topLeft, topRight, botLeft, botRight;
38786        if (ltr) {
38787          topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
38788          topRight = docLTR ? rightSide : wrapX(from, dir, "before");
38789          botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
38790          botRight = docLTR && openEnd && last ? rightSide : toPos.right;
38791        } else {
38792          topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
38793          topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
38794          botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
38795          botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
38796        }
38797        add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
38798        if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
38799        add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
38800      }
38801
38802      if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
38803      if (cmpCoords(toPos, start) < 0) { start = toPos; }
38804      if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
38805      if (cmpCoords(toPos, end) < 0) { end = toPos; }
38806    });
38807    return {start: start, end: end}
38808  }
38809
38810  var sFrom = range$$1.from(), sTo = range$$1.to();
38811  if (sFrom.line == sTo.line) {
38812    drawForLine(sFrom.line, sFrom.ch, sTo.ch);
38813  } else {
38814    var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
38815    var singleVLine = visualLine(fromLine) == visualLine(toLine);
38816    var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
38817    var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
38818    if (singleVLine) {
38819      if (leftEnd.top < rightStart.top - 2) {
38820        add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
38821        add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
38822      } else {
38823        add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
38824      }
38825    }
38826    if (leftEnd.bottom < rightStart.top)
38827      { add(leftSide, leftEnd.bottom, null, rightStart.top); }
38828  }
38829
38830  output.appendChild(fragment);
38831}
38832
38833// Cursor-blinking
38834function restartBlink(cm) {
38835  if (!cm.state.focused) { return }
38836  var display = cm.display;
38837  clearInterval(display.blinker);
38838  var on = true;
38839  display.cursorDiv.style.visibility = "";
38840  if (cm.options.cursorBlinkRate > 0)
38841    { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
38842      cm.options.cursorBlinkRate); }
38843  else if (cm.options.cursorBlinkRate < 0)
38844    { display.cursorDiv.style.visibility = "hidden"; }
38845}
38846
38847function ensureFocus(cm) {
38848  if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
38849}
38850
38851function delayBlurEvent(cm) {
38852  cm.state.delayingBlurEvent = true;
38853  setTimeout(function () { if (cm.state.delayingBlurEvent) {
38854    cm.state.delayingBlurEvent = false;
38855    onBlur(cm);
38856  } }, 100);
38857}
38858
38859function onFocus(cm, e) {
38860  if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
38861
38862  if (cm.options.readOnly == "nocursor") { return }
38863  if (!cm.state.focused) {
38864    signal(cm, "focus", cm, e);
38865    cm.state.focused = true;
38866    addClass(cm.display.wrapper, "CodeMirror-focused");
38867    // This test prevents this from firing when a context
38868    // menu is closed (since the input reset would kill the
38869    // select-all detection hack)
38870    if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
38871      cm.display.input.reset();
38872      if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
38873    }
38874    cm.display.input.receivedFocus();
38875  }
38876  restartBlink(cm);
38877}
38878function onBlur(cm, e) {
38879  if (cm.state.delayingBlurEvent) { return }
38880
38881  if (cm.state.focused) {
38882    signal(cm, "blur", cm, e);
38883    cm.state.focused = false;
38884    rmClass(cm.display.wrapper, "CodeMirror-focused");
38885  }
38886  clearInterval(cm.display.blinker);
38887  setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
38888}
38889
38890// Read the actual heights of the rendered lines, and update their
38891// stored heights to match.
38892function updateHeightsInViewport(cm) {
38893  var display = cm.display;
38894  var prevBottom = display.lineDiv.offsetTop;
38895  for (var i = 0; i < display.view.length; i++) {
38896    var cur = display.view[i], height = (void 0);
38897    if (cur.hidden) { continue }
38898    if (ie && ie_version < 8) {
38899      var bot = cur.node.offsetTop + cur.node.offsetHeight;
38900      height = bot - prevBottom;
38901      prevBottom = bot;
38902    } else {
38903      var box = cur.node.getBoundingClientRect();
38904      height = box.bottom - box.top;
38905    }
38906    var diff = cur.line.height - height;
38907    if (height < 2) { height = textHeight(display); }
38908    if (diff > .005 || diff < -.005) {
38909      updateLineHeight(cur.line, height);
38910      updateWidgetHeight(cur.line);
38911      if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
38912        { updateWidgetHeight(cur.rest[j]); } }
38913    }
38914  }
38915}
38916
38917// Read and store the height of line widgets associated with the
38918// given line.
38919function updateWidgetHeight(line) {
38920  if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
38921    var w = line.widgets[i], parent = w.node.parentNode;
38922    if (parent) { w.height = parent.offsetHeight; }
38923  } }
38924}
38925
38926// Compute the lines that are visible in a given viewport (defaults
38927// the the current scroll position). viewport may contain top,
38928// height, and ensure (see op.scrollToPos) properties.
38929function visibleLines(display, doc, viewport) {
38930  var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
38931  top = Math.floor(top - paddingTop(display));
38932  var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
38933
38934  var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
38935  // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
38936  // forces those lines into the viewport (if possible).
38937  if (viewport && viewport.ensure) {
38938    var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
38939    if (ensureFrom < from) {
38940      from = ensureFrom;
38941      to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
38942    } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
38943      from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
38944      to = ensureTo;
38945    }
38946  }
38947  return {from: from, to: Math.max(to, from + 1)}
38948}
38949
38950// Re-align line numbers and gutter marks to compensate for
38951// horizontal scrolling.
38952function alignHorizontally(cm) {
38953  var display = cm.display, view = display.view;
38954  if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
38955  var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
38956  var gutterW = display.gutters.offsetWidth, left = comp + "px";
38957  for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
38958    if (cm.options.fixedGutter) {
38959      if (view[i].gutter)
38960        { view[i].gutter.style.left = left; }
38961      if (view[i].gutterBackground)
38962        { view[i].gutterBackground.style.left = left; }
38963    }
38964    var align = view[i].alignable;
38965    if (align) { for (var j = 0; j < align.length; j++)
38966      { align[j].style.left = left; } }
38967  } }
38968  if (cm.options.fixedGutter)
38969    { display.gutters.style.left = (comp + gutterW) + "px"; }
38970}
38971
38972// Used to ensure that the line number gutter is still the right
38973// size for the current document size. Returns true when an update
38974// is needed.
38975function maybeUpdateLineNumberWidth(cm) {
38976  if (!cm.options.lineNumbers) { return false }
38977  var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
38978  if (last.length != display.lineNumChars) {
38979    var test = display.measure.appendChild(elt("div", [elt("div", last)],
38980                                               "CodeMirror-linenumber CodeMirror-gutter-elt"));
38981    var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
38982    display.lineGutter.style.width = "";
38983    display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
38984    display.lineNumWidth = display.lineNumInnerWidth + padding;
38985    display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
38986    display.lineGutter.style.width = display.lineNumWidth + "px";
38987    updateGutterSpace(cm);
38988    return true
38989  }
38990  return false
38991}
38992
38993// SCROLLING THINGS INTO VIEW
38994
38995// If an editor sits on the top or bottom of the window, partially
38996// scrolled out of view, this ensures that the cursor is visible.
38997function maybeScrollWindow(cm, rect) {
38998  if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
38999
39000  var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
39001  if (rect.top + box.top < 0) { doScroll = true; }
39002  else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
39003  if (doScroll != null && !phantom) {
39004    var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n                         top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n                         height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n                         left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
39005    cm.display.lineSpace.appendChild(scrollNode);
39006    scrollNode.scrollIntoView(doScroll);
39007    cm.display.lineSpace.removeChild(scrollNode);
39008  }
39009}
39010
39011// Scroll a given position into view (immediately), verifying that
39012// it actually became visible (as line heights are accurately
39013// measured, the position of something may 'drift' during drawing).
39014function scrollPosIntoView(cm, pos, end, margin) {
39015  if (margin == null) { margin = 0; }
39016  var rect;
39017  if (!cm.options.lineWrapping && pos == end) {
39018    // Set pos and end to the cursor positions around the character pos sticks to
39019    // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
39020    // If pos == Pos(_, 0, "before"), pos and end are unchanged
39021    pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
39022    end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
39023  }
39024  for (var limit = 0; limit < 5; limit++) {
39025    var changed = false;
39026    var coords = cursorCoords(cm, pos);
39027    var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
39028    rect = {left: Math.min(coords.left, endCoords.left),
39029            top: Math.min(coords.top, endCoords.top) - margin,
39030            right: Math.max(coords.left, endCoords.left),
39031            bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
39032    var scrollPos = calculateScrollPos(cm, rect);
39033    var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
39034    if (scrollPos.scrollTop != null) {
39035      updateScrollTop(cm, scrollPos.scrollTop);
39036      if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
39037    }
39038    if (scrollPos.scrollLeft != null) {
39039      setScrollLeft(cm, scrollPos.scrollLeft);
39040      if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
39041    }
39042    if (!changed) { break }
39043  }
39044  return rect
39045}
39046
39047// Scroll a given set of coordinates into view (immediately).
39048function scrollIntoView(cm, rect) {
39049  var scrollPos = calculateScrollPos(cm, rect);
39050  if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
39051  if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
39052}
39053
39054// Calculate a new scroll position needed to scroll the given
39055// rectangle into view. Returns an object with scrollTop and
39056// scrollLeft properties. When these are undefined, the
39057// vertical/horizontal position does not need to be adjusted.
39058function calculateScrollPos(cm, rect) {
39059  var display = cm.display, snapMargin = textHeight(cm.display);
39060  if (rect.top < 0) { rect.top = 0; }
39061  var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
39062  var screen = displayHeight(cm), result = {};
39063  if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
39064  var docBottom = cm.doc.height + paddingVert(display);
39065  var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
39066  if (rect.top < screentop) {
39067    result.scrollTop = atTop ? 0 : rect.top;
39068  } else if (rect.bottom > screentop + screen) {
39069    var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
39070    if (newTop != screentop) { result.scrollTop = newTop; }
39071  }
39072
39073  var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
39074  var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
39075  var tooWide = rect.right - rect.left > screenw;
39076  if (tooWide) { rect.right = rect.left + screenw; }
39077  if (rect.left < 10)
39078    { result.scrollLeft = 0; }
39079  else if (rect.left < screenleft)
39080    { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
39081  else if (rect.right > screenw + screenleft - 3)
39082    { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
39083  return result
39084}
39085
39086// Store a relative adjustment to the scroll position in the current
39087// operation (to be applied when the operation finishes).
39088function addToScrollTop(cm, top) {
39089  if (top == null) { return }
39090  resolveScrollToPos(cm);
39091  cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
39092}
39093
39094// Make sure that at the end of the operation the current cursor is
39095// shown.
39096function ensureCursorVisible(cm) {
39097  resolveScrollToPos(cm);
39098  var cur = cm.getCursor();
39099  cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
39100}
39101
39102function scrollToCoords(cm, x, y) {
39103  if (x != null || y != null) { resolveScrollToPos(cm); }
39104  if (x != null) { cm.curOp.scrollLeft = x; }
39105  if (y != null) { cm.curOp.scrollTop = y; }
39106}
39107
39108function scrollToRange(cm, range$$1) {
39109  resolveScrollToPos(cm);
39110  cm.curOp.scrollToPos = range$$1;
39111}
39112
39113// When an operation has its scrollToPos property set, and another
39114// scroll action is applied before the end of the operation, this
39115// 'simulates' scrolling that position into view in a cheap way, so
39116// that the effect of intermediate scroll commands is not ignored.
39117function resolveScrollToPos(cm) {
39118  var range$$1 = cm.curOp.scrollToPos;
39119  if (range$$1) {
39120    cm.curOp.scrollToPos = null;
39121    var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
39122    scrollToCoordsRange(cm, from, to, range$$1.margin);
39123  }
39124}
39125
39126function scrollToCoordsRange(cm, from, to, margin) {
39127  var sPos = calculateScrollPos(cm, {
39128    left: Math.min(from.left, to.left),
39129    top: Math.min(from.top, to.top) - margin,
39130    right: Math.max(from.right, to.right),
39131    bottom: Math.max(from.bottom, to.bottom) + margin
39132  });
39133  scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
39134}
39135
39136// Sync the scrollable area and scrollbars, ensure the viewport
39137// covers the visible area.
39138function updateScrollTop(cm, val) {
39139  if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
39140  if (!gecko) { updateDisplaySimple(cm, {top: val}); }
39141  setScrollTop(cm, val, true);
39142  if (gecko) { updateDisplaySimple(cm); }
39143  startWorker(cm, 100);
39144}
39145
39146function setScrollTop(cm, val, forceScroll) {
39147  val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
39148  if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
39149  cm.doc.scrollTop = val;
39150  cm.display.scrollbars.setScrollTop(val);
39151  if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
39152}
39153
39154// Sync scroller and scrollbar, ensure the gutter elements are
39155// aligned.
39156function setScrollLeft(cm, val, isScroller, forceScroll) {
39157  val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
39158  if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
39159  cm.doc.scrollLeft = val;
39160  alignHorizontally(cm);
39161  if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
39162  cm.display.scrollbars.setScrollLeft(val);
39163}
39164
39165// SCROLLBARS
39166
39167// Prepare DOM reads needed to update the scrollbars. Done in one
39168// shot to minimize update/measure roundtrips.
39169function measureForScrollbars(cm) {
39170  var d = cm.display, gutterW = d.gutters.offsetWidth;
39171  var docH = Math.round(cm.doc.height + paddingVert(cm.display));
39172  return {
39173    clientHeight: d.scroller.clientHeight,
39174    viewHeight: d.wrapper.clientHeight,
39175    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
39176    viewWidth: d.wrapper.clientWidth,
39177    barLeft: cm.options.fixedGutter ? gutterW : 0,
39178    docHeight: docH,
39179    scrollHeight: docH + scrollGap(cm) + d.barHeight,
39180    nativeBarWidth: d.nativeBarWidth,
39181    gutterWidth: gutterW
39182  }
39183}
39184
39185var NativeScrollbars = function(place, scroll, cm) {
39186  this.cm = cm;
39187  var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
39188  var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
39189  place(vert); place(horiz);
39190
39191  on(vert, "scroll", function () {
39192    if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
39193  });
39194  on(horiz, "scroll", function () {
39195    if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
39196  });
39197
39198  this.checkedZeroWidth = false;
39199  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
39200  if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
39201};
39202
39203NativeScrollbars.prototype.update = function (measure) {
39204  var needsH = measure.scrollWidth > measure.clientWidth + 1;
39205  var needsV = measure.scrollHeight > measure.clientHeight + 1;
39206  var sWidth = measure.nativeBarWidth;
39207
39208  if (needsV) {
39209    this.vert.style.display = "block";
39210    this.vert.style.bottom = needsH ? sWidth + "px" : "0";
39211    var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
39212    // A bug in IE8 can cause this value to be negative, so guard it.
39213    this.vert.firstChild.style.height =
39214      Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
39215  } else {
39216    this.vert.style.display = "";
39217    this.vert.firstChild.style.height = "0";
39218  }
39219
39220  if (needsH) {
39221    this.horiz.style.display = "block";
39222    this.horiz.style.right = needsV ? sWidth + "px" : "0";
39223    this.horiz.style.left = measure.barLeft + "px";
39224    var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
39225    this.horiz.firstChild.style.width =
39226      Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
39227  } else {
39228    this.horiz.style.display = "";
39229    this.horiz.firstChild.style.width = "0";
39230  }
39231
39232  if (!this.checkedZeroWidth && measure.clientHeight > 0) {
39233    if (sWidth == 0) { this.zeroWidthHack(); }
39234    this.checkedZeroWidth = true;
39235  }
39236
39237  return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
39238};
39239
39240NativeScrollbars.prototype.setScrollLeft = function (pos) {
39241  if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
39242  if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
39243};
39244
39245NativeScrollbars.prototype.setScrollTop = function (pos) {
39246  if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
39247  if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
39248};
39249
39250NativeScrollbars.prototype.zeroWidthHack = function () {
39251  var w = mac && !mac_geMountainLion ? "12px" : "18px";
39252  this.horiz.style.height = this.vert.style.width = w;
39253  this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
39254  this.disableHoriz = new Delayed;
39255  this.disableVert = new Delayed;
39256};
39257
39258NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
39259  bar.style.pointerEvents = "auto";
39260  function maybeDisable() {
39261    // To find out whether the scrollbar is still visible, we
39262    // check whether the element under the pixel in the bottom
39263    // right corner of the scrollbar box is the scrollbar box
39264    // itself (when the bar is still visible) or its filler child
39265    // (when the bar is hidden). If it is still visible, we keep
39266    // it enabled, if it's hidden, we disable pointer events.
39267    var box = bar.getBoundingClientRect();
39268    var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
39269        : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
39270    if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
39271    else { delay.set(1000, maybeDisable); }
39272  }
39273  delay.set(1000, maybeDisable);
39274};
39275
39276NativeScrollbars.prototype.clear = function () {
39277  var parent = this.horiz.parentNode;
39278  parent.removeChild(this.horiz);
39279  parent.removeChild(this.vert);
39280};
39281
39282var NullScrollbars = function () {};
39283
39284NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
39285NullScrollbars.prototype.setScrollLeft = function () {};
39286NullScrollbars.prototype.setScrollTop = function () {};
39287NullScrollbars.prototype.clear = function () {};
39288
39289function updateScrollbars(cm, measure) {
39290  if (!measure) { measure = measureForScrollbars(cm); }
39291  var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
39292  updateScrollbarsInner(cm, measure);
39293  for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
39294    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
39295      { updateHeightsInViewport(cm); }
39296    updateScrollbarsInner(cm, measureForScrollbars(cm));
39297    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
39298  }
39299}
39300
39301// Re-synchronize the fake scrollbars with the actual size of the
39302// content.
39303function updateScrollbarsInner(cm, measure) {
39304  var d = cm.display;
39305  var sizes = d.scrollbars.update(measure);
39306
39307  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
39308  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
39309  d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
39310
39311  if (sizes.right && sizes.bottom) {
39312    d.scrollbarFiller.style.display = "block";
39313    d.scrollbarFiller.style.height = sizes.bottom + "px";
39314    d.scrollbarFiller.style.width = sizes.right + "px";
39315  } else { d.scrollbarFiller.style.display = ""; }
39316  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
39317    d.gutterFiller.style.display = "block";
39318    d.gutterFiller.style.height = sizes.bottom + "px";
39319    d.gutterFiller.style.width = measure.gutterWidth + "px";
39320  } else { d.gutterFiller.style.display = ""; }
39321}
39322
39323var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
39324
39325function initScrollbars(cm) {
39326  if (cm.display.scrollbars) {
39327    cm.display.scrollbars.clear();
39328    if (cm.display.scrollbars.addClass)
39329      { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
39330  }
39331
39332  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
39333    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
39334    // Prevent clicks in the scrollbars from killing focus
39335    on(node, "mousedown", function () {
39336      if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
39337    });
39338    node.setAttribute("cm-not-content", "true");
39339  }, function (pos, axis) {
39340    if (axis == "horizontal") { setScrollLeft(cm, pos); }
39341    else { updateScrollTop(cm, pos); }
39342  }, cm);
39343  if (cm.display.scrollbars.addClass)
39344    { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
39345}
39346
39347// Operations are used to wrap a series of changes to the editor
39348// state in such a way that each change won't have to update the
39349// cursor and display (which would be awkward, slow, and
39350// error-prone). Instead, display updates are batched and then all
39351// combined and executed at once.
39352
39353var nextOpId = 0;
39354// Start a new operation.
39355function startOperation(cm) {
39356  cm.curOp = {
39357    cm: cm,
39358    viewChanged: false,      // Flag that indicates that lines might need to be redrawn
39359    startHeight: cm.doc.height, // Used to detect need to update scrollbar
39360    forceUpdate: false,      // Used to force a redraw
39361    updateInput: null,       // Whether to reset the input textarea
39362    typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
39363    changeObjs: null,        // Accumulated changes, for firing change events
39364    cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
39365    cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
39366    selectionChanged: false, // Whether the selection needs to be redrawn
39367    updateMaxLine: false,    // Set when the widest line needs to be determined anew
39368    scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
39369    scrollToPos: null,       // Used to scroll to a specific position
39370    focus: false,
39371    id: ++nextOpId           // Unique ID
39372  };
39373  pushOperation(cm.curOp);
39374}
39375
39376// Finish an operation, updating the display and signalling delayed events
39377function endOperation(cm) {
39378  var op = cm.curOp;
39379  finishOperation(op, function (group) {
39380    for (var i = 0; i < group.ops.length; i++)
39381      { group.ops[i].cm.curOp = null; }
39382    endOperations(group);
39383  });
39384}
39385
39386// The DOM updates done when an operation finishes are batched so
39387// that the minimum number of relayouts are required.
39388function endOperations(group) {
39389  var ops = group.ops;
39390  for (var i = 0; i < ops.length; i++) // Read DOM
39391    { endOperation_R1(ops[i]); }
39392  for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
39393    { endOperation_W1(ops[i$1]); }
39394  for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
39395    { endOperation_R2(ops[i$2]); }
39396  for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
39397    { endOperation_W2(ops[i$3]); }
39398  for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
39399    { endOperation_finish(ops[i$4]); }
39400}
39401
39402function endOperation_R1(op) {
39403  var cm = op.cm, display = cm.display;
39404  maybeClipScrollbars(cm);
39405  if (op.updateMaxLine) { findMaxLine(cm); }
39406
39407  op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
39408    op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
39409                       op.scrollToPos.to.line >= display.viewTo) ||
39410    display.maxLineChanged && cm.options.lineWrapping;
39411  op.update = op.mustUpdate &&
39412    new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
39413}
39414
39415function endOperation_W1(op) {
39416  op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
39417}
39418
39419function endOperation_R2(op) {
39420  var cm = op.cm, display = cm.display;
39421  if (op.updatedDisplay) { updateHeightsInViewport(cm); }
39422
39423  op.barMeasure = measureForScrollbars(cm);
39424
39425  // If the max line changed since it was last measured, measure it,
39426  // and ensure the document's width matches it.
39427  // updateDisplay_W2 will use these properties to do the actual resizing
39428  if (display.maxLineChanged && !cm.options.lineWrapping) {
39429    op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
39430    cm.display.sizerWidth = op.adjustWidthTo;
39431    op.barMeasure.scrollWidth =
39432      Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
39433    op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
39434  }
39435
39436  if (op.updatedDisplay || op.selectionChanged)
39437    { op.preparedSelection = display.input.prepareSelection(); }
39438}
39439
39440function endOperation_W2(op) {
39441  var cm = op.cm;
39442
39443  if (op.adjustWidthTo != null) {
39444    cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
39445    if (op.maxScrollLeft < cm.doc.scrollLeft)
39446      { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
39447    cm.display.maxLineChanged = false;
39448  }
39449
39450  var takeFocus = op.focus && op.focus == activeElt();
39451  if (op.preparedSelection)
39452    { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
39453  if (op.updatedDisplay || op.startHeight != cm.doc.height)
39454    { updateScrollbars(cm, op.barMeasure); }
39455  if (op.updatedDisplay)
39456    { setDocumentHeight(cm, op.barMeasure); }
39457
39458  if (op.selectionChanged) { restartBlink(cm); }
39459
39460  if (cm.state.focused && op.updateInput)
39461    { cm.display.input.reset(op.typing); }
39462  if (takeFocus) { ensureFocus(op.cm); }
39463}
39464
39465function endOperation_finish(op) {
39466  var cm = op.cm, display = cm.display, doc = cm.doc;
39467
39468  if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
39469
39470  // Abort mouse wheel delta measurement, when scrolling explicitly
39471  if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
39472    { display.wheelStartX = display.wheelStartY = null; }
39473
39474  // Propagate the scroll position to the actual DOM scroller
39475  if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
39476
39477  if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
39478  // If we need to scroll a specific position into view, do so.
39479  if (op.scrollToPos) {
39480    var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
39481                                 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
39482    maybeScrollWindow(cm, rect);
39483  }
39484
39485  // Fire events for markers that are hidden/unidden by editing or
39486  // undoing
39487  var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
39488  if (hidden) { for (var i = 0; i < hidden.length; ++i)
39489    { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
39490  if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
39491    { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
39492
39493  if (display.wrapper.offsetHeight)
39494    { doc.scrollTop = cm.display.scroller.scrollTop; }
39495
39496  // Fire change events, and delayed event handlers
39497  if (op.changeObjs)
39498    { signal(cm, "changes", cm, op.changeObjs); }
39499  if (op.update)
39500    { op.update.finish(); }
39501}
39502
39503// Run the given function in an operation
39504function runInOp(cm, f) {
39505  if (cm.curOp) { return f() }
39506  startOperation(cm);
39507  try { return f() }
39508  finally { endOperation(cm); }
39509}
39510// Wraps a function in an operation. Returns the wrapped function.
39511function operation(cm, f) {
39512  return function() {
39513    if (cm.curOp) { return f.apply(cm, arguments) }
39514    startOperation(cm);
39515    try { return f.apply(cm, arguments) }
39516    finally { endOperation(cm); }
39517  }
39518}
39519// Used to add methods to editor and doc instances, wrapping them in
39520// operations.
39521function methodOp(f) {
39522  return function() {
39523    if (this.curOp) { return f.apply(this, arguments) }
39524    startOperation(this);
39525    try { return f.apply(this, arguments) }
39526    finally { endOperation(this); }
39527  }
39528}
39529function docMethodOp(f) {
39530  return function() {
39531    var cm = this.cm;
39532    if (!cm || cm.curOp) { return f.apply(this, arguments) }
39533    startOperation(cm);
39534    try { return f.apply(this, arguments) }
39535    finally { endOperation(cm); }
39536  }
39537}
39538
39539// Updates the display.view data structure for a given change to the
39540// document. From and to are in pre-change coordinates. Lendiff is
39541// the amount of lines added or subtracted by the change. This is
39542// used for changes that span multiple lines, or change the way
39543// lines are divided into visual lines. regLineChange (below)
39544// registers single-line changes.
39545function regChange(cm, from, to, lendiff) {
39546  if (from == null) { from = cm.doc.first; }
39547  if (to == null) { to = cm.doc.first + cm.doc.size; }
39548  if (!lendiff) { lendiff = 0; }
39549
39550  var display = cm.display;
39551  if (lendiff && to < display.viewTo &&
39552      (display.updateLineNumbers == null || display.updateLineNumbers > from))
39553    { display.updateLineNumbers = from; }
39554
39555  cm.curOp.viewChanged = true;
39556
39557  if (from >= display.viewTo) { // Change after
39558    if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
39559      { resetView(cm); }
39560  } else if (to <= display.viewFrom) { // Change before
39561    if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
39562      resetView(cm);
39563    } else {
39564      display.viewFrom += lendiff;
39565      display.viewTo += lendiff;
39566    }
39567  } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
39568    resetView(cm);
39569  } else if (from <= display.viewFrom) { // Top overlap
39570    var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
39571    if (cut) {
39572      display.view = display.view.slice(cut.index);
39573      display.viewFrom = cut.lineN;
39574      display.viewTo += lendiff;
39575    } else {
39576      resetView(cm);
39577    }
39578  } else if (to >= display.viewTo) { // Bottom overlap
39579    var cut$1 = viewCuttingPoint(cm, from, from, -1);
39580    if (cut$1) {
39581      display.view = display.view.slice(0, cut$1.index);
39582      display.viewTo = cut$1.lineN;
39583    } else {
39584      resetView(cm);
39585    }
39586  } else { // Gap in the middle
39587    var cutTop = viewCuttingPoint(cm, from, from, -1);
39588    var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
39589    if (cutTop && cutBot) {
39590      display.view = display.view.slice(0, cutTop.index)
39591        .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
39592        .concat(display.view.slice(cutBot.index));
39593      display.viewTo += lendiff;
39594    } else {
39595      resetView(cm);
39596    }
39597  }
39598
39599  var ext = display.externalMeasured;
39600  if (ext) {
39601    if (to < ext.lineN)
39602      { ext.lineN += lendiff; }
39603    else if (from < ext.lineN + ext.size)
39604      { display.externalMeasured = null; }
39605  }
39606}
39607
39608// Register a change to a single line. Type must be one of "text",
39609// "gutter", "class", "widget"
39610function regLineChange(cm, line, type) {
39611  cm.curOp.viewChanged = true;
39612  var display = cm.display, ext = cm.display.externalMeasured;
39613  if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
39614    { display.externalMeasured = null; }
39615
39616  if (line < display.viewFrom || line >= display.viewTo) { return }
39617  var lineView = display.view[findViewIndex(cm, line)];
39618  if (lineView.node == null) { return }
39619  var arr = lineView.changes || (lineView.changes = []);
39620  if (indexOf(arr, type) == -1) { arr.push(type); }
39621}
39622
39623// Clear the view.
39624function resetView(cm) {
39625  cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
39626  cm.display.view = [];
39627  cm.display.viewOffset = 0;
39628}
39629
39630function viewCuttingPoint(cm, oldN, newN, dir) {
39631  var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
39632  if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
39633    { return {index: index, lineN: newN} }
39634  var n = cm.display.viewFrom;
39635  for (var i = 0; i < index; i++)
39636    { n += view[i].size; }
39637  if (n != oldN) {
39638    if (dir > 0) {
39639      if (index == view.length - 1) { return null }
39640      diff = (n + view[index].size) - oldN;
39641      index++;
39642    } else {
39643      diff = n - oldN;
39644    }
39645    oldN += diff; newN += diff;
39646  }
39647  while (visualLineNo(cm.doc, newN) != newN) {
39648    if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
39649    newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
39650    index += dir;
39651  }
39652  return {index: index, lineN: newN}
39653}
39654
39655// Force the view to cover a given range, adding empty view element
39656// or clipping off existing ones as needed.
39657function adjustView(cm, from, to) {
39658  var display = cm.display, view = display.view;
39659  if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
39660    display.view = buildViewArray(cm, from, to);
39661    display.viewFrom = from;
39662  } else {
39663    if (display.viewFrom > from)
39664      { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
39665    else if (display.viewFrom < from)
39666      { display.view = display.view.slice(findViewIndex(cm, from)); }
39667    display.viewFrom = from;
39668    if (display.viewTo < to)
39669      { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
39670    else if (display.viewTo > to)
39671      { display.view = display.view.slice(0, findViewIndex(cm, to)); }
39672  }
39673  display.viewTo = to;
39674}
39675
39676// Count the number of lines in the view whose DOM representation is
39677// out of date (or nonexistent).
39678function countDirtyView(cm) {
39679  var view = cm.display.view, dirty = 0;
39680  for (var i = 0; i < view.length; i++) {
39681    var lineView = view[i];
39682    if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
39683  }
39684  return dirty
39685}
39686
39687// HIGHLIGHT WORKER
39688
39689function startWorker(cm, time) {
39690  if (cm.doc.highlightFrontier < cm.display.viewTo)
39691    { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
39692}
39693
39694function highlightWorker(cm) {
39695  var doc = cm.doc;
39696  if (doc.highlightFrontier >= cm.display.viewTo) { return }
39697  var end = +new Date + cm.options.workTime;
39698  var context = getContextBefore(cm, doc.highlightFrontier);
39699  var changedLines = [];
39700
39701  doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
39702    if (context.line >= cm.display.viewFrom) { // Visible
39703      var oldStyles = line.styles;
39704      var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
39705      var highlighted = highlightLine(cm, line, context, true);
39706      if (resetState) { context.state = resetState; }
39707      line.styles = highlighted.styles;
39708      var oldCls = line.styleClasses, newCls = highlighted.classes;
39709      if (newCls) { line.styleClasses = newCls; }
39710      else if (oldCls) { line.styleClasses = null; }
39711      var ischange = !oldStyles || oldStyles.length != line.styles.length ||
39712        oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
39713      for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
39714      if (ischange) { changedLines.push(context.line); }
39715      line.stateAfter = context.save();
39716      context.nextLine();
39717    } else {
39718      if (line.text.length <= cm.options.maxHighlightLength)
39719        { processLine(cm, line.text, context); }
39720      line.stateAfter = context.line % 5 == 0 ? context.save() : null;
39721      context.nextLine();
39722    }
39723    if (+new Date > end) {
39724      startWorker(cm, cm.options.workDelay);
39725      return true
39726    }
39727  });
39728  doc.highlightFrontier = context.line;
39729  doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
39730  if (changedLines.length) { runInOp(cm, function () {
39731    for (var i = 0; i < changedLines.length; i++)
39732      { regLineChange(cm, changedLines[i], "text"); }
39733  }); }
39734}
39735
39736// DISPLAY DRAWING
39737
39738var DisplayUpdate = function(cm, viewport, force) {
39739  var display = cm.display;
39740
39741  this.viewport = viewport;
39742  // Store some values that we'll need later (but don't want to force a relayout for)
39743  this.visible = visibleLines(display, cm.doc, viewport);
39744  this.editorIsHidden = !display.wrapper.offsetWidth;
39745  this.wrapperHeight = display.wrapper.clientHeight;
39746  this.wrapperWidth = display.wrapper.clientWidth;
39747  this.oldDisplayWidth = displayWidth(cm);
39748  this.force = force;
39749  this.dims = getDimensions(cm);
39750  this.events = [];
39751};
39752
39753DisplayUpdate.prototype.signal = function (emitter, type) {
39754  if (hasHandler(emitter, type))
39755    { this.events.push(arguments); }
39756};
39757DisplayUpdate.prototype.finish = function () {
39758    var this$1 = this;
39759
39760  for (var i = 0; i < this.events.length; i++)
39761    { signal.apply(null, this$1.events[i]); }
39762};
39763
39764function maybeClipScrollbars(cm) {
39765  var display = cm.display;
39766  if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
39767    display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
39768    display.heightForcer.style.height = scrollGap(cm) + "px";
39769    display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
39770    display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
39771    display.scrollbarsClipped = true;
39772  }
39773}
39774
39775function selectionSnapshot(cm) {
39776  if (cm.hasFocus()) { return null }
39777  var active = activeElt();
39778  if (!active || !contains(cm.display.lineDiv, active)) { return null }
39779  var result = {activeElt: active};
39780  if (window.getSelection) {
39781    var sel = window.getSelection();
39782    if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
39783      result.anchorNode = sel.anchorNode;
39784      result.anchorOffset = sel.anchorOffset;
39785      result.focusNode = sel.focusNode;
39786      result.focusOffset = sel.focusOffset;
39787    }
39788  }
39789  return result
39790}
39791
39792function restoreSelection(snapshot) {
39793  if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
39794  snapshot.activeElt.focus();
39795  if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
39796    var sel = window.getSelection(), range$$1 = document.createRange();
39797    range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
39798    range$$1.collapse(false);
39799    sel.removeAllRanges();
39800    sel.addRange(range$$1);
39801    sel.extend(snapshot.focusNode, snapshot.focusOffset);
39802  }
39803}
39804
39805// Does the actual updating of the line display. Bails out
39806// (returning false) when there is nothing to be done and forced is
39807// false.
39808function updateDisplayIfNeeded(cm, update) {
39809  var display = cm.display, doc = cm.doc;
39810
39811  if (update.editorIsHidden) {
39812    resetView(cm);
39813    return false
39814  }
39815
39816  // Bail out if the visible area is already rendered and nothing changed.
39817  if (!update.force &&
39818      update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
39819      (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
39820      display.renderedView == display.view && countDirtyView(cm) == 0)
39821    { return false }
39822
39823  if (maybeUpdateLineNumberWidth(cm)) {
39824    resetView(cm);
39825    update.dims = getDimensions(cm);
39826  }
39827
39828  // Compute a suitable new viewport (from & to)
39829  var end = doc.first + doc.size;
39830  var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
39831  var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
39832  if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
39833  if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
39834  if (sawCollapsedSpans) {
39835    from = visualLineNo(cm.doc, from);
39836    to = visualLineEndNo(cm.doc, to);
39837  }
39838
39839  var different = from != display.viewFrom || to != display.viewTo ||
39840    display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
39841  adjustView(cm, from, to);
39842
39843  display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
39844  // Position the mover div to align with the current scroll position
39845  cm.display.mover.style.top = display.viewOffset + "px";
39846
39847  var toUpdate = countDirtyView(cm);
39848  if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
39849      (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
39850    { return false }
39851
39852  // For big changes, we hide the enclosing element during the
39853  // update, since that speeds up the operations on most browsers.
39854  var selSnapshot = selectionSnapshot(cm);
39855  if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
39856  patchDisplay(cm, display.updateLineNumbers, update.dims);
39857  if (toUpdate > 4) { display.lineDiv.style.display = ""; }
39858  display.renderedView = display.view;
39859  // There might have been a widget with a focused element that got
39860  // hidden or updated, if so re-focus it.
39861  restoreSelection(selSnapshot);
39862
39863  // Prevent selection and cursors from interfering with the scroll
39864  // width and height.
39865  removeChildren(display.cursorDiv);
39866  removeChildren(display.selectionDiv);
39867  display.gutters.style.height = display.sizer.style.minHeight = 0;
39868
39869  if (different) {
39870    display.lastWrapHeight = update.wrapperHeight;
39871    display.lastWrapWidth = update.wrapperWidth;
39872    startWorker(cm, 400);
39873  }
39874
39875  display.updateLineNumbers = null;
39876
39877  return true
39878}
39879
39880function postUpdateDisplay(cm, update) {
39881  var viewport = update.viewport;
39882
39883  for (var first = true;; first = false) {
39884    if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
39885      // Clip forced viewport to actual scrollable area.
39886      if (viewport && viewport.top != null)
39887        { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
39888      // Updated line heights might result in the drawn area not
39889      // actually covering the viewport. Keep looping until it does.
39890      update.visible = visibleLines(cm.display, cm.doc, viewport);
39891      if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
39892        { break }
39893    }
39894    if (!updateDisplayIfNeeded(cm, update)) { break }
39895    updateHeightsInViewport(cm);
39896    var barMeasure = measureForScrollbars(cm);
39897    updateSelection(cm);
39898    updateScrollbars(cm, barMeasure);
39899    setDocumentHeight(cm, barMeasure);
39900    update.force = false;
39901  }
39902
39903  update.signal(cm, "update", cm);
39904  if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
39905    update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
39906    cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
39907  }
39908}
39909
39910function updateDisplaySimple(cm, viewport) {
39911  var update = new DisplayUpdate(cm, viewport);
39912  if (updateDisplayIfNeeded(cm, update)) {
39913    updateHeightsInViewport(cm);
39914    postUpdateDisplay(cm, update);
39915    var barMeasure = measureForScrollbars(cm);
39916    updateSelection(cm);
39917    updateScrollbars(cm, barMeasure);
39918    setDocumentHeight(cm, barMeasure);
39919    update.finish();
39920  }
39921}
39922
39923// Sync the actual display DOM structure with display.view, removing
39924// nodes for lines that are no longer in view, and creating the ones
39925// that are not there yet, and updating the ones that are out of
39926// date.
39927function patchDisplay(cm, updateNumbersFrom, dims) {
39928  var display = cm.display, lineNumbers = cm.options.lineNumbers;
39929  var container = display.lineDiv, cur = container.firstChild;
39930
39931  function rm(node) {
39932    var next = node.nextSibling;
39933    // Works around a throw-scroll bug in OS X Webkit
39934    if (webkit && mac && cm.display.currentWheelTarget == node)
39935      { node.style.display = "none"; }
39936    else
39937      { node.parentNode.removeChild(node); }
39938    return next
39939  }
39940
39941  var view = display.view, lineN = display.viewFrom;
39942  // Loop over the elements in the view, syncing cur (the DOM nodes
39943  // in display.lineDiv) with the view as we go.
39944  for (var i = 0; i < view.length; i++) {
39945    var lineView = view[i];
39946    if (lineView.hidden) {
39947    } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
39948      var node = buildLineElement(cm, lineView, lineN, dims);
39949      container.insertBefore(node, cur);
39950    } else { // Already drawn
39951      while (cur != lineView.node) { cur = rm(cur); }
39952      var updateNumber = lineNumbers && updateNumbersFrom != null &&
39953        updateNumbersFrom <= lineN && lineView.lineNumber;
39954      if (lineView.changes) {
39955        if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
39956        updateLineForChanges(cm, lineView, lineN, dims);
39957      }
39958      if (updateNumber) {
39959        removeChildren(lineView.lineNumber);
39960        lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
39961      }
39962      cur = lineView.node.nextSibling;
39963    }
39964    lineN += lineView.size;
39965  }
39966  while (cur) { cur = rm(cur); }
39967}
39968
39969function updateGutterSpace(cm) {
39970  var width = cm.display.gutters.offsetWidth;
39971  cm.display.sizer.style.marginLeft = width + "px";
39972}
39973
39974function setDocumentHeight(cm, measure) {
39975  cm.display.sizer.style.minHeight = measure.docHeight + "px";
39976  cm.display.heightForcer.style.top = measure.docHeight + "px";
39977  cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
39978}
39979
39980// Rebuild the gutter elements, ensure the margin to the left of the
39981// code matches their width.
39982function updateGutters(cm) {
39983  var gutters = cm.display.gutters, specs = cm.options.gutters;
39984  removeChildren(gutters);
39985  var i = 0;
39986  for (; i < specs.length; ++i) {
39987    var gutterClass = specs[i];
39988    var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
39989    if (gutterClass == "CodeMirror-linenumbers") {
39990      cm.display.lineGutter = gElt;
39991      gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
39992    }
39993  }
39994  gutters.style.display = i ? "" : "none";
39995  updateGutterSpace(cm);
39996}
39997
39998// Make sure the gutters options contains the element
39999// "CodeMirror-linenumbers" when the lineNumbers option is true.
40000function setGuttersForLineNumbers(options) {
40001  var found = indexOf(options.gutters, "CodeMirror-linenumbers");
40002  if (found == -1 && options.lineNumbers) {
40003    options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
40004  } else if (found > -1 && !options.lineNumbers) {
40005    options.gutters = options.gutters.slice(0);
40006    options.gutters.splice(found, 1);
40007  }
40008}
40009
40010// Since the delta values reported on mouse wheel events are
40011// unstandardized between browsers and even browser versions, and
40012// generally horribly unpredictable, this code starts by measuring
40013// the scroll effect that the first few mouse wheel events have,
40014// and, from that, detects the way it can convert deltas to pixel
40015// offsets afterwards.
40016//
40017// The reason we want to know the amount a wheel event will scroll
40018// is that it gives us a chance to update the display before the
40019// actual scrolling happens, reducing flickering.
40020
40021var wheelSamples = 0;
40022var wheelPixelsPerUnit = null;
40023// Fill in a browser-detected starting value on browsers where we
40024// know one. These don't have to be accurate -- the result of them
40025// being wrong would just be a slight flicker on the first wheel
40026// scroll (if it is large enough).
40027if (ie) { wheelPixelsPerUnit = -.53; }
40028else if (gecko) { wheelPixelsPerUnit = 15; }
40029else if (chrome) { wheelPixelsPerUnit = -.7; }
40030else if (safari) { wheelPixelsPerUnit = -1/3; }
40031
40032function wheelEventDelta(e) {
40033  var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
40034  if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
40035  if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
40036  else if (dy == null) { dy = e.wheelDelta; }
40037  return {x: dx, y: dy}
40038}
40039function wheelEventPixels(e) {
40040  var delta = wheelEventDelta(e);
40041  delta.x *= wheelPixelsPerUnit;
40042  delta.y *= wheelPixelsPerUnit;
40043  return delta
40044}
40045
40046function onScrollWheel(cm, e) {
40047  var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
40048
40049  var display = cm.display, scroll = display.scroller;
40050  // Quit if there's nothing to scroll here
40051  var canScrollX = scroll.scrollWidth > scroll.clientWidth;
40052  var canScrollY = scroll.scrollHeight > scroll.clientHeight;
40053  if (!(dx && canScrollX || dy && canScrollY)) { return }
40054
40055  // Webkit browsers on OS X abort momentum scrolls when the target
40056  // of the scroll event is removed from the scrollable element.
40057  // This hack (see related code in patchDisplay) makes sure the
40058  // element is kept around.
40059  if (dy && mac && webkit) {
40060    outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
40061      for (var i = 0; i < view.length; i++) {
40062        if (view[i].node == cur) {
40063          cm.display.currentWheelTarget = cur;
40064          break outer
40065        }
40066      }
40067    }
40068  }
40069
40070  // On some browsers, horizontal scrolling will cause redraws to
40071  // happen before the gutter has been realigned, causing it to
40072  // wriggle around in a most unseemly way. When we have an
40073  // estimated pixels/delta value, we just handle horizontal
40074  // scrolling entirely here. It'll be slightly off from native, but
40075  // better than glitching out.
40076  if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
40077    if (dy && canScrollY)
40078      { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
40079    setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
40080    // Only prevent default scrolling if vertical scrolling is
40081    // actually possible. Otherwise, it causes vertical scroll
40082    // jitter on OSX trackpads when deltaX is small and deltaY
40083    // is large (issue #3579)
40084    if (!dy || (dy && canScrollY))
40085      { e_preventDefault(e); }
40086    display.wheelStartX = null; // Abort measurement, if in progress
40087    return
40088  }
40089
40090  // 'Project' the visible viewport to cover the area that is being
40091  // scrolled into view (if we know enough to estimate it).
40092  if (dy && wheelPixelsPerUnit != null) {
40093    var pixels = dy * wheelPixelsPerUnit;
40094    var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
40095    if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
40096    else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
40097    updateDisplaySimple(cm, {top: top, bottom: bot});
40098  }
40099
40100  if (wheelSamples < 20) {
40101    if (display.wheelStartX == null) {
40102      display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
40103      display.wheelDX = dx; display.wheelDY = dy;
40104      setTimeout(function () {
40105        if (display.wheelStartX == null) { return }
40106        var movedX = scroll.scrollLeft - display.wheelStartX;
40107        var movedY = scroll.scrollTop - display.wheelStartY;
40108        var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
40109          (movedX && display.wheelDX && movedX / display.wheelDX);
40110        display.wheelStartX = display.wheelStartY = null;
40111        if (!sample) { return }
40112        wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
40113        ++wheelSamples;
40114      }, 200);
40115    } else {
40116      display.wheelDX += dx; display.wheelDY += dy;
40117    }
40118  }
40119}
40120
40121// Selection objects are immutable. A new one is created every time
40122// the selection changes. A selection is one or more non-overlapping
40123// (and non-touching) ranges, sorted, and an integer that indicates
40124// which one is the primary selection (the one that's scrolled into
40125// view, that getCursor returns, etc).
40126var Selection = function(ranges, primIndex) {
40127  this.ranges = ranges;
40128  this.primIndex = primIndex;
40129};
40130
40131Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
40132
40133Selection.prototype.equals = function (other) {
40134    var this$1 = this;
40135
40136  if (other == this) { return true }
40137  if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
40138  for (var i = 0; i < this.ranges.length; i++) {
40139    var here = this$1.ranges[i], there = other.ranges[i];
40140    if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
40141  }
40142  return true
40143};
40144
40145Selection.prototype.deepCopy = function () {
40146    var this$1 = this;
40147
40148  var out = [];
40149  for (var i = 0; i < this.ranges.length; i++)
40150    { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
40151  return new Selection(out, this.primIndex)
40152};
40153
40154Selection.prototype.somethingSelected = function () {
40155    var this$1 = this;
40156
40157  for (var i = 0; i < this.ranges.length; i++)
40158    { if (!this$1.ranges[i].empty()) { return true } }
40159  return false
40160};
40161
40162Selection.prototype.contains = function (pos, end) {
40163    var this$1 = this;
40164
40165  if (!end) { end = pos; }
40166  for (var i = 0; i < this.ranges.length; i++) {
40167    var range = this$1.ranges[i];
40168    if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
40169      { return i }
40170  }
40171  return -1
40172};
40173
40174var Range = function(anchor, head) {
40175  this.anchor = anchor; this.head = head;
40176};
40177
40178Range.prototype.from = function () { return minPos(this.anchor, this.head) };
40179Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
40180Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
40181
40182// Take an unsorted, potentially overlapping set of ranges, and
40183// build a selection out of it. 'Consumes' ranges array (modifying
40184// it).
40185function normalizeSelection(ranges, primIndex) {
40186  var prim = ranges[primIndex];
40187  ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
40188  primIndex = indexOf(ranges, prim);
40189  for (var i = 1; i < ranges.length; i++) {
40190    var cur = ranges[i], prev = ranges[i - 1];
40191    if (cmp(prev.to(), cur.from()) >= 0) {
40192      var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
40193      var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
40194      if (i <= primIndex) { --primIndex; }
40195      ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
40196    }
40197  }
40198  return new Selection(ranges, primIndex)
40199}
40200
40201function simpleSelection(anchor, head) {
40202  return new Selection([new Range(anchor, head || anchor)], 0)
40203}
40204
40205// Compute the position of the end of a change (its 'to' property
40206// refers to the pre-change end).
40207function changeEnd(change) {
40208  if (!change.text) { return change.to }
40209  return Pos(change.from.line + change.text.length - 1,
40210             lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
40211}
40212
40213// Adjust a position to refer to the post-change position of the
40214// same text, or the end of the change if the change covers it.
40215function adjustForChange(pos, change) {
40216  if (cmp(pos, change.from) < 0) { return pos }
40217  if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
40218
40219  var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
40220  if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
40221  return Pos(line, ch)
40222}
40223
40224function computeSelAfterChange(doc, change) {
40225  var out = [];
40226  for (var i = 0; i < doc.sel.ranges.length; i++) {
40227    var range = doc.sel.ranges[i];
40228    out.push(new Range(adjustForChange(range.anchor, change),
40229                       adjustForChange(range.head, change)));
40230  }
40231  return normalizeSelection(out, doc.sel.primIndex)
40232}
40233
40234function offsetPos(pos, old, nw) {
40235  if (pos.line == old.line)
40236    { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
40237  else
40238    { return Pos(nw.line + (pos.line - old.line), pos.ch) }
40239}
40240
40241// Used by replaceSelections to allow moving the selection to the
40242// start or around the replaced test. Hint may be "start" or "around".
40243function computeReplacedSel(doc, changes, hint) {
40244  var out = [];
40245  var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
40246  for (var i = 0; i < changes.length; i++) {
40247    var change = changes[i];
40248    var from = offsetPos(change.from, oldPrev, newPrev);
40249    var to = offsetPos(changeEnd(change), oldPrev, newPrev);
40250    oldPrev = change.to;
40251    newPrev = to;
40252    if (hint == "around") {
40253      var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
40254      out[i] = new Range(inv ? to : from, inv ? from : to);
40255    } else {
40256      out[i] = new Range(from, from);
40257    }
40258  }
40259  return new Selection(out, doc.sel.primIndex)
40260}
40261
40262// Used to get the editor into a consistent state again when options change.
40263
40264function loadMode(cm) {
40265  cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
40266  resetModeState(cm);
40267}
40268
40269function resetModeState(cm) {
40270  cm.doc.iter(function (line) {
40271    if (line.stateAfter) { line.stateAfter = null; }
40272    if (line.styles) { line.styles = null; }
40273  });
40274  cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
40275  startWorker(cm, 100);
40276  cm.state.modeGen++;
40277  if (cm.curOp) { regChange(cm); }
40278}
40279
40280// DOCUMENT DATA STRUCTURE
40281
40282// By default, updates that start and end at the beginning of a line
40283// are treated specially, in order to make the association of line
40284// widgets and marker elements with the text behave more intuitive.
40285function isWholeLineUpdate(doc, change) {
40286  return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
40287    (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
40288}
40289
40290// Perform a change on the document data structure.
40291function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
40292  function spansFor(n) {return markedSpans ? markedSpans[n] : null}
40293  function update(line, text, spans) {
40294    updateLine(line, text, spans, estimateHeight$$1);
40295    signalLater(line, "change", line, change);
40296  }
40297  function linesFor(start, end) {
40298    var result = [];
40299    for (var i = start; i < end; ++i)
40300      { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
40301    return result
40302  }
40303
40304  var from = change.from, to = change.to, text = change.text;
40305  var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
40306  var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
40307
40308  // Adjust the line structure
40309  if (change.full) {
40310    doc.insert(0, linesFor(0, text.length));
40311    doc.remove(text.length, doc.size - text.length);
40312  } else if (isWholeLineUpdate(doc, change)) {
40313    // This is a whole-line replace. Treated specially to make
40314    // sure line objects move the way they are supposed to.
40315    var added = linesFor(0, text.length - 1);
40316    update(lastLine, lastLine.text, lastSpans);
40317    if (nlines) { doc.remove(from.line, nlines); }
40318    if (added.length) { doc.insert(from.line, added); }
40319  } else if (firstLine == lastLine) {
40320    if (text.length == 1) {
40321      update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
40322    } else {
40323      var added$1 = linesFor(1, text.length - 1);
40324      added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
40325      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
40326      doc.insert(from.line + 1, added$1);
40327    }
40328  } else if (text.length == 1) {
40329    update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
40330    doc.remove(from.line + 1, nlines);
40331  } else {
40332    update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
40333    update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
40334    var added$2 = linesFor(1, text.length - 1);
40335    if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
40336    doc.insert(from.line + 1, added$2);
40337  }
40338
40339  signalLater(doc, "change", doc, change);
40340}
40341
40342// Call f for all linked documents.
40343function linkedDocs(doc, f, sharedHistOnly) {
40344  function propagate(doc, skip, sharedHist) {
40345    if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
40346      var rel = doc.linked[i];
40347      if (rel.doc == skip) { continue }
40348      var shared = sharedHist && rel.sharedHist;
40349      if (sharedHistOnly && !shared) { continue }
40350      f(rel.doc, shared);
40351      propagate(rel.doc, doc, shared);
40352    } }
40353  }
40354  propagate(doc, null, true);
40355}
40356
40357// Attach a document to an editor.
40358function attachDoc(cm, doc) {
40359  if (doc.cm) { throw new Error("This document is already in use.") }
40360  cm.doc = doc;
40361  doc.cm = cm;
40362  estimateLineHeights(cm);
40363  loadMode(cm);
40364  setDirectionClass(cm);
40365  if (!cm.options.lineWrapping) { findMaxLine(cm); }
40366  cm.options.mode = doc.modeOption;
40367  regChange(cm);
40368}
40369
40370function setDirectionClass(cm) {
40371  (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
40372}
40373
40374function directionChanged(cm) {
40375  runInOp(cm, function () {
40376    setDirectionClass(cm);
40377    regChange(cm);
40378  });
40379}
40380
40381function History(startGen) {
40382  // Arrays of change events and selections. Doing something adds an
40383  // event to done and clears undo. Undoing moves events from done
40384  // to undone, redoing moves them in the other direction.
40385  this.done = []; this.undone = [];
40386  this.undoDepth = Infinity;
40387  // Used to track when changes can be merged into a single undo
40388  // event
40389  this.lastModTime = this.lastSelTime = 0;
40390  this.lastOp = this.lastSelOp = null;
40391  this.lastOrigin = this.lastSelOrigin = null;
40392  // Used by the isClean() method
40393  this.generation = this.maxGeneration = startGen || 1;
40394}
40395
40396// Create a history change event from an updateDoc-style change
40397// object.
40398function historyChangeFromChange(doc, change) {
40399  var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
40400  attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
40401  linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
40402  return histChange
40403}
40404
40405// Pop all selection events off the end of a history array. Stop at
40406// a change event.
40407function clearSelectionEvents(array) {
40408  while (array.length) {
40409    var last = lst(array);
40410    if (last.ranges) { array.pop(); }
40411    else { break }
40412  }
40413}
40414
40415// Find the top change event in the history. Pop off selection
40416// events that are in the way.
40417function lastChangeEvent(hist, force) {
40418  if (force) {
40419    clearSelectionEvents(hist.done);
40420    return lst(hist.done)
40421  } else if (hist.done.length && !lst(hist.done).ranges) {
40422    return lst(hist.done)
40423  } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
40424    hist.done.pop();
40425    return lst(hist.done)
40426  }
40427}
40428
40429// Register a change in the history. Merges changes that are within
40430// a single operation, or are close together with an origin that
40431// allows merging (starting with "+") into a single event.
40432function addChangeToHistory(doc, change, selAfter, opId) {
40433  var hist = doc.history;
40434  hist.undone.length = 0;
40435  var time = +new Date, cur;
40436  var last;
40437
40438  if ((hist.lastOp == opId ||
40439       hist.lastOrigin == change.origin && change.origin &&
40440       ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
40441        change.origin.charAt(0) == "*")) &&
40442      (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
40443    // Merge this change into the last event
40444    last = lst(cur.changes);
40445    if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
40446      // Optimized case for simple insertion -- don't want to add
40447      // new changesets for every character typed
40448      last.to = changeEnd(change);
40449    } else {
40450      // Add new sub-event
40451      cur.changes.push(historyChangeFromChange(doc, change));
40452    }
40453  } else {
40454    // Can not be merged, start a new event.
40455    var before = lst(hist.done);
40456    if (!before || !before.ranges)
40457      { pushSelectionToHistory(doc.sel, hist.done); }
40458    cur = {changes: [historyChangeFromChange(doc, change)],
40459           generation: hist.generation};
40460    hist.done.push(cur);
40461    while (hist.done.length > hist.undoDepth) {
40462      hist.done.shift();
40463      if (!hist.done[0].ranges) { hist.done.shift(); }
40464    }
40465  }
40466  hist.done.push(selAfter);
40467  hist.generation = ++hist.maxGeneration;
40468  hist.lastModTime = hist.lastSelTime = time;
40469  hist.lastOp = hist.lastSelOp = opId;
40470  hist.lastOrigin = hist.lastSelOrigin = change.origin;
40471
40472  if (!last) { signal(doc, "historyAdded"); }
40473}
40474
40475function selectionEventCanBeMerged(doc, origin, prev, sel) {
40476  var ch = origin.charAt(0);
40477  return ch == "*" ||
40478    ch == "+" &&
40479    prev.ranges.length == sel.ranges.length &&
40480    prev.somethingSelected() == sel.somethingSelected() &&
40481    new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
40482}
40483
40484// Called whenever the selection changes, sets the new selection as
40485// the pending selection in the history, and pushes the old pending
40486// selection into the 'done' array when it was significantly
40487// different (in number of selected ranges, emptiness, or time).
40488function addSelectionToHistory(doc, sel, opId, options) {
40489  var hist = doc.history, origin = options && options.origin;
40490
40491  // A new event is started when the previous origin does not match
40492  // the current, or the origins don't allow matching. Origins
40493  // starting with * are always merged, those starting with + are
40494  // merged when similar and close together in time.
40495  if (opId == hist.lastSelOp ||
40496      (origin && hist.lastSelOrigin == origin &&
40497       (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
40498        selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
40499    { hist.done[hist.done.length - 1] = sel; }
40500  else
40501    { pushSelectionToHistory(sel, hist.done); }
40502
40503  hist.lastSelTime = +new Date;
40504  hist.lastSelOrigin = origin;
40505  hist.lastSelOp = opId;
40506  if (options && options.clearRedo !== false)
40507    { clearSelectionEvents(hist.undone); }
40508}
40509
40510function pushSelectionToHistory(sel, dest) {
40511  var top = lst(dest);
40512  if (!(top && top.ranges && top.equals(sel)))
40513    { dest.push(sel); }
40514}
40515
40516// Used to store marked span information in the history.
40517function attachLocalSpans(doc, change, from, to) {
40518  var existing = change["spans_" + doc.id], n = 0;
40519  doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
40520    if (line.markedSpans)
40521      { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
40522    ++n;
40523  });
40524}
40525
40526// When un/re-doing restores text containing marked spans, those
40527// that have been explicitly cleared should not be restored.
40528function removeClearedSpans(spans) {
40529  if (!spans) { return null }
40530  var out;
40531  for (var i = 0; i < spans.length; ++i) {
40532    if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
40533    else if (out) { out.push(spans[i]); }
40534  }
40535  return !out ? spans : out.length ? out : null
40536}
40537
40538// Retrieve and filter the old marked spans stored in a change event.
40539function getOldSpans(doc, change) {
40540  var found = change["spans_" + doc.id];
40541  if (!found) { return null }
40542  var nw = [];
40543  for (var i = 0; i < change.text.length; ++i)
40544    { nw.push(removeClearedSpans(found[i])); }
40545  return nw
40546}
40547
40548// Used for un/re-doing changes from the history. Combines the
40549// result of computing the existing spans with the set of spans that
40550// existed in the history (so that deleting around a span and then
40551// undoing brings back the span).
40552function mergeOldSpans(doc, change) {
40553  var old = getOldSpans(doc, change);
40554  var stretched = stretchSpansOverChange(doc, change);
40555  if (!old) { return stretched }
40556  if (!stretched) { return old }
40557
40558  for (var i = 0; i < old.length; ++i) {
40559    var oldCur = old[i], stretchCur = stretched[i];
40560    if (oldCur && stretchCur) {
40561      spans: for (var j = 0; j < stretchCur.length; ++j) {
40562        var span = stretchCur[j];
40563        for (var k = 0; k < oldCur.length; ++k)
40564          { if (oldCur[k].marker == span.marker) { continue spans } }
40565        oldCur.push(span);
40566      }
40567    } else if (stretchCur) {
40568      old[i] = stretchCur;
40569    }
40570  }
40571  return old
40572}
40573
40574// Used both to provide a JSON-safe object in .getHistory, and, when
40575// detaching a document, to split the history in two
40576function copyHistoryArray(events, newGroup, instantiateSel) {
40577  var copy = [];
40578  for (var i = 0; i < events.length; ++i) {
40579    var event = events[i];
40580    if (event.ranges) {
40581      copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
40582      continue
40583    }
40584    var changes = event.changes, newChanges = [];
40585    copy.push({changes: newChanges});
40586    for (var j = 0; j < changes.length; ++j) {
40587      var change = changes[j], m = (void 0);
40588      newChanges.push({from: change.from, to: change.to, text: change.text});
40589      if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
40590        if (indexOf(newGroup, Number(m[1])) > -1) {
40591          lst(newChanges)[prop] = change[prop];
40592          delete change[prop];
40593        }
40594      } } }
40595    }
40596  }
40597  return copy
40598}
40599
40600// The 'scroll' parameter given to many of these indicated whether
40601// the new cursor position should be scrolled into view after
40602// modifying the selection.
40603
40604// If shift is held or the extend flag is set, extends a range to
40605// include a given position (and optionally a second position).
40606// Otherwise, simply returns the range between the given positions.
40607// Used for cursor motion and such.
40608function extendRange(range, head, other, extend) {
40609  if (extend) {
40610    var anchor = range.anchor;
40611    if (other) {
40612      var posBefore = cmp(head, anchor) < 0;
40613      if (posBefore != (cmp(other, anchor) < 0)) {
40614        anchor = head;
40615        head = other;
40616      } else if (posBefore != (cmp(head, other) < 0)) {
40617        head = other;
40618      }
40619    }
40620    return new Range(anchor, head)
40621  } else {
40622    return new Range(other || head, head)
40623  }
40624}
40625
40626// Extend the primary selection range, discard the rest.
40627function extendSelection(doc, head, other, options, extend) {
40628  if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
40629  setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
40630}
40631
40632// Extend all selections (pos is an array of selections with length
40633// equal the number of selections)
40634function extendSelections(doc, heads, options) {
40635  var out = [];
40636  var extend = doc.cm && (doc.cm.display.shift || doc.extend);
40637  for (var i = 0; i < doc.sel.ranges.length; i++)
40638    { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
40639  var newSel = normalizeSelection(out, doc.sel.primIndex);
40640  setSelection(doc, newSel, options);
40641}
40642
40643// Updates a single range in the selection.
40644function replaceOneSelection(doc, i, range, options) {
40645  var ranges = doc.sel.ranges.slice(0);
40646  ranges[i] = range;
40647  setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
40648}
40649
40650// Reset the selection to a single range.
40651function setSimpleSelection(doc, anchor, head, options) {
40652  setSelection(doc, simpleSelection(anchor, head), options);
40653}
40654
40655// Give beforeSelectionChange handlers a change to influence a
40656// selection update.
40657function filterSelectionChange(doc, sel, options) {
40658  var obj = {
40659    ranges: sel.ranges,
40660    update: function(ranges) {
40661      var this$1 = this;
40662
40663      this.ranges = [];
40664      for (var i = 0; i < ranges.length; i++)
40665        { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
40666                                   clipPos(doc, ranges[i].head)); }
40667    },
40668    origin: options && options.origin
40669  };
40670  signal(doc, "beforeSelectionChange", doc, obj);
40671  if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
40672  if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }
40673  else { return sel }
40674}
40675
40676function setSelectionReplaceHistory(doc, sel, options) {
40677  var done = doc.history.done, last = lst(done);
40678  if (last && last.ranges) {
40679    done[done.length - 1] = sel;
40680    setSelectionNoUndo(doc, sel, options);
40681  } else {
40682    setSelection(doc, sel, options);
40683  }
40684}
40685
40686// Set a new selection.
40687function setSelection(doc, sel, options) {
40688  setSelectionNoUndo(doc, sel, options);
40689  addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
40690}
40691
40692function setSelectionNoUndo(doc, sel, options) {
40693  if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
40694    { sel = filterSelectionChange(doc, sel, options); }
40695
40696  var bias = options && options.bias ||
40697    (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
40698  setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
40699
40700  if (!(options && options.scroll === false) && doc.cm)
40701    { ensureCursorVisible(doc.cm); }
40702}
40703
40704function setSelectionInner(doc, sel) {
40705  if (sel.equals(doc.sel)) { return }
40706
40707  doc.sel = sel;
40708
40709  if (doc.cm) {
40710    doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
40711    signalCursorActivity(doc.cm);
40712  }
40713  signalLater(doc, "cursorActivity", doc);
40714}
40715
40716// Verify that the selection does not partially select any atomic
40717// marked ranges.
40718function reCheckSelection(doc) {
40719  setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
40720}
40721
40722// Return a selection that does not partially select any atomic
40723// ranges.
40724function skipAtomicInSelection(doc, sel, bias, mayClear) {
40725  var out;
40726  for (var i = 0; i < sel.ranges.length; i++) {
40727    var range = sel.ranges[i];
40728    var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
40729    var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
40730    var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
40731    if (out || newAnchor != range.anchor || newHead != range.head) {
40732      if (!out) { out = sel.ranges.slice(0, i); }
40733      out[i] = new Range(newAnchor, newHead);
40734    }
40735  }
40736  return out ? normalizeSelection(out, sel.primIndex) : sel
40737}
40738
40739function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
40740  var line = getLine(doc, pos.line);
40741  if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
40742    var sp = line.markedSpans[i], m = sp.marker;
40743    if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
40744        (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
40745      if (mayClear) {
40746        signal(m, "beforeCursorEnter");
40747        if (m.explicitlyCleared) {
40748          if (!line.markedSpans) { break }
40749          else {--i; continue}
40750        }
40751      }
40752      if (!m.atomic) { continue }
40753
40754      if (oldPos) {
40755        var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
40756        if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
40757          { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
40758        if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
40759          { return skipAtomicInner(doc, near, pos, dir, mayClear) }
40760      }
40761
40762      var far = m.find(dir < 0 ? -1 : 1);
40763      if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
40764        { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
40765      return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
40766    }
40767  } }
40768  return pos
40769}
40770
40771// Ensure a given position is not inside an atomic range.
40772function skipAtomic(doc, pos, oldPos, bias, mayClear) {
40773  var dir = bias || 1;
40774  var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
40775      (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
40776      skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
40777      (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
40778  if (!found) {
40779    doc.cantEdit = true;
40780    return Pos(doc.first, 0)
40781  }
40782  return found
40783}
40784
40785function movePos(doc, pos, dir, line) {
40786  if (dir < 0 && pos.ch == 0) {
40787    if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
40788    else { return null }
40789  } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
40790    if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
40791    else { return null }
40792  } else {
40793    return new Pos(pos.line, pos.ch + dir)
40794  }
40795}
40796
40797function selectAll(cm) {
40798  cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
40799}
40800
40801// UPDATING
40802
40803// Allow "beforeChange" event handlers to influence a change
40804function filterChange(doc, change, update) {
40805  var obj = {
40806    canceled: false,
40807    from: change.from,
40808    to: change.to,
40809    text: change.text,
40810    origin: change.origin,
40811    cancel: function () { return obj.canceled = true; }
40812  };
40813  if (update) { obj.update = function (from, to, text, origin) {
40814    if (from) { obj.from = clipPos(doc, from); }
40815    if (to) { obj.to = clipPos(doc, to); }
40816    if (text) { obj.text = text; }
40817    if (origin !== undefined) { obj.origin = origin; }
40818  }; }
40819  signal(doc, "beforeChange", doc, obj);
40820  if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
40821
40822  if (obj.canceled) { return null }
40823  return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
40824}
40825
40826// Apply a change to a document, and add it to the document's
40827// history, and propagating it to all linked documents.
40828function makeChange(doc, change, ignoreReadOnly) {
40829  if (doc.cm) {
40830    if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
40831    if (doc.cm.state.suppressEdits) { return }
40832  }
40833
40834  if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
40835    change = filterChange(doc, change, true);
40836    if (!change) { return }
40837  }
40838
40839  // Possibly split or suppress the update based on the presence
40840  // of read-only spans in its range.
40841  var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
40842  if (split) {
40843    for (var i = split.length - 1; i >= 0; --i)
40844      { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
40845  } else {
40846    makeChangeInner(doc, change);
40847  }
40848}
40849
40850function makeChangeInner(doc, change) {
40851  if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
40852  var selAfter = computeSelAfterChange(doc, change);
40853  addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
40854
40855  makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
40856  var rebased = [];
40857
40858  linkedDocs(doc, function (doc, sharedHist) {
40859    if (!sharedHist && indexOf(rebased, doc.history) == -1) {
40860      rebaseHist(doc.history, change);
40861      rebased.push(doc.history);
40862    }
40863    makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
40864  });
40865}
40866
40867// Revert a change stored in a document's history.
40868function makeChangeFromHistory(doc, type, allowSelectionOnly) {
40869  var suppress = doc.cm && doc.cm.state.suppressEdits;
40870  if (suppress && !allowSelectionOnly) { return }
40871
40872  var hist = doc.history, event, selAfter = doc.sel;
40873  var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
40874
40875  // Verify that there is a useable event (so that ctrl-z won't
40876  // needlessly clear selection events)
40877  var i = 0;
40878  for (; i < source.length; i++) {
40879    event = source[i];
40880    if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
40881      { break }
40882  }
40883  if (i == source.length) { return }
40884  hist.lastOrigin = hist.lastSelOrigin = null;
40885
40886  for (;;) {
40887    event = source.pop();
40888    if (event.ranges) {
40889      pushSelectionToHistory(event, dest);
40890      if (allowSelectionOnly && !event.equals(doc.sel)) {
40891        setSelection(doc, event, {clearRedo: false});
40892        return
40893      }
40894      selAfter = event;
40895    } else if (suppress) {
40896      source.push(event);
40897      return
40898    } else { break }
40899  }
40900
40901  // Build up a reverse change object to add to the opposite history
40902  // stack (redo when undoing, and vice versa).
40903  var antiChanges = [];
40904  pushSelectionToHistory(selAfter, dest);
40905  dest.push({changes: antiChanges, generation: hist.generation});
40906  hist.generation = event.generation || ++hist.maxGeneration;
40907
40908  var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
40909
40910  var loop = function ( i ) {
40911    var change = event.changes[i];
40912    change.origin = type;
40913    if (filter && !filterChange(doc, change, false)) {
40914      source.length = 0;
40915      return {}
40916    }
40917
40918    antiChanges.push(historyChangeFromChange(doc, change));
40919
40920    var after = i ? computeSelAfterChange(doc, change) : lst(source);
40921    makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
40922    if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
40923    var rebased = [];
40924
40925    // Propagate to the linked documents
40926    linkedDocs(doc, function (doc, sharedHist) {
40927      if (!sharedHist && indexOf(rebased, doc.history) == -1) {
40928        rebaseHist(doc.history, change);
40929        rebased.push(doc.history);
40930      }
40931      makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
40932    });
40933  };
40934
40935  for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
40936    var returned = loop( i$1 );
40937
40938    if ( returned ) return returned.v;
40939  }
40940}
40941
40942// Sub-views need their line numbers shifted when text is added
40943// above or below them in the parent document.
40944function shiftDoc(doc, distance) {
40945  if (distance == 0) { return }
40946  doc.first += distance;
40947  doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
40948    Pos(range.anchor.line + distance, range.anchor.ch),
40949    Pos(range.head.line + distance, range.head.ch)
40950  ); }), doc.sel.primIndex);
40951  if (doc.cm) {
40952    regChange(doc.cm, doc.first, doc.first - distance, distance);
40953    for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
40954      { regLineChange(doc.cm, l, "gutter"); }
40955  }
40956}
40957
40958// More lower-level change function, handling only a single document
40959// (not linked ones).
40960function makeChangeSingleDoc(doc, change, selAfter, spans) {
40961  if (doc.cm && !doc.cm.curOp)
40962    { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
40963
40964  if (change.to.line < doc.first) {
40965    shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
40966    return
40967  }
40968  if (change.from.line > doc.lastLine()) { return }
40969
40970  // Clip the change to the size of this doc
40971  if (change.from.line < doc.first) {
40972    var shift = change.text.length - 1 - (doc.first - change.from.line);
40973    shiftDoc(doc, shift);
40974    change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
40975              text: [lst(change.text)], origin: change.origin};
40976  }
40977  var last = doc.lastLine();
40978  if (change.to.line > last) {
40979    change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
40980              text: [change.text[0]], origin: change.origin};
40981  }
40982
40983  change.removed = getBetween(doc, change.from, change.to);
40984
40985  if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
40986  if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
40987  else { updateDoc(doc, change, spans); }
40988  setSelectionNoUndo(doc, selAfter, sel_dontScroll);
40989}
40990
40991// Handle the interaction of a change to a document with the editor
40992// that this document is part of.
40993function makeChangeSingleDocInEditor(cm, change, spans) {
40994  var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
40995
40996  var recomputeMaxLength = false, checkWidthStart = from.line;
40997  if (!cm.options.lineWrapping) {
40998    checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
40999    doc.iter(checkWidthStart, to.line + 1, function (line) {
41000      if (line == display.maxLine) {
41001        recomputeMaxLength = true;
41002        return true
41003      }
41004    });
41005  }
41006
41007  if (doc.sel.contains(change.from, change.to) > -1)
41008    { signalCursorActivity(cm); }
41009
41010  updateDoc(doc, change, spans, estimateHeight(cm));
41011
41012  if (!cm.options.lineWrapping) {
41013    doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
41014      var len = lineLength(line);
41015      if (len > display.maxLineLength) {
41016        display.maxLine = line;
41017        display.maxLineLength = len;
41018        display.maxLineChanged = true;
41019        recomputeMaxLength = false;
41020      }
41021    });
41022    if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
41023  }
41024
41025  retreatFrontier(doc, from.line);
41026  startWorker(cm, 400);
41027
41028  var lendiff = change.text.length - (to.line - from.line) - 1;
41029  // Remember that these lines changed, for updating the display
41030  if (change.full)
41031    { regChange(cm); }
41032  else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
41033    { regLineChange(cm, from.line, "text"); }
41034  else
41035    { regChange(cm, from.line, to.line + 1, lendiff); }
41036
41037  var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
41038  if (changeHandler || changesHandler) {
41039    var obj = {
41040      from: from, to: to,
41041      text: change.text,
41042      removed: change.removed,
41043      origin: change.origin
41044    };
41045    if (changeHandler) { signalLater(cm, "change", cm, obj); }
41046    if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
41047  }
41048  cm.display.selForContextMenu = null;
41049}
41050
41051function replaceRange(doc, code, from, to, origin) {
41052  if (!to) { to = from; }
41053  if (cmp(to, from) < 0) { var assign;
41054    (assign = [to, from], from = assign[0], to = assign[1]); }
41055  if (typeof code == "string") { code = doc.splitLines(code); }
41056  makeChange(doc, {from: from, to: to, text: code, origin: origin});
41057}
41058
41059// Rebasing/resetting history to deal with externally-sourced changes
41060
41061function rebaseHistSelSingle(pos, from, to, diff) {
41062  if (to < pos.line) {
41063    pos.line += diff;
41064  } else if (from < pos.line) {
41065    pos.line = from;
41066    pos.ch = 0;
41067  }
41068}
41069
41070// Tries to rebase an array of history events given a change in the
41071// document. If the change touches the same lines as the event, the
41072// event, and everything 'behind' it, is discarded. If the change is
41073// before the event, the event's positions are updated. Uses a
41074// copy-on-write scheme for the positions, to avoid having to
41075// reallocate them all on every rebase, but also avoid problems with
41076// shared position objects being unsafely updated.
41077function rebaseHistArray(array, from, to, diff) {
41078  for (var i = 0; i < array.length; ++i) {
41079    var sub = array[i], ok = true;
41080    if (sub.ranges) {
41081      if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
41082      for (var j = 0; j < sub.ranges.length; j++) {
41083        rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
41084        rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
41085      }
41086      continue
41087    }
41088    for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
41089      var cur = sub.changes[j$1];
41090      if (to < cur.from.line) {
41091        cur.from = Pos(cur.from.line + diff, cur.from.ch);
41092        cur.to = Pos(cur.to.line + diff, cur.to.ch);
41093      } else if (from <= cur.to.line) {
41094        ok = false;
41095        break
41096      }
41097    }
41098    if (!ok) {
41099      array.splice(0, i + 1);
41100      i = 0;
41101    }
41102  }
41103}
41104
41105function rebaseHist(hist, change) {
41106  var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
41107  rebaseHistArray(hist.done, from, to, diff);
41108  rebaseHistArray(hist.undone, from, to, diff);
41109}
41110
41111// Utility for applying a change to a line by handle or number,
41112// returning the number and optionally registering the line as
41113// changed.
41114function changeLine(doc, handle, changeType, op) {
41115  var no = handle, line = handle;
41116  if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
41117  else { no = lineNo(handle); }
41118  if (no == null) { return null }
41119  if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
41120  return line
41121}
41122
41123// The document is represented as a BTree consisting of leaves, with
41124// chunk of lines in them, and branches, with up to ten leaves or
41125// other branch nodes below them. The top node is always a branch
41126// node, and is the document object itself (meaning it has
41127// additional methods and properties).
41128//
41129// All nodes have parent links. The tree is used both to go from
41130// line numbers to line objects, and to go from objects to numbers.
41131// It also indexes by height, and is used to convert between height
41132// and line object, and to find the total height of the document.
41133//
41134// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
41135
41136function LeafChunk(lines) {
41137  var this$1 = this;
41138
41139  this.lines = lines;
41140  this.parent = null;
41141  var height = 0;
41142  for (var i = 0; i < lines.length; ++i) {
41143    lines[i].parent = this$1;
41144    height += lines[i].height;
41145  }
41146  this.height = height;
41147}
41148
41149LeafChunk.prototype = {
41150  chunkSize: function() { return this.lines.length },
41151
41152  // Remove the n lines at offset 'at'.
41153  removeInner: function(at, n) {
41154    var this$1 = this;
41155
41156    for (var i = at, e = at + n; i < e; ++i) {
41157      var line = this$1.lines[i];
41158      this$1.height -= line.height;
41159      cleanUpLine(line);
41160      signalLater(line, "delete");
41161    }
41162    this.lines.splice(at, n);
41163  },
41164
41165  // Helper used to collapse a small branch into a single leaf.
41166  collapse: function(lines) {
41167    lines.push.apply(lines, this.lines);
41168  },
41169
41170  // Insert the given array of lines at offset 'at', count them as
41171  // having the given height.
41172  insertInner: function(at, lines, height) {
41173    var this$1 = this;
41174
41175    this.height += height;
41176    this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
41177    for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
41178  },
41179
41180  // Used to iterate over a part of the tree.
41181  iterN: function(at, n, op) {
41182    var this$1 = this;
41183
41184    for (var e = at + n; at < e; ++at)
41185      { if (op(this$1.lines[at])) { return true } }
41186  }
41187};
41188
41189function BranchChunk(children) {
41190  var this$1 = this;
41191
41192  this.children = children;
41193  var size = 0, height = 0;
41194  for (var i = 0; i < children.length; ++i) {
41195    var ch = children[i];
41196    size += ch.chunkSize(); height += ch.height;
41197    ch.parent = this$1;
41198  }
41199  this.size = size;
41200  this.height = height;
41201  this.parent = null;
41202}
41203
41204BranchChunk.prototype = {
41205  chunkSize: function() { return this.size },
41206
41207  removeInner: function(at, n) {
41208    var this$1 = this;
41209
41210    this.size -= n;
41211    for (var i = 0; i < this.children.length; ++i) {
41212      var child = this$1.children[i], sz = child.chunkSize();
41213      if (at < sz) {
41214        var rm = Math.min(n, sz - at), oldHeight = child.height;
41215        child.removeInner(at, rm);
41216        this$1.height -= oldHeight - child.height;
41217        if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
41218        if ((n -= rm) == 0) { break }
41219        at = 0;
41220      } else { at -= sz; }
41221    }
41222    // If the result is smaller than 25 lines, ensure that it is a
41223    // single leaf node.
41224    if (this.size - n < 25 &&
41225        (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
41226      var lines = [];
41227      this.collapse(lines);
41228      this.children = [new LeafChunk(lines)];
41229      this.children[0].parent = this;
41230    }
41231  },
41232
41233  collapse: function(lines) {
41234    var this$1 = this;
41235
41236    for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
41237  },
41238
41239  insertInner: function(at, lines, height) {
41240    var this$1 = this;
41241
41242    this.size += lines.length;
41243    this.height += height;
41244    for (var i = 0; i < this.children.length; ++i) {
41245      var child = this$1.children[i], sz = child.chunkSize();
41246      if (at <= sz) {
41247        child.insertInner(at, lines, height);
41248        if (child.lines && child.lines.length > 50) {
41249          // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
41250          // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
41251          var remaining = child.lines.length % 25 + 25;
41252          for (var pos = remaining; pos < child.lines.length;) {
41253            var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
41254            child.height -= leaf.height;
41255            this$1.children.splice(++i, 0, leaf);
41256            leaf.parent = this$1;
41257          }
41258          child.lines = child.lines.slice(0, remaining);
41259          this$1.maybeSpill();
41260        }
41261        break
41262      }
41263      at -= sz;
41264    }
41265  },
41266
41267  // When a node has grown, check whether it should be split.
41268  maybeSpill: function() {
41269    if (this.children.length <= 10) { return }
41270    var me = this;
41271    do {
41272      var spilled = me.children.splice(me.children.length - 5, 5);
41273      var sibling = new BranchChunk(spilled);
41274      if (!me.parent) { // Become the parent node
41275        var copy = new BranchChunk(me.children);
41276        copy.parent = me;
41277        me.children = [copy, sibling];
41278        me = copy;
41279     } else {
41280        me.size -= sibling.size;
41281        me.height -= sibling.height;
41282        var myIndex = indexOf(me.parent.children, me);
41283        me.parent.children.splice(myIndex + 1, 0, sibling);
41284      }
41285      sibling.parent = me.parent;
41286    } while (me.children.length > 10)
41287    me.parent.maybeSpill();
41288  },
41289
41290  iterN: function(at, n, op) {
41291    var this$1 = this;
41292
41293    for (var i = 0; i < this.children.length; ++i) {
41294      var child = this$1.children[i], sz = child.chunkSize();
41295      if (at < sz) {
41296        var used = Math.min(n, sz - at);
41297        if (child.iterN(at, used, op)) { return true }
41298        if ((n -= used) == 0) { break }
41299        at = 0;
41300      } else { at -= sz; }
41301    }
41302  }
41303};
41304
41305// Line widgets are block elements displayed above or below a line.
41306
41307var LineWidget = function(doc, node, options) {
41308  var this$1 = this;
41309
41310  if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
41311    { this$1[opt] = options[opt]; } } }
41312  this.doc = doc;
41313  this.node = node;
41314};
41315
vendor: 153,296 bytes, lines 41316-45274
41316LineWidget.prototype.clear = function () {
41317    var this$1 = this;
41318
41319  var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
41320  if (no == null || !ws) { return }
41321  for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
41322  if (!ws.length) { line.widgets = null; }
41323  var height = widgetHeight(this);
41324  updateLineHeight(line, Math.max(0, line.height - height));
41325  if (cm) {
41326    runInOp(cm, function () {
41327      adjustScrollWhenAboveVisible(cm, line, -height);
41328      regLineChange(cm, no, "widget");
41329    });
41330    signalLater(cm, "lineWidgetCleared", cm, this, no);
41331  }
41332};
41333
41334LineWidget.prototype.changed = function () {
41335    var this$1 = this;
41336
41337  var oldH = this.height, cm = this.doc.cm, line = this.line;
41338  this.height = null;
41339  var diff = widgetHeight(this) - oldH;
41340  if (!diff) { return }
41341  updateLineHeight(line, line.height + diff);
41342  if (cm) {
41343    runInOp(cm, function () {
41344      cm.curOp.forceUpdate = true;
41345      adjustScrollWhenAboveVisible(cm, line, diff);
41346      signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
41347    });
41348  }
41349};
41350eventMixin(LineWidget);
41351
41352function adjustScrollWhenAboveVisible(cm, line, diff) {
41353  if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
41354    { addToScrollTop(cm, diff); }
41355}
41356
41357function addLineWidget(doc, handle, node, options) {
41358  var widget = new LineWidget(doc, node, options);
41359  var cm = doc.cm;
41360  if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
41361  changeLine(doc, handle, "widget", function (line) {
41362    var widgets = line.widgets || (line.widgets = []);
41363    if (widget.insertAt == null) { widgets.push(widget); }
41364    else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
41365    widget.line = line;
41366    if (cm && !lineIsHidden(doc, line)) {
41367      var aboveVisible = heightAtLine(line) < doc.scrollTop;
41368      updateLineHeight(line, line.height + widgetHeight(widget));
41369      if (aboveVisible) { addToScrollTop(cm, widget.height); }
41370      cm.curOp.forceUpdate = true;
41371    }
41372    return true
41373  });
41374  if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); }
41375  return widget
41376}
41377
41378// TEXTMARKERS
41379
41380// Created with markText and setBookmark methods. A TextMarker is a
41381// handle that can be used to clear or find a marked position in the
41382// document. Line objects hold arrays (markedSpans) containing
41383// {from, to, marker} object pointing to such marker objects, and
41384// indicating that such a marker is present on that line. Multiple
41385// lines may point to the same marker when it spans across lines.
41386// The spans will have null for their from/to properties when the
41387// marker continues beyond the start/end of the line. Markers have
41388// links back to the lines they currently touch.
41389
41390// Collapsed markers have unique ids, in order to be able to order
41391// them, which is needed for uniquely determining an outer marker
41392// when they overlap (they may nest, but not partially overlap).
41393var nextMarkerId = 0;
41394
41395var TextMarker = function(doc, type) {
41396  this.lines = [];
41397  this.type = type;
41398  this.doc = doc;
41399  this.id = ++nextMarkerId;
41400};
41401
41402// Clear the marker.
41403TextMarker.prototype.clear = function () {
41404    var this$1 = this;
41405
41406  if (this.explicitlyCleared) { return }
41407  var cm = this.doc.cm, withOp = cm && !cm.curOp;
41408  if (withOp) { startOperation(cm); }
41409  if (hasHandler(this, "clear")) {
41410    var found = this.find();
41411    if (found) { signalLater(this, "clear", found.from, found.to); }
41412  }
41413  var min = null, max = null;
41414  for (var i = 0; i < this.lines.length; ++i) {
41415    var line = this$1.lines[i];
41416    var span = getMarkedSpanFor(line.markedSpans, this$1);
41417    if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
41418    else if (cm) {
41419      if (span.to != null) { max = lineNo(line); }
41420      if (span.from != null) { min = lineNo(line); }
41421    }
41422    line.markedSpans = removeMarkedSpan(line.markedSpans, span);
41423    if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
41424      { updateLineHeight(line, textHeight(cm.display)); }
41425  }
41426  if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
41427    var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
41428    if (len > cm.display.maxLineLength) {
41429      cm.display.maxLine = visual;
41430      cm.display.maxLineLength = len;
41431      cm.display.maxLineChanged = true;
41432    }
41433  } }
41434
41435  if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
41436  this.lines.length = 0;
41437  this.explicitlyCleared = true;
41438  if (this.atomic && this.doc.cantEdit) {
41439    this.doc.cantEdit = false;
41440    if (cm) { reCheckSelection(cm.doc); }
41441  }
41442  if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
41443  if (withOp) { endOperation(cm); }
41444  if (this.parent) { this.parent.clear(); }
41445};
41446
41447// Find the position of the marker in the document. Returns a {from,
41448// to} object by default. Side can be passed to get a specific side
41449// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
41450// Pos objects returned contain a line object, rather than a line
41451// number (used to prevent looking up the same line twice).
41452TextMarker.prototype.find = function (side, lineObj) {
41453    var this$1 = this;
41454
41455  if (side == null && this.type == "bookmark") { side = 1; }
41456  var from, to;
41457  for (var i = 0; i < this.lines.length; ++i) {
41458    var line = this$1.lines[i];
41459    var span = getMarkedSpanFor(line.markedSpans, this$1);
41460    if (span.from != null) {
41461      from = Pos(lineObj ? line : lineNo(line), span.from);
41462      if (side == -1) { return from }
41463    }
41464    if (span.to != null) {
41465      to = Pos(lineObj ? line : lineNo(line), span.to);
41466      if (side == 1) { return to }
41467    }
41468  }
41469  return from && {from: from, to: to}
41470};
41471
41472// Signals that the marker's widget changed, and surrounding layout
41473// should be recomputed.
41474TextMarker.prototype.changed = function () {
41475    var this$1 = this;
41476
41477  var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
41478  if (!pos || !cm) { return }
41479  runInOp(cm, function () {
41480    var line = pos.line, lineN = lineNo(pos.line);
41481    var view = findViewForLine(cm, lineN);
41482    if (view) {
41483      clearLineMeasurementCacheFor(view);
41484      cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
41485    }
41486    cm.curOp.updateMaxLine = true;
41487    if (!lineIsHidden(widget.doc, line) && widget.height != null) {
41488      var oldHeight = widget.height;
41489      widget.height = null;
41490      var dHeight = widgetHeight(widget) - oldHeight;
41491      if (dHeight)
41492        { updateLineHeight(line, line.height + dHeight); }
41493    }
41494    signalLater(cm, "markerChanged", cm, this$1);
41495  });
41496};
41497
41498TextMarker.prototype.attachLine = function (line) {
41499  if (!this.lines.length && this.doc.cm) {
41500    var op = this.doc.cm.curOp;
41501    if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
41502      { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
41503  }
41504  this.lines.push(line);
41505};
41506
41507TextMarker.prototype.detachLine = function (line) {
41508  this.lines.splice(indexOf(this.lines, line), 1);
41509  if (!this.lines.length && this.doc.cm) {
41510    var op = this.doc.cm.curOp;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
41511  }
41512};
41513eventMixin(TextMarker);
41514
41515// Create a marker, wire it up to the right lines, and
41516function markText(doc, from, to, options, type) {
41517  // Shared markers (across linked documents) are handled separately
41518  // (markTextShared will call out to this again, once per
41519  // document).
41520  if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
41521  // Ensure we are in an operation.
41522  if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
41523
41524  var marker = new TextMarker(doc, type), diff = cmp(from, to);
41525  if (options) { copyObj(options, marker, false); }
41526  // Don't connect empty markers unless clearWhenEmpty is false
41527  if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
41528    { return marker }
41529  if (marker.replacedWith) {
41530    // Showing up as a widget implies collapsed (widget replaces text)
41531    marker.collapsed = true;
41532    marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
41533    if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
41534    if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
41535  }
41536  if (marker.collapsed) {
41537    if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
41538        from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
41539      { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
41540    seeCollapsedSpans();
41541  }
41542
41543  if (marker.addToHistory)
41544    { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
41545
41546  var curLine = from.line, cm = doc.cm, updateMaxLine;
41547  doc.iter(curLine, to.line + 1, function (line) {
41548    if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
41549      { updateMaxLine = true; }
41550    if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
41551    addMarkedSpan(line, new MarkedSpan(marker,
41552                                       curLine == from.line ? from.ch : null,
41553                                       curLine == to.line ? to.ch : null));
41554    ++curLine;
41555  });
41556  // lineIsHidden depends on the presence of the spans, so needs a second pass
41557  if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
41558    if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
41559  }); }
41560
41561  if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
41562
41563  if (marker.readOnly) {
41564    seeReadOnlySpans();
41565    if (doc.history.done.length || doc.history.undone.length)
41566      { doc.clearHistory(); }
41567  }
41568  if (marker.collapsed) {
41569    marker.id = ++nextMarkerId;
41570    marker.atomic = true;
41571  }
41572  if (cm) {
41573    // Sync editor state
41574    if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
41575    if (marker.collapsed)
41576      { regChange(cm, from.line, to.line + 1); }
41577    else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
41578      { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
41579    if (marker.atomic) { reCheckSelection(cm.doc); }
41580    signalLater(cm, "markerAdded", cm, marker);
41581  }
41582  return marker
41583}
41584
41585// SHARED TEXTMARKERS
41586
41587// A shared marker spans multiple linked documents. It is
41588// implemented as a meta-marker-object controlling multiple normal
41589// markers.
41590var SharedTextMarker = function(markers, primary) {
41591  var this$1 = this;
41592
41593  this.markers = markers;
41594  this.primary = primary;
41595  for (var i = 0; i < markers.length; ++i)
41596    { markers[i].parent = this$1; }
41597};
41598
41599SharedTextMarker.prototype.clear = function () {
41600    var this$1 = this;
41601
41602  if (this.explicitlyCleared) { return }
41603  this.explicitlyCleared = true;
41604  for (var i = 0; i < this.markers.length; ++i)
41605    { this$1.markers[i].clear(); }
41606  signalLater(this, "clear");
41607};
41608
41609SharedTextMarker.prototype.find = function (side, lineObj) {
41610  return this.primary.find(side, lineObj)
41611};
41612eventMixin(SharedTextMarker);
41613
41614function markTextShared(doc, from, to, options, type) {
41615  options = copyObj(options);
41616  options.shared = false;
41617  var markers = [markText(doc, from, to, options, type)], primary = markers[0];
41618  var widget = options.widgetNode;
41619  linkedDocs(doc, function (doc) {
41620    if (widget) { options.widgetNode = widget.cloneNode(true); }
41621    markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
41622    for (var i = 0; i < doc.linked.length; ++i)
41623      { if (doc.linked[i].isParent) { return } }
41624    primary = lst(markers);
41625  });
41626  return new SharedTextMarker(markers, primary)
41627}
41628
41629function findSharedMarkers(doc) {
41630  return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
41631}
41632
41633function copySharedMarkers(doc, markers) {
41634  for (var i = 0; i < markers.length; i++) {
41635    var marker = markers[i], pos = marker.find();
41636    var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
41637    if (cmp(mFrom, mTo)) {
41638      var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
41639      marker.markers.push(subMark);
41640      subMark.parent = marker;
41641    }
41642  }
41643}
41644
41645function detachSharedMarkers(markers) {
41646  var loop = function ( i ) {
41647    var marker = markers[i], linked = [marker.primary.doc];
41648    linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
41649    for (var j = 0; j < marker.markers.length; j++) {
41650      var subMarker = marker.markers[j];
41651      if (indexOf(linked, subMarker.doc) == -1) {
41652        subMarker.parent = null;
41653        marker.markers.splice(j--, 1);
41654      }
41655    }
41656  };
41657
41658  for (var i = 0; i < markers.length; i++) loop( i );
41659}
41660
41661var nextDocId = 0;
41662var Doc = function(text, mode, firstLine, lineSep, direction) {
41663  if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
41664  if (firstLine == null) { firstLine = 0; }
41665
41666  BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
41667  this.first = firstLine;
41668  this.scrollTop = this.scrollLeft = 0;
41669  this.cantEdit = false;
41670  this.cleanGeneration = 1;
41671  this.modeFrontier = this.highlightFrontier = firstLine;
41672  var start = Pos(firstLine, 0);
41673  this.sel = simpleSelection(start);
41674  this.history = new History(null);
41675  this.id = ++nextDocId;
41676  this.modeOption = mode;
41677  this.lineSep = lineSep;
41678  this.direction = (direction == "rtl") ? "rtl" : "ltr";
41679  this.extend = false;
41680
41681  if (typeof text == "string") { text = this.splitLines(text); }
41682  updateDoc(this, {from: start, to: start, text: text});
41683  setSelection(this, simpleSelection(start), sel_dontScroll);
41684};
41685
41686Doc.prototype = createObj(BranchChunk.prototype, {
41687  constructor: Doc,
41688  // Iterate over the document. Supports two forms -- with only one
41689  // argument, it calls that for each line in the document. With
41690  // three, it iterates over the range given by the first two (with
41691  // the second being non-inclusive).
41692  iter: function(from, to, op) {
41693    if (op) { this.iterN(from - this.first, to - from, op); }
41694    else { this.iterN(this.first, this.first + this.size, from); }
41695  },
41696
41697  // Non-public interface for adding and removing lines.
41698  insert: function(at, lines) {
41699    var height = 0;
41700    for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
41701    this.insertInner(at - this.first, lines, height);
41702  },
41703  remove: function(at, n) { this.removeInner(at - this.first, n); },
41704
41705  // From here, the methods are part of the public interface. Most
41706  // are also available from CodeMirror (editor) instances.
41707
41708  getValue: function(lineSep) {
41709    var lines = getLines(this, this.first, this.first + this.size);
41710    if (lineSep === false) { return lines }
41711    return lines.join(lineSep || this.lineSeparator())
41712  },
41713  setValue: docMethodOp(function(code) {
41714    var top = Pos(this.first, 0), last = this.first + this.size - 1;
41715    makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
41716                      text: this.splitLines(code), origin: "setValue", full: true}, true);
41717    if (this.cm) { scrollToCoords(this.cm, 0, 0); }
41718    setSelection(this, simpleSelection(top), sel_dontScroll);
41719  }),
41720  replaceRange: function(code, from, to, origin) {
41721    from = clipPos(this, from);
41722    to = to ? clipPos(this, to) : from;
41723    replaceRange(this, code, from, to, origin);
41724  },
41725  getRange: function(from, to, lineSep) {
41726    var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
41727    if (lineSep === false) { return lines }
41728    return lines.join(lineSep || this.lineSeparator())
41729  },
41730
41731  getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
41732
41733  getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
41734  getLineNumber: function(line) {return lineNo(line)},
41735
41736  getLineHandleVisualStart: function(line) {
41737    if (typeof line == "number") { line = getLine(this, line); }
41738    return visualLine(line)
41739  },
41740
41741  lineCount: function() {return this.size},
41742  firstLine: function() {return this.first},
41743  lastLine: function() {return this.first + this.size - 1},
41744
41745  clipPos: function(pos) {return clipPos(this, pos)},
41746
41747  getCursor: function(start) {
41748    var range$$1 = this.sel.primary(), pos;
41749    if (start == null || start == "head") { pos = range$$1.head; }
41750    else if (start == "anchor") { pos = range$$1.anchor; }
41751    else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
41752    else { pos = range$$1.from(); }
41753    return pos
41754  },
41755  listSelections: function() { return this.sel.ranges },
41756  somethingSelected: function() {return this.sel.somethingSelected()},
41757
41758  setCursor: docMethodOp(function(line, ch, options) {
41759    setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
41760  }),
41761  setSelection: docMethodOp(function(anchor, head, options) {
41762    setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
41763  }),
41764  extendSelection: docMethodOp(function(head, other, options) {
41765    extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
41766  }),
41767  extendSelections: docMethodOp(function(heads, options) {
41768    extendSelections(this, clipPosArray(this, heads), options);
41769  }),
41770  extendSelectionsBy: docMethodOp(function(f, options) {
41771    var heads = map(this.sel.ranges, f);
41772    extendSelections(this, clipPosArray(this, heads), options);
41773  }),
41774  setSelections: docMethodOp(function(ranges, primary, options) {
41775    var this$1 = this;
41776
41777    if (!ranges.length) { return }
41778    var out = [];
41779    for (var i = 0; i < ranges.length; i++)
41780      { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
41781                         clipPos(this$1, ranges[i].head)); }
41782    if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
41783    setSelection(this, normalizeSelection(out, primary), options);
41784  }),
41785  addSelection: docMethodOp(function(anchor, head, options) {
41786    var ranges = this.sel.ranges.slice(0);
41787    ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
41788    setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
41789  }),
41790
41791  getSelection: function(lineSep) {
41792    var this$1 = this;
41793
41794    var ranges = this.sel.ranges, lines;
41795    for (var i = 0; i < ranges.length; i++) {
41796      var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
41797      lines = lines ? lines.concat(sel) : sel;
41798    }
41799    if (lineSep === false) { return lines }
41800    else { return lines.join(lineSep || this.lineSeparator()) }
41801  },
41802  getSelections: function(lineSep) {
41803    var this$1 = this;
41804
41805    var parts = [], ranges = this.sel.ranges;
41806    for (var i = 0; i < ranges.length; i++) {
41807      var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
41808      if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
41809      parts[i] = sel;
41810    }
41811    return parts
41812  },
41813  replaceSelection: function(code, collapse, origin) {
41814    var dup = [];
41815    for (var i = 0; i < this.sel.ranges.length; i++)
41816      { dup[i] = code; }
41817    this.replaceSelections(dup, collapse, origin || "+input");
41818  },
41819  replaceSelections: docMethodOp(function(code, collapse, origin) {
41820    var this$1 = this;
41821
41822    var changes = [], sel = this.sel;
41823    for (var i = 0; i < sel.ranges.length; i++) {
41824      var range$$1 = sel.ranges[i];
41825      changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
41826    }
41827    var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
41828    for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
41829      { makeChange(this$1, changes[i$1]); }
41830    if (newSel) { setSelectionReplaceHistory(this, newSel); }
41831    else if (this.cm) { ensureCursorVisible(this.cm); }
41832  }),
41833  undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
41834  redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
41835  undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
41836  redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
41837
41838  setExtending: function(val) {this.extend = val;},
41839  getExtending: function() {return this.extend},
41840
41841  historySize: function() {
41842    var hist = this.history, done = 0, undone = 0;
41843    for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
41844    for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
41845    return {undo: done, redo: undone}
41846  },
41847  clearHistory: function() {this.history = new History(this.history.maxGeneration);},
41848
41849  markClean: function() {
41850    this.cleanGeneration = this.changeGeneration(true);
41851  },
41852  changeGeneration: function(forceSplit) {
41853    if (forceSplit)
41854      { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
41855    return this.history.generation
41856  },
41857  isClean: function (gen) {
41858    return this.history.generation == (gen || this.cleanGeneration)
41859  },
41860
41861  getHistory: function() {
41862    return {done: copyHistoryArray(this.history.done),
41863            undone: copyHistoryArray(this.history.undone)}
41864  },
41865  setHistory: function(histData) {
41866    var hist = this.history = new History(this.history.maxGeneration);
41867    hist.done = copyHistoryArray(histData.done.slice(0), null, true);
41868    hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
41869  },
41870
41871  setGutterMarker: docMethodOp(function(line, gutterID, value) {
41872    return changeLine(this, line, "gutter", function (line) {
41873      var markers = line.gutterMarkers || (line.gutterMarkers = {});
41874      markers[gutterID] = value;
41875      if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
41876      return true
41877    })
41878  }),
41879
41880  clearGutter: docMethodOp(function(gutterID) {
41881    var this$1 = this;
41882
41883    this.iter(function (line) {
41884      if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
41885        changeLine(this$1, line, "gutter", function () {
41886          line.gutterMarkers[gutterID] = null;
41887          if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
41888          return true
41889        });
41890      }
41891    });
41892  }),
41893
41894  lineInfo: function(line) {
41895    var n;
41896    if (typeof line == "number") {
41897      if (!isLine(this, line)) { return null }
41898      n = line;
41899      line = getLine(this, line);
41900      if (!line) { return null }
41901    } else {
41902      n = lineNo(line);
41903      if (n == null) { return null }
41904    }
41905    return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
41906            textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
41907            widgets: line.widgets}
41908  },
41909
41910  addLineClass: docMethodOp(function(handle, where, cls) {
41911    return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
41912      var prop = where == "text" ? "textClass"
41913               : where == "background" ? "bgClass"
41914               : where == "gutter" ? "gutterClass" : "wrapClass";
41915      if (!line[prop]) { line[prop] = cls; }
41916      else if (classTest(cls).test(line[prop])) { return false }
41917      else { line[prop] += " " + cls; }
41918      return true
41919    })
41920  }),
41921  removeLineClass: docMethodOp(function(handle, where, cls) {
41922    return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
41923      var prop = where == "text" ? "textClass"
41924               : where == "background" ? "bgClass"
41925               : where == "gutter" ? "gutterClass" : "wrapClass";
41926      var cur = line[prop];
41927      if (!cur) { return false }
41928      else if (cls == null) { line[prop] = null; }
41929      else {
41930        var found = cur.match(classTest(cls));
41931        if (!found) { return false }
41932        var end = found.index + found[0].length;
41933        line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
41934      }
41935      return true
41936    })
41937  }),
41938
41939  addLineWidget: docMethodOp(function(handle, node, options) {
41940    return addLineWidget(this, handle, node, options)
41941  }),
41942  removeLineWidget: function(widget) { widget.clear(); },
41943
41944  markText: function(from, to, options) {
41945    return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
41946  },
41947  setBookmark: function(pos, options) {
41948    var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
41949                    insertLeft: options && options.insertLeft,
41950                    clearWhenEmpty: false, shared: options && options.shared,
41951                    handleMouseEvents: options && options.handleMouseEvents};
41952    pos = clipPos(this, pos);
41953    return markText(this, pos, pos, realOpts, "bookmark")
41954  },
41955  findMarksAt: function(pos) {
41956    pos = clipPos(this, pos);
41957    var markers = [], spans = getLine(this, pos.line).markedSpans;
41958    if (spans) { for (var i = 0; i < spans.length; ++i) {
41959      var span = spans[i];
41960      if ((span.from == null || span.from <= pos.ch) &&
41961          (span.to == null || span.to >= pos.ch))
41962        { markers.push(span.marker.parent || span.marker); }
41963    } }
41964    return markers
41965  },
41966  findMarks: function(from, to, filter) {
41967    from = clipPos(this, from); to = clipPos(this, to);
41968    var found = [], lineNo$$1 = from.line;
41969    this.iter(from.line, to.line + 1, function (line) {
41970      var spans = line.markedSpans;
41971      if (spans) { for (var i = 0; i < spans.length; i++) {
41972        var span = spans[i];
41973        if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
41974              span.from == null && lineNo$$1 != from.line ||
41975              span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
41976            (!filter || filter(span.marker)))
41977          { found.push(span.marker.parent || span.marker); }
41978      } }
41979      ++lineNo$$1;
41980    });
41981    return found
41982  },
41983  getAllMarks: function() {
41984    var markers = [];
41985    this.iter(function (line) {
41986      var sps = line.markedSpans;
41987      if (sps) { for (var i = 0; i < sps.length; ++i)
41988        { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
41989    });
41990    return markers
41991  },
41992
41993  posFromIndex: function(off) {
41994    var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
41995    this.iter(function (line) {
41996      var sz = line.text.length + sepSize;
41997      if (sz > off) { ch = off; return true }
41998      off -= sz;
41999      ++lineNo$$1;
42000    });
42001    return clipPos(this, Pos(lineNo$$1, ch))
42002  },
42003  indexFromPos: function (coords) {
42004    coords = clipPos(this, coords);
42005    var index = coords.ch;
42006    if (coords.line < this.first || coords.ch < 0) { return 0 }
42007    var sepSize = this.lineSeparator().length;
42008    this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
42009      index += line.text.length + sepSize;
42010    });
42011    return index
42012  },
42013
42014  copy: function(copyHistory) {
42015    var doc = new Doc(getLines(this, this.first, this.first + this.size),
42016                      this.modeOption, this.first, this.lineSep, this.direction);
42017    doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
42018    doc.sel = this.sel;
42019    doc.extend = false;
42020    if (copyHistory) {
42021      doc.history.undoDepth = this.history.undoDepth;
42022      doc.setHistory(this.getHistory());
42023    }
42024    return doc
42025  },
42026
42027  linkedDoc: function(options) {
42028    if (!options) { options = {}; }
42029    var from = this.first, to = this.first + this.size;
42030    if (options.from != null && options.from > from) { from = options.from; }
42031    if (options.to != null && options.to < to) { to = options.to; }
42032    var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
42033    if (options.sharedHist) { copy.history = this.history
42034    ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
42035    copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
42036    copySharedMarkers(copy, findSharedMarkers(this));
42037    return copy
42038  },
42039  unlinkDoc: function(other) {
42040    var this$1 = this;
42041
42042    if (other instanceof CodeMirror$1) { other = other.doc; }
42043    if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
42044      var link = this$1.linked[i];
42045      if (link.doc != other) { continue }
42046      this$1.linked.splice(i, 1);
42047      other.unlinkDoc(this$1);
42048      detachSharedMarkers(findSharedMarkers(this$1));
42049      break
42050    } }
42051    // If the histories were shared, split them again
42052    if (other.history == this.history) {
42053      var splitIds = [other.id];
42054      linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
42055      other.history = new History(null);
42056      other.history.done = copyHistoryArray(this.history.done, splitIds);
42057      other.history.undone = copyHistoryArray(this.history.undone, splitIds);
42058    }
42059  },
42060  iterLinkedDocs: function(f) {linkedDocs(this, f);},
42061
42062  getMode: function() {return this.mode},
42063  getEditor: function() {return this.cm},
42064
42065  splitLines: function(str) {
42066    if (this.lineSep) { return str.split(this.lineSep) }
42067    return splitLinesAuto(str)
42068  },
42069  lineSeparator: function() { return this.lineSep || "\n" },
42070
42071  setDirection: docMethodOp(function (dir) {
42072    if (dir != "rtl") { dir = "ltr"; }
42073    if (dir == this.direction) { return }
42074    this.direction = dir;
42075    this.iter(function (line) { return line.order = null; });
42076    if (this.cm) { directionChanged(this.cm); }
42077  })
42078});
42079
42080// Public alias.
42081Doc.prototype.eachLine = Doc.prototype.iter;
42082
42083// Kludge to work around strange IE behavior where it'll sometimes
42084// re-fire a series of drag-related events right after the drop (#1551)
42085var lastDrop = 0;
42086
42087function onDrop(e) {
42088  var cm = this;
42089  clearDragCursor(cm);
42090  if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
42091    { return }
42092  e_preventDefault(e);
42093  if (ie) { lastDrop = +new Date; }
42094  var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
42095  if (!pos || cm.isReadOnly()) { return }
42096  // Might be a file drop, in which case we simply extract the text
42097  // and insert it.
42098  if (files && files.length && window.FileReader && window.File) {
42099    var n = files.length, text = Array(n), read = 0;
42100    var loadFile = function (file, i) {
42101      if (cm.options.allowDropFileTypes &&
42102          indexOf(cm.options.allowDropFileTypes, file.type) == -1)
42103        { return }
42104
42105      var reader = new FileReader;
42106      reader.onload = operation(cm, function () {
42107        var content = reader.result;
42108        if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
42109        text[i] = content;
42110        if (++read == n) {
42111          pos = clipPos(cm.doc, pos);
42112          var change = {from: pos, to: pos,
42113                        text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
42114                        origin: "paste"};
42115          makeChange(cm.doc, change);
42116          setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
42117        }
42118      });
42119      reader.readAsText(file);
42120    };
42121    for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
42122  } else { // Normal drop
42123    // Don't do a replace if the drop happened inside of the selected text.
42124    if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
42125      cm.state.draggingText(e);
42126      // Ensure the editor is re-focused
42127      setTimeout(function () { return cm.display.input.focus(); }, 20);
42128      return
42129    }
42130    try {
42131      var text$1 = e.dataTransfer.getData("Text");
42132      if (text$1) {
42133        var selected;
42134        if (cm.state.draggingText && !cm.state.draggingText.copy)
42135          { selected = cm.listSelections(); }
42136        setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
42137        if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
42138          { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
42139        cm.replaceSelection(text$1, "around", "paste");
42140        cm.display.input.focus();
42141      }
42142    }
42143    catch(e){}
42144  }
42145}
42146
42147function onDragStart(cm, e) {
42148  if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
42149  if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
42150
42151  e.dataTransfer.setData("Text", cm.getSelection());
42152  e.dataTransfer.effectAllowed = "copyMove";
42153
42154  // Use dummy image instead of default browsers image.
42155  // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
42156  if (e.dataTransfer.setDragImage && !safari) {
42157    var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
42158    img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
42159    if (presto) {
42160      img.width = img.height = 1;
42161      cm.display.wrapper.appendChild(img);
42162      // Force a relayout, or Opera won't use our image for some obscure reason
42163      img._top = img.offsetTop;
42164    }
42165    e.dataTransfer.setDragImage(img, 0, 0);
42166    if (presto) { img.parentNode.removeChild(img); }
42167  }
42168}
42169
42170function onDragOver(cm, e) {
42171  var pos = posFromMouse(cm, e);
42172  if (!pos) { return }
42173  var frag = document.createDocumentFragment();
42174  drawSelectionCursor(cm, pos, frag);
42175  if (!cm.display.dragCursor) {
42176    cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
42177    cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
42178  }
42179  removeChildrenAndAdd(cm.display.dragCursor, frag);
42180}
42181
42182function clearDragCursor(cm) {
42183  if (cm.display.dragCursor) {
42184    cm.display.lineSpace.removeChild(cm.display.dragCursor);
42185    cm.display.dragCursor = null;
42186  }
42187}
42188
42189// These must be handled carefully, because naively registering a
42190// handler for each editor will cause the editors to never be
42191// garbage collected.
42192
42193function forEachCodeMirror(f) {
42194  if (!document.getElementsByClassName) { return }
42195  var byClass = document.getElementsByClassName("CodeMirror");
42196  for (var i = 0; i < byClass.length; i++) {
42197    var cm = byClass[i].CodeMirror;
42198    if (cm) { f(cm); }
42199  }
42200}
42201
42202var globalsRegistered = false;
42203function ensureGlobalHandlers() {
42204  if (globalsRegistered) { return }
42205  registerGlobalHandlers();
42206  globalsRegistered = true;
42207}
42208function registerGlobalHandlers() {
42209  // When the window resizes, we need to refresh active editors.
42210  var resizeTimer;
42211  on(window, "resize", function () {
42212    if (resizeTimer == null) { resizeTimer = setTimeout(function () {
42213      resizeTimer = null;
42214      forEachCodeMirror(onResize);
42215    }, 100); }
42216  });
42217  // When the window loses focus, we want to show the editor as blurred
42218  on(window, "blur", function () { return forEachCodeMirror(onBlur); });
42219}
42220// Called when the window resizes
42221function onResize(cm) {
42222  var d = cm.display;
42223  if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
42224    { return }
42225  // Might be a text scaling operation, clear size caches.
42226  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
42227  d.scrollbarsClipped = false;
42228  cm.setSize();
42229}
42230
42231var keyNames = {
42232  3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
42233  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
42234  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
42235  46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
42236  106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
42237  173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
42238  221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
42239  63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
42240};
42241
42242// Number keys
42243for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
42244// Alphabetic keys
42245for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
42246// Function keys
42247for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
42248
42249var keyMap = {};
42250
42251keyMap.basic = {
42252  "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
42253  "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
42254  "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
42255  "Tab": "defaultTab", "Shift-Tab": "indentAuto",
42256  "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
42257  "Esc": "singleSelection"
42258};
42259// Note that the save and find-related commands aren't defined by
42260// default. User code or addons can define them. Unknown commands
42261// are simply ignored.
42262keyMap.pcDefault = {
42263  "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
42264  "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
42265  "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
42266  "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
42267  "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
42268  "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
42269  "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
42270  fallthrough: "basic"
42271};
42272// Very basic readline/emacs-style bindings, which are standard on Mac.
42273keyMap.emacsy = {
42274  "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
42275  "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
42276  "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
42277  "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
42278  "Ctrl-O": "openLine"
42279};
42280keyMap.macDefault = {
42281  "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
42282  "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
42283  "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
42284  "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
42285  "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
42286  "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
42287  "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
42288  fallthrough: ["basic", "emacsy"]
42289};
42290keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
42291
42292// KEYMAP DISPATCH
42293
42294function normalizeKeyName(name) {
42295  var parts = name.split(/-(?!$)/);
42296  name = parts[parts.length - 1];
42297  var alt, ctrl, shift, cmd;
42298  for (var i = 0; i < parts.length - 1; i++) {
42299    var mod = parts[i];
42300    if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
42301    else if (/^a(lt)?$/i.test(mod)) { alt = true; }
42302    else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
42303    else if (/^s(hift)?$/i.test(mod)) { shift = true; }
42304    else { throw new Error("Unrecognized modifier name: " + mod) }
42305  }
42306  if (alt) { name = "Alt-" + name; }
42307  if (ctrl) { name = "Ctrl-" + name; }
42308  if (cmd) { name = "Cmd-" + name; }
42309  if (shift) { name = "Shift-" + name; }
42310  return name
42311}
42312
42313// This is a kludge to keep keymaps mostly working as raw objects
42314// (backwards compatibility) while at the same time support features
42315// like normalization and multi-stroke key bindings. It compiles a
42316// new normalized keymap, and then updates the old object to reflect
42317// this.
42318function normalizeKeyMap(keymap) {
42319  var copy = {};
42320  for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
42321    var value = keymap[keyname];
42322    if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
42323    if (value == "...") { delete keymap[keyname]; continue }
42324
42325    var keys = map(keyname.split(" "), normalizeKeyName);
42326    for (var i = 0; i < keys.length; i++) {
42327      var val = (void 0), name = (void 0);
42328      if (i == keys.length - 1) {
42329        name = keys.join(" ");
42330        val = value;
42331      } else {
42332        name = keys.slice(0, i + 1).join(" ");
42333        val = "...";
42334      }
42335      var prev = copy[name];
42336      if (!prev) { copy[name] = val; }
42337      else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
42338    }
42339    delete keymap[keyname];
42340  } }
42341  for (var prop in copy) { keymap[prop] = copy[prop]; }
42342  return keymap
42343}
42344
42345function lookupKey(key, map$$1, handle, context) {
42346  map$$1 = getKeyMap(map$$1);
42347  var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
42348  if (found === false) { return "nothing" }
42349  if (found === "...") { return "multi" }
42350  if (found != null && handle(found)) { return "handled" }
42351
42352  if (map$$1.fallthrough) {
42353    if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
42354      { return lookupKey(key, map$$1.fallthrough, handle, context) }
42355    for (var i = 0; i < map$$1.fallthrough.length; i++) {
42356      var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
42357      if (result) { return result }
42358    }
42359  }
42360}
42361
42362// Modifier key presses don't count as 'real' key presses for the
42363// purpose of keymap fallthrough.
42364function isModifierKey(value) {
42365  var name = typeof value == "string" ? value : keyNames[value.keyCode];
42366  return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
42367}
42368
42369function addModifierNames(name, event, noShift) {
42370  var base = name;
42371  if (event.altKey && base != "Alt") { name = "Alt-" + name; }
42372  if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
42373  if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
42374  if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
42375  return name
42376}
42377
42378// Look up the name of a key as indicated by an event object.
42379function keyName(event, noShift) {
42380  if (presto && event.keyCode == 34 && event["char"]) { return false }
42381  var name = keyNames[event.keyCode];
42382  if (name == null || event.altGraphKey) { return false }
42383  // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
42384  // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
42385  if (event.keyCode == 3 && event.code) { name = event.code; }
42386  return addModifierNames(name, event, noShift)
42387}
42388
42389function getKeyMap(val) {
42390  return typeof val == "string" ? keyMap[val] : val
42391}
42392
42393// Helper for deleting text near the selection(s), used to implement
42394// backspace, delete, and similar functionality.
42395function deleteNearSelection(cm, compute) {
42396  var ranges = cm.doc.sel.ranges, kill = [];
42397  // Build up a set of ranges to kill first, merging overlapping
42398  // ranges.
42399  for (var i = 0; i < ranges.length; i++) {
42400    var toKill = compute(ranges[i]);
42401    while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
42402      var replaced = kill.pop();
42403      if (cmp(replaced.from, toKill.from) < 0) {
42404        toKill.from = replaced.from;
42405        break
42406      }
42407    }
42408    kill.push(toKill);
42409  }
42410  // Next, remove those actual ranges.
42411  runInOp(cm, function () {
42412    for (var i = kill.length - 1; i >= 0; i--)
42413      { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
42414    ensureCursorVisible(cm);
42415  });
42416}
42417
42418function moveCharLogically(line, ch, dir) {
42419  var target = skipExtendingChars(line.text, ch + dir, dir);
42420  return target < 0 || target > line.text.length ? null : target
42421}
42422
42423function moveLogically(line, start, dir) {
42424  var ch = moveCharLogically(line, start.ch, dir);
42425  return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
42426}
42427
42428function endOfLine(visually, cm, lineObj, lineNo, dir) {
42429  if (visually) {
42430    var order = getOrder(lineObj, cm.doc.direction);
42431    if (order) {
42432      var part = dir < 0 ? lst(order) : order[0];
42433      var moveInStorageOrder = (dir < 0) == (part.level == 1);
42434      var sticky = moveInStorageOrder ? "after" : "before";
42435      var ch;
42436      // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
42437      // it could be that the last bidi part is not on the last visual line,
42438      // since visual lines contain content order-consecutive chunks.
42439      // Thus, in rtl, we are looking for the first (content-order) character
42440      // in the rtl chunk that is on the last line (that is, the same line
42441      // as the last (content-order) character).
42442      if (part.level > 0 || cm.doc.direction == "rtl") {
42443        var prep = prepareMeasureForLine(cm, lineObj);
42444        ch = dir < 0 ? lineObj.text.length - 1 : 0;
42445        var targetTop = measureCharPrepared(cm, prep, ch).top;
42446        ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
42447        if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
42448      } else { ch = dir < 0 ? part.to : part.from; }
42449      return new Pos(lineNo, ch, sticky)
42450    }
42451  }
42452  return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
42453}
42454
42455function moveVisually(cm, line, start, dir) {
42456  var bidi = getOrder(line, cm.doc.direction);
42457  if (!bidi) { return moveLogically(line, start, dir) }
42458  if (start.ch >= line.text.length) {
42459    start.ch = line.text.length;
42460    start.sticky = "before";
42461  } else if (start.ch <= 0) {
42462    start.ch = 0;
42463    start.sticky = "after";
42464  }
42465  var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
42466  if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
42467    // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
42468    // nothing interesting happens.
42469    return moveLogically(line, start, dir)
42470  }
42471
42472  var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
42473  var prep;
42474  var getWrappedLineExtent = function (ch) {
42475    if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
42476    prep = prep || prepareMeasureForLine(cm, line);
42477    return wrappedLineExtentChar(cm, line, prep, ch)
42478  };
42479  var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
42480
42481  if (cm.doc.direction == "rtl" || part.level == 1) {
42482    var moveInStorageOrder = (part.level == 1) == (dir < 0);
42483    var ch = mv(start, moveInStorageOrder ? 1 : -1);
42484    if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
42485      // Case 2: We move within an rtl part or in an rtl editor on the same visual line
42486      var sticky = moveInStorageOrder ? "before" : "after";
42487      return new Pos(start.line, ch, sticky)
42488    }
42489  }
42490
42491  // Case 3: Could not move within this bidi part in this visual line, so leave
42492  // the current bidi part
42493
42494  var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
42495    var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
42496      ? new Pos(start.line, mv(ch, 1), "before")
42497      : new Pos(start.line, ch, "after"); };
42498
42499    for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
42500      var part = bidi[partPos];
42501      var moveInStorageOrder = (dir > 0) == (part.level != 1);
42502      var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
42503      if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
42504      ch = moveInStorageOrder ? part.from : mv(part.to, -1);
42505      if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
42506    }
42507  };
42508
42509  // Case 3a: Look for other bidi parts on the same visual line
42510  var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
42511  if (res) { return res }
42512
42513  // Case 3b: Look for other bidi parts on the next visual line
42514  var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
42515  if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
42516    res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
42517    if (res) { return res }
42518  }
42519
42520  // Case 4: Nowhere to move
42521  return null
42522}
42523
42524// Commands are parameter-less actions that can be performed on an
42525// editor, mostly used for keybindings.
42526var commands = {
42527  selectAll: selectAll,
42528  singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
42529  killLine: function (cm) { return deleteNearSelection(cm, function (range) {
42530    if (range.empty()) {
42531      var len = getLine(cm.doc, range.head.line).text.length;
42532      if (range.head.ch == len && range.head.line < cm.lastLine())
42533        { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
42534      else
42535        { return {from: range.head, to: Pos(range.head.line, len)} }
42536    } else {
42537      return {from: range.from(), to: range.to()}
42538    }
42539  }); },
42540  deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
42541    from: Pos(range.from().line, 0),
42542    to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
42543  }); }); },
42544  delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
42545    from: Pos(range.from().line, 0), to: range.from()
42546  }); }); },
42547  delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
42548    var top = cm.charCoords(range.head, "div").top + 5;
42549    var leftPos = cm.coordsChar({left: 0, top: top}, "div");
42550    return {from: leftPos, to: range.from()}
42551  }); },
42552  delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
42553    var top = cm.charCoords(range.head, "div").top + 5;
42554    var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
42555    return {from: range.from(), to: rightPos }
42556  }); },
42557  undo: function (cm) { return cm.undo(); },
42558  redo: function (cm) { return cm.redo(); },
42559  undoSelection: function (cm) { return cm.undoSelection(); },
42560  redoSelection: function (cm) { return cm.redoSelection(); },
42561  goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
42562  goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
42563  goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
42564    {origin: "+move", bias: 1}
42565  ); },
42566  goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
42567    {origin: "+move", bias: 1}
42568  ); },
42569  goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
42570    {origin: "+move", bias: -1}
42571  ); },
42572  goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
42573    var top = cm.cursorCoords(range.head, "div").top + 5;
42574    return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
42575  }, sel_move); },
42576  goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
42577    var top = cm.cursorCoords(range.head, "div").top + 5;
42578    return cm.coordsChar({left: 0, top: top}, "div")
42579  }, sel_move); },
42580  goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
42581    var top = cm.cursorCoords(range.head, "div").top + 5;
42582    var pos = cm.coordsChar({left: 0, top: top}, "div");
42583    if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
42584    return pos
42585  }, sel_move); },
42586  goLineUp: function (cm) { return cm.moveV(-1, "line"); },
42587  goLineDown: function (cm) { return cm.moveV(1, "line"); },
42588  goPageUp: function (cm) { return cm.moveV(-1, "page"); },
42589  goPageDown: function (cm) { return cm.moveV(1, "page"); },
42590  goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
42591  goCharRight: function (cm) { return cm.moveH(1, "char"); },
42592  goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
42593  goColumnRight: function (cm) { return cm.moveH(1, "column"); },
42594  goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
42595  goGroupRight: function (cm) { return cm.moveH(1, "group"); },
42596  goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
42597  goWordRight: function (cm) { return cm.moveH(1, "word"); },
42598  delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
42599  delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
42600  delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
42601  delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
42602  delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
42603  delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
42604  indentAuto: function (cm) { return cm.indentSelection("smart"); },
42605  indentMore: function (cm) { return cm.indentSelection("add"); },
42606  indentLess: function (cm) { return cm.indentSelection("subtract"); },
42607  insertTab: function (cm) { return cm.replaceSelection("\t"); },
42608  insertSoftTab: function (cm) {
42609    var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
42610    for (var i = 0; i < ranges.length; i++) {
42611      var pos = ranges[i].from();
42612      var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
42613      spaces.push(spaceStr(tabSize - col % tabSize));
42614    }
42615    cm.replaceSelections(spaces);
42616  },
42617  defaultTab: function (cm) {
42618    if (cm.somethingSelected()) { cm.indentSelection("add"); }
42619    else { cm.execCommand("insertTab"); }
42620  },
42621  // Swap the two chars left and right of each selection's head.
42622  // Move cursor behind the two swapped characters afterwards.
42623  //
42624  // Doesn't consider line feeds a character.
42625  // Doesn't scan more than one line above to find a character.
42626  // Doesn't do anything on an empty line.
42627  // Doesn't do anything with non-empty selections.
42628  transposeChars: function (cm) { return runInOp(cm, function () {
42629    var ranges = cm.listSelections(), newSel = [];
42630    for (var i = 0; i < ranges.length; i++) {
42631      if (!ranges[i].empty()) { continue }
42632      var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
42633      if (line) {
42634        if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
42635        if (cur.ch > 0) {
42636          cur = new Pos(cur.line, cur.ch + 1);
42637          cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
42638                          Pos(cur.line, cur.ch - 2), cur, "+transpose");
42639        } else if (cur.line > cm.doc.first) {
42640          var prev = getLine(cm.doc, cur.line - 1).text;
42641          if (prev) {
42642            cur = new Pos(cur.line, 1);
42643            cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
42644                            prev.charAt(prev.length - 1),
42645                            Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
42646          }
42647        }
42648      }
42649      newSel.push(new Range(cur, cur));
42650    }
42651    cm.setSelections(newSel);
42652  }); },
42653  newlineAndIndent: function (cm) { return runInOp(cm, function () {
42654    var sels = cm.listSelections();
42655    for (var i = sels.length - 1; i >= 0; i--)
42656      { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
42657    sels = cm.listSelections();
42658    for (var i$1 = 0; i$1 < sels.length; i$1++)
42659      { cm.indentLine(sels[i$1].from().line, null, true); }
42660    ensureCursorVisible(cm);
42661  }); },
42662  openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
42663  toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
42664};
42665
42666
42667function lineStart(cm, lineN) {
42668  var line = getLine(cm.doc, lineN);
42669  var visual = visualLine(line);
42670  if (visual != line) { lineN = lineNo(visual); }
42671  return endOfLine(true, cm, visual, lineN, 1)
42672}
42673function lineEnd(cm, lineN) {
42674  var line = getLine(cm.doc, lineN);
42675  var visual = visualLineEnd(line);
42676  if (visual != line) { lineN = lineNo(visual); }
42677  return endOfLine(true, cm, line, lineN, -1)
42678}
42679function lineStartSmart(cm, pos) {
42680  var start = lineStart(cm, pos.line);
42681  var line = getLine(cm.doc, start.line);
42682  var order = getOrder(line, cm.doc.direction);
42683  if (!order || order[0].level == 0) {
42684    var firstNonWS = Math.max(0, line.text.search(/\S/));
42685    var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
42686    return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
42687  }
42688  return start
42689}
42690
42691// Run a handler that was bound to a key.
42692function doHandleBinding(cm, bound, dropShift) {
42693  if (typeof bound == "string") {
42694    bound = commands[bound];
42695    if (!bound) { return false }
42696  }
42697  // Ensure previous input has been read, so that the handler sees a
42698  // consistent view of the document
42699  cm.display.input.ensurePolled();
42700  var prevShift = cm.display.shift, done = false;
42701  try {
42702    if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
42703    if (dropShift) { cm.display.shift = false; }
42704    done = bound(cm) != Pass;
42705  } finally {
42706    cm.display.shift = prevShift;
42707    cm.state.suppressEdits = false;
42708  }
42709  return done
42710}
42711
42712function lookupKeyForEditor(cm, name, handle) {
42713  for (var i = 0; i < cm.state.keyMaps.length; i++) {
42714    var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
42715    if (result) { return result }
42716  }
42717  return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
42718    || lookupKey(name, cm.options.keyMap, handle, cm)
42719}
42720
42721// Note that, despite the name, this function is also used to check
42722// for bound mouse clicks.
42723
42724var stopSeq = new Delayed;
42725
42726function dispatchKey(cm, name, e, handle) {
42727  var seq = cm.state.keySeq;
42728  if (seq) {
42729    if (isModifierKey(name)) { return "handled" }
42730    if (/\'$/.test(name))
42731      { cm.state.keySeq = null; }
42732    else
42733      { stopSeq.set(50, function () {
42734        if (cm.state.keySeq == seq) {
42735          cm.state.keySeq = null;
42736          cm.display.input.reset();
42737        }
42738      }); }
42739    if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
42740  }
42741  return dispatchKeyInner(cm, name, e, handle)
42742}
42743
42744function dispatchKeyInner(cm, name, e, handle) {
42745  var result = lookupKeyForEditor(cm, name, handle);
42746
42747  if (result == "multi")
42748    { cm.state.keySeq = name; }
42749  if (result == "handled")
42750    { signalLater(cm, "keyHandled", cm, name, e); }
42751
42752  if (result == "handled" || result == "multi") {
42753    e_preventDefault(e);
42754    restartBlink(cm);
42755  }
42756
42757  return !!result
42758}
42759
42760// Handle a key from the keydown event.
42761function handleKeyBinding(cm, e) {
42762  var name = keyName(e, true);
42763  if (!name) { return false }
42764
42765  if (e.shiftKey && !cm.state.keySeq) {
42766    // First try to resolve full name (including 'Shift-'). Failing
42767    // that, see if there is a cursor-motion command (starting with
42768    // 'go') bound to the keyname without 'Shift-'.
42769    return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
42770        || dispatchKey(cm, name, e, function (b) {
42771             if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
42772               { return doHandleBinding(cm, b) }
42773           })
42774  } else {
42775    return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
42776  }
42777}
42778
42779// Handle a key from the keypress event
42780function handleCharBinding(cm, e, ch) {
42781  return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
42782}
42783
42784var lastStoppedKey = null;
42785function onKeyDown(e) {
42786  var cm = this;
42787  cm.curOp.focus = activeElt();
42788  if (signalDOMEvent(cm, e)) { return }
42789  // IE does strange things with escape.
42790  if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
42791  var code = e.keyCode;
42792  cm.display.shift = code == 16 || e.shiftKey;
42793  var handled = handleKeyBinding(cm, e);
42794  if (presto) {
42795    lastStoppedKey = handled ? code : null;
42796    // Opera has no cut event... we try to at least catch the key combo
42797    if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
42798      { cm.replaceSelection("", null, "cut"); }
42799  }
42800
42801  // Turn mouse into crosshair when Alt is held on Mac.
42802  if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
42803    { showCrossHair(cm); }
42804}
42805
42806function showCrossHair(cm) {
42807  var lineDiv = cm.display.lineDiv;
42808  addClass(lineDiv, "CodeMirror-crosshair");
42809
42810  function up(e) {
42811    if (e.keyCode == 18 || !e.altKey) {
42812      rmClass(lineDiv, "CodeMirror-crosshair");
42813      off(document, "keyup", up);
42814      off(document, "mouseover", up);
42815    }
42816  }
42817  on(document, "keyup", up);
42818  on(document, "mouseover", up);
42819}
42820
42821function onKeyUp(e) {
42822  if (e.keyCode == 16) { this.doc.sel.shift = false; }
42823  signalDOMEvent(this, e);
42824}
42825
42826function onKeyPress(e) {
42827  var cm = this;
42828  if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
42829  var keyCode = e.keyCode, charCode = e.charCode;
42830  if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
42831  if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
42832  var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
42833  // Some browsers fire keypress events for backspace
42834  if (ch == "\x08") { return }
42835  if (handleCharBinding(cm, e, ch)) { return }
42836  cm.display.input.onKeyPress(e);
42837}
42838
42839var DOUBLECLICK_DELAY = 400;
42840
42841var PastClick = function(time, pos, button) {
42842  this.time = time;
42843  this.pos = pos;
42844  this.button = button;
42845};
42846
42847PastClick.prototype.compare = function (time, pos, button) {
42848  return this.time + DOUBLECLICK_DELAY > time &&
42849    cmp(pos, this.pos) == 0 && button == this.button
42850};
42851
42852var lastClick;
42853var lastDoubleClick;
42854function clickRepeat(pos, button) {
42855  var now = +new Date;
42856  if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
42857    lastClick = lastDoubleClick = null;
42858    return "triple"
42859  } else if (lastClick && lastClick.compare(now, pos, button)) {
42860    lastDoubleClick = new PastClick(now, pos, button);
42861    lastClick = null;
42862    return "double"
42863  } else {
42864    lastClick = new PastClick(now, pos, button);
42865    lastDoubleClick = null;
42866    return "single"
42867  }
42868}
42869
42870// A mouse down can be a single click, double click, triple click,
42871// start of selection drag, start of text drag, new cursor
42872// (ctrl-click), rectangle drag (alt-drag), or xwin
42873// middle-click-paste. Or it might be a click on something we should
42874// not interfere with, such as a scrollbar or widget.
42875function onMouseDown(e) {
42876  var cm = this, display = cm.display;
42877  if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
42878  display.input.ensurePolled();
42879  display.shift = e.shiftKey;
42880
42881  if (eventInWidget(display, e)) {
42882    if (!webkit) {
42883      // Briefly turn off draggability, to allow widgets to do
42884      // normal dragging things.
42885      display.scroller.draggable = false;
42886      setTimeout(function () { return display.scroller.draggable = true; }, 100);
42887    }
42888    return
42889  }
42890  if (clickInGutter(cm, e)) { return }
42891  var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
42892  window.focus();
42893
42894  // #3261: make sure, that we're not starting a second selection
42895  if (button == 1 && cm.state.selectingText)
42896    { cm.state.selectingText(e); }
42897
42898  if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
42899
42900  if (button == 1) {
42901    if (pos) { leftButtonDown(cm, pos, repeat, e); }
42902    else if (e_target(e) == display.scroller) { e_preventDefault(e); }
42903  } else if (button == 2) {
42904    if (pos) { extendSelection(cm.doc, pos); }
42905    setTimeout(function () { return display.input.focus(); }, 20);
42906  } else if (button == 3) {
42907    if (captureRightClick) { onContextMenu(cm, e); }
42908    else { delayBlurEvent(cm); }
42909  }
42910}
42911
42912function handleMappedButton(cm, button, pos, repeat, event) {
42913  var name = "Click";
42914  if (repeat == "double") { name = "Double" + name; }
42915  else if (repeat == "triple") { name = "Triple" + name; }
42916  name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
42917
42918  return dispatchKey(cm,  addModifierNames(name, event), event, function (bound) {
42919    if (typeof bound == "string") { bound = commands[bound]; }
42920    if (!bound) { return false }
42921    var done = false;
42922    try {
42923      if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
42924      done = bound(cm, pos) != Pass;
42925    } finally {
42926      cm.state.suppressEdits = false;
42927    }
42928    return done
42929  })
42930}
42931
42932function configureMouse(cm, repeat, event) {
42933  var option = cm.getOption("configureMouse");
42934  var value = option ? option(cm, repeat, event) : {};
42935  if (value.unit == null) {
42936    var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
42937    value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
42938  }
42939  if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
42940  if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
42941  if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
42942  return value
42943}
42944
42945function leftButtonDown(cm, pos, repeat, event) {
42946  if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
42947  else { cm.curOp.focus = activeElt(); }
42948
42949  var behavior = configureMouse(cm, repeat, event);
42950
42951  var sel = cm.doc.sel, contained;
42952  if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
42953      repeat == "single" && (contained = sel.contains(pos)) > -1 &&
42954      (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
42955      (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
42956    { leftButtonStartDrag(cm, event, pos, behavior); }
42957  else
42958    { leftButtonSelect(cm, event, pos, behavior); }
42959}
42960
42961// Start a text drag. When it ends, see if any dragging actually
42962// happen, and treat as a click if it didn't.
42963function leftButtonStartDrag(cm, event, pos, behavior) {
42964  var display = cm.display, moved = false;
42965  var dragEnd = operation(cm, function (e) {
42966    if (webkit) { display.scroller.draggable = false; }
42967    cm.state.draggingText = false;
42968    off(display.wrapper.ownerDocument, "mouseup", dragEnd);
42969    off(display.wrapper.ownerDocument, "mousemove", mouseMove);
42970    off(display.scroller, "dragstart", dragStart);
42971    off(display.scroller, "drop", dragEnd);
42972    if (!moved) {
42973      e_preventDefault(e);
42974      if (!behavior.addNew)
42975        { extendSelection(cm.doc, pos, null, null, behavior.extend); }
42976      // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
42977      if (webkit || ie && ie_version == 9)
42978        { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
42979      else
42980        { display.input.focus(); }
42981    }
42982  });
42983  var mouseMove = function(e2) {
42984    moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
42985  };
42986  var dragStart = function () { return moved = true; };
42987  // Let the drag handler handle this.
42988  if (webkit) { display.scroller.draggable = true; }
42989  cm.state.draggingText = dragEnd;
42990  dragEnd.copy = !behavior.moveOnDrag;
42991  // IE's approach to draggable
42992  if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
42993  on(display.wrapper.ownerDocument, "mouseup", dragEnd);
42994  on(display.wrapper.ownerDocument, "mousemove", mouseMove);
42995  on(display.scroller, "dragstart", dragStart);
42996  on(display.scroller, "drop", dragEnd);
42997
42998  delayBlurEvent(cm);
42999  setTimeout(function () { return display.input.focus(); }, 20);
43000}
43001
43002function rangeForUnit(cm, pos, unit) {
43003  if (unit == "char") { return new Range(pos, pos) }
43004  if (unit == "word") { return cm.findWordAt(pos) }
43005  if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
43006  var result = unit(cm, pos);
43007  return new Range(result.from, result.to)
43008}
43009
43010// Normal selection, as opposed to text dragging.
43011function leftButtonSelect(cm, event, start, behavior) {
43012  var display = cm.display, doc = cm.doc;
43013  e_preventDefault(event);
43014
43015  var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
43016  if (behavior.addNew && !behavior.extend) {
43017    ourIndex = doc.sel.contains(start);
43018    if (ourIndex > -1)
43019      { ourRange = ranges[ourIndex]; }
43020    else
43021      { ourRange = new Range(start, start); }
43022  } else {
43023    ourRange = doc.sel.primary();
43024    ourIndex = doc.sel.primIndex;
43025  }
43026
43027  if (behavior.unit == "rectangle") {
43028    if (!behavior.addNew) { ourRange = new Range(start, start); }
43029    start = posFromMouse(cm, event, true, true);
43030    ourIndex = -1;
43031  } else {
43032    var range$$1 = rangeForUnit(cm, start, behavior.unit);
43033    if (behavior.extend)
43034      { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
43035    else
43036      { ourRange = range$$1; }
43037  }
43038
43039  if (!behavior.addNew) {
43040    ourIndex = 0;
43041    setSelection(doc, new Selection([ourRange], 0), sel_mouse);
43042    startSel = doc.sel;
43043  } else if (ourIndex == -1) {
43044    ourIndex = ranges.length;
43045    setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
43046                 {scroll: false, origin: "*mouse"});
43047  } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
43048    setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
43049                 {scroll: false, origin: "*mouse"});
43050    startSel = doc.sel;
43051  } else {
43052    replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
43053  }
43054
43055  var lastPos = start;
43056  function extendTo(pos) {
43057    if (cmp(lastPos, pos) == 0) { return }
43058    lastPos = pos;
43059
43060    if (behavior.unit == "rectangle") {
43061      var ranges = [], tabSize = cm.options.tabSize;
43062      var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
43063      var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
43064      var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
43065      for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
43066           line <= end; line++) {
43067        var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
43068        if (left == right)
43069          { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
43070        else if (text.length > leftPos)
43071          { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
43072      }
43073      if (!ranges.length) { ranges.push(new Range(start, start)); }
43074      setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
43075                   {origin: "*mouse", scroll: false});
43076      cm.scrollIntoView(pos);
43077    } else {
43078      var oldRange = ourRange;
43079      var range$$1 = rangeForUnit(cm, pos, behavior.unit);
43080      var anchor = oldRange.anchor, head;
43081      if (cmp(range$$1.anchor, anchor) > 0) {
43082        head = range$$1.head;
43083        anchor = minPos(oldRange.from(), range$$1.anchor);
43084      } else {
43085        head = range$$1.anchor;
43086        anchor = maxPos(oldRange.to(), range$$1.head);
43087      }
43088      var ranges$1 = startSel.ranges.slice(0);
43089      ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
43090      setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse);
43091    }
43092  }
43093
43094  var editorSize = display.wrapper.getBoundingClientRect();
43095  // Used to ensure timeout re-tries don't fire when another extend
43096  // happened in the meantime (clearTimeout isn't reliable -- at
43097  // least on Chrome, the timeouts still happen even when cleared,
43098  // if the clear happens after their scheduled firing time).
43099  var counter = 0;
43100
43101  function extend(e) {
43102    var curCount = ++counter;
43103    var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
43104    if (!cur) { return }
43105    if (cmp(cur, lastPos) != 0) {
43106      cm.curOp.focus = activeElt();
43107      extendTo(cur);
43108      var visible = visibleLines(display, doc);
43109      if (cur.line >= visible.to || cur.line < visible.from)
43110        { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
43111    } else {
43112      var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
43113      if (outside) { setTimeout(operation(cm, function () {
43114        if (counter != curCount) { return }
43115        display.scroller.scrollTop += outside;
43116        extend(e);
43117      }), 50); }
43118    }
43119  }
43120
43121  function done(e) {
43122    cm.state.selectingText = false;
43123    counter = Infinity;
43124    e_preventDefault(e);
43125    display.input.focus();
43126    off(display.wrapper.ownerDocument, "mousemove", move);
43127    off(display.wrapper.ownerDocument, "mouseup", up);
43128    doc.history.lastSelOrigin = null;
43129  }
43130
43131  var move = operation(cm, function (e) {
43132    if (!e_button(e)) { done(e); }
43133    else { extend(e); }
43134  });
43135  var up = operation(cm, done);
43136  cm.state.selectingText = up;
43137  on(display.wrapper.ownerDocument, "mousemove", move);
43138  on(display.wrapper.ownerDocument, "mouseup", up);
43139}
43140
43141// Used when mouse-selecting to adjust the anchor to the proper side
43142// of a bidi jump depending on the visual position of the head.
43143function bidiSimplify(cm, range$$1) {
43144  var anchor = range$$1.anchor;
43145  var head = range$$1.head;
43146  var anchorLine = getLine(cm.doc, anchor.line);
43147  if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
43148  var order = getOrder(anchorLine);
43149  if (!order) { return range$$1 }
43150  var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
43151  if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
43152  var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
43153  if (boundary == 0 || boundary == order.length) { return range$$1 }
43154
43155  // Compute the relative visual position of the head compared to the
43156  // anchor (<0 is to the left, >0 to the right)
43157  var leftSide;
43158  if (head.line != anchor.line) {
43159    leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
43160  } else {
43161    var headIndex = getBidiPartAt(order, head.ch, head.sticky);
43162    var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
43163    if (headIndex == boundary - 1 || headIndex == boundary)
43164      { leftSide = dir < 0; }
43165    else
43166      { leftSide = dir > 0; }
43167  }
43168
43169  var usePart = order[boundary + (leftSide ? -1 : 0)];
43170  var from = leftSide == (usePart.level == 1);
43171  var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
43172  return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
43173}
43174
43175
43176// Determines whether an event happened in the gutter, and fires the
43177// handlers for the corresponding event.
43178function gutterEvent(cm, e, type, prevent) {
43179  var mX, mY;
43180  if (e.touches) {
43181    mX = e.touches[0].clientX;
43182    mY = e.touches[0].clientY;
43183  } else {
43184    try { mX = e.clientX; mY = e.clientY; }
43185    catch(e) { return false }
43186  }
43187  if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
43188  if (prevent) { e_preventDefault(e); }
43189
43190  var display = cm.display;
43191  var lineBox = display.lineDiv.getBoundingClientRect();
43192
43193  if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
43194  mY -= lineBox.top - display.viewOffset;
43195
43196  for (var i = 0; i < cm.options.gutters.length; ++i) {
43197    var g = display.gutters.childNodes[i];
43198    if (g && g.getBoundingClientRect().right >= mX) {
43199      var line = lineAtHeight(cm.doc, mY);
43200      var gutter = cm.options.gutters[i];
43201      signal(cm, type, cm, line, gutter, e);
43202      return e_defaultPrevented(e)
43203    }
43204  }
43205}
43206
43207function clickInGutter(cm, e) {
43208  return gutterEvent(cm, e, "gutterClick", true)
43209}
43210
43211// CONTEXT MENU HANDLING
43212
43213// To make the context menu work, we need to briefly unhide the
43214// textarea (making it as unobtrusive as possible) to let the
43215// right-click take effect on it.
43216function onContextMenu(cm, e) {
43217  if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
43218  if (signalDOMEvent(cm, e, "contextmenu")) { return }
43219  cm.display.input.onContextMenu(e);
43220}
43221
43222function contextMenuInGutter(cm, e) {
43223  if (!hasHandler(cm, "gutterContextMenu")) { return false }
43224  return gutterEvent(cm, e, "gutterContextMenu", false)
43225}
43226
43227function themeChanged(cm) {
43228  cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
43229    cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
43230  clearCaches(cm);
43231}
43232
43233var Init = {toString: function(){return "CodeMirror.Init"}};
43234
43235var defaults = {};
43236var optionHandlers = {};
43237
43238function defineOptions(CodeMirror) {
43239  var optionHandlers = CodeMirror.optionHandlers;
43240
43241  function option(name, deflt, handle, notOnInit) {
43242    CodeMirror.defaults[name] = deflt;
43243    if (handle) { optionHandlers[name] =
43244      notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
43245  }
43246
43247  CodeMirror.defineOption = option;
43248
43249  // Passed to option handlers when there is no old value.
43250  CodeMirror.Init = Init;
43251
43252  // These two are, on init, called from the constructor because they
43253  // have to be initialized before the editor can start at all.
43254  option("value", "", function (cm, val) { return cm.setValue(val); }, true);
43255  option("mode", null, function (cm, val) {
43256    cm.doc.modeOption = val;
43257    loadMode(cm);
43258  }, true);
43259
43260  option("indentUnit", 2, loadMode, true);
43261  option("indentWithTabs", false);
43262  option("smartIndent", true);
43263  option("tabSize", 4, function (cm) {
43264    resetModeState(cm);
43265    clearCaches(cm);
43266    regChange(cm);
43267  }, true);
43268
43269  option("lineSeparator", null, function (cm, val) {
43270    cm.doc.lineSep = val;
43271    if (!val) { return }
43272    var newBreaks = [], lineNo = cm.doc.first;
43273    cm.doc.iter(function (line) {
43274      for (var pos = 0;;) {
43275        var found = line.text.indexOf(val, pos);
43276        if (found == -1) { break }
43277        pos = found + val.length;
43278        newBreaks.push(Pos(lineNo, found));
43279      }
43280      lineNo++;
43281    });
43282    for (var i = newBreaks.length - 1; i >= 0; i--)
43283      { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
43284  });
43285  option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
43286    cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
43287    if (old != Init) { cm.refresh(); }
43288  });
43289  option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
43290  option("electricChars", true);
43291  option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
43292    throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
43293  }, true);
43294  option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
43295  option("rtlMoveVisually", !windows);
43296  option("wholeLineUpdateBefore", true);
43297
43298  option("theme", "default", function (cm) {
43299    themeChanged(cm);
43300    guttersChanged(cm);
43301  }, true);
43302  option("keyMap", "default", function (cm, val, old) {
43303    var next = getKeyMap(val);
43304    var prev = old != Init && getKeyMap(old);
43305    if (prev && prev.detach) { prev.detach(cm, next); }
43306    if (next.attach) { next.attach(cm, prev || null); }
43307  });
43308  option("extraKeys", null);
43309  option("configureMouse", null);
43310
43311  option("lineWrapping", false, wrappingChanged, true);
43312  option("gutters", [], function (cm) {
43313    setGuttersForLineNumbers(cm.options);
43314    guttersChanged(cm);
43315  }, true);
43316  option("fixedGutter", true, function (cm, val) {
43317    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
43318    cm.refresh();
43319  }, true);
43320  option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
43321  option("scrollbarStyle", "native", function (cm) {
43322    initScrollbars(cm);
43323    updateScrollbars(cm);
43324    cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
43325    cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
43326  }, true);
43327  option("lineNumbers", false, function (cm) {
43328    setGuttersForLineNumbers(cm.options);
43329    guttersChanged(cm);
43330  }, true);
43331  option("firstLineNumber", 1, guttersChanged, true);
43332  option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
43333  option("showCursorWhenSelecting", false, updateSelection, true);
43334
43335  option("resetSelectionOnContextMenu", true);
43336  option("lineWiseCopyCut", true);
43337  option("pasteLinesPerSelection", true);
43338
43339  option("readOnly", false, function (cm, val) {
43340    if (val == "nocursor") {
43341      onBlur(cm);
43342      cm.display.input.blur();
43343    }
43344    cm.display.input.readOnlyChanged(val);
43345  });
43346  option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
43347  option("dragDrop", true, dragDropChanged);
43348  option("allowDropFileTypes", null);
43349
43350  option("cursorBlinkRate", 530);
43351  option("cursorScrollMargin", 0);
43352  option("cursorHeight", 1, updateSelection, true);
43353  option("singleCursorHeightPerLine", true, updateSelection, true);
43354  option("workTime", 100);
43355  option("workDelay", 100);
43356  option("flattenSpans", true, resetModeState, true);
43357  option("addModeClass", false, resetModeState, true);
43358  option("pollInterval", 100);
43359  option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
43360  option("historyEventDelay", 1250);
43361  option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
43362  option("maxHighlightLength", 10000, resetModeState, true);
43363  option("moveInputWithCursor", true, function (cm, val) {
43364    if (!val) { cm.display.input.resetPosition(); }
43365  });
43366
43367  option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
43368  option("autofocus", null);
43369  option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
43370}
43371
43372function guttersChanged(cm) {
43373  updateGutters(cm);
43374  regChange(cm);
43375  alignHorizontally(cm);
43376}
43377
43378function dragDropChanged(cm, value, old) {
43379  var wasOn = old && old != Init;
43380  if (!value != !wasOn) {
43381    var funcs = cm.display.dragFunctions;
43382    var toggle = value ? on : off;
43383    toggle(cm.display.scroller, "dragstart", funcs.start);
43384    toggle(cm.display.scroller, "dragenter", funcs.enter);
43385    toggle(cm.display.scroller, "dragover", funcs.over);
43386    toggle(cm.display.scroller, "dragleave", funcs.leave);
43387    toggle(cm.display.scroller, "drop", funcs.drop);
43388  }
43389}
43390
43391function wrappingChanged(cm) {
43392  if (cm.options.lineWrapping) {
43393    addClass(cm.display.wrapper, "CodeMirror-wrap");
43394    cm.display.sizer.style.minWidth = "";
43395    cm.display.sizerWidth = null;
43396  } else {
43397    rmClass(cm.display.wrapper, "CodeMirror-wrap");
43398    findMaxLine(cm);
43399  }
43400  estimateLineHeights(cm);
43401  regChange(cm);
43402  clearCaches(cm);
43403  setTimeout(function () { return updateScrollbars(cm); }, 100);
43404}
43405
43406// A CodeMirror instance represents an editor. This is the object
43407// that user code is usually dealing with.
43408
43409function CodeMirror$1(place, options) {
43410  var this$1 = this;
43411
43412  if (!(this instanceof CodeMirror$1)) { return new CodeMirror$1(place, options) }
43413
43414  this.options = options = options ? copyObj(options) : {};
43415  // Determine effective options based on given values and defaults.
43416  copyObj(defaults, options, false);
43417  setGuttersForLineNumbers(options);
43418
43419  var doc = options.value;
43420  if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
43421  this.doc = doc;
43422
43423  var input = new CodeMirror$1.inputStyles[options.inputStyle](this);
43424  var display = this.display = new Display(place, doc, input);
43425  display.wrapper.CodeMirror = this;
43426  updateGutters(this);
43427  themeChanged(this);
43428  if (options.lineWrapping)
43429    { this.display.wrapper.className += " CodeMirror-wrap"; }
43430  initScrollbars(this);
43431
43432  this.state = {
43433    keyMaps: [],  // stores maps added by addKeyMap
43434    overlays: [], // highlighting overlays, as added by addOverlay
43435    modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info
43436    overwrite: false,
43437    delayingBlurEvent: false,
43438    focused: false,
43439    suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
43440    pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
43441    selectingText: false,
43442    draggingText: false,
43443    highlight: new Delayed(), // stores highlight worker timeout
43444    keySeq: null,  // Unfinished key sequence
43445    specialChars: null
43446  };
43447
43448  if (options.autofocus && !mobile) { display.input.focus(); }
43449
43450  // Override magic textarea content restore that IE sometimes does
43451  // on our hidden textarea on reload
43452  if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
43453
43454  registerEventHandlers(this);
43455  ensureGlobalHandlers();
43456
43457  startOperation(this);
43458  this.curOp.forceUpdate = true;
43459  attachDoc(this, doc);
43460
43461  if ((options.autofocus && !mobile) || this.hasFocus())
43462    { setTimeout(bind(onFocus, this), 20); }
43463  else
43464    { onBlur(this); }
43465
43466  for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
43467    { optionHandlers[opt](this$1, options[opt], Init); } }
43468  maybeUpdateLineNumberWidth(this);
43469  if (options.finishInit) { options.finishInit(this); }
43470  for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
43471  endOperation(this);
43472  // Suppress optimizelegibility in Webkit, since it breaks text
43473  // measuring on line wrapping boundaries.
43474  if (webkit && options.lineWrapping &&
43475      getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
43476    { display.lineDiv.style.textRendering = "auto"; }
43477}
43478
43479// The default configuration options.
43480CodeMirror$1.defaults = defaults;
43481// Functions to run when options are changed.
43482CodeMirror$1.optionHandlers = optionHandlers;
43483
43484// Attach the necessary event handlers when initializing the editor
43485function registerEventHandlers(cm) {
43486  var d = cm.display;
43487  on(d.scroller, "mousedown", operation(cm, onMouseDown));
43488  // Older IE's will not fire a second mousedown for a double click
43489  if (ie && ie_version < 11)
43490    { on(d.scroller, "dblclick", operation(cm, function (e) {
43491      if (signalDOMEvent(cm, e)) { return }
43492      var pos = posFromMouse(cm, e);
43493      if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
43494      e_preventDefault(e);
43495      var word = cm.findWordAt(pos);
43496      extendSelection(cm.doc, word.anchor, word.head);
43497    })); }
43498  else
43499    { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
43500  // Some browsers fire contextmenu *after* opening the menu, at
43501  // which point we can't mess with it anymore. Context menu is
43502  // handled in onMouseDown for these browsers.
43503  if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); }
43504
43505  // Used to suppress mouse event handling when a touch happens
43506  var touchFinished, prevTouch = {end: 0};
43507  function finishTouch() {
43508    if (d.activeTouch) {
43509      touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
43510      prevTouch = d.activeTouch;
43511      prevTouch.end = +new Date;
43512    }
43513  }
43514  function isMouseLikeTouchEvent(e) {
43515    if (e.touches.length != 1) { return false }
43516    var touch = e.touches[0];
43517    return touch.radiusX <= 1 && touch.radiusY <= 1
43518  }
43519  function farAway(touch, other) {
43520    if (other.left == null) { return true }
43521    var dx = other.left - touch.left, dy = other.top - touch.top;
43522    return dx * dx + dy * dy > 20 * 20
43523  }
43524  on(d.scroller, "touchstart", function (e) {
43525    if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
43526      d.input.ensurePolled();
43527      clearTimeout(touchFinished);
43528      var now = +new Date;
43529      d.activeTouch = {start: now, moved: false,
43530                       prev: now - prevTouch.end <= 300 ? prevTouch : null};
43531      if (e.touches.length == 1) {
43532        d.activeTouch.left = e.touches[0].pageX;
43533        d.activeTouch.top = e.touches[0].pageY;
43534      }
43535    }
43536  });
43537  on(d.scroller, "touchmove", function () {
43538    if (d.activeTouch) { d.activeTouch.moved = true; }
43539  });
43540  on(d.scroller, "touchend", function (e) {
43541    var touch = d.activeTouch;
43542    if (touch && !eventInWidget(d, e) && touch.left != null &&
43543        !touch.moved && new Date - touch.start < 300) {
43544      var pos = cm.coordsChar(d.activeTouch, "page"), range;
43545      if (!touch.prev || farAway(touch, touch.prev)) // Single tap
43546        { range = new Range(pos, pos); }
43547      else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
43548        { range = cm.findWordAt(pos); }
43549      else // Triple tap
43550        { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
43551      cm.setSelection(range.anchor, range.head);
43552      cm.focus();
43553      e_preventDefault(e);
43554    }
43555    finishTouch();
43556  });
43557  on(d.scroller, "touchcancel", finishTouch);
43558
43559  // Sync scrolling between fake scrollbars and real scrollable
43560  // area, ensure viewport is updated when scrolling.
43561  on(d.scroller, "scroll", function () {
43562    if (d.scroller.clientHeight) {
43563      updateScrollTop(cm, d.scroller.scrollTop);
43564      setScrollLeft(cm, d.scroller.scrollLeft, true);
43565      signal(cm, "scroll", cm);
43566    }
43567  });
43568
43569  // Listen to wheel events in order to try and update the viewport on time.
43570  on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
43571  on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
43572
43573  // Prevent wrapper from ever scrolling
43574  on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
43575
43576  d.dragFunctions = {
43577    enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
43578    over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
43579    start: function (e) { return onDragStart(cm, e); },
43580    drop: operation(cm, onDrop),
43581    leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
43582  };
43583
43584  var inp = d.input.getField();
43585  on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
43586  on(inp, "keydown", operation(cm, onKeyDown));
43587  on(inp, "keypress", operation(cm, onKeyPress));
43588  on(inp, "focus", function (e) { return onFocus(cm, e); });
43589  on(inp, "blur", function (e) { return onBlur(cm, e); });
43590}
43591
43592var initHooks = [];
43593CodeMirror$1.defineInitHook = function (f) { return initHooks.push(f); };
43594
43595// Indent the given line. The how parameter can be "smart",
43596// "add"/null, "subtract", or "prev". When aggressive is false
43597// (typically set to true for forced single-line indents), empty
43598// lines are not indented, and places where the mode returns Pass
43599// are left alone.
43600function indentLine(cm, n, how, aggressive) {
43601  var doc = cm.doc, state;
43602  if (how == null) { how = "add"; }
43603  if (how == "smart") {
43604    // Fall back to "prev" when the mode doesn't have an indentation
43605    // method.
43606    if (!doc.mode.indent) { how = "prev"; }
43607    else { state = getContextBefore(cm, n).state; }
43608  }
43609
43610  var tabSize = cm.options.tabSize;
43611  var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
43612  if (line.stateAfter) { line.stateAfter = null; }
43613  var curSpaceString = line.text.match(/^\s*/)[0], indentation;
43614  if (!aggressive && !/\S/.test(line.text)) {
43615    indentation = 0;
43616    how = "not";
43617  } else if (how == "smart") {
43618    indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
43619    if (indentation == Pass || indentation > 150) {
43620      if (!aggressive) { return }
43621      how = "prev";
43622    }
43623  }
43624  if (how == "prev") {
43625    if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
43626    else { indentation = 0; }
43627  } else if (how == "add") {
43628    indentation = curSpace + cm.options.indentUnit;
43629  } else if (how == "subtract") {
43630    indentation = curSpace - cm.options.indentUnit;
43631  } else if (typeof how == "number") {
43632    indentation = curSpace + how;
43633  }
43634  indentation = Math.max(0, indentation);
43635
43636  var indentString = "", pos = 0;
43637  if (cm.options.indentWithTabs)
43638    { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
43639  if (pos < indentation) { indentString += spaceStr(indentation - pos); }
43640
43641  if (indentString != curSpaceString) {
43642    replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
43643    line.stateAfter = null;
43644    return true
43645  } else {
43646    // Ensure that, if the cursor was in the whitespace at the start
43647    // of the line, it is moved to the end of that space.
43648    for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
43649      var range = doc.sel.ranges[i$1];
43650      if (range.head.line == n && range.head.ch < curSpaceString.length) {
43651        var pos$1 = Pos(n, curSpaceString.length);
43652        replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
43653        break
43654      }
43655    }
43656  }
43657}
43658
43659// This will be set to a {lineWise: bool, text: [string]} object, so
43660// that, when pasting, we know what kind of selections the copied
43661// text was made out of.
43662var lastCopied = null;
43663
43664function setLastCopied(newLastCopied) {
43665  lastCopied = newLastCopied;
43666}
43667
43668function applyTextInput(cm, inserted, deleted, sel, origin) {
43669  var doc = cm.doc;
43670  cm.display.shift = false;
43671  if (!sel) { sel = doc.sel; }
43672
43673  var paste = cm.state.pasteIncoming || origin == "paste";
43674  var textLines = splitLinesAuto(inserted), multiPaste = null;
43675  // When pasting N lines into N selections, insert one line per selection
43676  if (paste && sel.ranges.length > 1) {
43677    if (lastCopied && lastCopied.text.join("\n") == inserted) {
43678      if (sel.ranges.length % lastCopied.text.length == 0) {
43679        multiPaste = [];
43680        for (var i = 0; i < lastCopied.text.length; i++)
43681          { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
43682      }
43683    } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
43684      multiPaste = map(textLines, function (l) { return [l]; });
43685    }
43686  }
43687
43688  var updateInput;
43689  // Normal behavior is to insert the new text into every selection
43690  for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
43691    var range$$1 = sel.ranges[i$1];
43692    var from = range$$1.from(), to = range$$1.to();
43693    if (range$$1.empty()) {
43694      if (deleted && deleted > 0) // Handle deletion
43695        { from = Pos(from.line, from.ch - deleted); }
43696      else if (cm.state.overwrite && !paste) // Handle overwrite
43697        { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
43698      else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
43699        { from = to = Pos(from.line, 0); }
43700    }
43701    updateInput = cm.curOp.updateInput;
43702    var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
43703                       origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
43704    makeChange(cm.doc, changeEvent);
43705    signalLater(cm, "inputRead", cm, changeEvent);
43706  }
43707  if (inserted && !paste)
43708    { triggerElectric(cm, inserted); }
43709
43710  ensureCursorVisible(cm);
43711  cm.curOp.updateInput = updateInput;
43712  cm.curOp.typing = true;
43713  cm.state.pasteIncoming = cm.state.cutIncoming = false;
43714}
43715
43716function handlePaste(e, cm) {
43717  var pasted = e.clipboardData && e.clipboardData.getData("Text");
43718  if (pasted) {
43719    e.preventDefault();
43720    if (!cm.isReadOnly() && !cm.options.disableInput)
43721      { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
43722    return true
43723  }
43724}
43725
43726function triggerElectric(cm, inserted) {
43727  // When an 'electric' character is inserted, immediately trigger a reindent
43728  if (!cm.options.electricChars || !cm.options.smartIndent) { return }
43729  var sel = cm.doc.sel;
43730
43731  for (var i = sel.ranges.length - 1; i >= 0; i--) {
43732    var range$$1 = sel.ranges[i];
43733    if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
43734    var mode = cm.getModeAt(range$$1.head);
43735    var indented = false;
43736    if (mode.electricChars) {
43737      for (var j = 0; j < mode.electricChars.length; j++)
43738        { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
43739          indented = indentLine(cm, range$$1.head.line, "smart");
43740          break
43741        } }
43742    } else if (mode.electricInput) {
43743      if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
43744        { indented = indentLine(cm, range$$1.head.line, "smart"); }
43745    }
43746    if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
43747  }
43748}
43749
43750function copyableRanges(cm) {
43751  var text = [], ranges = [];
43752  for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
43753    var line = cm.doc.sel.ranges[i].head.line;
43754    var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
43755    ranges.push(lineRange);
43756    text.push(cm.getRange(lineRange.anchor, lineRange.head));
43757  }
43758  return {text: text, ranges: ranges}
43759}
43760
43761function disableBrowserMagic(field, spellcheck) {
43762  field.setAttribute("autocorrect", "off");
43763  field.setAttribute("autocapitalize", "off");
43764  field.setAttribute("spellcheck", !!spellcheck);
43765}
43766
43767function hiddenTextarea() {
43768  var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
43769  var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
43770  // The textarea is kept positioned near the cursor to prevent the
43771  // fact that it'll be scrolled into view on input from scrolling
43772  // our fake cursor out of view. On webkit, when wrap=off, paste is
43773  // very slow. So make the area wide instead.
43774  if (webkit) { te.style.width = "1000px"; }
43775  else { te.setAttribute("wrap", "off"); }
43776  // If border: 0; -- iOS fails to open keyboard (issue #1287)
43777  if (ios) { te.style.border = "1px solid black"; }
43778  disableBrowserMagic(te);
43779  return div
43780}
43781
43782// The publicly visible API. Note that methodOp(f) means
43783// 'wrap f in an operation, performed on its `this` parameter'.
43784
43785// This is not the complete set of editor methods. Most of the
43786// methods defined on the Doc type are also injected into
43787// CodeMirror.prototype, for backwards compatibility and
43788// convenience.
43789
43790var addEditorMethods = function(CodeMirror) {
43791  var optionHandlers = CodeMirror.optionHandlers;
43792
43793  var helpers = CodeMirror.helpers = {};
43794
43795  CodeMirror.prototype = {
43796    constructor: CodeMirror,
43797    focus: function(){window.focus(); this.display.input.focus();},
43798
43799    setOption: function(option, value) {
43800      var options = this.options, old = options[option];
43801      if (options[option] == value && option != "mode") { return }
43802      options[option] = value;
43803      if (optionHandlers.hasOwnProperty(option))
43804        { operation(this, optionHandlers[option])(this, value, old); }
43805      signal(this, "optionChange", this, option);
43806    },
43807
43808    getOption: function(option) {return this.options[option]},
43809    getDoc: function() {return this.doc},
43810
43811    addKeyMap: function(map$$1, bottom) {
43812      this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
43813    },
43814    removeKeyMap: function(map$$1) {
43815      var maps = this.state.keyMaps;
43816      for (var i = 0; i < maps.length; ++i)
43817        { if (maps[i] == map$$1 || maps[i].name == map$$1) {
43818          maps.splice(i, 1);
43819          return true
43820        } }
43821    },
43822
43823    addOverlay: methodOp(function(spec, options) {
43824      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
43825      if (mode.startState) { throw new Error("Overlays may not be stateful.") }
43826      insertSorted(this.state.overlays,
43827                   {mode: mode, modeSpec: spec, opaque: options && options.opaque,
43828                    priority: (options && options.priority) || 0},
43829                   function (overlay) { return overlay.priority; });
43830      this.state.modeGen++;
43831      regChange(this);
43832    }),
43833    removeOverlay: methodOp(function(spec) {
43834      var this$1 = this;
43835
43836      var overlays = this.state.overlays;
43837      for (var i = 0; i < overlays.length; ++i) {
43838        var cur = overlays[i].modeSpec;
43839        if (cur == spec || typeof spec == "string" && cur.name == spec) {
43840          overlays.splice(i, 1);
43841          this$1.state.modeGen++;
43842          regChange(this$1);
43843          return
43844        }
43845      }
43846    }),
43847
43848    indentLine: methodOp(function(n, dir, aggressive) {
43849      if (typeof dir != "string" && typeof dir != "number") {
43850        if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
43851        else { dir = dir ? "add" : "subtract"; }
43852      }
43853      if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
43854    }),
43855    indentSelection: methodOp(function(how) {
43856      var this$1 = this;
43857
43858      var ranges = this.doc.sel.ranges, end = -1;
43859      for (var i = 0; i < ranges.length; i++) {
43860        var range$$1 = ranges[i];
43861        if (!range$$1.empty()) {
43862          var from = range$$1.from(), to = range$$1.to();
43863          var start = Math.max(end, from.line);
43864          end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
43865          for (var j = start; j < end; ++j)
43866            { indentLine(this$1, j, how); }
43867          var newRanges = this$1.doc.sel.ranges;
43868          if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
43869            { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
43870        } else if (range$$1.head.line > end) {
43871          indentLine(this$1, range$$1.head.line, how, true);
43872          end = range$$1.head.line;
43873          if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
43874        }
43875      }
43876    }),
43877
43878    // Fetch the parser token for a given character. Useful for hacks
43879    // that want to inspect the mode state (say, for completion).
43880    getTokenAt: function(pos, precise) {
43881      return takeToken(this, pos, precise)
43882    },
43883
43884    getLineTokens: function(line, precise) {
43885      return takeToken(this, Pos(line), precise, true)
43886    },
43887
43888    getTokenTypeAt: function(pos) {
43889      pos = clipPos(this.doc, pos);
43890      var styles = getLineStyles(this, getLine(this.doc, pos.line));
43891      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
43892      var type;
43893      if (ch == 0) { type = styles[2]; }
43894      else { for (;;) {
43895        var mid = (before + after) >> 1;
43896        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
43897        else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
43898        else { type = styles[mid * 2 + 2]; break }
43899      } }
43900      var cut = type ? type.indexOf("overlay ") : -1;
43901      return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
43902    },
43903
43904    getModeAt: function(pos) {
43905      var mode = this.doc.mode;
43906      if (!mode.innerMode) { return mode }
43907      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
43908    },
43909
43910    getHelper: function(pos, type) {
43911      return this.getHelpers(pos, type)[0]
43912    },
43913
43914    getHelpers: function(pos, type) {
43915      var this$1 = this;
43916
43917      var found = [];
43918      if (!helpers.hasOwnProperty(type)) { return found }
43919      var help = helpers[type], mode = this.getModeAt(pos);
43920      if (typeof mode[type] == "string") {
43921        if (help[mode[type]]) { found.push(help[mode[type]]); }
43922      } else if (mode[type]) {
43923        for (var i = 0; i < mode[type].length; i++) {
43924          var val = help[mode[type][i]];
43925          if (val) { found.push(val); }
43926        }
43927      } else if (mode.helperType && help[mode.helperType]) {
43928        found.push(help[mode.helperType]);
43929      } else if (help[mode.name]) {
43930        found.push(help[mode.name]);
43931      }
43932      for (var i$1 = 0; i$1 < help._global.length; i$1++) {
43933        var cur = help._global[i$1];
43934        if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
43935          { found.push(cur.val); }
43936      }
43937      return found
43938    },
43939
43940    getStateAfter: function(line, precise) {
43941      var doc = this.doc;
43942      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
43943      return getContextBefore(this, line + 1, precise).state
43944    },
43945
43946    cursorCoords: function(start, mode) {
43947      var pos, range$$1 = this.doc.sel.primary();
43948      if (start == null) { pos = range$$1.head; }
43949      else if (typeof start == "object") { pos = clipPos(this.doc, start); }
43950      else { pos = start ? range$$1.from() : range$$1.to(); }
43951      return cursorCoords(this, pos, mode || "page")
43952    },
43953
43954    charCoords: function(pos, mode) {
43955      return charCoords(this, clipPos(this.doc, pos), mode || "page")
43956    },
43957
43958    coordsChar: function(coords, mode) {
43959      coords = fromCoordSystem(this, coords, mode || "page");
43960      return coordsChar(this, coords.left, coords.top)
43961    },
43962
43963    lineAtHeight: function(height, mode) {
43964      height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
43965      return lineAtHeight(this.doc, height + this.display.viewOffset)
43966    },
43967    heightAtLine: function(line, mode, includeWidgets) {
43968      var end = false, lineObj;
43969      if (typeof line == "number") {
43970        var last = this.doc.first + this.doc.size - 1;
43971        if (line < this.doc.first) { line = this.doc.first; }
43972        else if (line > last) { line = last; end = true; }
43973        lineObj = getLine(this.doc, line);
43974      } else {
43975        lineObj = line;
43976      }
43977      return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
43978        (end ? this.doc.height - heightAtLine(lineObj) : 0)
43979    },
43980
43981    defaultTextHeight: function() { return textHeight(this.display) },
43982    defaultCharWidth: function() { return charWidth(this.display) },
43983
43984    getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
43985
43986    addWidget: function(pos, node, scroll, vert, horiz) {
43987      var display = this.display;
43988      pos = cursorCoords(this, clipPos(this.doc, pos));
43989      var top = pos.bottom, left = pos.left;
43990      node.style.position = "absolute";
43991      node.setAttribute("cm-ignore-events", "true");
43992      this.display.input.setUneditable(node);
43993      display.sizer.appendChild(node);
43994      if (vert == "over") {
43995        top = pos.top;
43996      } else if (vert == "above" || vert == "near") {
43997        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
43998        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
43999        // Default to positioning above (if specified and possible); otherwise default to positioning below
44000        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
44001          { top = pos.top - node.offsetHeight; }
44002        else if (pos.bottom + node.offsetHeight <= vspace)
44003          { top = pos.bottom; }
44004        if (left + node.offsetWidth > hspace)
44005          { left = hspace - node.offsetWidth; }
44006      }
44007      node.style.top = top + "px";
44008      node.style.left = node.style.right = "";
44009      if (horiz == "right") {
44010        left = display.sizer.clientWidth - node.offsetWidth;
44011        node.style.right = "0px";
44012      } else {
44013        if (horiz == "left") { left = 0; }
44014        else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
44015        node.style.left = left + "px";
44016      }
44017      if (scroll)
44018        { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
44019    },
44020
44021    triggerOnKeyDown: methodOp(onKeyDown),
44022    triggerOnKeyPress: methodOp(onKeyPress),
44023    triggerOnKeyUp: onKeyUp,
44024    triggerOnMouseDown: methodOp(onMouseDown),
44025
44026    execCommand: function(cmd) {
44027      if (commands.hasOwnProperty(cmd))
44028        { return commands[cmd].call(null, this) }
44029    },
44030
44031    triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
44032
44033    findPosH: function(from, amount, unit, visually) {
44034      var this$1 = this;
44035
44036      var dir = 1;
44037      if (amount < 0) { dir = -1; amount = -amount; }
44038      var cur = clipPos(this.doc, from);
44039      for (var i = 0; i < amount; ++i) {
44040        cur = findPosH(this$1.doc, cur, dir, unit, visually);
44041        if (cur.hitSide) { break }
44042      }
44043      return cur
44044    },
44045
44046    moveH: methodOp(function(dir, unit) {
44047      var this$1 = this;
44048
44049      this.extendSelectionsBy(function (range$$1) {
44050        if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
44051          { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
44052        else
44053          { return dir < 0 ? range$$1.from() : range$$1.to() }
44054      }, sel_move);
44055    }),
44056
44057    deleteH: methodOp(function(dir, unit) {
44058      var sel = this.doc.sel, doc = this.doc;
44059      if (sel.somethingSelected())
44060        { doc.replaceSelection("", null, "+delete"); }
44061      else
44062        { deleteNearSelection(this, function (range$$1) {
44063          var other = findPosH(doc, range$$1.head, dir, unit, false);
44064          return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
44065        }); }
44066    }),
44067
44068    findPosV: function(from, amount, unit, goalColumn) {
44069      var this$1 = this;
44070
44071      var dir = 1, x = goalColumn;
44072      if (amount < 0) { dir = -1; amount = -amount; }
44073      var cur = clipPos(this.doc, from);
44074      for (var i = 0; i < amount; ++i) {
44075        var coords = cursorCoords(this$1, cur, "div");
44076        if (x == null) { x = coords.left; }
44077        else { coords.left = x; }
44078        cur = findPosV(this$1, coords, dir, unit);
44079        if (cur.hitSide) { break }
44080      }
44081      return cur
44082    },
44083
44084    moveV: methodOp(function(dir, unit) {
44085      var this$1 = this;
44086
44087      var doc = this.doc, goals = [];
44088      var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
44089      doc.extendSelectionsBy(function (range$$1) {
44090        if (collapse)
44091          { return dir < 0 ? range$$1.from() : range$$1.to() }
44092        var headPos = cursorCoords(this$1, range$$1.head, "div");
44093        if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
44094        goals.push(headPos.left);
44095        var pos = findPosV(this$1, headPos, dir, unit);
44096        if (unit == "page" && range$$1 == doc.sel.primary())
44097          { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
44098        return pos
44099      }, sel_move);
44100      if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
44101        { doc.sel.ranges[i].goalColumn = goals[i]; } }
44102    }),
44103
44104    // Find the word at the given position (as returned by coordsChar).
44105    findWordAt: function(pos) {
44106      var doc = this.doc, line = getLine(doc, pos.line).text;
44107      var start = pos.ch, end = pos.ch;
44108      if (line) {
44109        var helper = this.getHelper(pos, "wordChars");
44110        if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
44111        var startChar = line.charAt(start);
44112        var check = isWordChar(startChar, helper)
44113          ? function (ch) { return isWordChar(ch, helper); }
44114          : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
44115          : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
44116        while (start > 0 && check(line.charAt(start - 1))) { --start; }
44117        while (end < line.length && check(line.charAt(end))) { ++end; }
44118      }
44119      return new Range(Pos(pos.line, start), Pos(pos.line, end))
44120    },
44121
44122    toggleOverwrite: function(value) {
44123      if (value != null && value == this.state.overwrite) { return }
44124      if (this.state.overwrite = !this.state.overwrite)
44125        { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
44126      else
44127        { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
44128
44129      signal(this, "overwriteToggle", this, this.state.overwrite);
44130    },
44131    hasFocus: function() { return this.display.input.getField() == activeElt() },
44132    isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
44133
44134    scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
44135    getScrollInfo: function() {
44136      var scroller = this.display.scroller;
44137      return {left: scroller.scrollLeft, top: scroller.scrollTop,
44138              height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
44139              width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
44140              clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
44141    },
44142
44143    scrollIntoView: methodOp(function(range$$1, margin) {
44144      if (range$$1 == null) {
44145        range$$1 = {from: this.doc.sel.primary().head, to: null};
44146        if (margin == null) { margin = this.options.cursorScrollMargin; }
44147      } else if (typeof range$$1 == "number") {
44148        range$$1 = {from: Pos(range$$1, 0), to: null};
44149      } else if (range$$1.from == null) {
44150        range$$1 = {from: range$$1, to: null};
44151      }
44152      if (!range$$1.to) { range$$1.to = range$$1.from; }
44153      range$$1.margin = margin || 0;
44154
44155      if (range$$1.from.line != null) {
44156        scrollToRange(this, range$$1);
44157      } else {
44158        scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
44159      }
44160    }),
44161
44162    setSize: methodOp(function(width, height) {
44163      var this$1 = this;
44164
44165      var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
44166      if (width != null) { this.display.wrapper.style.width = interpret(width); }
44167      if (height != null) { this.display.wrapper.style.height = interpret(height); }
44168      if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
44169      var lineNo$$1 = this.display.viewFrom;
44170      this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
44171        if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
44172          { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
44173        ++lineNo$$1;
44174      });
44175      this.curOp.forceUpdate = true;
44176      signal(this, "refresh", this);
44177    }),
44178
44179    operation: function(f){return runInOp(this, f)},
44180    startOperation: function(){return startOperation(this)},
44181    endOperation: function(){return endOperation(this)},
44182
44183    refresh: methodOp(function() {
44184      var oldHeight = this.display.cachedTextHeight;
44185      regChange(this);
44186      this.curOp.forceUpdate = true;
44187      clearCaches(this);
44188      scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
44189      updateGutterSpace(this);
44190      if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
44191        { estimateLineHeights(this); }
44192      signal(this, "refresh", this);
44193    }),
44194
44195    swapDoc: methodOp(function(doc) {
44196      var old = this.doc;
44197      old.cm = null;
44198      attachDoc(this, doc);
44199      clearCaches(this);
44200      this.display.input.reset();
44201      scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
44202      this.curOp.forceScroll = true;
44203      signalLater(this, "swapDoc", this, old);
44204      return old
44205    }),
44206
44207    getInputField: function(){return this.display.input.getField()},
44208    getWrapperElement: function(){return this.display.wrapper},
44209    getScrollerElement: function(){return this.display.scroller},
44210    getGutterElement: function(){return this.display.gutters}
44211  };
44212  eventMixin(CodeMirror);
44213
44214  CodeMirror.registerHelper = function(type, name, value) {
44215    if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
44216    helpers[type][name] = value;
44217  };
44218  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
44219    CodeMirror.registerHelper(type, name, value);
44220    helpers[type]._global.push({pred: predicate, val: value});
44221  };
44222};
44223
44224// Used for horizontal relative motion. Dir is -1 or 1 (left or
44225// right), unit can be "char", "column" (like char, but doesn't
44226// cross line boundaries), "word" (across next word), or "group" (to
44227// the start of next group of word or non-word-non-whitespace
44228// chars). The visually param controls whether, in right-to-left
44229// text, direction 1 means to move towards the next index in the
44230// string, or towards the character to the right of the current
44231// position. The resulting position will have a hitSide=true
44232// property if it reached the end of the document.
44233function findPosH(doc, pos, dir, unit, visually) {
44234  var oldPos = pos;
44235  var origDir = dir;
44236  var lineObj = getLine(doc, pos.line);
44237  function findNextLine() {
44238    var l = pos.line + dir;
44239    if (l < doc.first || l >= doc.first + doc.size) { return false }
44240    pos = new Pos(l, pos.ch, pos.sticky);
44241    return lineObj = getLine(doc, l)
44242  }
44243  function moveOnce(boundToLine) {
44244    var next;
44245    if (visually) {
44246      next = moveVisually(doc.cm, lineObj, pos, dir);
44247    } else {
44248      next = moveLogically(lineObj, pos, dir);
44249    }
44250    if (next == null) {
44251      if (!boundToLine && findNextLine())
44252        { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
44253      else
44254        { return false }
44255    } else {
44256      pos = next;
44257    }
44258    return true
44259  }
44260
44261  if (unit == "char") {
44262    moveOnce();
44263  } else if (unit == "column") {
44264    moveOnce(true);
44265  } else if (unit == "word" || unit == "group") {
44266    var sawType = null, group = unit == "group";
44267    var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
44268    for (var first = true;; first = false) {
44269      if (dir < 0 && !moveOnce(!first)) { break }
44270      var cur = lineObj.text.charAt(pos.ch) || "\n";
44271      var type = isWordChar(cur, helper) ? "w"
44272        : group && cur == "\n" ? "n"
44273        : !group || /\s/.test(cur) ? null
44274        : "p";
44275      if (group && !first && !type) { type = "s"; }
44276      if (sawType && sawType != type) {
44277        if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
44278        break
44279      }
44280
44281      if (type) { sawType = type; }
44282      if (dir > 0 && !moveOnce(!first)) { break }
44283    }
44284  }
44285  var result = skipAtomic(doc, pos, oldPos, origDir, true);
44286  if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
44287  return result
44288}
44289
44290// For relative vertical movement. Dir may be -1 or 1. Unit can be
44291// "page" or "line". The resulting position will have a hitSide=true
44292// property if it reached the end of the document.
44293function findPosV(cm, pos, dir, unit) {
44294  var doc = cm.doc, x = pos.left, y;
44295  if (unit == "page") {
44296    var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
44297    var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
44298    y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
44299
44300  } else if (unit == "line") {
44301    y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
44302  }
44303  var target;
44304  for (;;) {
44305    target = coordsChar(cm, x, y);
44306    if (!target.outside) { break }
44307    if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
44308    y += dir * 5;
44309  }
44310  return target
44311}
44312
44313// CONTENTEDITABLE INPUT STYLE
44314
44315var ContentEditableInput = function(cm) {
44316  this.cm = cm;
44317  this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
44318  this.polling = new Delayed();
44319  this.composing = null;
44320  this.gracePeriod = false;
44321  this.readDOMTimeout = null;
44322};
44323
44324ContentEditableInput.prototype.init = function (display) {
44325    var this$1 = this;
44326
44327  var input = this, cm = input.cm;
44328  var div = input.div = display.lineDiv;
44329  disableBrowserMagic(div, cm.options.spellcheck);
44330
44331  on(div, "paste", function (e) {
44332    if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
44333    // IE doesn't fire input events, so we schedule a read for the pasted content in this way
44334    if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
44335  });
44336
44337  on(div, "compositionstart", function (e) {
44338    this$1.composing = {data: e.data, done: false};
44339  });
44340  on(div, "compositionupdate", function (e) {
44341    if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
44342  });
44343  on(div, "compositionend", function (e) {
44344    if (this$1.composing) {
44345      if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
44346      this$1.composing.done = true;
44347    }
44348  });
44349
44350  on(div, "touchstart", function () { return input.forceCompositionEnd(); });
44351
44352  on(div, "input", function () {
44353    if (!this$1.composing) { this$1.readFromDOMSoon(); }
44354  });
44355
44356  function onCopyCut(e) {
44357    if (signalDOMEvent(cm, e)) { return }
44358    if (cm.somethingSelected()) {
44359      setLastCopied({lineWise: false, text: cm.getSelections()});
44360      if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
44361    } else if (!cm.options.lineWiseCopyCut) {
44362      return
44363    } else {
44364      var ranges = copyableRanges(cm);
44365      setLastCopied({lineWise: true, text: ranges.text});
44366      if (e.type == "cut") {
44367        cm.operation(function () {
44368          cm.setSelections(ranges.ranges, 0, sel_dontScroll);
44369          cm.replaceSelection("", null, "cut");
44370        });
44371      }
44372    }
44373    if (e.clipboardData) {
44374      e.clipboardData.clearData();
44375      var content = lastCopied.text.join("\n");
44376      // iOS exposes the clipboard API, but seems to discard content inserted into it
44377      e.clipboardData.setData("Text", content);
44378      if (e.clipboardData.getData("Text") == content) {
44379        e.preventDefault();
44380        return
44381      }
44382    }
44383    // Old-fashioned briefly-focus-a-textarea hack
44384    var kludge = hiddenTextarea(), te = kludge.firstChild;
44385    cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
44386    te.value = lastCopied.text.join("\n");
44387    var hadFocus = document.activeElement;
44388    selectInput(te);
44389    setTimeout(function () {
44390      cm.display.lineSpace.removeChild(kludge);
44391      hadFocus.focus();
44392      if (hadFocus == div) { input.showPrimarySelection(); }
44393    }, 50);
44394  }
44395  on(div, "copy", onCopyCut);
44396  on(div, "cut", onCopyCut);
44397};
44398
44399ContentEditableInput.prototype.prepareSelection = function () {
44400  var result = prepareSelection(this.cm, false);
44401  result.focus = this.cm.state.focused;
44402  return result
44403};
44404
44405ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
44406  if (!info || !this.cm.display.view.length) { return }
44407  if (info.focus || takeFocus) { this.showPrimarySelection(); }
44408  this.showMultipleSelections(info);
44409};
44410
44411ContentEditableInput.prototype.showPrimarySelection = function () {
44412  var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
44413  var from = prim.from(), to = prim.to();
44414
44415  if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
44416    sel.removeAllRanges();
44417    return
44418  }
44419
44420  var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
44421  var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
44422  if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
44423      cmp(minPos(curAnchor, curFocus), from) == 0 &&
44424      cmp(maxPos(curAnchor, curFocus), to) == 0)
44425    { return }
44426
44427  var view = cm.display.view;
44428  var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
44429      {node: view[0].measure.map[2], offset: 0};
44430  var end = to.line < cm.display.viewTo && posToDOM(cm, to);
44431  if (!end) {
44432    var measure = view[view.length - 1].measure;
44433    var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
44434    end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
44435  }
44436
44437  if (!start || !end) {
44438    sel.removeAllRanges();
44439    return
44440  }
44441
44442  var old = sel.rangeCount && sel.getRangeAt(0), rng;
44443  try { rng = range(start.node, start.offset, end.offset, end.node); }
44444  catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
44445  if (rng) {
44446    if (!gecko && cm.state.focused) {
44447      sel.collapse(start.node, start.offset);
44448      if (!rng.collapsed) {
44449        sel.removeAllRanges();
44450        sel.addRange(rng);
44451      }
44452    } else {
44453      sel.removeAllRanges();
44454      sel.addRange(rng);
44455    }
44456    if (old && sel.anchorNode == null) { sel.addRange(old); }
44457    else if (gecko) { this.startGracePeriod(); }
44458  }
44459  this.rememberSelection();
44460};
44461
44462ContentEditableInput.prototype.startGracePeriod = function () {
44463    var this$1 = this;
44464
44465  clearTimeout(this.gracePeriod);
44466  this.gracePeriod = setTimeout(function () {
44467    this$1.gracePeriod = false;
44468    if (this$1.selectionChanged())
44469      { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
44470  }, 20);
44471};
44472
44473ContentEditableInput.prototype.showMultipleSelections = function (info) {
44474  removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
44475  removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
44476};
44477
44478ContentEditableInput.prototype.rememberSelection = function () {
44479  var sel = window.getSelection();
44480  this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
44481  this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
44482};
44483
44484ContentEditableInput.prototype.selectionInEditor = function () {
44485  var sel = window.getSelection();
44486  if (!sel.rangeCount) { return false }
44487  var node = sel.getRangeAt(0).commonAncestorContainer;
44488  return contains(this.div, node)
44489};
44490
44491ContentEditableInput.prototype.focus = function () {
44492  if (this.cm.options.readOnly != "nocursor") {
44493    if (!this.selectionInEditor())
44494      { this.showSelection(this.prepareSelection(), true); }
44495    this.div.focus();
44496  }
44497};
44498ContentEditableInput.prototype.blur = function () { this.div.blur(); };
44499ContentEditableInput.prototype.getField = function () { return this.div };
44500
44501ContentEditableInput.prototype.supportsTouch = function () { return true };
44502
44503ContentEditableInput.prototype.receivedFocus = function () {
44504  var input = this;
44505  if (this.selectionInEditor())
44506    { this.pollSelection(); }
44507  else
44508    { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
44509
44510  function poll() {
44511    if (input.cm.state.focused) {
44512      input.pollSelection();
44513      input.polling.set(input.cm.options.pollInterval, poll);
44514    }
44515  }
44516  this.polling.set(this.cm.options.pollInterval, poll);
44517};
44518
44519ContentEditableInput.prototype.selectionChanged = function () {
44520  var sel = window.getSelection();
44521  return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
44522    sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
44523};
44524
44525ContentEditableInput.prototype.pollSelection = function () {
44526  if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
44527  var sel = window.getSelection(), cm = this.cm;
44528  // On Android Chrome (version 56, at least), backspacing into an
44529  // uneditable block element will put the cursor in that element,
44530  // and then, because it's not editable, hide the virtual keyboard.
44531  // Because Android doesn't allow us to actually detect backspace
44532  // presses in a sane way, this code checks for when that happens
44533  // and simulates a backspace press in this case.
44534  if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
44535    this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
44536    this.blur();
44537    this.focus();
44538    return
44539  }
44540  if (this.composing) { return }
44541  this.rememberSelection();
44542  var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
44543  var head = domToPos(cm, sel.focusNode, sel.focusOffset);
44544  if (anchor && head) { runInOp(cm, function () {
44545    setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
44546    if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
44547  }); }
44548};
44549
44550ContentEditableInput.prototype.pollContent = function () {
44551  if (this.readDOMTimeout != null) {
44552    clearTimeout(this.readDOMTimeout);
44553    this.readDOMTimeout = null;
44554  }
44555
44556  var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
44557  var from = sel.from(), to = sel.to();
44558  if (from.ch == 0 && from.line > cm.firstLine())
44559    { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
44560  if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
44561    { to = Pos(to.line + 1, 0); }
44562  if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
44563
44564  var fromIndex, fromLine, fromNode;
44565  if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
44566    fromLine = lineNo(display.view[0].line);
44567    fromNode = display.view[0].node;
44568  } else {
44569    fromLine = lineNo(display.view[fromIndex].line);
44570    fromNode = display.view[fromIndex - 1].node.nextSibling;
44571  }
44572  var toIndex = findViewIndex(cm, to.line);
44573  var toLine, toNode;
44574  if (toIndex == display.view.length - 1) {
44575    toLine = display.viewTo - 1;
44576    toNode = display.lineDiv.lastChild;
44577  } else {
44578    toLine = lineNo(display.view[toIndex + 1].line) - 1;
44579    toNode = display.view[toIndex + 1].node.previousSibling;
44580  }
44581
44582  if (!fromNode) { return false }
44583  var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
44584  var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
44585  while (newText.length > 1 && oldText.length > 1) {
44586    if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
44587    else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
44588    else { break }
44589  }
44590
44591  var cutFront = 0, cutEnd = 0;
44592  var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
44593  while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
44594    { ++cutFront; }
44595  var newBot = lst(newText), oldBot = lst(oldText);
44596  var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
44597                           oldBot.length - (oldText.length == 1 ? cutFront : 0));
44598  while (cutEnd < maxCutEnd &&
44599         newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
44600    { ++cutEnd; }
44601  // Try to move start of change to start of selection if ambiguous
44602  if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
44603    while (cutFront && cutFront > from.ch &&
44604           newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
44605      cutFront--;
44606      cutEnd++;
44607    }
44608  }
44609
44610  newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
44611  newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
44612
44613  var chFrom = Pos(fromLine, cutFront);
44614  var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
44615  if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
44616    replaceRange(cm.doc, newText, chFrom, chTo, "+input");
44617    return true
44618  }
44619};
44620
44621ContentEditableInput.prototype.ensurePolled = function () {
44622  this.forceCompositionEnd();
44623};
44624ContentEditableInput.prototype.reset = function () {
44625  this.forceCompositionEnd();
44626};
44627ContentEditableInput.prototype.forceCompositionEnd = function () {
44628  if (!this.composing) { return }
44629  clearTimeout(this.readDOMTimeout);
44630  this.composing = null;
44631  this.updateFromDOM();
44632  this.div.blur();
44633  this.div.focus();
44634};
44635ContentEditableInput.prototype.readFromDOMSoon = function () {
44636    var this$1 = this;
44637
44638  if (this.readDOMTimeout != null) { return }
44639  this.readDOMTimeout = setTimeout(function () {
44640    this$1.readDOMTimeout = null;
44641    if (this$1.composing) {
44642      if (this$1.composing.done) { this$1.composing = null; }
44643      else { return }
44644    }
44645    this$1.updateFromDOM();
44646  }, 80);
44647};
44648
44649ContentEditableInput.prototype.updateFromDOM = function () {
44650    var this$1 = this;
44651
44652  if (this.cm.isReadOnly() || !this.pollContent())
44653    { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
44654};
44655
44656ContentEditableInput.prototype.setUneditable = function (node) {
44657  node.contentEditable = "false";
44658};
44659
44660ContentEditableInput.prototype.onKeyPress = function (e) {
44661  if (e.charCode == 0 || this.composing) { return }
44662  e.preventDefault();
44663  if (!this.cm.isReadOnly())
44664    { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
44665};
44666
44667ContentEditableInput.prototype.readOnlyChanged = function (val) {
44668  this.div.contentEditable = String(val != "nocursor");
44669};
44670
44671ContentEditableInput.prototype.onContextMenu = function () {};
44672ContentEditableInput.prototype.resetPosition = function () {};
44673
44674ContentEditableInput.prototype.needsContentAttribute = true;
44675
44676function posToDOM(cm, pos) {
44677  var view = findViewForLine(cm, pos.line);
44678  if (!view || view.hidden) { return null }
44679  var line = getLine(cm.doc, pos.line);
44680  var info = mapFromLineView(view, line, pos.line);
44681
44682  var order = getOrder(line, cm.doc.direction), side = "left";
44683  if (order) {
44684    var partPos = getBidiPartAt(order, pos.ch);
44685    side = partPos % 2 ? "right" : "left";
44686  }
44687  var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
44688  result.offset = result.collapse == "right" ? result.end : result.start;
44689  return result
44690}
44691
44692function isInGutter(node) {
44693  for (var scan = node; scan; scan = scan.parentNode)
44694    { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
44695  return false
44696}
44697
44698function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
44699
44700function domTextBetween(cm, from, to, fromLine, toLine) {
44701  var text = "", closing = false, lineSep = cm.doc.lineSeparator();
44702  function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
44703  function close() {
44704    if (closing) {
44705      text += lineSep;
44706      closing = false;
44707    }
44708  }
44709  function addText(str) {
44710    if (str) {
44711      close();
44712      text += str;
44713    }
44714  }
44715  function walk(node) {
44716    if (node.nodeType == 1) {
44717      var cmText = node.getAttribute("cm-text");
44718      if (cmText != null) {
44719        addText(cmText || node.textContent.replace(/\u200b/g, ""));
44720        return
44721      }
44722      var markerID = node.getAttribute("cm-marker"), range$$1;
44723      if (markerID) {
44724        var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
44725        if (found.length && (range$$1 = found[0].find(0)))
44726          { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
44727        return
44728      }
44729      if (node.getAttribute("contenteditable") == "false") { return }
44730      var isBlock = /^(pre|div|p)$/i.test(node.nodeName);
44731      if (isBlock) { close(); }
44732      for (var i = 0; i < node.childNodes.length; i++)
44733        { walk(node.childNodes[i]); }
44734      if (isBlock) { closing = true; }
44735    } else if (node.nodeType == 3) {
44736      addText(node.nodeValue);
44737    }
44738  }
44739  for (;;) {
44740    walk(from);
44741    if (from == to) { break }
44742    from = from.nextSibling;
44743  }
44744  return text
44745}
44746
44747function domToPos(cm, node, offset) {
44748  var lineNode;
44749  if (node == cm.display.lineDiv) {
44750    lineNode = cm.display.lineDiv.childNodes[offset];
44751    if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
44752    node = null; offset = 0;
44753  } else {
44754    for (lineNode = node;; lineNode = lineNode.parentNode) {
44755      if (!lineNode || lineNode == cm.display.lineDiv) { return null }
44756      if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
44757    }
44758  }
44759  for (var i = 0; i < cm.display.view.length; i++) {
44760    var lineView = cm.display.view[i];
44761    if (lineView.node == lineNode)
44762      { return locateNodeInLineView(lineView, node, offset) }
44763  }
44764}
44765
44766function locateNodeInLineView(lineView, node, offset) {
44767  var wrapper = lineView.text.firstChild, bad = false;
44768  if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
44769  if (node == wrapper) {
44770    bad = true;
44771    node = wrapper.childNodes[offset];
44772    offset = 0;
44773    if (!node) {
44774      var line = lineView.rest ? lst(lineView.rest) : lineView.line;
44775      return badPos(Pos(lineNo(line), line.text.length), bad)
44776    }
44777  }
44778
44779  var textNode = node.nodeType == 3 ? node : null, topNode = node;
44780  if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
44781    textNode = node.firstChild;
44782    if (offset) { offset = textNode.nodeValue.length; }
44783  }
44784  while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
44785  var measure = lineView.measure, maps = measure.maps;
44786
44787  function find(textNode, topNode, offset) {
44788    for (var i = -1; i < (maps ? maps.length : 0); i++) {
44789      var map$$1 = i < 0 ? measure.map : maps[i];
44790      for (var j = 0; j < map$$1.length; j += 3) {
44791        var curNode = map$$1[j + 2];
44792        if (curNode == textNode || curNode == topNode) {
44793          var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
44794          var ch = map$$1[j] + offset;
44795          if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
44796          return Pos(line, ch)
44797        }
44798      }
44799    }
44800  }
44801  var found = find(textNode, topNode, offset);
44802  if (found) { return badPos(found, bad) }
44803
44804  // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
44805  for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
44806    found = find(after, after.firstChild, 0);
44807    if (found)
44808      { return badPos(Pos(found.line, found.ch - dist), bad) }
44809    else
44810      { dist += after.textContent.length; }
44811  }
44812  for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
44813    found = find(before, before.firstChild, -1);
44814    if (found)
44815      { return badPos(Pos(found.line, found.ch + dist$1), bad) }
44816    else
44817      { dist$1 += before.textContent.length; }
44818  }
44819}
44820
44821// TEXTAREA INPUT STYLE
44822
44823var TextareaInput = function(cm) {
44824  this.cm = cm;
44825  // See input.poll and input.reset
44826  this.prevInput = "";
44827
44828  // Flag that indicates whether we expect input to appear real soon
44829  // now (after some event like 'keypress' or 'input') and are
44830  // polling intensively.
44831  this.pollingFast = false;
44832  // Self-resetting timeout for the poller
44833  this.polling = new Delayed();
44834  // Used to work around IE issue with selection being forgotten when focus moves away from textarea
44835  this.hasSelection = false;
44836  this.composing = null;
44837};
44838
44839TextareaInput.prototype.init = function (display) {
44840    var this$1 = this;
44841
44842  var input = this, cm = this.cm;
44843  this.createField(display);
44844  var te = this.textarea;
44845
44846  display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);
44847
44848  // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
44849  if (ios) { te.style.width = "0px"; }
44850
44851  on(te, "input", function () {
44852    if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
44853    input.poll();
44854  });
44855
44856  on(te, "paste", function (e) {
44857    if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
44858
44859    cm.state.pasteIncoming = true;
44860    input.fastPoll();
44861  });
44862
44863  function prepareCopyCut(e) {
44864    if (signalDOMEvent(cm, e)) { return }
44865    if (cm.somethingSelected()) {
44866      setLastCopied({lineWise: false, text: cm.getSelections()});
44867    } else if (!cm.options.lineWiseCopyCut) {
44868      return
44869    } else {
44870      var ranges = copyableRanges(cm);
44871      setLastCopied({lineWise: true, text: ranges.text});
44872      if (e.type == "cut") {
44873        cm.setSelections(ranges.ranges, null, sel_dontScroll);
44874      } else {
44875        input.prevInput = "";
44876        te.value = ranges.text.join("\n");
44877        selectInput(te);
44878      }
44879    }
44880    if (e.type == "cut") { cm.state.cutIncoming = true; }
44881  }
44882  on(te, "cut", prepareCopyCut);
44883  on(te, "copy", prepareCopyCut);
44884
44885  on(display.scroller, "paste", function (e) {
44886    if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
44887    cm.state.pasteIncoming = true;
44888    input.focus();
44889  });
44890
44891  // Prevent normal selection in the editor (we handle our own)
44892  on(display.lineSpace, "selectstart", function (e) {
44893    if (!eventInWidget(display, e)) { e_preventDefault(e); }
44894  });
44895
44896  on(te, "compositionstart", function () {
44897    var start = cm.getCursor("from");
44898    if (input.composing) { input.composing.range.clear(); }
44899    input.composing = {
44900      start: start,
44901      range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
44902    };
44903  });
44904  on(te, "compositionend", function () {
44905    if (input.composing) {
44906      input.poll();
44907      input.composing.range.clear();
44908      input.composing = null;
44909    }
44910  });
44911};
44912
44913TextareaInput.prototype.createField = function (_display) {
44914  // Wraps and hides input textarea
44915  this.wrapper = hiddenTextarea();
44916  // The semihidden textarea that is focused when the editor is
44917  // focused, and receives input.
44918  this.textarea = this.wrapper.firstChild;
44919};
44920
44921TextareaInput.prototype.prepareSelection = function () {
44922  // Redraw the selection and/or cursor
44923  var cm = this.cm, display = cm.display, doc = cm.doc;
44924  var result = prepareSelection(cm);
44925
44926  // Move the hidden textarea near the cursor to prevent scrolling artifacts
44927  if (cm.options.moveInputWithCursor) {
44928    var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
44929    var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
44930    result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
44931                                        headPos.top + lineOff.top - wrapOff.top));
44932    result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
44933                                         headPos.left + lineOff.left - wrapOff.left));
44934  }
44935
44936  return result
44937};
44938
44939TextareaInput.prototype.showSelection = function (drawn) {
44940  var cm = this.cm, display = cm.display;
44941  removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
44942  removeChildrenAndAdd(display.selectionDiv, drawn.selection);
44943  if (drawn.teTop != null) {
44944    this.wrapper.style.top = drawn.teTop + "px";
44945    this.wrapper.style.left = drawn.teLeft + "px";
44946  }
44947};
44948
44949// Reset the input to correspond to the selection (or to be empty,
44950// when not typing and nothing is selected)
44951TextareaInput.prototype.reset = function (typing) {
44952  if (this.contextMenuPending || this.composing) { return }
44953  var cm = this.cm;
44954  if (cm.somethingSelected()) {
44955    this.prevInput = "";
44956    var content = cm.getSelection();
44957    this.textarea.value = content;
44958    if (cm.state.focused) { selectInput(this.textarea); }
44959    if (ie && ie_version >= 9) { this.hasSelection = content; }
44960  } else if (!typing) {
44961    this.prevInput = this.textarea.value = "";
44962    if (ie && ie_version >= 9) { this.hasSelection = null; }
44963  }
44964};
44965
44966TextareaInput.prototype.getField = function () { return this.textarea };
44967
44968TextareaInput.prototype.supportsTouch = function () { return false };
44969
44970TextareaInput.prototype.focus = function () {
44971  if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
44972    try { this.textarea.focus(); }
44973    catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
44974  }
44975};
44976
44977TextareaInput.prototype.blur = function () { this.textarea.blur(); };
44978
44979TextareaInput.prototype.resetPosition = function () {
44980  this.wrapper.style.top = this.wrapper.style.left = 0;
44981};
44982
44983TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
44984
44985// Poll for input changes, using the normal rate of polling. This
44986// runs as long as the editor is focused.
44987TextareaInput.prototype.slowPoll = function () {
44988    var this$1 = this;
44989
44990  if (this.pollingFast) { return }
44991  this.polling.set(this.cm.options.pollInterval, function () {
44992    this$1.poll();
44993    if (this$1.cm.state.focused) { this$1.slowPoll(); }
44994  });
44995};
44996
44997// When an event has just come in that is likely to add or change
44998// something in the input textarea, we poll faster, to ensure that
44999// the change appears on the screen quickly.
45000TextareaInput.prototype.fastPoll = function () {
45001  var missed = false, input = this;
45002  input.pollingFast = true;
45003  function p() {
45004    var changed = input.poll();
45005    if (!changed && !missed) {missed = true; input.polling.set(60, p);}
45006    else {input.pollingFast = false; input.slowPoll();}
45007  }
45008  input.polling.set(20, p);
45009};
45010
45011// Read input from the textarea, and update the document to match.
45012// When something is selected, it is present in the textarea, and
45013// selected (unless it is huge, in which case a placeholder is
45014// used). When nothing is selected, the cursor sits after previously
45015// seen text (can be empty), which is stored in prevInput (we must
45016// not reset the textarea when typing, because that breaks IME).
45017TextareaInput.prototype.poll = function () {
45018    var this$1 = this;
45019
45020  var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
45021  // Since this is called a *lot*, try to bail out as cheaply as
45022  // possible when it is clear that nothing happened. hasSelection
45023  // will be the case when there is a lot of text in the textarea,
45024  // in which case reading its value would be expensive.
45025  if (this.contextMenuPending || !cm.state.focused ||
45026      (hasSelection(input) && !prevInput && !this.composing) ||
45027      cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
45028    { return false }
45029
45030  var text = input.value;
45031  // If nothing changed, bail.
45032  if (text == prevInput && !cm.somethingSelected()) { return false }
45033  // Work around nonsensical selection resetting in IE9/10, and
45034  // inexplicable appearance of private area unicode characters on
45035  // some key combos in Mac (#2689).
45036  if (ie && ie_version >= 9 && this.hasSelection === text ||
45037      mac && /[\uf700-\uf7ff]/.test(text)) {
45038    cm.display.input.reset();
45039    return false
45040  }
45041
45042  if (cm.doc.sel == cm.display.selForContextMenu) {
45043    var first = text.charCodeAt(0);
45044    if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
45045    if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
45046  }
45047  // Find the part of the input that is actually new
45048  var same = 0, l = Math.min(prevInput.length, text.length);
45049  while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
45050
45051  runInOp(cm, function () {
45052    applyTextInput(cm, text.slice(same), prevInput.length - same,
45053                   null, this$1.composing ? "*compose" : null);
45054
45055    // Don't leave long text in the textarea, since it makes further polling slow
45056    if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
45057    else { this$1.prevInput = text; }
45058
45059    if (this$1.composing) {
45060      this$1.composing.range.clear();
45061      this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
45062                                         {className: "CodeMirror-composing"});
45063    }
45064  });
45065  return true
45066};
45067
45068TextareaInput.prototype.ensurePolled = function () {
45069  if (this.pollingFast && this.poll()) { this.pollingFast = false; }
45070};
45071
45072TextareaInput.prototype.onKeyPress = function () {
45073  if (ie && ie_version >= 9) { this.hasSelection = null; }
45074  this.fastPoll();
45075};
45076
45077TextareaInput.prototype.onContextMenu = function (e) {
45078  var input = this, cm = input.cm, display = cm.display, te = input.textarea;
45079  var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
45080  if (!pos || presto) { return } // Opera is difficult.
45081
45082  // Reset the current text selection only if the click is done outside of the selection
45083  // and 'resetSelectionOnContextMenu' option is true.
45084  var reset = cm.options.resetSelectionOnContextMenu;
45085  if (reset && cm.doc.sel.contains(pos) == -1)
45086    { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
45087
45088  var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
45089  input.wrapper.style.cssText = "position: absolute";
45090  var wrapperBox = input.wrapper.getBoundingClientRect();
45091  te.style.cssText = "position: absolute; width: 30px; height: 30px;\n      top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n      z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
45092  var oldScrollY;
45093  if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
45094  display.input.focus();
45095  if (webkit) { window.scrollTo(null, oldScrollY); }
45096  display.input.reset();
45097  // Adds "Select all" to context menu in FF
45098  if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
45099  input.contextMenuPending = true;
45100  display.selForContextMenu = cm.doc.sel;
45101  clearTimeout(display.detectingSelectAll);
45102
45103  // Select-all will be greyed out if there's nothing to select, so
45104  // this adds a zero-width space so that we can later check whether
45105  // it got selected.
45106  function prepareSelectAllHack() {
45107    if (te.selectionStart != null) {
45108      var selected = cm.somethingSelected();
45109      var extval = "\u200b" + (selected ? te.value : "");
45110      te.value = "\u21da"; // Used to catch context-menu undo
45111      te.value = extval;
45112      input.prevInput = selected ? "" : "\u200b";
45113      te.selectionStart = 1; te.selectionEnd = extval.length;
45114      // Re-set this, in case some other handler touched the
45115      // selection in the meantime.
45116      display.selForContextMenu = cm.doc.sel;
45117    }
45118  }
45119  function rehide() {
45120    input.contextMenuPending = false;
45121    input.wrapper.style.cssText = oldWrapperCSS;
45122    te.style.cssText = oldCSS;
45123    if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
45124
45125    // Try to detect the user choosing select-all
45126    if (te.selectionStart != null) {
45127      if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
45128      var i = 0, poll = function () {
45129        if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
45130            te.selectionEnd > 0 && input.prevInput == "\u200b") {
45131          operation(cm, selectAll)(cm);
45132        } else if (i++ < 10) {
45133          display.detectingSelectAll = setTimeout(poll, 500);
45134        } else {
45135          display.selForContextMenu = null;
45136          display.input.reset();
45137        }
45138      };
45139      display.detectingSelectAll = setTimeout(poll, 200);
45140    }
45141  }
45142
45143  if (ie && ie_version >= 9) { prepareSelectAllHack(); }
45144  if (captureRightClick) {
45145    e_stop(e);
45146    var mouseup = function () {
45147      off(window, "mouseup", mouseup);
45148      setTimeout(rehide, 20);
45149    };
45150    on(window, "mouseup", mouseup);
45151  } else {
45152    setTimeout(rehide, 50);
45153  }
45154};
45155
45156TextareaInput.prototype.readOnlyChanged = function (val) {
45157  if (!val) { this.reset(); }
45158  this.textarea.disabled = val == "nocursor";
45159};
45160
45161TextareaInput.prototype.setUneditable = function () {};
45162
45163TextareaInput.prototype.needsContentAttribute = false;
45164
45165function fromTextArea(textarea, options) {
45166  options = options ? copyObj(options) : {};
45167  options.value = textarea.value;
45168  if (!options.tabindex && textarea.tabIndex)
45169    { options.tabindex = textarea.tabIndex; }
45170  if (!options.placeholder && textarea.placeholder)
45171    { options.placeholder = textarea.placeholder; }
45172  // Set autofocus to true if this textarea is focused, or if it has
45173  // autofocus and no other element is focused.
45174  if (options.autofocus == null) {
45175    var hasFocus = activeElt();
45176    options.autofocus = hasFocus == textarea ||
45177      textarea.getAttribute("autofocus") != null && hasFocus == document.body;
45178  }
45179
45180  function save() {textarea.value = cm.getValue();}
45181
45182  var realSubmit;
45183  if (textarea.form) {
45184    on(textarea.form, "submit", save);
45185    // Deplorable hack to make the submit method do the right thing.
45186    if (!options.leaveSubmitMethodAlone) {
45187      var form = textarea.form;
45188      realSubmit = form.submit;
45189      try {
45190        var wrappedSubmit = form.submit = function () {
45191          save();
45192          form.submit = realSubmit;
45193          form.submit();
45194          form.submit = wrappedSubmit;
45195        };
45196      } catch(e) {}
45197    }
45198  }
45199
45200  options.finishInit = function (cm) {
45201    cm.save = save;
45202    cm.getTextArea = function () { return textarea; };
45203    cm.toTextArea = function () {
45204      cm.toTextArea = isNaN; // Prevent this from being ran twice
45205      save();
45206      textarea.parentNode.removeChild(cm.getWrapperElement());
45207      textarea.style.display = "";
45208      if (textarea.form) {
45209        off(textarea.form, "submit", save);
45210        if (typeof textarea.form.submit == "function")
45211          { textarea.form.submit = realSubmit; }
45212      }
45213    };
45214  };
45215
45216  textarea.style.display = "none";
45217  var cm = CodeMirror$1(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
45218    options);
45219  return cm
45220}
45221
45222function addLegacyProps(CodeMirror) {
45223  CodeMirror.off = off;
45224  CodeMirror.on = on;
45225  CodeMirror.wheelEventPixels = wheelEventPixels;
45226  CodeMirror.Doc = Doc;
45227  CodeMirror.splitLines = splitLinesAuto;
45228  CodeMirror.countColumn = countColumn;
45229  CodeMirror.findColumn = findColumn;
45230  CodeMirror.isWordChar = isWordCharBasic;
45231  CodeMirror.Pass = Pass;
45232  CodeMirror.signal = signal;
45233  CodeMirror.Line = Line;
45234  CodeMirror.changeEnd = changeEnd;
45235  CodeMirror.scrollbarModel = scrollbarModel;
45236  CodeMirror.Pos = Pos;
45237  CodeMirror.cmpPos = cmp;
45238  CodeMirror.modes = modes;
45239  CodeMirror.mimeModes = mimeModes;
45240  CodeMirror.resolveMode = resolveMode;
45241  CodeMirror.getMode = getMode;
45242  CodeMirror.modeExtensions = modeExtensions;
45243  CodeMirror.extendMode = extendMode;
45244  CodeMirror.copyState = copyState;
45245  CodeMirror.startState = startState;
45246  CodeMirror.innerMode = innerMode;
45247  CodeMirror.commands = commands;
45248  CodeMirror.keyMap = keyMap;
45249  CodeMirror.keyName = keyName;
45250  CodeMirror.isModifierKey = isModifierKey;
45251  CodeMirror.lookupKey = lookupKey;
45252  CodeMirror.normalizeKeyMap = normalizeKeyMap;
45253  CodeMirror.StringStream = StringStream;
45254  CodeMirror.SharedTextMarker = SharedTextMarker;
45255  CodeMirror.TextMarker = TextMarker;
45256  CodeMirror.LineWidget = LineWidget;
45257  CodeMirror.e_preventDefault = e_preventDefault;
45258  CodeMirror.e_stopPropagation = e_stopPropagation;
45259  CodeMirror.e_stop = e_stop;
45260  CodeMirror.addClass = addClass;
45261  CodeMirror.contains = contains;
45262  CodeMirror.rmClass = rmClass;
45263  CodeMirror.keyNames = keyNames;
45264}
45265
45266// EDITOR CONSTRUCTOR
45267
45268defineOptions(CodeMirror$1);
45269
45270addEditorMethods(CodeMirror$1);
45271
45272// Set up methods on CodeMirror's prototype to redirect to the editor's document.
45273var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
45274for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
45275  { CodeMirror$1.prototype[prop] = (function(method) {
45276    return function() {return method.apply(this.doc, arguments)}
45277  })(Doc.prototype[prop]); } }
45278
45279eventMixin(Doc);
45280
45281// INPUT HANDLING
45282
45283CodeMirror$1.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
45284
45285// MODE DEFINITION AND QUERYING
45286
45287// Extra arguments are stored as the mode's dependencies, which is
45288// used by (legacy) mechanisms like loadmode.js to automatically
45289// load a mode. (Preferred mechanism is the require/define calls.)
45290CodeMirror$1.defineMode = function(name/*, mode, …*/) {
45291  if (!CodeMirror$1.defaults.mode && name != "null") { CodeMirror$1.defaults.mode = name; }
45292  defineMode.apply(this, arguments);
45293};
45294
45295CodeMirror$1.defineMIME = defineMIME;
45296
45297// Minimal default mode.
45298CodeMirror$1.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
45299CodeMirror$1.defineMIME("text/plain", "null");
45300
45301// EXTENSIONS
45302
45303CodeMirror$1.defineExtension = function (name, func) {
45304  CodeMirror$1.prototype[name] = func;
45305};
45306CodeMirror$1.defineDocExtension = function (name, func) {
45307  Doc.prototype[name] = func;
45308};
45309
45310CodeMirror$1.fromTextArea = fromTextArea;
45311
45312addLegacyProps(CodeMirror$1);
45313
45314CodeMirror$1.version = "5.37.0";
45315
45316return CodeMirror$1;
45317
45318})));
45319
45320},{}],7:[function(require,module,exports){
45321// CodeMirror, copyright (c) by Marijn Haverbeke and others
45322// Distributed under an MIT license: http://codemirror.net/LICENSE
45323
45324(function(mod) {
45325  if (typeof exports == "object" && typeof module == "object") // CommonJS
45326    mod(require("../../lib/codemirror"));
45327  else if (typeof define == "function" && define.amd) // AMD
45328    define(["../../lib/codemirror"], mod);
45329  else // Plain browser env
45330    mod(CodeMirror);
45331})(function(CodeMirror) {
45332"use strict";
45333
45334CodeMirror.defineMode("css", function(config, parserConfig) {
45335  var inline = parserConfig.inline
45336  if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
45337
45338  var indentUnit = config.indentUnit,
45339      tokenHooks = parserConfig.tokenHooks,
45340      documentTypes = parserConfig.documentTypes || {},
45341      mediaTypes = parserConfig.mediaTypes || {},
45342      mediaFeatures = parserConfig.mediaFeatures || {},
45343      mediaValueKeywords = parserConfig.mediaValueKeywords || {},
45344      propertyKeywords = parserConfig.propertyKeywords || {},
45345      nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
45346      fontProperties = parserConfig.fontProperties || {},
45347      counterDescriptors = parserConfig.counterDescriptors || {},
45348      colorKeywords = parserConfig.colorKeywords || {},
45349      valueKeywords = parserConfig.valueKeywords || {},
45350      allowNested = parserConfig.allowNested,
45351      lineComment = parserConfig.lineComment,
vendor: 16,574 bytes, lines 45352-45799
45352      supportsAtComponent = parserConfig.supportsAtComponent === true;
45353
45354  var type, override;
45355  function ret(style, tp) { type = tp; return style; }
45356
45357  // Tokenizers
45358
45359  function tokenBase(stream, state) {
45360    var ch = stream.next();
45361    if (tokenHooks[ch]) {
45362      var result = tokenHooks[ch](stream, state);
45363      if (result !== false) return result;
45364    }
45365    if (ch == "@") {
45366      stream.eatWhile(/[\w\\\-]/);
45367      return ret("def", stream.current());
45368    } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
45369      return ret(null, "compare");
45370    } else if (ch == "\"" || ch == "'") {
45371      state.tokenize = tokenString(ch);
45372      return state.tokenize(stream, state);
45373    } else if (ch == "#") {
45374      stream.eatWhile(/[\w\\\-]/);
45375      return ret("atom", "hash");
45376    } else if (ch == "!") {
45377      stream.match(/^\s*\w*/);
45378      return ret("keyword", "important");
45379    } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
45380      stream.eatWhile(/[\w.%]/);
45381      return ret("number", "unit");
45382    } else if (ch === "-") {
45383      if (/[\d.]/.test(stream.peek())) {
45384        stream.eatWhile(/[\w.%]/);
45385        return ret("number", "unit");
45386      } else if (stream.match(/^-[\w\\\-]+/)) {
45387        stream.eatWhile(/[\w\\\-]/);
45388        if (stream.match(/^\s*:/, false))
45389          return ret("variable-2", "variable-definition");
45390        return ret("variable-2", "variable");
45391      } else if (stream.match(/^\w+-/)) {
45392        return ret("meta", "meta");
45393      }
45394    } else if (/[,+>*\/]/.test(ch)) {
45395      return ret(null, "select-op");
45396    } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
45397      return ret("qualifier", "qualifier");
45398    } else if (/[:;{}\[\]\(\)]/.test(ch)) {
45399      return ret(null, ch);
45400    } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
45401               ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
45402               ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
45403      stream.backUp(1);
45404      state.tokenize = tokenParenthesized;
45405      return ret("property", "word");
45406    } else if (/[\w\\\-]/.test(ch)) {
45407      stream.eatWhile(/[\w\\\-]/);
45408      return ret("property", "word");
45409    } else {
45410      return ret(null, null);
45411    }
45412  }
45413
45414  function tokenString(quote) {
45415    return function(stream, state) {
45416      var escaped = false, ch;
45417      while ((ch = stream.next()) != null) {
45418        if (ch == quote && !escaped) {
45419          if (quote == ")") stream.backUp(1);
45420          break;
45421        }
45422        escaped = !escaped && ch == "\\";
45423      }
45424      if (ch == quote || !escaped && quote != ")") state.tokenize = null;
45425      return ret("string", "string");
45426    };
45427  }
45428
45429  function tokenParenthesized(stream, state) {
45430    stream.next(); // Must be '('
45431    if (!stream.match(/\s*[\"\')]/, false))
45432      state.tokenize = tokenString(")");
45433    else
45434      state.tokenize = null;
45435    return ret(null, "(");
45436  }
45437
45438  // Context management
45439
45440  function Context(type, indent, prev) {
45441    this.type = type;
45442    this.indent = indent;
45443    this.prev = prev;
45444  }
45445
45446  function pushContext(state, stream, type, indent) {
45447    state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
45448    return type;
45449  }
45450
45451  function popContext(state) {
45452    if (state.context.prev)
45453      state.context = state.context.prev;
45454    return state.context.type;
45455  }
45456
45457  function pass(type, stream, state) {
45458    return states[state.context.type](type, stream, state);
45459  }
45460  function popAndPass(type, stream, state, n) {
45461    for (var i = n || 1; i > 0; i--)
45462      state.context = state.context.prev;
45463    return pass(type, stream, state);
45464  }
45465
45466  // Parser
45467
45468  function wordAsValue(stream) {
45469    var word = stream.current().toLowerCase();
45470    if (valueKeywords.hasOwnProperty(word))
45471      override = "atom";
45472    else if (colorKeywords.hasOwnProperty(word))
45473      override = "keyword";
45474    else
45475      override = "variable";
45476  }
45477
45478  var states = {};
45479
45480  states.top = function(type, stream, state) {
45481    if (type == "{") {
45482      return pushContext(state, stream, "block");
45483    } else if (type == "}" && state.context.prev) {
45484      return popContext(state);
45485    } else if (supportsAtComponent && /@component/i.test(type)) {
45486      return pushContext(state, stream, "atComponentBlock");
45487    } else if (/^@(-moz-)?document$/i.test(type)) {
45488      return pushContext(state, stream, "documentTypes");
45489    } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
45490      return pushContext(state, stream, "atBlock");
45491    } else if (/^@(font-face|counter-style)/i.test(type)) {
45492      state.stateArg = type;
45493      return "restricted_atBlock_before";
45494    } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
45495      return "keyframes";
45496    } else if (type && type.charAt(0) == "@") {
45497      return pushContext(state, stream, "at");
45498    } else if (type == "hash") {
45499      override = "builtin";
45500    } else if (type == "word") {
45501      override = "tag";
45502    } else if (type == "variable-definition") {
45503      return "maybeprop";
45504    } else if (type == "interpolation") {
45505      return pushContext(state, stream, "interpolation");
45506    } else if (type == ":") {
45507      return "pseudo";
45508    } else if (allowNested && type == "(") {
45509      return pushContext(state, stream, "parens");
45510    }
45511    return state.context.type;
45512  };
45513
45514  states.block = function(type, stream, state) {
45515    if (type == "word") {
45516      var word = stream.current().toLowerCase();
45517      if (propertyKeywords.hasOwnProperty(word)) {
45518        override = "property";
45519        return "maybeprop";
45520      } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
45521        override = "string-2";
45522        return "maybeprop";
45523      } else if (allowNested) {
45524        override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
45525        return "block";
45526      } else {
45527        override += " error";
45528        return "maybeprop";
45529      }
45530    } else if (type == "meta") {
45531      return "block";
45532    } else if (!allowNested && (type == "hash" || type == "qualifier")) {
45533      override = "error";
45534      return "block";
45535    } else {
45536      return states.top(type, stream, state);
45537    }
45538  };
45539
45540  states.maybeprop = function(type, stream, state) {
45541    if (type == ":") return pushContext(state, stream, "prop");
45542    return pass(type, stream, state);
45543  };
45544
45545  states.prop = function(type, stream, state) {
45546    if (type == ";") return popContext(state);
45547    if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
45548    if (type == "}" || type == "{") return popAndPass(type, stream, state);
45549    if (type == "(") return pushContext(state, stream, "parens");
45550
45551    if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
45552      override += " error";
45553    } else if (type == "word") {
45554      wordAsValue(stream);
45555    } else if (type == "interpolation") {
45556      return pushContext(state, stream, "interpolation");
45557    }
45558    return "prop";
45559  };
45560
45561  states.propBlock = function(type, _stream, state) {
45562    if (type == "}") return popContext(state);
45563    if (type == "word") { override = "property"; return "maybeprop"; }
45564    return state.context.type;
45565  };
45566
45567  states.parens = function(type, stream, state) {
45568    if (type == "{" || type == "}") return popAndPass(type, stream, state);
45569    if (type == ")") return popContext(state);
45570    if (type == "(") return pushContext(state, stream, "parens");
45571    if (type == "interpolation") return pushContext(state, stream, "interpolation");
45572    if (type == "word") wordAsValue(stream);
45573    return "parens";
45574  };
45575
45576  states.pseudo = function(type, stream, state) {
45577    if (type == "meta") return "pseudo";
45578
45579    if (type == "word") {
45580      override = "variable-3";
45581      return state.context.type;
45582    }
45583    return pass(type, stream, state);
45584  };
45585
45586  states.documentTypes = function(type, stream, state) {
45587    if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
45588      override = "tag";
45589      return state.context.type;
45590    } else {
45591      return states.atBlock(type, stream, state);
45592    }
45593  };
45594
45595  states.atBlock = function(type, stream, state) {
45596    if (type == "(") return pushContext(state, stream, "atBlock_parens");
45597    if (type == "}" || type == ";") return popAndPass(type, stream, state);
45598    if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
45599
45600    if (type == "interpolation") return pushContext(state, stream, "interpolation");
45601
45602    if (type == "word") {
45603      var word = stream.current().toLowerCase();
45604      if (word == "only" || word == "not" || word == "and" || word == "or")
45605        override = "keyword";
45606      else if (mediaTypes.hasOwnProperty(word))
45607        override = "attribute";
45608      else if (mediaFeatures.hasOwnProperty(word))
45609        override = "property";
45610      else if (mediaValueKeywords.hasOwnProperty(word))
45611        override = "keyword";
45612      else if (propertyKeywords.hasOwnProperty(word))
45613        override = "property";
45614      else if (nonStandardPropertyKeywords.hasOwnProperty(word))
45615        override = "string-2";
45616      else if (valueKeywords.hasOwnProperty(word))
45617        override = "atom";
45618      else if (colorKeywords.hasOwnProperty(word))
45619        override = "keyword";
45620      else
45621        override = "error";
45622    }
45623    return state.context.type;
45624  };
45625
45626  states.atComponentBlock = function(type, stream, state) {
45627    if (type == "}")
45628      return popAndPass(type, stream, state);
45629    if (type == "{")
45630      return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
45631    if (type == "word")
45632      override = "error";
45633    return state.context.type;
45634  };
45635
45636  states.atBlock_parens = function(type, stream, state) {
45637    if (type == ")") return popContext(state);
45638    if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
45639    return states.atBlock(type, stream, state);
45640  };
45641
45642  states.restricted_atBlock_before = function(type, stream, state) {
45643    if (type == "{")
45644      return pushContext(state, stream, "restricted_atBlock");
45645    if (type == "word" && state.stateArg == "@counter-style") {
45646      override = "variable";
45647      return "restricted_atBlock_before";
45648    }
45649    return pass(type, stream, state);
45650  };
45651
45652  states.restricted_atBlock = function(type, stream, state) {
45653    if (type == "}") {
45654      state.stateArg = null;
45655      return popContext(state);
45656    }
45657    if (type == "word") {
45658      if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
45659          (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
45660        override = "error";
45661      else
45662        override = "property";
45663      return "maybeprop";
45664    }
45665    return "restricted_atBlock";
45666  };
45667
45668  states.keyframes = function(type, stream, state) {
45669    if (type == "word") { override = "variable"; return "keyframes"; }
45670    if (type == "{") return pushContext(state, stream, "top");
45671    return pass(type, stream, state);
45672  };
45673
45674  states.at = function(type, stream, state) {
45675    if (type == ";") return popContext(state);
45676    if (type == "{" || type == "}") return popAndPass(type, stream, state);
45677    if (type == "word") override = "tag";
45678    else if (type == "hash") override = "builtin";
45679    return "at";
45680  };
45681
45682  states.interpolation = function(type, stream, state) {
45683    if (type == "}") return popContext(state);
45684    if (type == "{" || type == ";") return popAndPass(type, stream, state);
45685    if (type == "word") override = "variable";
45686    else if (type != "variable" && type != "(" && type != ")") override = "error";
45687    return "interpolation";
45688  };
45689
45690  return {
45691    startState: function(base) {
45692      return {tokenize: null,
45693              state: inline ? "block" : "top",
45694              stateArg: null,
45695              context: new Context(inline ? "block" : "top", base || 0, null)};
45696    },
45697
45698    token: function(stream, state) {
45699      if (!state.tokenize && stream.eatSpace()) return null;
45700      var style = (state.tokenize || tokenBase)(stream, state);
45701      if (style && typeof style == "object") {
45702        type = style[1];
45703        style = style[0];
45704      }
45705      override = style;
45706      if (type != "comment")
45707        state.state = states[state.state](type, stream, state);
45708      return override;
45709    },
45710
45711    indent: function(state, textAfter) {
45712      var cx = state.context, ch = textAfter && textAfter.charAt(0);
45713      var indent = cx.indent;
45714      if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
45715      if (cx.prev) {
45716        if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
45717                          cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
45718          // Resume indentation from parent context.
45719          cx = cx.prev;
45720          indent = cx.indent;
45721        } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
45722            ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
45723          // Dedent relative to current context.
45724          indent = Math.max(0, cx.indent - indentUnit);
45725        }
45726      }
45727      return indent;
45728    },
45729
45730    electricChars: "}",
45731    blockCommentStart: "/*",
45732    blockCommentEnd: "*/",
45733    blockCommentContinue: " * ",
45734    lineComment: lineComment,
45735    fold: "brace"
45736  };
45737});
45738
45739  function keySet(array) {
45740    var keys = {};
45741    for (var i = 0; i < array.length; ++i) {
45742      keys[array[i].toLowerCase()] = true;
45743    }
45744    return keys;
45745  }
45746
45747  var documentTypes_ = [
45748    "domain", "regexp", "url", "url-prefix"
45749  ], documentTypes = keySet(documentTypes_);
45750
45751  var mediaTypes_ = [
45752    "all", "aural", "braille", "handheld", "print", "projection", "screen",
45753    "tty", "tv", "embossed"
45754  ], mediaTypes = keySet(mediaTypes_);
45755
45756  var mediaFeatures_ = [
45757    "width", "min-width", "max-width", "height", "min-height", "max-height",
45758    "device-width", "min-device-width", "max-device-width", "device-height",
45759    "min-device-height", "max-device-height", "aspect-ratio",
45760    "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
45761    "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
45762    "max-color", "color-index", "min-color-index", "max-color-index",
45763    "monochrome", "min-monochrome", "max-monochrome", "resolution",
45764    "min-resolution", "max-resolution", "scan", "grid", "orientation",
45765    "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
45766    "pointer", "any-pointer", "hover", "any-hover"
45767  ], mediaFeatures = keySet(mediaFeatures_);
45768
45769  var mediaValueKeywords_ = [
45770    "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
45771    "interlace", "progressive"
45772  ], mediaValueKeywords = keySet(mediaValueKeywords_);
45773
45774  var propertyKeywords_ = [
45775    "align-content", "align-items", "align-self", "alignment-adjust",
45776    "alignment-baseline", "anchor-point", "animation", "animation-delay",
45777    "animation-direction", "animation-duration", "animation-fill-mode",
45778    "animation-iteration-count", "animation-name", "animation-play-state",
45779    "animation-timing-function", "appearance", "azimuth", "backface-visibility",
45780    "background", "background-attachment", "background-blend-mode", "background-clip",
45781    "background-color", "background-image", "background-origin", "background-position",
45782    "background-repeat", "background-size", "baseline-shift", "binding",
45783    "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
45784    "bookmark-target", "border", "border-bottom", "border-bottom-color",
45785    "border-bottom-left-radius", "border-bottom-right-radius",
45786    "border-bottom-style", "border-bottom-width", "border-collapse",
45787    "border-color", "border-image", "border-image-outset",
45788    "border-image-repeat", "border-image-slice", "border-image-source",
45789    "border-image-width", "border-left", "border-left-color",
45790    "border-left-style", "border-left-width", "border-radius", "border-right",
45791    "border-right-color", "border-right-style", "border-right-width",
45792    "border-spacing", "border-style", "border-top", "border-top-color",
45793    "border-top-left-radius", "border-top-right-radius", "border-top-style",
45794    "border-top-width", "border-width", "bottom", "box-decoration-break",
45795    "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
45796    "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
45797    "column-fill", "column-gap", "column-rule", "column-rule-color",
45798    "column-rule-style", "column-rule-width", "column-span", "column-width",
45799    "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
45800    "cue-after", "cue-before", "cursor", "direction", "display",
45801    "dominant-baseline", "drop-initial-after-adjust",
45802    "drop-initial-after-align", "drop-initial-before-adjust",
45803    "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
45804    "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
45805    "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
45806    "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
45807    "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
45808    "font-stretch", "font-style", "font-synthesis", "font-variant",
45809    "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
45810    "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
45811    "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
45812    "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
45813    "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
45814    "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
45815    "grid-template-rows", "hanging-punctuation", "height", "hyphens",
45816    "icon", "image-orientation", "image-rendering", "image-resolution",
45817    "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
45818    "line-break", "line-height", "line-stacking", "line-stacking-ruby",
45819    "line-stacking-shift", "line-stacking-strategy", "list-style",
45820    "list-style-image", "list-style-position", "list-style-type", "margin",
45821    "margin-bottom", "margin-left", "margin-right", "margin-top",
45822    "marks", "marquee-direction", "marquee-loop",
45823    "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
45824    "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
45825    "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
45826    "opacity", "order", "orphans", "outline",
45827    "outline-color", "outline-offset", "outline-style", "outline-width",
45828    "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
45829    "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
45830    "page", "page-break-after", "page-break-before", "page-break-inside",
45831    "page-policy", "pause", "pause-after", "pause-before", "perspective",
45832    "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
45833    "presentation-level", "punctuation-trim", "quotes", "region-break-after",
45834    "region-break-before", "region-break-inside", "region-fragment",
45835    "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
45836    "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
45837    "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
45838    "shape-outside", "size", "speak", "speak-as", "speak-header",
45839    "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
45840    "tab-size", "table-layout", "target", "target-name", "target-new",
45841    "target-position", "text-align", "text-align-last", "text-decoration",
45842    "text-decoration-color", "text-decoration-line", "text-decoration-skip",
45843    "text-decoration-style", "text-emphasis", "text-emphasis-color",
45844    "text-emphasis-position", "text-emphasis-style", "text-height",
45845    "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
45846    "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
45847    "text-wrap", "top", "transform", "transform-origin", "transform-style",
45848    "transition", "transition-delay", "transition-duration",
45849    "transition-property", "transition-timing-function", "unicode-bidi",
45850    "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
45851    "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
45852    "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
45853    "word-spacing", "word-wrap", "z-index",
45854    // SVG-specific
45855    "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
45856    "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
45857    "color-interpolation", "color-interpolation-filters",
45858    "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
45859    "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
45860    "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
45861    "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
45862    "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
45863    "glyph-orientation-vertical", "text-anchor", "writing-mode"
45864  ], propertyKeywords = keySet(propertyKeywords_);
45865
45866  var nonStandardPropertyKeywords_ = [
45867    "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
45868    "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
45869    "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
45870    "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
45871    "searchfield-results-decoration", "zoom"
45872  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
45873
45874  var fontProperties_ = [
45875    "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
45876    "font-stretch", "font-weight", "font-style"
45877  ], fontProperties = keySet(fontProperties_);
45878
45879  var counterDescriptors_ = [
45880    "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
45881    "speak-as", "suffix", "symbols", "system"
45882  ], counterDescriptors = keySet(counterDescriptors_);
45883
45884  var colorKeywords_ = [
45885    "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
45886    "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
45887    "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
45888    "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
45889    "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
45890    "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
45891    "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
45892    "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
45893    "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
45894    "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
45895    "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
45896    "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
45897    "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
45898    "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
45899    "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
45900    "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
45901    "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
45902    "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
45903    "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
45904    "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
45905    "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
45906    "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
45907    "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
45908    "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
45909    "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
45910    "whitesmoke", "yellow", "yellowgreen"
45911  ], colorKeywords = keySet(colorKeywords_);
45912
45913  var valueKeywords_ = [
45914    "above", "absolute", "activeborder", "additive", "activecaption", "afar",
45915    "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
45916    "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
45917    "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
45918    "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
45919    "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
45920    "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
45921    "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
45922    "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
45923    "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
45924    "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
45925    "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
45926    "compact", "condensed", "contain", "content", "contents",
45927    "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
45928    "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
45929    "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
45930    "destination-in", "destination-out", "destination-over", "devanagari", "difference",
45931    "disc", "discard", "disclosure-closed", "disclosure-open", "document",
45932    "dot-dash", "dot-dot-dash",
45933    "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
45934    "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
45935    "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
45936    "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
45937    "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
45938    "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
45939    "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
45940    "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
45941    "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
45942    "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
45943    "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
45944    "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
45945    "help", "hidden", "hide", "higher", "highlight", "highlighttext",
45946    "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
45947    "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
45948    "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
45949    "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
45950    "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
45951    "katakana", "katakana-iroha", "keep-all", "khmer",
45952    "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
45953    "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
45954    "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
45955    "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
45956    "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
45957    "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
45958    "media-controls-background", "media-current-time-display",
45959    "media-fullscreen-button", "media-mute-button", "media-play-button",
45960    "media-return-to-realtime-button", "media-rewind-button",
45961    "media-seek-back-button", "media-seek-forward-button", "media-slider",
45962    "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
45963    "media-volume-slider-container", "media-volume-sliderthumb", "medium",
45964    "menu", "menulist", "menulist-button", "menulist-text",
45965    "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
45966    "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
45967    "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
45968    "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
45969    "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
45970    "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
45971    "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
45972    "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
45973    "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
45974    "progress", "push-button", "radial-gradient", "radio", "read-only",
45975    "read-write", "read-write-plaintext-only", "rectangle", "region",
45976    "relative", "repeat", "repeating-linear-gradient",
45977    "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
45978    "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
45979    "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
45980    "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
45981    "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
45982    "searchfield-cancel-button", "searchfield-decoration",
45983    "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
45984    "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
45985    "simp-chinese-formal", "simp-chinese-informal", "single",
45986    "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
vendor: 19,176 bytes, lines 45987-46502
45987    "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
45988    "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
45989    "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
45990    "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
45991    "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
45992    "table-caption", "table-cell", "table-column", "table-column-group",
45993    "table-footer-group", "table-header-group", "table-row", "table-row-group",
45994    "tamil",
45995    "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
45996    "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
45997    "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
45998    "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
45999    "trad-chinese-formal", "trad-chinese-informal", "transform",
46000    "translate", "translate3d", "translateX", "translateY", "translateZ",
46001    "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
46002    "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
46003    "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
46004    "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
46005    "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
46006    "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
46007    "xx-large", "xx-small"
46008  ], valueKeywords = keySet(valueKeywords_);
46009
46010  var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
46011    .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
46012    .concat(valueKeywords_);
46013  CodeMirror.registerHelper("hintWords", "css", allWords);
46014
46015  function tokenCComment(stream, state) {
46016    var maybeEnd = false, ch;
46017    while ((ch = stream.next()) != null) {
46018      if (maybeEnd && ch == "/") {
46019        state.tokenize = null;
46020        break;
46021      }
46022      maybeEnd = (ch == "*");
46023    }
46024    return ["comment", "comment"];
46025  }
46026
46027  CodeMirror.defineMIME("text/css", {
46028    documentTypes: documentTypes,
46029    mediaTypes: mediaTypes,
46030    mediaFeatures: mediaFeatures,
46031    mediaValueKeywords: mediaValueKeywords,
46032    propertyKeywords: propertyKeywords,
46033    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
46034    fontProperties: fontProperties,
46035    counterDescriptors: counterDescriptors,
46036    colorKeywords: colorKeywords,
46037    valueKeywords: valueKeywords,
46038    tokenHooks: {
46039      "/": function(stream, state) {
46040        if (!stream.eat("*")) return false;
46041        state.tokenize = tokenCComment;
46042        return tokenCComment(stream, state);
46043      }
46044    },
46045    name: "css"
46046  });
46047
46048  CodeMirror.defineMIME("text/x-scss", {
46049    mediaTypes: mediaTypes,
46050    mediaFeatures: mediaFeatures,
46051    mediaValueKeywords: mediaValueKeywords,
46052    propertyKeywords: propertyKeywords,
46053    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
46054    colorKeywords: colorKeywords,
46055    valueKeywords: valueKeywords,
46056    fontProperties: fontProperties,
46057    allowNested: true,
46058    lineComment: "//",
46059    tokenHooks: {
46060      "/": function(stream, state) {
46061        if (stream.eat("/")) {
46062          stream.skipToEnd();
46063          return ["comment", "comment"];
46064        } else if (stream.eat("*")) {
46065          state.tokenize = tokenCComment;
46066          return tokenCComment(stream, state);
46067        } else {
46068          return ["operator", "operator"];
46069        }
46070      },
46071      ":": function(stream) {
46072        if (stream.match(/\s*\{/, false))
46073          return [null, null]
46074        return false;
46075      },
46076      "$": function(stream) {
46077        stream.match(/^[\w-]+/);
46078        if (stream.match(/^\s*:/, false))
46079          return ["variable-2", "variable-definition"];
46080        return ["variable-2", "variable"];
46081      },
46082      "#": function(stream) {
46083        if (!stream.eat("{")) return false;
46084        return [null, "interpolation"];
46085      }
46086    },
46087    name: "css",
46088    helperType: "scss"
46089  });
46090
46091  CodeMirror.defineMIME("text/x-less", {
46092    mediaTypes: mediaTypes,
46093    mediaFeatures: mediaFeatures,
46094    mediaValueKeywords: mediaValueKeywords,
46095    propertyKeywords: propertyKeywords,
46096    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
46097    colorKeywords: colorKeywords,
46098    valueKeywords: valueKeywords,
46099    fontProperties: fontProperties,
46100    allowNested: true,
46101    lineComment: "//",
46102    tokenHooks: {
46103      "/": function(stream, state) {
46104        if (stream.eat("/")) {
46105          stream.skipToEnd();
46106          return ["comment", "comment"];
46107        } else if (stream.eat("*")) {
46108          state.tokenize = tokenCComment;
46109          return tokenCComment(stream, state);
46110        } else {
46111          return ["operator", "operator"];
46112        }
46113      },
46114      "@": function(stream) {
46115        if (stream.eat("{")) return [null, "interpolation"];
46116        if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
46117        stream.eatWhile(/[\w\\\-]/);
46118        if (stream.match(/^\s*:/, false))
46119          return ["variable-2", "variable-definition"];
46120        return ["variable-2", "variable"];
46121      },
46122      "&": function() {
46123        return ["atom", "atom"];
46124      }
46125    },
46126    name: "css",
46127    helperType: "less"
46128  });
46129
46130  CodeMirror.defineMIME("text/x-gss", {
46131    documentTypes: documentTypes,
46132    mediaTypes: mediaTypes,
46133    mediaFeatures: mediaFeatures,
46134    propertyKeywords: propertyKeywords,
46135    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
46136    fontProperties: fontProperties,
46137    counterDescriptors: counterDescriptors,
46138    colorKeywords: colorKeywords,
46139    valueKeywords: valueKeywords,
46140    supportsAtComponent: true,
46141    tokenHooks: {
46142      "/": function(stream, state) {
46143        if (!stream.eat("*")) return false;
46144        state.tokenize = tokenCComment;
46145        return tokenCComment(stream, state);
46146      }
46147    },
46148    name: "css",
46149    helperType: "gss"
46150  });
46151
46152});
46153
46154},{"../../lib/codemirror":6}],8:[function(require,module,exports){
46155// CodeMirror, copyright (c) by Marijn Haverbeke and others
46156// Distributed under an MIT license: http://codemirror.net/LICENSE
46157
46158(function(mod) {
46159  if (typeof exports == "object" && typeof module == "object") // CommonJS
46160    mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
46161  else if (typeof define == "function" && define.amd) // AMD
46162    define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
46163  else // Plain browser env
46164    mod(CodeMirror);
46165})(function(CodeMirror) {
46166  "use strict";
46167
46168  var defaultTags = {
46169    script: [
46170      ["lang", /(javascript|babel)/i, "javascript"],
46171      ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
46172      ["type", /./, "text/plain"],
46173      [null, null, "javascript"]
46174    ],
46175    style:  [
46176      ["lang", /^css$/i, "css"],
46177      ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
46178      ["type", /./, "text/plain"],
46179      [null, null, "css"]
46180    ]
46181  };
46182
46183  function maybeBackup(stream, pat, style) {
46184    var cur = stream.current(), close = cur.search(pat);
46185    if (close > -1) {
46186      stream.backUp(cur.length - close);
46187    } else if (cur.match(/<\/?$/)) {
46188      stream.backUp(cur.length);
46189      if (!stream.match(pat, false)) stream.match(cur);
46190    }
46191    return style;
46192  }
46193
46194  var attrRegexpCache = {};
46195  function getAttrRegexp(attr) {
46196    var regexp = attrRegexpCache[attr];
46197    if (regexp) return regexp;
46198    return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
46199  }
46200
46201  function getAttrValue(text, attr) {
46202    var match = text.match(getAttrRegexp(attr))
46203    return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
46204  }
46205
46206  function getTagRegexp(tagName, anchored) {
46207    return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
46208  }
46209
46210  function addTags(from, to) {
46211    for (var tag in from) {
46212      var dest = to[tag] || (to[tag] = []);
46213      var source = from[tag];
46214      for (var i = source.length - 1; i >= 0; i--)
46215        dest.unshift(source[i])
46216    }
46217  }
46218
46219  function findMatchingMode(tagInfo, tagText) {
46220    for (var i = 0; i < tagInfo.length; i++) {
46221      var spec = tagInfo[i];
46222      if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
46223    }
46224  }
46225
46226  CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
46227    var htmlMode = CodeMirror.getMode(config, {
46228      name: "xml",
46229      htmlMode: true,
46230      multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
46231      multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
46232    });
46233
46234    var tags = {};
46235    var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
46236    addTags(defaultTags, tags);
46237    if (configTags) addTags(configTags, tags);
46238    if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
46239      tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
46240
46241    function html(stream, state) {
46242      var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
46243      if (tag && !/[<>\s\/]/.test(stream.current()) &&
46244          (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
46245          tags.hasOwnProperty(tagName)) {
46246        state.inTag = tagName + " "
46247      } else if (state.inTag && tag && />$/.test(stream.current())) {
46248        var inTag = /^([\S]+) (.*)/.exec(state.inTag)
46249        state.inTag = null
46250        var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
46251        var mode = CodeMirror.getMode(config, modeSpec)
46252        var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
46253        state.token = function (stream, state) {
46254          if (stream.match(endTagA, false)) {
46255            state.token = html;
46256            state.localState = state.localMode = null;
46257            return null;
46258          }
46259          return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
46260        };
46261        state.localMode = mode;
46262        state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
46263      } else if (state.inTag) {
46264        state.inTag += stream.current()
46265        if (stream.eol()) state.inTag += " "
46266      }
46267      return style;
46268    };
46269
46270    return {
46271      startState: function () {
46272        var state = CodeMirror.startState(htmlMode);
46273        return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
46274      },
46275
46276      copyState: function (state) {
46277        var local;
46278        if (state.localState) {
46279          local = CodeMirror.copyState(state.localMode, state.localState);
46280        }
46281        return {token: state.token, inTag: state.inTag,
46282                localMode: state.localMode, localState: local,
46283                htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
46284      },
46285
46286      token: function (stream, state) {
46287        return state.token(stream, state);
46288      },
46289
46290      indent: function (state, textAfter, line) {
46291        if (!state.localMode || /^\s*<\//.test(textAfter))
46292          return htmlMode.indent(state.htmlState, textAfter);
46293        else if (state.localMode.indent)
46294          return state.localMode.indent(state.localState, textAfter, line);
46295        else
46296          return CodeMirror.Pass;
46297      },
46298
46299      innerMode: function (state) {
46300        return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
46301      }
46302    };
46303  }, "xml", "javascript", "css");
46304
46305  CodeMirror.defineMIME("text/html", "htmlmixed");
46306});
46307
46308},{"../../lib/codemirror":6,"../css/css":7,"../javascript/javascript":9,"../xml/xml":10}],9:[function(require,module,exports){
46309// CodeMirror, copyright (c) by Marijn Haverbeke and others
46310// Distributed under an MIT license: http://codemirror.net/LICENSE
46311
46312(function(mod) {
46313  if (typeof exports == "object" && typeof module == "object") // CommonJS
46314    mod(require("../../lib/codemirror"));
46315  else if (typeof define == "function" && define.amd) // AMD
46316    define(["../../lib/codemirror"], mod);
46317  else // Plain browser env
46318    mod(CodeMirror);
46319})(function(CodeMirror) {
46320"use strict";
46321
46322CodeMirror.defineMode("javascript", function(config, parserConfig) {
46323  var indentUnit = config.indentUnit;
46324  var statementIndent = parserConfig.statementIndent;
46325  var jsonldMode = parserConfig.jsonld;
46326  var jsonMode = parserConfig.json || jsonldMode;
46327  var isTS = parserConfig.typescript;
46328  var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
46329
46330  // Tokenizer
46331
46332  var keywords = function(){
46333    function kw(type) {return {type: type, style: "keyword"};}
46334    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
46335    var operator = kw("operator"), atom = {type: "atom", style: "atom"};
46336
46337    return {
46338      "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
46339      "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
46340      "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
46341      "function": kw("function"), "catch": kw("catch"),
46342      "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
46343      "in": operator, "typeof": operator, "instanceof": operator,
46344      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
46345      "this": kw("this"), "class": kw("class"), "super": kw("atom"),
46346      "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
46347      "await": C
46348    };
46349  }();
46350
46351  var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
46352  var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
46353
46354  function readRegexp(stream) {
46355    var escaped = false, next, inSet = false;
46356    while ((next = stream.next()) != null) {
46357      if (!escaped) {
46358        if (next == "/" && !inSet) return;
46359        if (next == "[") inSet = true;
46360        else if (inSet && next == "]") inSet = false;
46361      }
46362      escaped = !escaped && next == "\\";
46363    }
46364  }
46365
46366  // Used as scratch variables to communicate multiple values without
46367  // consing up tons of objects.
46368  var type, content;
46369  function ret(tp, style, cont) {
46370    type = tp; content = cont;
46371    return style;
46372  }
46373  function tokenBase(stream, state) {
46374    var ch = stream.next();
46375    if (ch == '"' || ch == "'") {
46376      state.tokenize = tokenString(ch);
46377      return state.tokenize(stream, state);
46378    } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
46379      return ret("number", "number");
46380    } else if (ch == "." && stream.match("..")) {
46381      return ret("spread", "meta");
46382    } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
46383      return ret(ch);
46384    } else if (ch == "=" && stream.eat(">")) {
46385      return ret("=>", "operator");
46386    } else if (ch == "0" && stream.eat(/x/i)) {
46387      stream.eatWhile(/[\da-f]/i);
46388      return ret("number", "number");
46389    } else if (ch == "0" && stream.eat(/o/i)) {
46390      stream.eatWhile(/[0-7]/i);
46391      return ret("number", "number");
46392    } else if (ch == "0" && stream.eat(/b/i)) {
46393      stream.eatWhile(/[01]/i);
46394      return ret("number", "number");
46395    } else if (/\d/.test(ch)) {
46396      stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
46397      return ret("number", "number");
46398    } else if (ch == "/") {
46399      if (stream.eat("*")) {
46400        state.tokenize = tokenComment;
46401        return tokenComment(stream, state);
46402      } else if (stream.eat("/")) {
46403        stream.skipToEnd();
46404        return ret("comment", "comment");
46405      } else if (expressionAllowed(stream, state, 1)) {
46406        readRegexp(stream);
46407        stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
46408        return ret("regexp", "string-2");
46409      } else {
46410        stream.eat("=");
46411        return ret("operator", "operator", stream.current());
46412      }
46413    } else if (ch == "`") {
46414      state.tokenize = tokenQuasi;
46415      return tokenQuasi(stream, state);
46416    } else if (ch == "#") {
46417      stream.skipToEnd();
46418      return ret("error", "error");
46419    } else if (isOperatorChar.test(ch)) {
46420      if (ch != ">" || !state.lexical || state.lexical.type != ">") {
46421        if (stream.eat("=")) {
46422          if (ch == "!" || ch == "=") stream.eat("=")
46423        } else if (/[<>*+\-]/.test(ch)) {
46424          stream.eat(ch)
46425          if (ch == ">") stream.eat(ch)
46426        }
46427      }
46428      return ret("operator", "operator", stream.current());
46429    } else if (wordRE.test(ch)) {
46430      stream.eatWhile(wordRE);
46431      var word = stream.current()
46432      if (state.lastType != ".") {
46433        if (keywords.propertyIsEnumerable(word)) {
46434          var kw = keywords[word]
46435          return ret(kw.type, kw.style, word)
46436        }
46437        if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false))
46438          return ret("async", "keyword", word)
46439      }
46440      return ret("variable", "variable", word)
46441    }
46442  }
46443
46444  function tokenString(quote) {
46445    return function(stream, state) {
46446      var escaped = false, next;
46447      if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
46448        state.tokenize = tokenBase;
46449        return ret("jsonld-keyword", "meta");
46450      }
46451      while ((next = stream.next()) != null) {
46452        if (next == quote && !escaped) break;
46453        escaped = !escaped && next == "\\";
46454      }
46455      if (!escaped) state.tokenize = tokenBase;
46456      return ret("string", "string");
46457    };
46458  }
46459
46460  function tokenComment(stream, state) {
46461    var maybeEnd = false, ch;
46462    while (ch = stream.next()) {
46463      if (ch == "/" && maybeEnd) {
46464        state.tokenize = tokenBase;
46465        break;
46466      }
46467      maybeEnd = (ch == "*");
46468    }
46469    return ret("comment", "comment");
46470  }
46471
46472  function tokenQuasi(stream, state) {
46473    var escaped = false, next;
46474    while ((next = stream.next()) != null) {
46475      if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
46476        state.tokenize = tokenBase;
46477        break;
46478      }
46479      escaped = !escaped && next == "\\";
46480    }
46481    return ret("quasi", "string-2", stream.current());
46482  }
46483
46484  var brackets = "([{}])";
46485  // This is a crude lookahead trick to try and notice that we're
46486  // parsing the argument patterns for a fat-arrow function before we
46487  // actually hit the arrow token. It only works if the arrow is on
46488  // the same line as the arguments and there's no strange noise
46489  // (comments) in between. Fallback is to only notice when we hit the
46490  // arrow, and not declare the arguments as locals for the arrow
46491  // body.
46492  function findFatArrow(stream, state) {
46493    if (state.fatArrowAt) state.fatArrowAt = null;
46494    var arrow = stream.string.indexOf("=>", stream.start);
46495    if (arrow < 0) return;
46496
46497    if (isTS) { // Try to skip TypeScript return type declarations after the arguments
46498      var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
46499      if (m) arrow = m.index
46500    }
46501
46502    var depth = 0, sawSomething = false;
46503    for (var pos = arrow - 1; pos >= 0; --pos) {
46504      var ch = stream.string.charAt(pos);
46505      var bracket = brackets.indexOf(ch);
46506      if (bracket >= 0 && bracket < 3) {
46507        if (!depth) { ++pos; break; }
46508        if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
46509      } else if (bracket >= 3 && bracket < 6) {
46510        ++depth;
46511      } else if (wordRE.test(ch)) {
46512        sawSomething = true;
46513      } else if (/["'\/]/.test(ch)) {
46514        return;
46515      } else if (sawSomething && !depth) {
46516        ++pos;
46517        break;
46518      }
46519    }
46520    if (sawSomething && !depth) state.fatArrowAt = pos;
46521  }
46522
46523  // Parser
46524
46525  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
46526
46527  function JSLexical(indented, column, type, align, prev, info) {
46528    this.indented = indented;
46529    this.column = column;
46530    this.type = type;
46531    this.prev = prev;
46532    this.info = info;
46533    if (align != null) this.align = align;
46534  }
46535
46536  function inScope(state, varname) {
46537    for (var v = state.localVars; v; v = v.next)
46538      if (v.name == varname) return true;
46539    for (var cx = state.context; cx; cx = cx.prev) {
46540      for (var v = cx.vars; v; v = v.next)
46541        if (v.name == varname) return true;
46542    }
46543  }
46544
46545  function parseJS(state, style, type, content, stream) {
46546    var cc = state.cc;
46547    // Communicate our context to the combinators.
46548    // (Less wasteful than consing up a hundred closures on every call.)
46549    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
46550
46551    if (!state.lexical.hasOwnProperty("align"))
46552      state.lexical.align = true;
46553
46554    while(true) {
46555      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
46556      if (combinator(type, content)) {
46557        while(cc.length && cc[cc.length - 1].lex)
46558          cc.pop()();
46559        if (cx.marked) return cx.marked;
46560        if (type == "variable" && inScope(state, content)) return "variable-2";
46561        return style;
46562      }
46563    }
46564  }
46565
46566  // Combinator utils
46567
46568  var cx = {state: null, column: null, marked: null, cc: null};
46569  function pass() {
46570    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
46571  }
46572  function cont() {
46573    pass.apply(null, arguments);
46574    return true;
46575  }
46576  function register(varname) {
46577    function inList(list) {
46578      for (var v = list; v; v = v.next)
46579        if (v.name == varname) return true;
46580      return false;
46581    }
46582    var state = cx.state;
46583    cx.marked = "def";
46584    if (state.context) {
46585      if (inList(state.localVars)) return;
46586      state.localVars = {name: varname, next: state.localVars};
46587    } else {
46588      if (inList(state.globalVars)) return;
46589      if (parserConfig.globalVars)
46590        state.globalVars = {name: varname, next: state.globalVars};
46591    }
46592  }
46593
46594  function isModifier(name) {
46595    return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
46596  }
46597
46598  // Combinators
46599
46600  var defaultVars = {name: "this", next: {name: "arguments"}};
46601  function pushcontext() {
46602    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
46603    cx.state.localVars = defaultVars;
46604  }
46605  function popcontext() {
46606    cx.state.localVars = cx.state.context.vars;
46607    cx.state.context = cx.state.context.prev;
46608  }
46609  function pushlex(type, info) {
46610    var result = function() {
46611      var state = cx.state, indent = state.indented;
46612      if (state.lexical.type == "stat") indent = state.lexical.indented;
46613      else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
46614        indent = outer.indented;
46615      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
46616    };
46617    result.lex = true;
46618    return result;
46619  }
46620  function poplex() {
46621    var state = cx.state;
46622    if (state.lexical.prev) {
46623      if (state.lexical.type == ")")
46624        state.indented = state.lexical.indented;
46625      state.lexical = state.lexical.prev;
46626    }
46627  }
46628  poplex.lex = true;
46629
46630  function expect(wanted) {
46631    function exp(type) {
46632      if (type == wanted) return cont();
46633      else if (wanted == ";") return pass();
46634      else return cont(exp);
46635    };
46636    return exp;
46637  }
46638
vendor: 37,501 bytes, lines 46639-47624
46639  function statement(type, value) {
46640    if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
46641    if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
46642    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
46643    if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
46644    if (type == "debugger") return cont(expect(";"));
46645    if (type == "{") return cont(pushlex("}"), block, poplex);
46646    if (type == ";") return cont();
46647    if (type == "if") {
46648      if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
46649        cx.state.cc.pop()();
46650      return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
46651    }
46652    if (type == "function") return cont(functiondef);
46653    if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
46654    if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
46655    if (type == "variable") {
46656      if (isTS && value == "declare") {
46657        cx.marked = "keyword"
46658        return cont(statement)
46659      } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
46660        cx.marked = "keyword"
46661        if (value == "enum") return cont(enumdef);
46662        else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
46663        else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
46664      } else if (isTS && value == "namespace") {
46665        cx.marked = "keyword"
46666        return cont(pushlex("form"), expression, block, poplex)
46667      } else if (isTS && value == "abstract") {
46668        cx.marked = "keyword"
46669        return cont(statement)
46670      } else {
46671        return cont(pushlex("stat"), maybelabel);
46672      }
46673    }
46674    if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
46675                                      block, poplex, poplex);
46676    if (type == "case") return cont(expression, expect(":"));
46677    if (type == "default") return cont(expect(":"));
46678    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
46679                                     statement, poplex, popcontext);
46680    if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
46681    if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
46682    if (type == "async") return cont(statement)
46683    if (value == "@") return cont(expression, statement)
46684    return pass(pushlex("stat"), expression, expect(";"), poplex);
46685  }
46686  function expression(type, value) {
46687    return expressionInner(type, value, false);
46688  }
46689  function expressionNoComma(type, value) {
46690    return expressionInner(type, value, true);
46691  }
46692  function parenExpr(type) {
46693    if (type != "(") return pass()
46694    return cont(pushlex(")"), expression, expect(")"), poplex)
46695  }
46696  function expressionInner(type, value, noComma) {
46697    if (cx.state.fatArrowAt == cx.stream.start) {
46698      var body = noComma ? arrowBodyNoComma : arrowBody;
46699      if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
46700      else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
46701    }
46702
46703    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
46704    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
46705    if (type == "function") return cont(functiondef, maybeop);
46706    if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
46707    if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
46708    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
46709    if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
46710    if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
46711    if (type == "{") return contCommasep(objprop, "}", null, maybeop);
46712    if (type == "quasi") return pass(quasi, maybeop);
46713    if (type == "new") return cont(maybeTarget(noComma));
46714    if (type == "import") return cont(expression);
46715    return cont();
46716  }
46717  function maybeexpression(type) {
46718    if (type.match(/[;\}\)\],]/)) return pass();
46719    return pass(expression);
46720  }
46721
46722  function maybeoperatorComma(type, value) {
46723    if (type == ",") return cont(expression);
46724    return maybeoperatorNoComma(type, value, false);
46725  }
46726  function maybeoperatorNoComma(type, value, noComma) {
46727    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
46728    var expr = noComma == false ? expression : expressionNoComma;
46729    if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
46730    if (type == "operator") {
46731      if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
46732      if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
46733        return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
46734      if (value == "?") return cont(expression, expect(":"), expr);
46735      return cont(expr);
46736    }
46737    if (type == "quasi") { return pass(quasi, me); }
46738    if (type == ";") return;
46739    if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
46740    if (type == ".") return cont(property, me);
46741    if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
46742    if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
46743    if (type == "regexp") {
46744      cx.state.lastType = cx.marked = "operator"
46745      cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
46746      return cont(expr)
46747    }
46748  }
46749  function quasi(type, value) {
46750    if (type != "quasi") return pass();
46751    if (value.slice(value.length - 2) != "${") return cont(quasi);
46752    return cont(expression, continueQuasi);
46753  }
46754  function continueQuasi(type) {
46755    if (type == "}") {
46756      cx.marked = "string-2";
46757      cx.state.tokenize = tokenQuasi;
46758      return cont(quasi);
46759    }
46760  }
46761  function arrowBody(type) {
46762    findFatArrow(cx.stream, cx.state);
46763    return pass(type == "{" ? statement : expression);
46764  }
46765  function arrowBodyNoComma(type) {
46766    findFatArrow(cx.stream, cx.state);
46767    return pass(type == "{" ? statement : expressionNoComma);
46768  }
46769  function maybeTarget(noComma) {
46770    return function(type) {
46771      if (type == ".") return cont(noComma ? targetNoComma : target);
46772      else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
46773      else return pass(noComma ? expressionNoComma : expression);
46774    };
46775  }
46776  function target(_, value) {
46777    if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
46778  }
46779  function targetNoComma(_, value) {
46780    if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
46781  }
46782  function maybelabel(type) {
46783    if (type == ":") return cont(poplex, statement);
46784    return pass(maybeoperatorComma, expect(";"), poplex);
46785  }
46786  function property(type) {
46787    if (type == "variable") {cx.marked = "property"; return cont();}
46788  }
46789  function objprop(type, value) {
46790    if (type == "async") {
46791      cx.marked = "property";
46792      return cont(objprop);
46793    } else if (type == "variable" || cx.style == "keyword") {
46794      cx.marked = "property";
46795      if (value == "get" || value == "set") return cont(getterSetter);
46796      var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
46797      if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
46798        cx.state.fatArrowAt = cx.stream.pos + m[0].length
46799      return cont(afterprop);
46800    } else if (type == "number" || type == "string") {
46801      cx.marked = jsonldMode ? "property" : (cx.style + " property");
46802      return cont(afterprop);
46803    } else if (type == "jsonld-keyword") {
46804      return cont(afterprop);
46805    } else if (isTS && isModifier(value)) {
46806      cx.marked = "keyword"
46807      return cont(objprop)
46808    } else if (type == "[") {
46809      return cont(expression, maybetype, expect("]"), afterprop);
46810    } else if (type == "spread") {
46811      return cont(expressionNoComma, afterprop);
46812    } else if (value == "*") {
46813      cx.marked = "keyword";
46814      return cont(objprop);
46815    } else if (type == ":") {
46816      return pass(afterprop)
46817    }
46818  }
46819  function getterSetter(type) {
46820    if (type != "variable") return pass(afterprop);
46821    cx.marked = "property";
46822    return cont(functiondef);
46823  }
46824  function afterprop(type) {
46825    if (type == ":") return cont(expressionNoComma);
46826    if (type == "(") return pass(functiondef);
46827  }
46828  function commasep(what, end, sep) {
46829    function proceed(type, value) {
46830      if (sep ? sep.indexOf(type) > -1 : type == ",") {
46831        var lex = cx.state.lexical;
46832        if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
46833        return cont(function(type, value) {
46834          if (type == end || value == end) return pass()
46835          return pass(what)
46836        }, proceed);
46837      }
46838      if (type == end || value == end) return cont();
46839      return cont(expect(end));
46840    }
46841    return function(type, value) {
46842      if (type == end || value == end) return cont();
46843      return pass(what, proceed);
46844    };
46845  }
46846  function contCommasep(what, end, info) {
46847    for (var i = 3; i < arguments.length; i++)
46848      cx.cc.push(arguments[i]);
46849    return cont(pushlex(end, info), commasep(what, end), poplex);
46850  }
46851  function block(type) {
46852    if (type == "}") return cont();
46853    return pass(statement, block);
46854  }
46855  function maybetype(type, value) {
46856    if (isTS) {
46857      if (type == ":") return cont(typeexpr);
46858      if (value == "?") return cont(maybetype);
46859    }
46860  }
46861  function mayberettype(type) {
46862    if (isTS && type == ":") {
46863      if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
46864      else return cont(typeexpr)
46865    }
46866  }
46867  function isKW(_, value) {
46868    if (value == "is") {
46869      cx.marked = "keyword"
46870      return cont()
46871    }
46872  }
46873  function typeexpr(type, value) {
46874    if (value == "keyof" || value == "typeof") {
46875      cx.marked = "keyword"
46876      return cont(value == "keyof" ? typeexpr : expressionNoComma)
46877    }
46878    if (type == "variable" || value == "void") {
46879      cx.marked = "type"
46880      return cont(afterType)
46881    }
46882    if (type == "string" || type == "number" || type == "atom") return cont(afterType);
46883    if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
46884    if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
46885    if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
46886    if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
46887  }
46888  function maybeReturnType(type) {
46889    if (type == "=>") return cont(typeexpr)
46890  }
46891  function typeprop(type, value) {
46892    if (type == "variable" || cx.style == "keyword") {
46893      cx.marked = "property"
46894      return cont(typeprop)
46895    } else if (value == "?") {
46896      return cont(typeprop)
46897    } else if (type == ":") {
46898      return cont(typeexpr)
46899    } else if (type == "[") {
46900      return cont(expression, maybetype, expect("]"), typeprop)
46901    }
46902  }
46903  function typearg(type, value) {
46904    if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
46905    if (type == ":") return cont(typeexpr)
46906    return pass(typeexpr)
46907  }
46908  function afterType(type, value) {
46909    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
46910    if (value == "|" || type == "." || value == "&") return cont(typeexpr)
46911    if (type == "[") return cont(expect("]"), afterType)
46912    if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
46913  }
46914  function maybeTypeArgs(_, value) {
46915    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
46916  }
46917  function typeparam() {
46918    return pass(typeexpr, maybeTypeDefault)
46919  }
46920  function maybeTypeDefault(_, value) {
46921    if (value == "=") return cont(typeexpr)
46922  }
46923  function vardef(_, value) {
46924    if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)}
46925    return pass(pattern, maybetype, maybeAssign, vardefCont);
46926  }
46927  function pattern(type, value) {
46928    if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
46929    if (type == "variable") { register(value); return cont(); }
46930    if (type == "spread") return cont(pattern);
46931    if (type == "[") return contCommasep(pattern, "]");
46932    if (type == "{") return contCommasep(proppattern, "}");
46933  }
46934  function proppattern(type, value) {
46935    if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
46936      register(value);
46937      return cont(maybeAssign);
46938    }
46939    if (type == "variable") cx.marked = "property";
46940    if (type == "spread") return cont(pattern);
46941    if (type == "}") return pass();
46942    return cont(expect(":"), pattern, maybeAssign);
46943  }
46944  function maybeAssign(_type, value) {
46945    if (value == "=") return cont(expressionNoComma);
46946  }
46947  function vardefCont(type) {
46948    if (type == ",") return cont(vardef);
46949  }
46950  function maybeelse(type, value) {
46951    if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
46952  }
46953  function forspec(type, value) {
46954    if (value == "await") return cont(forspec);
46955    if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
46956  }
46957  function forspec1(type) {
46958    if (type == "var") return cont(vardef, expect(";"), forspec2);
46959    if (type == ";") return cont(forspec2);
46960    if (type == "variable") return cont(formaybeinof);
46961    return pass(expression, expect(";"), forspec2);
46962  }
46963  function formaybeinof(_type, value) {
46964    if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
46965    return cont(maybeoperatorComma, forspec2);
46966  }
46967  function forspec2(type, value) {
46968    if (type == ";") return cont(forspec3);
46969    if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
46970    return pass(expression, expect(";"), forspec3);
46971  }
46972  function forspec3(type) {
46973    if (type != ")") cont(expression);
46974  }
46975  function functiondef(type, value) {
46976    if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
46977    if (type == "variable") {register(value); return cont(functiondef);}
46978    if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
46979    if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
46980  }
46981  function funarg(type, value) {
46982    if (value == "@") cont(expression, funarg)
46983    if (type == "spread") return cont(funarg);
46984    if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
46985    return pass(pattern, maybetype, maybeAssign);
46986  }
46987  function classExpression(type, value) {
46988    // Class expressions may have an optional name.
46989    if (type == "variable") return className(type, value);
46990    return classNameAfter(type, value);
46991  }
46992  function className(type, value) {
46993    if (type == "variable") {register(value); return cont(classNameAfter);}
46994  }
46995  function classNameAfter(type, value) {
46996    if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
46997    if (value == "extends" || value == "implements" || (isTS && type == ",")) {
46998      if (value == "implements") cx.marked = "keyword";
46999      return cont(isTS ? typeexpr : expression, classNameAfter);
47000    }
47001    if (type == "{") return cont(pushlex("}"), classBody, poplex);
47002  }
47003  function classBody(type, value) {
47004    if (type == "async" ||
47005        (type == "variable" &&
47006         (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
47007         cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
47008      cx.marked = "keyword";
47009      return cont(classBody);
47010    }
47011    if (type == "variable" || cx.style == "keyword") {
47012      cx.marked = "property";
47013      return cont(isTS ? classfield : functiondef, classBody);
47014    }
47015    if (type == "[")
47016      return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
47017    if (value == "*") {
47018      cx.marked = "keyword";
47019      return cont(classBody);
47020    }
47021    if (type == ";") return cont(classBody);
47022    if (type == "}") return cont();
47023    if (value == "@") return cont(expression, classBody)
47024  }
47025  function classfield(type, value) {
47026    if (value == "?") return cont(classfield)
47027    if (type == ":") return cont(typeexpr, maybeAssign)
47028    if (value == "=") return cont(expressionNoComma)
47029    return pass(functiondef)
47030  }
47031  function afterExport(type, value) {
47032    if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
47033    if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
47034    if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
47035    return pass(statement);
47036  }
47037  function exportField(type, value) {
47038    if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
47039    if (type == "variable") return pass(expressionNoComma, exportField);
47040  }
47041  function afterImport(type) {
47042    if (type == "string") return cont();
47043    if (type == "(") return pass(expression);
47044    return pass(importSpec, maybeMoreImports, maybeFrom);
47045  }
47046  function importSpec(type, value) {
47047    if (type == "{") return contCommasep(importSpec, "}");
47048    if (type == "variable") register(value);
47049    if (value == "*") cx.marked = "keyword";
47050    return cont(maybeAs);
47051  }
47052  function maybeMoreImports(type) {
47053    if (type == ",") return cont(importSpec, maybeMoreImports)
47054  }
47055  function maybeAs(_type, value) {
47056    if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
47057  }
47058  function maybeFrom(_type, value) {
47059    if (value == "from") { cx.marked = "keyword"; return cont(expression); }
47060  }
47061  function arrayLiteral(type) {
47062    if (type == "]") return cont();
47063    return pass(commasep(expressionNoComma, "]"));
47064  }
47065  function enumdef() {
47066    return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex)
47067  }
47068  function enummember() {
47069    return pass(pattern, maybeAssign);
47070  }
47071
47072  function isContinuedStatement(state, textAfter) {
47073    return state.lastType == "operator" || state.lastType == "," ||
47074      isOperatorChar.test(textAfter.charAt(0)) ||
47075      /[,.]/.test(textAfter.charAt(0));
47076  }
47077
47078  function expressionAllowed(stream, state, backUp) {
47079    return state.tokenize == tokenBase &&
47080      /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
47081      (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
47082  }
47083
47084  // Interface
47085
47086  return {
47087    startState: function(basecolumn) {
47088      var state = {
47089        tokenize: tokenBase,
47090        lastType: "sof",
47091        cc: [],
47092        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
47093        localVars: parserConfig.localVars,
47094        context: parserConfig.localVars && {vars: parserConfig.localVars},
47095        indented: basecolumn || 0
47096      };
47097      if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
47098        state.globalVars = parserConfig.globalVars;
47099      return state;
47100    },
47101
47102    token: function(stream, state) {
47103      if (stream.sol()) {
47104        if (!state.lexical.hasOwnProperty("align"))
47105          state.lexical.align = false;
47106        state.indented = stream.indentation();
47107        findFatArrow(stream, state);
47108      }
47109      if (state.tokenize != tokenComment && stream.eatSpace()) return null;
47110      var style = state.tokenize(stream, state);
47111      if (type == "comment") return style;
47112      state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
47113      return parseJS(state, style, type, content, stream);
47114    },
47115
47116    indent: function(state, textAfter) {
47117      if (state.tokenize == tokenComment) return CodeMirror.Pass;
47118      if (state.tokenize != tokenBase) return 0;
47119      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
47120      // Kludge to prevent 'maybelse' from blocking lexical scope pops
47121      if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
47122        var c = state.cc[i];
47123        if (c == poplex) lexical = lexical.prev;
47124        else if (c != maybeelse) break;
47125      }
47126      while ((lexical.type == "stat" || lexical.type == "form") &&
47127             (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
47128                                   (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
47129                                   !/^[,\.=+\-*:?[\(]/.test(textAfter))))
47130        lexical = lexical.prev;
47131      if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
47132        lexical = lexical.prev;
47133      var type = lexical.type, closing = firstChar == type;
47134
47135      if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
47136      else if (type == "form" && firstChar == "{") return lexical.indented;
47137      else if (type == "form") return lexical.indented + indentUnit;
47138      else if (type == "stat")
47139        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
47140      else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
47141        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
47142      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
47143      else return lexical.indented + (closing ? 0 : indentUnit);
47144    },
47145
47146    electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
47147    blockCommentStart: jsonMode ? null : "/*",
47148    blockCommentEnd: jsonMode ? null : "*/",
47149    blockCommentContinue: jsonMode ? null : " * ",
47150    lineComment: jsonMode ? null : "//",
47151    fold: "brace",
47152    closeBrackets: "()[]{}''\"\"``",
47153
47154    helperType: jsonMode ? "json" : "javascript",
47155    jsonldMode: jsonldMode,
47156    jsonMode: jsonMode,
47157
47158    expressionAllowed: expressionAllowed,
47159
47160    skipExpression: function(state) {
47161      var top = state.cc[state.cc.length - 1]
47162      if (top == expression || top == expressionNoComma) state.cc.pop()
47163    }
47164  };
47165});
47166
47167CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
47168
47169CodeMirror.defineMIME("text/javascript", "javascript");
47170CodeMirror.defineMIME("text/ecmascript", "javascript");
47171CodeMirror.defineMIME("application/javascript", "javascript");
47172CodeMirror.defineMIME("application/x-javascript", "javascript");
47173CodeMirror.defineMIME("application/ecmascript", "javascript");
47174CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
47175CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
47176CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
47177CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
47178CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
47179
47180});
47181
47182},{"../../lib/codemirror":6}],10:[function(require,module,exports){
47183// CodeMirror, copyright (c) by Marijn Haverbeke and others
47184// Distributed under an MIT license: http://codemirror.net/LICENSE
47185
47186(function(mod) {
47187  if (typeof exports == "object" && typeof module == "object") // CommonJS
47188    mod(require("../../lib/codemirror"));
47189  else if (typeof define == "function" && define.amd) // AMD
47190    define(["../../lib/codemirror"], mod);
47191  else // Plain browser env
47192    mod(CodeMirror);
47193})(function(CodeMirror) {
47194"use strict";
47195
47196var htmlConfig = {
47197  autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
47198                    'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
47199                    'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
47200                    'track': true, 'wbr': true, 'menuitem': true},
47201  implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
47202                     'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
47203                     'th': true, 'tr': true},
47204  contextGrabbers: {
47205    'dd': {'dd': true, 'dt': true},
47206    'dt': {'dd': true, 'dt': true},
47207    'li': {'li': true},
47208    'option': {'option': true, 'optgroup': true},
47209    'optgroup': {'optgroup': true},
47210    'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
47211          'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
47212          'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
47213          'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
47214          'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
47215    'rp': {'rp': true, 'rt': true},
47216    'rt': {'rp': true, 'rt': true},
47217    'tbody': {'tbody': true, 'tfoot': true},
47218    'td': {'td': true, 'th': true},
47219    'tfoot': {'tbody': true},
47220    'th': {'td': true, 'th': true},
47221    'thead': {'tbody': true, 'tfoot': true},
47222    'tr': {'tr': true}
47223  },
47224  doNotIndent: {"pre": true},
47225  allowUnquoted: true,
47226  allowMissing: true,
47227  caseFold: true
47228}
47229
47230var xmlConfig = {
47231  autoSelfClosers: {},
47232  implicitlyClosed: {},
47233  contextGrabbers: {},
47234  doNotIndent: {},
47235  allowUnquoted: false,
47236  allowMissing: false,
47237  allowMissingTagName: false,
47238  caseFold: false
47239}
47240
47241CodeMirror.defineMode("xml", function(editorConf, config_) {
47242  var indentUnit = editorConf.indentUnit
47243  var config = {}
47244  var defaults = config_.htmlMode ? htmlConfig : xmlConfig
47245  for (var prop in defaults) config[prop] = defaults[prop]
47246  for (var prop in config_) config[prop] = config_[prop]
47247
47248  // Return variables for tokenizers
47249  var type, setStyle;
47250
47251  function inText(stream, state) {
47252    function chain(parser) {
47253      state.tokenize = parser;
47254      return parser(stream, state);
47255    }
47256
47257    var ch = stream.next();
47258    if (ch == "<") {
47259      if (stream.eat("!")) {
47260        if (stream.eat("[")) {
47261          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
47262          else return null;
47263        } else if (stream.match("--")) {
47264          return chain(inBlock("comment", "-->"));
47265        } else if (stream.match("DOCTYPE", true, true)) {
47266          stream.eatWhile(/[\w\._\-]/);
47267          return chain(doctype(1));
47268        } else {
47269          return null;
47270        }
47271      } else if (stream.eat("?")) {
47272        stream.eatWhile(/[\w\._\-]/);
47273        state.tokenize = inBlock("meta", "?>");
47274        return "meta";
47275      } else {
47276        type = stream.eat("/") ? "closeTag" : "openTag";
47277        state.tokenize = inTag;
47278        return "tag bracket";
47279      }
47280    } else if (ch == "&") {
47281      var ok;
47282      if (stream.eat("#")) {
47283        if (stream.eat("x")) {
47284          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
47285        } else {
47286          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
47287        }
47288      } else {
47289        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
47290      }
47291      return ok ? "atom" : "error";
47292    } else {
47293      stream.eatWhile(/[^&<]/);
47294      return null;
47295    }
47296  }
47297  inText.isInText = true;
47298
47299  function inTag(stream, state) {
47300    var ch = stream.next();
47301    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
47302      state.tokenize = inText;
47303      type = ch == ">" ? "endTag" : "selfcloseTag";
47304      return "tag bracket";
47305    } else if (ch == "=") {
47306      type = "equals";
47307      return null;
47308    } else if (ch == "<") {
47309      state.tokenize = inText;
47310      state.state = baseState;
47311      state.tagName = state.tagStart = null;
47312      var next = state.tokenize(stream, state);
47313      return next ? next + " tag error" : "tag error";
47314    } else if (/[\'\"]/.test(ch)) {
47315      state.tokenize = inAttribute(ch);
47316      state.stringStartCol = stream.column();
47317      return state.tokenize(stream, state);
47318    } else {
47319      stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
47320      return "word";
47321    }
47322  }
47323
47324  function inAttribute(quote) {
47325    var closure = function(stream, state) {
47326      while (!stream.eol()) {
47327        if (stream.next() == quote) {
47328          state.tokenize = inTag;
47329          break;
47330        }
47331      }
47332      return "string";
47333    };
47334    closure.isInAttribute = true;
47335    return closure;
47336  }
47337
47338  function inBlock(style, terminator) {
47339    return function(stream, state) {
47340      while (!stream.eol()) {
47341        if (stream.match(terminator)) {
47342          state.tokenize = inText;
47343          break;
47344        }
47345        stream.next();
47346      }
47347      return style;
47348    };
47349  }
47350  function doctype(depth) {
47351    return function(stream, state) {
47352      var ch;
47353      while ((ch = stream.next()) != null) {
47354        if (ch == "<") {
47355          state.tokenize = doctype(depth + 1);
47356          return state.tokenize(stream, state);
47357        } else if (ch == ">") {
47358          if (depth == 1) {
47359            state.tokenize = inText;
47360            break;
47361          } else {
47362            state.tokenize = doctype(depth - 1);
47363            return state.tokenize(stream, state);
47364          }
47365        }
47366      }
47367      return "meta";
47368    };
47369  }
47370
47371  function Context(state, tagName, startOfLine) {
47372    this.prev = state.context;
47373    this.tagName = tagName;
47374    this.indent = state.indented;
47375    this.startOfLine = startOfLine;
47376    if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
47377      this.noIndent = true;
47378  }
47379  function popContext(state) {
47380    if (state.context) state.context = state.context.prev;
47381  }
47382  function maybePopContext(state, nextTagName) {
47383    var parentTagName;
47384    while (true) {
47385      if (!state.context) {
47386        return;
47387      }
47388      parentTagName = state.context.tagName;
47389      if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
47390          !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
47391        return;
47392      }
47393      popContext(state);
47394    }
47395  }
47396
47397  function baseState(type, stream, state) {
47398    if (type == "openTag") {
47399      state.tagStart = stream.column();
47400      return tagNameState;
47401    } else if (type == "closeTag") {
47402      return closeTagNameState;
47403    } else {
47404      return baseState;
47405    }
47406  }
47407  function tagNameState(type, stream, state) {
47408    if (type == "word") {
47409      state.tagName = stream.current();
47410      setStyle = "tag";
47411      return attrState;
47412    } else if (config.allowMissingTagName && type == "endTag") {
47413      setStyle = "tag bracket";
47414      return attrState(type, stream, state);
47415    } else {
47416      setStyle = "error";
47417      return tagNameState;
47418    }
47419  }
47420  function closeTagNameState(type, stream, state) {
47421    if (type == "word") {
47422      var tagName = stream.current();
47423      if (state.context && state.context.tagName != tagName &&
47424          config.implicitlyClosed.hasOwnProperty(state.context.tagName))
47425        popContext(state);
47426      if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
47427        setStyle = "tag";
47428        return closeState;
47429      } else {
47430        setStyle = "tag error";
47431        return closeStateErr;
47432      }
47433    } else if (config.allowMissingTagName && type == "endTag") {
47434      setStyle = "tag bracket";
47435      return closeState(type, stream, state);
47436    } else {
47437      setStyle = "error";
47438      return closeStateErr;
47439    }
47440  }
47441
47442  function closeState(type, _stream, state) {
47443    if (type != "endTag") {
47444      setStyle = "error";
47445      return closeState;
47446    }
47447    popContext(state);
47448    return baseState;
47449  }
47450  function closeStateErr(type, stream, state) {
47451    setStyle = "error";
47452    return closeState(type, stream, state);
47453  }
47454
47455  function attrState(type, _stream, state) {
47456    if (type == "word") {
47457      setStyle = "attribute";
47458      return attrEqState;
47459    } else if (type == "endTag" || type == "selfcloseTag") {
47460      var tagName = state.tagName, tagStart = state.tagStart;
47461      state.tagName = state.tagStart = null;
47462      if (type == "selfcloseTag" ||
47463          config.autoSelfClosers.hasOwnProperty(tagName)) {
47464        maybePopContext(state, tagName);
47465      } else {
47466        maybePopContext(state, tagName);
47467        state.context = new Context(state, tagName, tagStart == state.indented);
47468      }
47469      return baseState;
47470    }
47471    setStyle = "error";
47472    return attrState;
47473  }
47474  function attrEqState(type, stream, state) {
47475    if (type == "equals") return attrValueState;
47476    if (!config.allowMissing) setStyle = "error";
47477    return attrState(type, stream, state);
47478  }
47479  function attrValueState(type, stream, state) {
47480    if (type == "string") return attrContinuedState;
47481    if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
47482    setStyle = "error";
47483    return attrState(type, stream, state);
47484  }
47485  function attrContinuedState(type, stream, state) {
47486    if (type == "string") return attrContinuedState;
47487    return attrState(type, stream, state);
47488  }
47489
47490  return {
47491    startState: function(baseIndent) {
47492      var state = {tokenize: inText,
47493                   state: baseState,
47494                   indented: baseIndent || 0,
47495                   tagName: null, tagStart: null,
47496                   context: null}
47497      if (baseIndent != null) state.baseIndent = baseIndent
47498      return state
47499    },
47500
47501    token: function(stream, state) {
47502      if (!state.tagName && stream.sol())
47503        state.indented = stream.indentation();
47504
47505      if (stream.eatSpace()) return null;
47506      type = null;
47507      var style = state.tokenize(stream, state);
47508      if ((style || type) && style != "comment") {
47509        setStyle = null;
47510        state.state = state.state(type || style, stream, state);
47511        if (setStyle)
47512          style = setStyle == "error" ? style + " error" : setStyle;
47513      }
47514      return style;
47515    },
47516
47517    indent: function(state, textAfter, fullLine) {
47518      var context = state.context;
47519      // Indent multi-line strings (e.g. css).
47520      if (state.tokenize.isInAttribute) {
47521        if (state.tagStart == state.indented)
47522          return state.stringStartCol + 1;
47523        else
47524          return state.indented + indentUnit;
47525      }
47526      if (context && context.noIndent) return CodeMirror.Pass;
47527      if (state.tokenize != inTag && state.tokenize != inText)
47528        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
47529      // Indent the starts of attribute names.
47530      if (state.tagName) {
47531        if (config.multilineTagIndentPastTag !== false)
47532          return state.tagStart + state.tagName.length + 2;
47533        else
47534          return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
47535      }
47536      if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
47537      var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
47538      if (tagAfter && tagAfter[1]) { // Closing tag spotted
47539        while (context) {
47540          if (context.tagName == tagAfter[2]) {
47541            context = context.prev;
47542            break;
47543          } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
47544            context = context.prev;
47545          } else {
47546            break;
47547          }
47548        }
47549      } else if (tagAfter) { // Opening tag spotted
47550        while (context) {
47551          var grabbers = config.contextGrabbers[context.tagName];
47552          if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
47553            context = context.prev;
47554          else
47555            break;
47556        }
47557      }
47558      while (context && context.prev && !context.startOfLine)
47559        context = context.prev;
47560      if (context) return context.indent + indentUnit;
47561      else return state.baseIndent || 0;
47562    },
47563
47564    electricInput: /<\/[\s\w:]+>$/,
47565    blockCommentStart: "<!--",
47566    blockCommentEnd: "-->",
47567
47568    configuration: config.htmlMode ? "html" : "xml",
47569    helperType: config.htmlMode ? "html" : "xml",
47570
47571    skipAttribute: function(state) {
47572      if (state.state == attrValueState)
47573        state.state = attrState
47574    }
47575  };
47576});
47577
47578CodeMirror.defineMIME("text/xml", "xml");
47579CodeMirror.defineMIME("application/xml", "xml");
47580if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
47581  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
47582
47583});
47584
47585},{"../../lib/codemirror":6}],11:[function(require,module,exports){
47586(function (global){
47587/**
47588 * marked - a markdown parser
47589 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
47590 * https://github.com/markedjs/marked
47591 */
47592
47593;(function(root) {
47594'use strict';
47595
47596/**
47597 * Block-Level Grammar
47598 */
47599
47600var block = {
47601  newline: /^\n+/,
47602  code: /^( {4}[^\n]+\n*)+/,
47603  fences: noop,
47604  hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
47605  heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
47606  nptable: noop,
47607  blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
47608  list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
47609  html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
47610  def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
47611  table: noop,
47612  lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
47613  paragraph: /^([^\n]+(?:\n?(?!hr|heading|lheading| {0,3}>|tag)[^\n]+)+)/,
47614  text: /^[^\n]+/
47615};
47616
47617block._label = /(?:\\[\[\]]|[^\[\]])+/;
47618block._title = /(?:"(?:\\"|[^"]|"[^"\n]*")*"|'\n?(?:[^'\n]+\n?)*'|\([^()]*\))/;
47619block.def = edit(block.def)
47620  .replace('label', block._label)
47621  .replace('title', block._title)
47622  .getRegex();
47623
47624block.bullet = /(?:[*+-]|\d+\.)/;
47625block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
47626block.item = edit(block.item, 'gm')
47627  .replace(/bull/g, block.bullet)
47628  .getRegex();
47629
47630block.list = edit(block.list)
47631  .replace(/bull/g, block.bullet)
47632  .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
47633  .replace('def', '\\n+(?=' + block.def.source + ')')
47634  .getRegex();
47635
47636block._tag = '(?!(?:'
47637  + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
47638  + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
47639  + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b';
47640
47641block.html = edit(block.html)
47642  .replace('comment', /<!--[\s\S]*?-->/)
47643  .replace('closed', /<(tag)[\s\S]+?<\/\1>/)
47644  .replace('closing', /<tag(?:"[^"]*"|'[^']*'|\s[^'"\/>\s]*)*?\/?>/)
47645  .replace(/tag/g, block._tag)
47646  .getRegex();
47647
47648block.paragraph = edit(block.paragraph)
47649  .replace('hr', block.hr)
47650  .replace('heading', block.heading)
47651  .replace('lheading', block.lheading)
47652  .replace('tag', '<' + block._tag)
47653  .getRegex();
47654
47655block.blockquote = edit(block.blockquote)
47656  .replace('paragraph', block.paragraph)
47657  .getRegex();
47658
47659/**
47660 * Normal Block Grammar
47661 */
47662
47663block.normal = merge({}, block);
47664
47665/**
47666 * GFM Block Grammar
47667 */
47668
47669block.gfm = merge({}, block.normal, {
47670  fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,
47671  paragraph: /^/,
47672  heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
47673});
47674
47675block.gfm.paragraph = edit(block.paragraph)
47676  .replace('(?!', '(?!'
47677    + block.gfm.fences.source.replace('\\1', '\\2') + '|'
47678    + block.list.source.replace('\\1', '\\3') + '|')
47679  .getRegex();
47680
47681/**
47682 * GFM + Tables Block Grammar
47683 */
47684
47685block.tables = merge({}, block.gfm, {
47686  nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
47687  table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
47688});
47689
47690/**
47691 * Block Lexer
47692 */
47693
47694function Lexer(options) {
47695  this.tokens = [];
47696  this.tokens.links = {};
47697  this.options = options || marked.defaults;
47698  this.rules = block.normal;
47699
47700  if (this.options.gfm) {
47701    if (this.options.tables) {
47702      this.rules = block.tables;
47703    } else {
47704      this.rules = block.gfm;
47705    }
47706  }
47707}
47708
47709/**
47710 * Expose Block Rules
47711 */
47712
47713Lexer.rules = block;
47714
47715/**
47716 * Static Lex Method
47717 */
47718
47719Lexer.lex = function(src, options) {
47720  var lexer = new Lexer(options);
47721  return lexer.lex(src);
47722};
47723
47724/**
47725 * Preprocessing
47726 */
47727
47728Lexer.prototype.lex = function(src) {
47729  src = src
47730    .replace(/\r\n|\r/g, '\n')
47731    .replace(/\t/g, '    ')
47732    .replace(/\u00a0/g, ' ')
47733    .replace(/\u2424/g, '\n');
47734
47735  return this.token(src, true);
47736};
47737
47738/**
47739 * Lexing
47740 */
47741
47742Lexer.prototype.token = function(src, top) {
47743  src = src.replace(/^ +$/gm, '');
47744  var next,
47745      loose,
47746      cap,
47747      bull,
47748      b,
47749      item,
47750      space,
47751      i,
47752      tag,
47753      l,
47754      isordered;
47755
47756  while (src) {
47757    // newline
47758    if (cap = this.rules.newline.exec(src)) {
47759      src = src.substring(cap[0].length);
47760      if (cap[0].length > 1) {
47761        this.tokens.push({
47762          type: 'space'
47763        });
47764      }
47765    }
47766
47767    // code
47768    if (cap = this.rules.code.exec(src)) {
47769      src = src.substring(cap[0].length);
47770      cap = cap[0].replace(/^ {4}/gm, '');
47771      this.tokens.push({
47772        type: 'code',
47773        text: !this.options.pedantic
47774          ? cap.replace(/\n+$/, '')
47775          : cap
47776      });
47777      continue;
47778    }
47779
47780    // fences (gfm)
47781    if (cap = this.rules.fences.exec(src)) {
47782      src = src.substring(cap[0].length);
47783      this.tokens.push({
47784        type: 'code',
47785        lang: cap[2],
47786        text: cap[3] || ''
47787      });
47788      continue;
47789    }
47790
47791    // heading
47792    if (cap = this.rules.heading.exec(src)) {
47793      src = src.substring(cap[0].length);
47794      this.tokens.push({
47795        type: 'heading',
47796        depth: cap[1].length,
47797        text: cap[2]
47798      });
47799      continue;
47800    }
47801
47802    // table no leading pipe (gfm)
47803    if (top && (cap = this.rules.nptable.exec(src))) {
47804      src = src.substring(cap[0].length);
47805
47806      item = {
47807        type: 'table',
47808        header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
47809        align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
47810        cells: cap[3].replace(/\n$/, '').split('\n')
47811      };
47812
47813      for (i = 0; i < item.align.length; i++) {
47814        if (/^ *-+: *$/.test(item.align[i])) {
47815          item.align[i] = 'right';
47816        } else if (/^ *:-+: *$/.test(item.align[i])) {
47817          item.align[i] = 'center';
47818        } else if (/^ *:-+ *$/.test(item.align[i])) {
47819          item.align[i] = 'left';
47820        } else {
47821          item.align[i] = null;
47822        }
47823      }
47824
47825      for (i = 0; i < item.cells.length; i++) {
47826        item.cells[i] = item.cells[i].split(/ *\| */);
47827      }
47828
47829      this.tokens.push(item);
47830
47831      continue;
47832    }
47833
47834    // hr
47835    if (cap = this.rules.hr.exec(src)) {
47836      src = src.substring(cap[0].length);
47837      this.tokens.push({
47838        type: 'hr'
47839      });
47840      continue;
47841    }
47842
47843    // blockquote
47844    if (cap = this.rules.blockquote.exec(src)) {
47845      src = src.substring(cap[0].length);
47846
47847      this.tokens.push({
47848        type: 'blockquote_start'
47849      });
47850
47851      cap = cap[0].replace(/^ *> ?/gm, '');
47852
47853      // Pass `top` to keep the current
47854      // "toplevel" state. This is exactly
47855      // how markdown.pl works.
47856      this.token(cap, top);
47857
47858      this.tokens.push({
47859        type: 'blockquote_end'
47860      });
47861
47862      continue;
47863    }
47864
47865    // list
47866    if (cap = this.rules.list.exec(src)) {
47867      src = src.substring(cap[0].length);
47868      bull = cap[2];
47869      isordered = bull.length > 1;
47870
47871      this.tokens.push({
47872        type: 'list_start',
47873        ordered: isordered,
47874        start: isordered ? +bull : ''
47875      });
47876
47877      // Get each top-level item.
47878      cap = cap[0].match(this.rules.item);
47879
47880      next = false;
47881      l = cap.length;
47882      i = 0;
47883
47884      for (; i < l; i++) {
47885        item = cap[i];
47886
47887        // Remove the list item's bullet
47888        // so it is seen as the next token.
47889        space = item.length;
47890        item = item.replace(/^ *([*+-]|\d+\.) +/, '');
47891
47892        // Outdent whatever the
47893        // list item contains. Hacky.
47894        if (~item.indexOf('\n ')) {
47895          space -= item.length;
47896          item = !this.options.pedantic
47897            ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
47898            : item.replace(/^ {1,4}/gm, '');
47899        }
47900
47901        // Determine whether the next list item belongs here.
47902        // Backpedal if it does not belong in this list.
47903        if (this.options.smartLists && i !== l - 1) {
47904          b = block.bullet.exec(cap[i + 1])[0];
47905          if (bull !== b && !(bull.length > 1 && b.length > 1)) {
47906            src = cap.slice(i + 1).join('\n') + src;
47907            i = l - 1;
47908          }
47909        }
47910
47911        // Determine whether item is loose or not.
47912        // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
47913        // for discount behavior.
47914        loose = next || /\n\n(?!\s*$)/.test(item);
47915        if (i !== l - 1) {
47916          next = item.charAt(item.length - 1) === '\n';
47917          if (!loose) loose = next;
47918        }
47919
47920        this.tokens.push({
47921          type: loose
47922            ? 'loose_item_start'
47923            : 'list_item_start'
47924        });
47925
47926        // Recurse.
47927        this.token(item, false);
47928
47929        this.tokens.push({
47930          type: 'list_item_end'
47931        });
47932      }
47933
47934      this.tokens.push({
47935        type: 'list_end'
47936      });
47937
47938      continue;
47939    }
47940
47941    // html
47942    if (cap = this.rules.html.exec(src)) {
47943      src = src.substring(cap[0].length);
47944      this.tokens.push({
47945        type: this.options.sanitize
47946          ? 'paragraph'
47947          : 'html',
47948        pre: !this.options.sanitizer
47949          && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
47950        text: cap[0]
47951      });
47952      continue;
47953    }
47954
47955    // def
47956    if (top && (cap = this.rules.def.exec(src))) {
47957      src = src.substring(cap[0].length);
47958      if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
47959      tag = cap[1].toLowerCase();
47960      if (!this.tokens.links[tag]) {
47961        this.tokens.links[tag] = {
47962          href: cap[2],
47963          title: cap[3]
47964        };
47965      }
47966      continue;
47967    }
47968
47969    // table (gfm)
47970    if (top && (cap = this.rules.table.exec(src))) {
47971      src = src.substring(cap[0].length);
47972
47973      item = {
47974        type: 'table',
47975        header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
47976        align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
47977        cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
47978      };
47979
47980      for (i = 0; i < item.align.length; i++) {
47981        if (/^ *-+: *$/.test(item.align[i])) {
47982          item.align[i] = 'right';
47983        } else if (/^ *:-+: *$/.test(item.align[i])) {
47984          item.align[i] = 'center';
47985        } else if (/^ *:-+ *$/.test(item.align[i])) {
47986          item.align[i] = 'left';
47987        } else {
47988          item.align[i] = null;
47989        }
47990      }
47991
47992      for (i = 0; i < item.cells.length; i++) {
47993        item.cells[i] = item.cells[i]
47994          .replace(/^ *\| *| *\| *$/g, '')
47995          .split(/ *\| */);
47996      }
47997
47998      this.tokens.push(item);
47999
48000      continue;
48001    }
48002
48003    // lheading
48004    if (cap = this.rules.lheading.exec(src)) {
48005      src = src.substring(cap[0].length);
48006      this.tokens.push({
48007        type: 'heading',
48008        depth: cap[2] === '=' ? 1 : 2,
48009        text: cap[1]
48010      });
48011      continue;
48012    }
48013
48014    // top-level paragraph
48015    if (top && (cap = this.rules.paragraph.exec(src))) {
48016      src = src.substring(cap[0].length);
48017      this.tokens.push({
48018        type: 'paragraph',
48019        text: cap[1].charAt(cap[1].length - 1) === '\n'
48020          ? cap[1].slice(0, -1)
48021          : cap[1]
48022      });
48023      continue;
48024    }
48025
48026    // text
48027    if (cap = this.rules.text.exec(src)) {
48028      // Top-level should never reach here.
48029      src = src.substring(cap[0].length);
48030      this.tokens.push({
48031        type: 'text',
48032        text: cap[0]
48033      });
48034      continue;
48035    }
48036
48037    if (src) {
48038      throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
48039    }
48040  }
48041
48042  return this.tokens;
48043};
48044
48045/**
48046 * Inline-Level Grammar
48047 */
48048
48049var inline = {
48050  escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
48051  autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
48052  url: noop,
48053  tag: /^<!--[\s\S]*?-->|^<\/?[a-zA-Z0-9\-]+(?:"[^"]*"|'[^']*'|\s[^<'">\/\s]*)*?\/?>/,
48054  link: /^!?\[(inside)\]\(href\)/,
48055  reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
48056  nolink: /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\]/,
48057  strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
48058  em: /^_([^\s_](?:[^_]|__)+?[^\s_])_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)/,
48059  code: /^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,
48060  br: /^ {2,}\n(?!\s*$)/,
48061  del: noop,
48062  text: /^[\s\S]+?(?=[\\<!\[`*]|\b_| {2,}\n|$)/
48063};
48064
48065inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
48066inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
48067
48068inline.autolink = edit(inline.autolink)
48069  .replace('scheme', inline._scheme)
48070  .replace('email', inline._email)
48071  .getRegex()
48072
48073inline._inside = /(?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]]|\](?=[^\[]*\]))*/;
48074inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
48075
48076inline.link = edit(inline.link)
48077  .replace('inside', inline._inside)
48078  .replace('href', inline._href)
48079  .getRegex();
48080
48081inline.reflink = edit(inline.reflink)
48082  .replace('inside', inline._inside)
48083  .getRegex();
48084
48085/**
48086 * Normal Inline Grammar
48087 */
48088
48089inline.normal = merge({}, inline);
48090
48091/**
48092 * Pedantic Inline Grammar
48093 */
48094
48095inline.pedantic = merge({}, inline.normal, {
48096  strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
48097  em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
48098});
48099
48100/**
48101 * GFM Inline Grammar
48102 */
48103
48104inline.gfm = merge({}, inline.normal, {
48105  escape: edit(inline.escape).replace('])', '~|])').getRegex(),
48106  url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/)
48107    .replace('email', inline._email)
48108    .getRegex(),
48109  _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
48110  del: /^~~(?=\S)([\s\S]*?\S)~~/,
48111  text: edit(inline.text)
48112    .replace(']|', '~]|')
48113    .replace('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|')
48114    .getRegex()
48115});
48116
48117/**
48118 * GFM + Line Breaks Inline Grammar
48119 */
48120
48121inline.breaks = merge({}, inline.gfm, {
48122  br: edit(inline.br).replace('{2,}', '*').getRegex(),
48123  text: edit(inline.gfm.text).replace('{2,}', '*').getRegex()
48124});
48125
48126/**
48127 * Inline Lexer & Compiler
48128 */
48129
48130function InlineLexer(links, options) {
48131  this.options = options || marked.defaults;
48132  this.links = links;
48133  this.rules = inline.normal;
48134  this.renderer = this.options.renderer || new Renderer();
48135  this.renderer.options = this.options;
48136
48137  if (!this.links) {
48138    throw new Error('Tokens array requires a `links` property.');
48139  }
48140
48141  if (this.options.gfm) {
48142    if (this.options.breaks) {
48143      this.rules = inline.breaks;
48144    } else {
48145      this.rules = inline.gfm;
48146    }
48147  } else if (this.options.pedantic) {
48148    this.rules = inline.pedantic;
48149  }
48150}
48151
48152/**
48153 * Expose Inline Rules
48154 */
48155
48156InlineLexer.rules = inline;
48157
48158/**
48159 * Static Lexing/Compiling Method
48160 */
48161
48162InlineLexer.output = function(src, links, options) {
48163  var inline = new InlineLexer(links, options);
48164  return inline.output(src);
48165};
48166
48167/**
48168 * Lexing/Compiling
48169 */
48170
48171InlineLexer.prototype.output = function(src) {
48172  var out = '',
48173      link,
48174      text,
48175      href,
48176      cap;
48177
48178  while (src) {
48179    // escape
48180    if (cap = this.rules.escape.exec(src)) {
48181      src = src.substring(cap[0].length);
48182      out += cap[1];
48183      continue;
48184    }
48185
48186    // autolink
48187    if (cap = this.rules.autolink.exec(src)) {
48188      src = src.substring(cap[0].length);
48189      if (cap[2] === '@') {
48190        text = escape(this.mangle(cap[1]));
48191        href = 'mailto:' + text;
48192      } else {
48193        text = escape(cap[1]);
48194        href = text;
48195      }
48196      out += this.renderer.link(href, null, text);
48197      continue;
48198    }
48199
48200    // url (gfm)
48201    if (!this.inLink && (cap = this.rules.url.exec(src))) {
48202      cap[0] = this.rules._backpedal.exec(cap[0])[0];
48203      src = src.substring(cap[0].length);
48204      if (cap[2] === '@') {
48205        text = escape(cap[0]);
48206        href = 'mailto:' + text;
48207      } else {
48208        text = escape(cap[0]);
48209        if (cap[1] === 'www.') {
48210          href = 'http://' + text;
48211        } else {
48212          href = text;
48213        }
48214      }
48215      out += this.renderer.link(href, null, text);
48216      continue;
48217    }
48218
48219    // tag
48220    if (cap = this.rules.tag.exec(src)) {
48221      if (!this.inLink && /^<a /i.test(cap[0])) {
48222        this.inLink = true;
48223      } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
48224        this.inLink = false;
48225      }
48226      src = src.substring(cap[0].length);
48227      out += this.options.sanitize
48228        ? this.options.sanitizer
48229          ? this.options.sanitizer(cap[0])
48230          : escape(cap[0])
48231        : cap[0]
48232      continue;
48233    }
48234
48235    // link
48236    if (cap = this.rules.link.exec(src)) {
48237      src = src.substring(cap[0].length);
48238      this.inLink = true;
48239      out += this.outputLink(cap, {
48240        href: cap[2],
48241        title: cap[3]
48242      });
48243      this.inLink = false;
48244      continue;
48245    }
48246
48247    // reflink, nolink
48248    if ((cap = this.rules.reflink.exec(src))
48249        || (cap = this.rules.nolink.exec(src))) {
48250      src = src.substring(cap[0].length);
48251      link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
48252      link = this.links[link.toLowerCase()];
48253      if (!link || !link.href) {
48254        out += cap[0].charAt(0);
48255        src = cap[0].substring(1) + src;
48256        continue;
48257      }
48258      this.inLink = true;
48259      out += this.outputLink(cap, link);
48260      this.inLink = false;
48261      continue;
48262    }
48263
48264    // strong
48265    if (cap = this.rules.strong.exec(src)) {
48266      src = src.substring(cap[0].length);
48267      out += this.renderer.strong(this.output(cap[2] || cap[1]));
48268      continue;
48269    }
48270
48271    // em
48272    if (cap = this.rules.em.exec(src)) {
48273      src = src.substring(cap[0].length);
48274      out += this.renderer.em(this.output(cap[2] || cap[1]));
48275      continue;
48276    }
48277
48278    // code
48279    if (cap = this.rules.code.exec(src)) {
48280      src = src.substring(cap[0].length);
48281      out += this.renderer.codespan(escape(cap[2].trim(), true));
48282      continue;
48283    }
48284
48285    // br
48286    if (cap = this.rules.br.exec(src)) {
48287      src = src.substring(cap[0].length);
48288      out += this.renderer.br();
48289      continue;
48290    }
48291
48292    // del (gfm)
48293    if (cap = this.rules.del.exec(src)) {
48294      src = src.substring(cap[0].length);
48295      out += this.renderer.del(this.output(cap[1]));
48296      continue;
48297    }
48298
48299    // text
48300    if (cap = this.rules.text.exec(src)) {
48301      src = src.substring(cap[0].length);
48302      out += this.renderer.text(escape(this.smartypants(cap[0])));
48303      continue;
48304    }
48305
48306    if (src) {
48307      throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
48308    }
48309  }
48310
48311  return out;
48312};
48313
48314/**
48315 * Compile Link
48316 */
48317
48318InlineLexer.prototype.outputLink = function(cap, link) {
48319  var href = escape(link.href),
48320      title = link.title ? escape(link.title) : null;
48321
48322  return cap[0].charAt(0) !== '!'
48323    ? this.renderer.link(href, title, this.output(cap[1]))
48324    : this.renderer.image(href, title, escape(cap[1]));
48325};
48326
48327/**
48328 * Smartypants Transformations
48329 */
48330
48331InlineLexer.prototype.smartypants = function(text) {
48332  if (!this.options.smartypants) return text;
48333  return text
48334    // em-dashes
48335    .replace(/---/g, '\u2014')
48336    // en-dashes
48337    .replace(/--/g, '\u2013')
48338    // opening singles
48339    .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
48340    // closing singles & apostrophes
48341    .replace(/'/g, '\u2019')
48342    // opening doubles
48343    .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
48344    // closing doubles
48345    .replace(/"/g, '\u201d')
48346    // ellipses
48347    .replace(/\.{3}/g, '\u2026');
48348};
48349
48350/**
48351 * Mangle Links
48352 */
48353
48354InlineLexer.prototype.mangle = function(text) {
48355  if (!this.options.mangle) return text;
48356  var out = '',
48357      l = text.length,
48358      i = 0,
48359      ch;
48360
48361  for (; i < l; i++) {
48362    ch = text.charCodeAt(i);
48363    if (Math.random() > 0.5) {
48364      ch = 'x' + ch.toString(16);
48365    }
48366    out += '&#' + ch + ';';
48367  }
48368
48369  return out;
48370};
48371
48372/**
48373 * Renderer
48374 */
48375
48376function Renderer(options) {
48377  this.options = options || {};
48378}
48379
48380Renderer.prototype.code = function(code, lang, escaped) {
48381  if (this.options.highlight) {
48382    var out = this.options.highlight(code, lang);
48383    if (out != null && out !== code) {
48384      escaped = true;
48385      code = out;
48386    }
48387  }
48388
48389  if (!lang) {
48390    return '<pre><code>'
48391      + (escaped ? code : escape(code, true))
48392      + '\n</code></pre>';
48393  }
48394
48395  return '<pre><code class="'
48396    + this.options.langPrefix
48397    + escape(lang, true)
48398    + '">'
48399    + (escaped ? code : escape(code, true))
48400    + '\n</code></pre>\n';
48401};
48402
48403Renderer.prototype.blockquote = function(quote) {
48404  return '<blockquote>\n' + quote + '</blockquote>\n';
48405};
48406
48407Renderer.prototype.html = function(html) {
48408  return html;
48409};
48410
48411Renderer.prototype.heading = function(text, level, raw) {
48412  return '<h'
48413    + level
48414    + ' id="'
48415    + this.options.headerPrefix
48416    + raw.toLowerCase().replace(/[^\w]+/g, '-')
48417    + '">'
48418    + text
48419    + '</h'
48420    + level
48421    + '>\n';
48422};
48423
48424Renderer.prototype.hr = function() {
48425  return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
48426};
48427
48428Renderer.prototype.list = function(body, ordered, start) {
48429  var type = ordered ? 'ol' : 'ul',
48430      startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
48431  return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
48432};
48433
48434Renderer.prototype.listitem = function(text) {
48435  return '<li>
48435' + text + '</li>\n';
48436};
48437
48438Renderer.prototype.paragraph = function(text) {
48439  return '<p>' + text + '</p>\n';
48440};
48441
48442Renderer.prototype.table = function(header, body) {
48443  return '<table>\n'
48444    + '<thead>\n'
48445    + header
48446    + '</thead>\n'
48447    + '<tbody>\n'
48448    + body
48449    + '</tbody>\n'
48450    + '</table>\n';
48451};
48452
48453Renderer.prototype.tablerow = function(content) {
48454  return '<tr>\n' + content + '</tr>\n';
48455};
48456
48457Renderer.prototype.tablecell = function(content, flags) {
48458  var type = flags.header ? 'th' : 'td';
48459  var tag = flags.align
48460    ? '<' + type + ' style="text-align:' + flags.align + '">'
48461    : '<' + type + '>';
48462  return tag + content + '</' + type + '>\n';
48463};
48464
48465// span level renderer
48466Renderer.prototype.strong = function(text) {
48467  return '<strong>' + text + '</strong>';
48468};
48469
48470Renderer.prototype.em = function(text) {
48471  return '<em>' + text + '</em>';
48472};
48473
48474Renderer.prototype.codespan = function(text) {
48475  return '<code>' + text + '</code>';
48476};
48477
48478Renderer.prototype.br = function() {
48479  return this.options.xhtml ? '<br/>' : '<br>';
48480};
48481
48482Renderer.prototype.del = function(text) {
48483  return '<del>' + text + '</del>';
48484};
48485
48486Renderer.prototype.link = function(href, title, text) {
48487  if (this.options.sanitize) {
48488    try {
48489      var prot = decodeURIComponent(unescape(href))
48490        .replace(/[^\w:]/g, '')
48491        .toLowerCase();
48492    } catch (e) {
48493      return text;
48494    }
48495    if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
48496      return text;
48497    }
48498  }
48499  if (this.options.baseUrl && !originIndependentUrl.test(href)) {
48500    href = resolveUrl(this.options.baseUrl, href);
48501  }
48502  var out = '<a href="' + href + '"';
48503  if (title) {
48504    out += ' title="' + title + '"';
48505  }
48506  out += '>
48506' + text + '</a>';
48507  return out;
48508};
48509
48510Renderer.prototype.image = function(href, title, text) {
48511  if (this.options.baseUrl && !originIndependentUrl.test(href)) {
48512    href = resolveUrl(this.options.baseUrl, href);
48513  }
48514  var out = '<img src="' + href + '" alt="' + text + '"';
48515  if (title) {
48516    out += ' title="' + title + '"';
48517  }
48518  out += this.options.xhtml ? '/>' : '>';
48519  return out;
48520};
48521
48522Renderer.prototype.text = function(text) {
48523  return text;
48524};
48525
48526/**
48527 * TextRenderer
48528 * returns only the textual part of the token
48529 */
48530
48531function TextRenderer() {}
48532
48533// no need for block level renderers
48534
48535TextRenderer.prototype.strong =
48536TextRenderer.prototype.em =
48537TextRenderer.prototype.codespan =
48538TextRenderer.prototype.del =
48539TextRenderer.prototype.text = function (text) {
48540  return text;
48541}
48542
48543TextRenderer.prototype.link =
48544TextRenderer.prototype.image = function(href, title, text) {
48545  return '' + text;
48546}
48547
48548TextRenderer.prototype.br = function() {
48549  return '';
48550}
48551
48552/**
48553 * Parsing & Compiling
48554 */
48555
48556function Parser(options) {
48557  this.tokens = [];
48558  this.token = null;
48559  this.options = options || marked.defaults;
48560  this.options.renderer = this.options.renderer || new Renderer();
48561  this.renderer = this.options.renderer;
48562  this.renderer.options = this.options;
48563}
48564
48565/**
48566 * Static Parse Method
48567 */
48568
48569Parser.parse = function(src, options) {
48570  var parser = new Parser(options);
48571  return parser.parse(src);
48572};
48573
48574/**
48575 * Parse Loop
48576 */
48577
48578Parser.prototype.parse = function(src) {
48579  this.inline = new InlineLexer(src.links, this.options);
48580  // use an InlineLexer with a TextRenderer to extract pure text
48581  this.inlineText = new InlineLexer(
48582    src.links,
48583    merge({}, this.options, {renderer: new TextRenderer()})
48584  );
48585  this.tokens = src.reverse();
48586
48587  var out = '';
48588  while (this.next()) {
48589    out += this.tok();
48590  }
48591
48592  return out;
48593};
48594
48595/**
48596 * Next Token
48597 */
48598
48599Parser.prototype.next = function() {
48600  return this.token = this.tokens.pop();
48601};
48602
48603/**
48604 * Preview Next Token
48605 */
48606
48607Parser.prototype.peek = function() {
48608  return this.tokens[this.tokens.length - 1] || 0;
48609};
48610
48611/**
48612 * Parse Text Tokens
48613 */
48614
48615Parser.prototype.parseText = function() {
48616  var body = this.token.text;
48617
48618  while (this.peek().type === 'text') {
48619    body += '\n' + this.next().text;
48620  }
48621
48622  return this.inline.output(body);
48623};
48624
48625/**
48626 * Parse Current Token
48627 */
48628
48629Parser.prototype.tok = function() {
48630  switch (this.token.type) {
48631    case 'space': {
48632      return '';
48633    }
48634    case 'hr': {
48635      return this.renderer.hr();
48636    }
48637    case 'heading': {
48638      return this.renderer.heading(
48639        this.inline.output(this.token.text),
48640        this.token.depth,
48641        unescape(this.inlineText.output(this.token.text)));
48642    }
48643    case 'code': {
48644      return this.renderer.code(this.token.text,
48645        this.token.lang,
48646        this.token.escaped);
48647    }
48648    case 'table': {
48649      var header = '',
48650          body = '',
48651          i,
48652          row,
48653          cell,
48654          j;
48655
48656      // header
48657      cell = '';
48658      for (i = 0; i < this.token.header.length; i++) {
48659        cell += this.renderer.tablecell(
48660          this.inline.output(this.token.header[i]),
48661          { header: true, align: this.token.align[i] }
48662        );
48663      }
48664      header += this.renderer.tablerow(cell);
48665
48666      for (i = 0; i < this.token.cells.length; i++) {
48667        row = this.token.cells[i];
48668
48669        cell = '';
48670        for (j = 0; j < row.length; j++) {
48671          cell += this.renderer.tablecell(
48672            this.inline.output(row[j]),
48673            { header: false, align: this.token.align[j] }
48674          );
48675        }
48676
48677        body += this.renderer.tablerow(cell);
48678      }
48679      return this.renderer.table(header, body);
48680    }
48681    case 'blockquote_start': {
48682      body = '';
48683
48684      while (this.next().type !== 'blockquote_end') {
48685        body += this.tok();
48686      }
48687
48688      return this.renderer.blockquote(body);
48689    }
48690    case 'list_start': {
48691      body = '';
48692      var ordered = this.token.ordered,
48693          start = this.token.start;
48694
48695      while (this.next().type !== 'list_end') {
48696        body += this.tok();
48697      }
48698
48699      return this.renderer.list(body, ordered, start);
48700    }
48701    case 'list_item_start': {
48702      body = '';
48703
48704      while (this.next().type !== 'list_item_end') {
48705        body += this.token.type === 'text'
48706          ? this.parseText()
48707          : this.tok();
48708      }
48709
48710      return this.renderer.listitem(body);
48711    }
48712    case 'loose_item_start': {
48713      body = '';
48714
48715      while (this.next().type !== 'list_item_end') {
48716        body += this.tok();
48717      }
48718
48719      return this.renderer.listitem(body);
48720    }
48721    case 'html': {
48722      var html = !this.token.pre && !this.options.pedantic
48723        ? this.inline.output(this.token.text)
48724        : this.token.text;
48725      return this.renderer.html(html);
48726    }
48727    case 'paragraph': {
48728      return this.renderer.paragraph(this.inline.output(this.token.text));
48729    }
48730    case 'text': {
48731      return this.renderer.paragraph(this.parseText());
48732    }
48733  }
48734};
48735
48736/**
48737 * Helpers
48738 */
48739
48740function escape(html, encode) {
48741  return html
48742    .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
48743    .replace(/</g, '&lt;')
48744    .replace(/>/g, '&gt;')
48745    .replace(/"/g, '&quot;')
48746    .replace(/'/g, '&#39;');
48747}
48748
48749function unescape(html) {
48750  // explicitly match decimal, hex, and named HTML entities
48751  return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) {
48752    n = n.toLowerCase();
48753    if (n === 'colon') return ':';
48754    if (n.charAt(0) === '#') {
48755      return n.charAt(1) === 'x'
48756        ? String.fromCharCode(parseInt(n.substring(2), 16))
48757        : String.fromCharCode(+n.substring(1));
48758    }
48759    return '';
48760  });
48761}
48762
48763function edit(regex, opt) {
48764  regex = regex.source;
48765  opt = opt || '';
48766  return {
48767    replace: function(name, val) {
48768      val = val.source || val;
48769      val = val.replace(/(^|[^\[])\^/g, '$1');
48770      regex = regex.replace(name, val);
48771      return this;
48772    },
48773    getRegex: function() {
48774      return new RegExp(regex, opt);
48775    }
48776  };
48777}
48778
48779function resolveUrl(base, href) {
48780  if (!baseUrls[' ' + base]) {
48781    // we can ignore everything in base after the last slash of its path component,
48782    // but we might need to add _that_
48783    // https://tools.ietf.org/html/rfc3986#section-3
48784    if (/^[^:]+:\/*[^/]*$/.test(base)) {
48785      baseUrls[' ' + base] = base + '/';
48786    } else {
48787      baseUrls[' ' + base] = base.replace(/[^/]*$/, '');
48788    }
48789  }
48790  base = baseUrls[' ' + base];
48791
48792  if (href.slice(0, 2) === '//') {
48793    return base.replace(/:[\s\S]*/, ':') + href;
48794  } else if (href.charAt(0) === '/') {
48795    return base.replace(/(:\/*[^/]*)[\s\S]*/, '$1') + href;
48796  } else {
48797    return base + href;
48798  }
48799}
48800var baseUrls = {};
48801var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
48802
48803function noop() {}
48804noop.exec = noop;
48805
48806function merge(obj) {
48807  var i = 1,
48808      target,
48809      key;
48810
48811  for (; i < arguments.length; i++) {
48812    target = arguments[i];
48813    for (key in target) {
48814      if (Object.prototype.hasOwnProperty.call(target, key)) {
48815        obj[key] = target[key];
48816      }
48817    }
48818  }
48819
48820  return obj;
48821}
48822
48823/**
48824 * Marked
48825 */
48826
48827function marked(src, opt, callback) {
48828  // throw error in case of non string input
48829  if (typeof src === 'undefined' || src === null) {
48830    throw new Error('marked(): input parameter is undefined or null');
48831  }
48832  if (typeof src !== 'string') {
48833    throw new Error('marked(): input parameter is of type '
48834      + Object.prototype.toString.call(src) + ', string expected');
48835  }
48836
48837  if (callback || typeof opt === 'function') {
48838    if (!callback) {
48839      callback = opt;
48840      opt = null;
48841    }
48842
48843    opt = merge({}, marked.defaults, opt || {});
48844
48845    var highlight = opt.highlight,
48846        tokens,
48847        pending,
48848        i = 0;
48849
48850    try {
48851      tokens = Lexer.lex(src, opt)
48852    } catch (e) {
48853      return callback(e);
48854    }
48855
48856    pending = tokens.length;
48857
48858    var done = function(err) {
48859      if (err) {
48860        opt.highlight = highlight;
48861        return callback(err);
48862      }
48863
48864      var out;
48865
48866      try {
48867        out = Parser.parse(tokens, opt);
48868      } catch (e) {
48869        err = e;
48870      }
48871
48872      opt.highlight = highlight;
48873
48874      return err
48875        ? callback(err)
48876        : callback(null, out);
48877    };
48878
48879    if (!highlight || highlight.length < 3) {
48880      return done();
48881    }
48882
48883    delete opt.highlight;
48884
48885    if (!pending) return done();
48886
48887    for (; i < tokens.length; i++) {
48888      (function(token) {
48889        if (token.type !== 'code') {
48890          return --pending || done();
48891        }
48892        return highlight(token.text, token.lang, function(err, code) {
48893          if (err) return done(err);
48894          if (code == null || code === token.text) {
48895            return --pending || done();
48896          }
48897          token.text = code;
48898          token.escaped = true;
48899          --pending || done();
48900        });
48901      })(tokens[i]);
48902    }
48903
48904    return;
48905  }
48906  try {
48907    if (opt) opt = merge({}, marked.defaults, opt);
48908    return Parser.parse(Lexer.lex(src, opt), opt);
48909  } catch (e) {
48910    e.message += '\nPlease report this to https://github.com/markedjs/marked.';
48911    if ((opt || marked.defaults).silent) {
48912      return '<p>An error occurred:</p><pre>'
48913        + escape(e.message + '', true)
48914        + '</pre>';
48915    }
48916    throw e;
48917  }
48918}
48919
48920/**
48921 * Options
48922 */
48923
48924marked.options =
48925marked.setOptions = function(opt) {
48926  merge(marked.defaults, opt);
48927  return marked;
48928};
48929
48930marked.defaults = {
48931  gfm: true,
48932  tables: true,
48933  breaks: false,
48934  pedantic: false,
48935  sanitize: false,
48936  sanitizer: null,
48937  mangle: true,
48938  smartLists: false,
48939  silent: false,
48940  highlight: null,
48941  langPrefix: 'lang-',
48942  smartypants: false,
48943  headerPrefix: '',
48944  renderer: new Renderer(),
48945  xhtml: false,
48946  baseUrl: null
48947};
48948
48949/**
48950 * Expose
48951 */
48952
48953marked.Parser = Parser;
48954marked.parser = Parser.parse;
48955
48956marked.Renderer = Renderer;
48957marked.TextRenderer = TextRenderer;
48958
48959marked.Lexer = Lexer;
48960marked.lexer = Lexer.lex;
48961
48962marked.InlineLexer = InlineLexer;
48963marked.inlineLexer = InlineLexer.output;
48964
48965marked.parse = marked;
48966
48967if (typeof module !== 'undefined' && typeof exports === 'object') {
48968  module.exports = marked;
48969} else if (typeof define === 'function' && define.amd) {
48970  define(function() { return marked; });
48971} else {
48972  root.marked = marked;
48973}
48974})(this || (typeof window !== 'undefined' ? window : global));
48975
48976}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
48977},{}],12:[function(require,module,exports){
48978/**
48979 * UI-Router Extras: Sticky states, Future States, Deep State Redirect, Transition promise
48980 * Monolithic build (all modules)
48981 * @version 0.1.3
48982 * @link http://christopherthielen.github.io/ui-router-extras/
48983 * @license MIT License, http://www.opensource.org/licenses/MIT
48984 */
48985(function (root, factory) {
48986    'use strict';
48987
48988    if (typeof define === 'function' && define.amd) {
48989        define(['angular'], function (angular) {
48990            factory(angular);
48991        });
48992    } else if (typeof exports === 'object') {
48993        factory(require('angular'));
48994    } else {
48995        factory(root.angular);
48996    }
48997}(this, function (angular, undefined) {
48998    var mod_core = angular.module("ct.ui.router.extras.core", [ "ui.router" ]);
48999
49000var internalStates = {}, stateRegisteredCallbacks = [];
49001mod_core.config([ '$stateProvider', '$injector', function ($stateProvider, $injector) {
49002  // Decorate any state attribute in order to get access to the internal state representation.
49003  $stateProvider.decorator('parent', function (state, parentFn) {
49004    // Capture each internal UI-Router state representations as opposed to the user-defined state object.
49005    // The internal state is, e.g., the state returned by $state.$current as opposed to $state.current
49006    internalStates[state.self.name] = state;
49007    // Add an accessor for the internal state from the user defined state
49008    state.self.$$state = function () {
49009      return internalStates[state.self.name];
49010    };
49011
49012    angular.forEach(stateRegisteredCallbacks, function(callback) { callback(state); });
49013    return parentFn(state);
49014  });
49015}]);
49016
49017var DEBUG = false;
49018
49019var forEach = angular.forEach;
49020var extend = angular.extend;
49021var isArray = angular.isArray;
49022
49023var map = function (collection, callback) {
49024  "use strict";
49025  var result = [];
49026  forEach(collection, function (item, index) {
49027    result.push(callback(item, index));
49028  });
49029  return result;
49030};
49031
49032var keys = function (collection) {
49033  "use strict";
49034  return map(collection, function (collection, key) {
49035    return key;
49036  });
49037};
49038
49039var filter = function (collection, callback) {
49040  "use strict";
49041  var result = [];
49042  forEach(collection, function (item, index) {
49043    if (callback(item, index)) {
49044      result.push(item);
49045    }
49046  });
49047  return result;
49048};
49049
49050var filterObj = function (collection, callback) {
49051  "use strict";
49052  var result = {};
49053  forEach(collection, function (item, index) {
49054    if (callback(item, index)) {
49055      result[index] = item;
49056    }
49057  });
49058  return result;
49059};
49060
49061// Duplicates code in UI-Router common.js
49062function ancestors(first, second) {
49063  var path = [];
49064
49065  for (var n in first.path) {
49066    if (first.path[n] !== second.path[n]) break;
49067    path.push(first.path[n]);
49068  }
49069  return path;
49070}
49071
49072// Duplicates code in UI-Router common.js
49073function objectKeys(object) {
49074  if (Object.keys) {
49075    return Object.keys(object);
49076  }
49077  var result = [];
49078
49079  angular.forEach(object, function (val, key) {
49080    result.push(key);
49081  });
49082  return result;
49083}
49084
49085/**
49086 * like objectKeys, but includes keys from prototype chain.
49087 * @param object the object whose prototypal keys will be returned
49088 * @param ignoreKeys an array of keys to ignore
49089 */
49090// Duplicates code in UI-Router common.js
49091function protoKeys(object, ignoreKeys) {
49092  var result = [];
49093  for (var key in object) {
49094    if (!ignoreKeys || ignoreKeys.indexOf(key) === -1)
49095      result.push(key);
49096  }
49097  return result;
49098}
49099
49100// Duplicates code in UI-Router common.js
49101function arraySearch(array, value) {
49102  if (Array.prototype.indexOf) {
49103    return array.indexOf(value, Number(arguments[2]) || 0);
49104  }
49105  var len = array.length >>> 0, from = Number(arguments[2]) || 0;
49106  from = (from < 0) ? Math.ceil(from) : Math.floor(from);
49107
49108  if (from < 0) from += len;
49109
49110  for (; from < len; from++) {
49111    if (from in array && array[from] === value) return from;
49112  }
49113  return -1;
49114}
49115
49116// Duplicates code in UI-Router common.js
49117// Added compatibility code  (isArray check) to support both 0.2.x and 0.3.x series of UI-Router.
49118function inheritParams(currentParams, newParams, $current, $to) {
49119  var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
49120
49121  for (var i in parents) {
49122    if (!parents[i].params) continue;
49123    // This test allows compatibility with 0.2.x and 0.3.x (optional and object params)
49124    parentParams = isArray(parents[i].params) ? parents[i].params : objectKeys(parents[i].params);
49125    if (!parentParams.length) continue;
49126
49127    for (var j in parentParams) {
49128      if (arraySearch(inheritList, parentParams[j]) >= 0) continue;
49129      inheritList.push(parentParams[j]);
49130      inherited[parentParams[j]] = currentParams[parentParams[j]];
49131    }
49132  }
49133  return extend({}, inherited, newParams);
49134}
49135
49136function inherit(parent, extra) {
49137  return extend(new (extend(function () { }, {prototype: parent}))(), extra);
49138}
49139
49140function onStateRegistered(callback) { stateRegisteredCallbacks.push(callback); }
49141
49142mod_core.provider("uirextras_core", function() {
49143  var core = {
49144    internalStates: internalStates,
49145    onStateRegistered: onStateRegistered,
49146    forEach: forEach,
49147    extend: extend,
49148    isArray: isArray,
49149    map: map,
49150    keys: keys,
49151    filter: filter,
49152    filterObj: filterObj,
49153    ancestors: ancestors,
49154    objectKeys: objectKeys,
49155    protoKeys: protoKeys,
49156    arraySearch: arraySearch,
49157    inheritParams: inheritParams,
49158    inherit: inherit
49159  };
49160
49161  angular.extend(this, core);
49162
49163  this.$get = function() {
49164    return core;
49165  };
49166});
49167
49168
49169var ignoreDsr;
49170function resetIgnoreDsr() {
49171  ignoreDsr = undefined;
49172}
49173
49174// Decorate $state.transitionTo to gain access to the last transition.options variable.
49175// This is used to process the options.ignoreDsr option
49176angular.module('ct.ui.router.extras.dsr', [ 'ct.ui.router.extras.core' ]).config([ "$provide", function ($provide) {
49177  var $state_transitionTo;
49178  $provide.decorator("$state", ['$delegate', '$q', function ($state, $q) {
49179    $state_transitionTo = $state.transitionTo;
49180    $state.transitionTo = function (to, toParams, options) {
49181      if (options && options.ignoreDsr) {
49182        ignoreDsr = options.ignoreDsr;
49183      }
49184
49185      return $state_transitionTo.apply($state, arguments).then(
49186        function (result) {
49187          resetIgnoreDsr();
49188          return result;
49189        },
49190        function (err) {
49191          resetIgnoreDsr();
49192          return $q.reject(err);
49193        }
49194      );
49195    };
49196    return $state;
49197  }]);
49198}]);
49199
49200angular.module('ct.ui.router.extras.dsr').service("$deepStateRedirect", [ '$rootScope', '$state', '$injector', function ($rootScope, $state, $injector) {
49201  var lastSubstate = {};
49202  var deepStateRedirectsByName = {};
49203
49204  var REDIRECT = "Redirect", ANCESTOR_REDIRECT = "AncestorRedirect";
49205
49206  function computeDeepStateStatus(state) {
49207    var name = state.name;
49208    if (deepStateRedirectsByName.hasOwnProperty(name))
49209      return deepStateRedirectsByName[name];
49210    recordDeepStateRedirectStatus(name);
49211  }
49212
49213  function getConfig(state) {
49214    var declaration = state.deepStateRedirect || state.dsr;
49215    if (!declaration) return { dsr: false };
49216    var dsrCfg = { dsr: true };
49217
49218    if (angular.isFunction(declaration)) {
49219      dsrCfg.fn = declaration;
49220    } else if (angular.isObject(declaration)) {
49221      dsrCfg = angular.extend(dsrCfg, declaration);
49222    }
49223
49224    if (angular.isString(dsrCfg['default'])) {
49225      dsrCfg['default'] = { state: dsrCfg['default'] };
49226    }
49227
49228    if (!dsrCfg.fn) {
49229      dsrCfg.fn = [ '$dsr$', function($dsr$) {
49230        return $dsr$.redirect.state != $dsr$.to.state;
49231      } ];
49232    }
49233    return dsrCfg;
49234  }
49235
49236  function recordDeepStateRedirectStatus(stateName) {
49237    var state = $state.get(stateName);
49238    if (!state) return false;
49239    var cfg = getConfig(state);
49240    if (cfg.dsr) {
49241      deepStateRedirectsByName[state.name] = REDIRECT;
49242      if (lastSubstate[stateName] === undefined)
49243        lastSubstate[stateName] = {};
49244    }
49245
49246    var parent = state.$$state && state.$$state().parent;
49247    if (parent) {
49248      var parentStatus = recordDeepStateRedirectStatus(parent.self.name);
49249      if (parentStatus && deepStateRedirectsByName[state.name] === undefined) {
49250        deepStateRedirectsByName[state.name] = ANCESTOR_REDIRECT;
49251      }
49252    }
49253    return deepStateRedirectsByName[state.name] || false;
49254  }
49255
49256  function getMatchParams(params, dsrParams) {
49257    if (dsrParams === true) dsrParams = Object.keys(params);
49258    if (dsrParams === null || dsrParams === undefined) dsrParams = [];
49259
49260    var matchParams = {};
49261    angular.forEach(dsrParams.sort(), function(name) { matchParams[name] = params[name]; });
49262    return matchParams;
49263  }
49264
49265  function getParamsString(params, dsrParams) {
49266    var matchParams = getMatchParams(params, dsrParams);
49267    function safeString(input) { return !input ? input : input.toString(); }
49268    var paramsToString = {};
49269    angular.forEach(matchParams, function(val, name) { paramsToString[name] = safeString(val); });
49270    return angular.toJson(paramsToString);
49271  }
49272
49273  $rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
49274    var cfg = getConfig(toState);
49275    if (ignoreDsr || (computeDeepStateStatus(toState) !== REDIRECT) && !cfg['default']) return;
49276    // We're changing directly to one of the redirect (tab) states.
49277    // Get the DSR key for this state by calculating the DSRParams option
49278    var key = getParamsString(toParams, cfg.params);
49279    var redirect = lastSubstate[toState.name][key] || cfg['default'];
49280    if (!redirect) return;
49281
49282    // we have a last substate recorded
49283    var $dsr$ = { redirect: { state: redirect.state, params: redirect.params}, to: { state: toState.name, params: toParams } };
49284    var result = $injector.invoke(cfg.fn, toState, { $dsr$: $dsr$ });
49285    if (!result) return;
49286    if (result.state) redirect = result;
49287    event.preventDefault();
49288    var redirectParams = getMatchParams(toParams, cfg.params);
49289    $state.go(redirect.state, angular.extend(redirectParams, redirect.params));
49290  });
49291
49292  $rootScope.$on("$stateChangeSuccess", function (event, toState, toParams, fromState, fromParams) {
49293    var deepStateStatus = computeDeepStateStatus(toState);
49294    if (deepStateStatus) {
49295      var name = toState.name;
49296      angular.forEach(lastSubstate, function (redirect, dsrState) {
49297        // update Last-SubState&params for each DSR that this transition matches.
49298        var cfg = getConfig($state.get(dsrState));
49299        var key = getParamsString(toParams, cfg.params);
49300        if (toState.$$state().includes[dsrState]) {
49301          lastSubstate[dsrState][key] = { state: name, params: angular.copy(toParams) };
49302        }
49303      });
49304    }
49305  });
49306
49307  return {
49308    getRedirect: function(dsrState, params) {
49309      var state = $state.get(dsrState);
49310      computeDeepStateStatus(state)
49311      var cfg = getConfig(state);
49312      var key = getParamsString(params, cfg.params);
49313      var redirect = lastSubstate[state.name];
49314      if (redirect && redirect[key]) {
49315        redirect = redirect[key];
49316      } else {
49317        redirect = cfg['default'];
49318      }
49319      return redirect;
49320    },
49321    reset: function(stateOrName, params) {
49322      if (!stateOrName) {
49323        angular.forEach(lastSubstate, function(redirect, dsrState) { lastSubstate[dsrState] = {}; });
49324      } else {
49325        var state = $state.get(stateOrName);
49326        if (!state) throw new Error("Unknown state: " + stateOrName);
49327        if (lastSubstate[state.name]) {
49328          if (params) {
49329            var key = getParamsString(params, getConfig(state).params);
49330            delete lastSubstate[state.name][key];
49331          } else {
49332            lastSubstate[state.name] = {};
49333          }
49334        }
49335      }
49336    }
49337  };
49338}]);
49339
49340angular.module('ct.ui.router.extras.dsr').run(['$deepStateRedirect', function ($deepStateRedirect) {
49341  // Make sure $deepStateRedirect is instantiated
49342}]);
49343
49344angular.module("ct.ui.router.extras.sticky", [ 'ct.ui.router.extras.core' ]);
49345
49346var mod_sticky = angular.module("ct.ui.router.extras.sticky");
49347
49348$StickyStateProvider.$inject = [ '$stateProvider', 'uirextras_coreProvider' ];
49349function $StickyStateProvider($stateProvider, uirextras_coreProvider) {
49350  var core = uirextras_coreProvider;
49351  var inheritParams = core.inheritParams;
49352  var objectKeys = core.objectKeys;
49353  var protoKeys = core.protoKeys;
49354  var forEach = core.forEach;
49355  var map = core.map;
49356
49357  // Holds all the states which are inactivated.  Inactivated states can be either sticky states, or descendants of sticky states.
49358  var inactiveStates = {}; // state.name -> (state)
49359  var stickyStates = {}; // state.name -> true
49360  var $state;
49361  var DEBUG = false;
49362
49363  // Called by $stateProvider.registerState();
49364  // registers a sticky state with $stickyStateProvider
49365  this.registerStickyState = function (state) {
49366    stickyStates[state.name] = state;
49367    // console.log("Registered sticky state: ", state);
49368  };
49369
49370  this.enableDebug = this.debugMode = function (enabled) {
49371    if (angular.isDefined(enabled))
49372      DEBUG = enabled;
49373    return DEBUG;
49374  };
49375
49376  this.$get = [  '$rootScope', '$state', '$stateParams', '$injector', '$log',
49377    function ($rootScope, $state, $stateParams, $injector, $log) {
49378      // Each inactive states is either a sticky state, or a child of a sticky state.
49379      // This function finds the closest ancestor sticky state, then find that state's parent.
49380      // Map all inactive states to their closest parent-to-sticky state.
49381      function mapInactives() {
49382        var mappedStates = {};
49383        angular.forEach(inactiveStates, function (state, name) {
49384          var stickyAncestors = getStickyStateStack(state);
49385          for (var i = 0; i < stickyAncestors.length; i++) {
49386            var parent = stickyAncestors[i].parent;
49387            mappedStates[parent.name] = mappedStates[parent.name] || [];
49388            mappedStates[parent.name].push(state);
49389          }
49390          if (mappedStates['']) {
49391            // This is necessary to compute Transition.inactives when there are sticky states are children to root state.
49392            mappedStates['__inactives'] = mappedStates[''];  // jshint ignore:line
49393          }
49394        });
49395        return mappedStates;
49396      }
49397
49398      function mapInactivesByImmediateParent() {
49399        var inactivesByAllParents ={};
49400        forEach(inactiveStates, function(state) {
49401          forEach(state.path, function(ancestor) {
49402            if (ancestor === state) return;
49403            inactivesByAllParents[ancestor.name] = inactivesByAllParents[ancestor.name] || [];
49404            inactivesByAllParents[ancestor.name].push(state);
49405          });
49406        });
49407        return inactivesByAllParents;
49408      }
49409
49410      // Given a state, returns all ancestor states which are sticky.
49411      // Walks up the view's state's ancestry tree and locates each ancestor state which is marked as sticky.
49412      // Returns an array populated with only those ancestor sticky states.
49413      function getStickyStateStack(state) {
49414        var stack = [];
49415        if (!state) return stack;
49416        do {
49417          if (state.sticky) stack.push(state);
49418          state = state.parent;
49419        } while (state);
49420        stack.reverse();
49421        return stack;
49422      }
49423
49424      // Returns a sticky transition type necessary to enter the state.
49425      // Transition can be: reactivate, reload, or enter
49426
49427      // Note: if a state is being reactivated but params dont match, we treat
49428      // it as a Exit/Enter, thus the special "reload" transition.
49429      // If a parent inactivated state has "reload" transition type, then
49430      // all descendant states must also be exit/entered, thus the first line of this function.
49431      function getEnterTransition(state, stateParams, reloadStateTree, ancestorReloaded) {
49432        if (ancestorReloaded) return "reload";
49433        var inactiveState = inactiveStates[state.self.name];
49434        if (!inactiveState) return "enter";
49435        if (state.self === reloadStateTree) return "reload";
49436        var paramsMatch = paramsEqualForState(state.ownParams, stateParams, inactiveState.locals.globals.$stateParams);
49437        return paramsMatch ? "reactivate" : "reload";
49438      }
49439
49440      // Given a state and (optional) stateParams, returns the inactivated state from the inactive sticky 
49440state registry.
49441      function getInactivatedState(state, stateParams) {
49442        var inactiveState = inactiveStates[state.name];
49443        if (!inactiveState) return null;
49444        if (!stateParams) return inactiveState;
49445        var paramsMatch = paramsEqualForState(state.ownParams, stateParams, inactiveState.locals.globals.$stateParams);
49446        return paramsMatch ? inactiveState : null;
49447      }
49448
49449      function paramsEqualForState(ownParams, stateParams, stateParams2) {
49450        if (typeof ownParams.$$equals === 'function')
49451          return ownParams.$$equals(stateParams, stateParams2);
49452        return equalForKeys(stateParams, stateParams2, ownParams);
49453      }
49454
49455      // Duplicates logic in $state.transitionTo, primarily to find the pivot state (i.e., the "keep" value)
49456      function equalForKeys(a, b, keys) {
49457        if (!angular.isArray(keys) && angular.isObject(keys)) {
49458          keys = protoKeys(keys, ["$$keys", "$$values", "$$equals", "$$validates", "$$new", "$$parent"]);
49459        }
49460        if (!keys) {
49461          keys = [];
49462          for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
49463        }
49464
49465        for (var i = 0; i < keys.length; i++) {
49466          var k = keys[i];
49467          if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
49468        }
49469        return true;
49470      }
49471
49472      function calcTreeChanges(transition) {
49473        var fromPath = transition.fromState.path;
49474        var toPath = transition.toState.path;
49475        var toParams = transition.toParams;
49476        var keep = 0, state = toPath[keep];
49477
49478        if (transition.options && transition.options.inherit) {
49479          toParams = transition.toParams =
49480              inheritParams($stateParams, toParams || {}, $state.$current, transition.toState);
49481        }
49482
49483        while (state && state === fromPath[keep] && paramsEqualForState(state.ownParams, toParams, transition.fromParams)) {
49484          // We're "keeping" this state. bump keep var and get the next state in toPath for the next iteration.
49485          state = toPath[++keep];
49486        }
49487
49488        return {
49489          keep: keep,
49490          retained: fromPath.slice(0, keep),
49491          exiting: fromPath.slice(keep),
49492          entering: toPath.slice(keep)
49493        };
49494      }
49495
49496      function sortByStateDepth(a,b) {
49497        return a.name.split(".").length - b.name.split(".").length;
49498      }
49499
49500      var stickySupport = {
49501        getInactiveStates: function () {
49502          return map(inactiveStates, angular.identity).sort(sortByStateDepth);
49503        },
49504        getInactiveStatesByParent: function () {
49505          return mapInactives();
49506        },
49507        // Main API for $stickyState, used by $state.
49508        // Processes a potential transition, returns an object with the following attributes:
49509        // {
49510        //    keep: The number of states being "kept"
49511        //    inactives: Array of all states which will be inactive if the transition is completed.
49512        //    reactivatingStates: Array of all states which will be reactivated if the transition is completed.
49513        //    orphans: Array of previously inactive states, which are being orphaned by the transition
49514        //        Note: Transitioning directly to an inactive state with inactive children will reactivate the state, but exit all the inactive children.
49515        //    enter: Enter transition type for all added states.  This is a parallel array to "toStates" array in $state.transitionTo.
49516        //    exit: Exit transition type for all removed states.  This is a parallel array to "fromStates" array in $state.transitionTo.
49517        // }
49518        processTransition: function (transition) {
49519          var treeChanges = calcTreeChanges(transition);
49520          var currentInactives = stickySupport.getInactiveStates();
49521          var futureInactives, exitingTypes, enteringTypes;
49522          var keep = treeChanges.keep;
49523
49524
49525          /////////////////////////////////////////
49526          // helper functions
49527          function notIn(array) { return function (elem) { return array.indexOf(elem) === -1; }; }
49528          function flattenReduce(memo, list) { return memo.concat(list); }
49529          function uniqReduce(memo, orphan) { if (notIn(memo)(orphan)) memo.push(orphan); return memo; }
49530          function prop(attr) { return function(obj) { return obj[attr]; } }
49531          function typeIs(type) { return function(obj) { return obj.type === type; } }
49532          function isChildOf(state) { return function(other) { return other.parent === state; }; }
49533          var notEntering = notIn(treeChanges.entering);
49534          function notSticky(state) { return !state.sticky; }
49535          ////////////////////////////////////
49536
49537
49538          // Calculate the "exit" transition types for states being exited in fromPath
49539          // Exit types will be either "inactivate" or "exit"
49540          // Two things must be satisfied in order to inactivate the "exiting" states (instead of exit them):
49541          // - The first element of the exiting path must be sticky
49542          // - We must be entering any sibling state of the sticky (we can check this using entering.length)
49543          var shouldInactivate = treeChanges.exiting[0] && treeChanges.exiting[0].sticky && treeChanges.entering.length > 0;
49544          exitingTypes = treeChanges.exiting.map(function (state) {
49545              var stateRentering = treeChanges.entering.indexOf(state) !== -1;
49546              var type = shouldInactivate && !stateRentering ? "inactivate" : "exit";
49547              return { type: type, state: state };
49548          });
49549
49550
49551          // Calculate the "enter" transition types for states being entered in toPath
49552          // Enter types will be either "enter", "reactivate", or "reload" where:
49553          //   enter: full resolve, no special logic
49554          //   reactivate: use previous locals
49555          //   reload: like 'enter', except exit the inactive state before entering it.
49556          var reloaded = transition.options && !!transition.options.reload;
49557          enteringTypes = treeChanges.entering.map(function(state) {
49558            var type = getEnterTransition(state, transition.toParams, transition.reloadStateTree, reloaded);
49559            reloaded = reloaded || type === 'reload';
49560            return { type: type, state: state };
49561          });
49562
49563          // Find all the "orphaned" states.  those states that are :
49564          //  - are siblings of the entering states
49565          //  - previously inactive
49566          //  - are not being reactivated (entered)
49567          //  - are not sticky
49568          // unioned with:
49569          //  - children of the toState
49570          //  - previously inactive
49571          //
49572          // Given:
49573          //   - states A (sticky: true), B, A.foo, A.bar
49574          //   - A.foo is currently inactive
49575          //   - B is currently active
49576          // Orphan case 1)
49577          //   - Transition to A.bar orphans the inactive state A.foo; it should be exited
49578          // Orphan case 2)
49579          //   - Transition directly to A orphans the inactive state A.foo; it should be exited
49580          //
49581          // Given:
49582          //   - states A (sticky: true), B, A.foo (sticky), A.bar
49583          //   - A.foo is currently inactive
49584          //   - B is currently active
49585          // Orphan case 3)
49586          //   - Transition directly to A orphans the inactive sticky state A.foo; it should be exited
49587          // Note: transition from B to A.bar does not orphan A.foo
49588          // Note 2: each orphaned state might be the parent of a larger inactive subtree.
49589          var orphanedRoots = treeChanges.entering
49590              // For each entering state in the path, find all sibling states which are currently inactive
49591              .map(function (entering) { return currentInactives.filter(isChildOf(entering.parent)); })
49592              // Flatten nested arrays. Now we have an array of inactive states that are children of the ones being entered.
49593              .reduce(flattenReduce, [])
49594              // Consider "orphaned": only those children that are themselves not currently being entered
49595              .filter(notEntering)
49596              // Consider "orphaned": only those children that are not themselves sticky states.
49597              .filter(notSticky)
49598              // Finally, union that set with any inactive children of the "to state"
49599              .concat(currentInactives.filter(isChildOf(transition.toState)));
49600
49601          var currentInactivesByParent = mapInactivesByImmediateParent();
49602          var allOrphans = orphanedRoots
49603              .map(function(root) { return currentInactivesByParent[root.name] })
49604              .filter(angular.isDefined)
49605              .reduce(flattenReduce, [])
49606              .concat(orphanedRoots)
49607              // Sort by depth to exit orphans in proper order
49608              .sort(sortByStateDepth);
49609
49610          // Add them to the list of states being exited.
49611          var exitOrOrphaned = exitingTypes
49612              .filter(typeIs("exit"))
49613              .map(prop("state"))
49614              .concat(allOrphans);
49615
49616          // Now calculate the states that will be inactive if this transition succeeds.
49617          // We have already pushed the transitionType == "inactivate" states to 'inactives'.
49618          // Second, add all the existing inactive states
49619          futureInactives = currentInactives
49620              .filter(notIn(exitOrOrphaned))
49621              .filter(notIn(treeChanges.entering))
49622              .concat(exitingTypes.filter(typeIs("inactivate")).map(prop("state")))
49623              .sort(sortByStateDepth);
49624
49625          return {
49626            keep: keep,
49627            enter: new Array(keep).concat(enteringTypes.map(prop("type"))),
49628            exit: new Array(keep).concat(exitingTypes.map(prop("type"))),
49629            inactives: futureInactives,
49630            reactivatingStates: enteringTypes.filter(typeIs("reactivate")).map(prop("state")),
49631            orphans: allOrphans
49632          };
49633        },
49634
49635        // Adds a state to the inactivated sticky state registry.
49636        stateInactivated: function (state) {
49637          // Keep locals around.
49638          inactiveStates[state.self.name] = state;
49639          // Notify states they are being Inactivated (i.e., a different
49640          // sticky state tree is now active).
49641          state.self.status = 'inactive';
49642          if (state.self.onInactivate)
49643            $injector.invoke(state.self.onInactivate, state.self, state.locals.globals);
49644        },
49645
49646        // Removes a previously inactivated state from the inactive sticky state registry
49647        stateReactivated: function (state) {
49648          if (inactiveStates[state.self.name]) {
49649            delete inactiveStates[state.self.name];
49650          }
49651          state.self.status = 'entered';
49652//        if (state.locals == null || state.locals.globals == null) debugger;
49653          if (state.self.onReactivate)
49654            $injector.invoke(state.self.onReactivate, state.self, state.locals.globals);
49655        },
49656
49657        // Exits all inactivated descendant substates when the ancestor state is exited.
49658        // When transitionTo is exiting a state, this function is called with the state being exited.  It checks the
49659        // registry of inactivated states for descendants of the exited state and also exits those descendants.  It then
49660        // removes the locals and de-registers the state from the inactivated registry.
49661        stateExiting: function (exiting, exitQueue, onExit) {
49662          var exitingNames = {};
49663          angular.forEach(exitQueue, function (state) {
49664            exitingNames[state.self.name] = true;
49665          });
49666
49667          angular.forEach(inactiveStates, function (inactiveExiting, name) {
49668            // TODO: Might need to run the inactivations in the proper depth-first order?
49669            if (!exitingNames[name] && inactiveExiting.includes[exiting.name]) {
49670              if (DEBUG) $log.debug("Exiting " + name + " because it's a substate of " + exiting.name + " and wasn't found in ", exitingNames);
49671              if (inactiveExiting.self.onExit)
49672                $injector.invoke(inactiveExiting.self.onExit, inactiveExiting.self, inactiveExiting.locals.globals);
49673              angular.forEach(inactiveExiting.locals, function(localval, key) {
49674                delete inactivePseudoState.locals[key];
49675              });
49676              inactiveExiting.locals = null;
49677              inactiveExiting.self.status = 'exited';
49678              delete inactiveStates[name];
49679            }
49680          });
49681
49682          if (onExit)
49683            $injector.invoke(onExit, exiting.self, exiting.locals.globals);
49684          exiting.locals = null;
49685          exiting.self.status = 'exited';
49686          delete inactiveStates[exiting.self.name];
49687        },
49688
49689        // Removes a previously inactivated state from the inactive sticky state registry
49690        stateEntering: function (entering, params, onEnter, updateParams) {
49691          var inactivatedState = getInactivatedState(entering);
49692          if (inactivatedState && (updateParams || !getInactivatedState(entering, params))) {
49693            var savedLocals = entering.locals;
49694            this.stateExiting(inactivatedState);
49695            entering.locals = savedLocals;
49696          }
49697          entering.self.status = 'entered';
49698
49699          if (onEnter)
49700            $injector.invoke(onEnter, entering.self, entering.locals.globals);
49701        },
49702        reset: function reset(inactiveState, params) {
49703          function resetOne(state) { stickySupport.reset(state); }
49704          if (inactiveState === "*") {
49705            angular.forEach(stickySupport.getInactiveStates(), resetOne);
49706            return true;
49707          }
49708          var state = $state.get(inactiveState);
49709          if (!state) return false;
49710          var exiting = getInactivatedState(state, params);
49711          if (!exiting) return false;
49712          stickySupport.stateExiting(exiting);
49713          $rootScope.$broadcast("$viewContentLoading");
49714          return true;
49715        }
49716      };
49717
49718      return stickySupport;
49719    }];
49720}
49721
49722mod_sticky.provider("$stickyState", $StickyStateProvider);
49723
49724/**
49725 * Sticky States makes entire state trees "sticky". Sticky state trees are retained until their parent state is
49726 * exited. This can be useful to allow multiple modules, peers to each other, each module having its own independent
49727 * state tree.  The peer modules can be activated and inactivated without any loss of their internal context, including
49728 * DOM content such as unvalidated/partially filled in forms, and even scroll position.
49729 *
49730 * DOM content is retained by declaring a named ui-view in the parent state, and filling it in with a named view from the
49731 * sticky state.
49732 *
49733 * Technical overview:
49734 *
49735 * ---PATHS---
49736 * UI-Router uses state paths to manage entering and exiting of individual states.  Each state "A.B.C.X" has its own path, starting
49737 * from the root state ("") and ending at the state "X".  The path is composed the final state "X"'s ancestors, e.g.,
49738 * [ "", "A", "B", "C", "X" ].
49739 *
49740 * When a transition is processed, the previous path (fromState.path) is compared with the requested destination path
49741 * (toState.path).  All states that the from and to paths have in common are "kept" during the transition.  The last
49742 * "kept" element in the path is the "pivot".
49743 *
49744 * ---VIEWS---
49745 * A View in UI-Router consists of a controller and a template.  Each view belongs to one state, and a state can have many
49746 * views.  Each view plugs into a ui-view element in the DOM of one of the parent state's view(s).
49747 *
49748 * View context is managed in UI-Router using a 'state locals' concept. When a state's views are fully loaded, those views
49749 * are placed on the states 'locals' object.  Each locals object prototypally inherits from its parent state's locals object.
49750 * This means that state "A.B.C.X"'s locals object also has all of state "A.B.C"'s locals as well as those from "A.B" and "A".
49751 * The root state ("") defines no views, but it is included in the protypal inheritance chain.
49752 *
49753 * The locals object is used by the ui-view directive to load the template, render the content, create the child scope,
49754 * initialize the controller, etc.  The ui-view directives caches the locals in a closure variable.  If the locals are
49755 * identical (===), then the ui-view directive exits early, and does no rendering.
49756 *
49757 * In stock UI-Router, when a state is exited, that state's locals object is deleted and those views are cleaned up by
49758 * the ui-view directive shortly.
49759 *
49760 * ---Sticky States---
49761 * UI-Router Extras keeps views for inactive states live, even when UI-Router thinks it has exited them.  It does this
49762 * by creating a pseudo state called "__inactives" that is the parent of the root state.  It also then defines a locals
49763 * object on the "__inactives" state, which the root state protoypally inherits from.  By doing this, views for inactive
49764 * states are accessible through locals object's protoypal inheritance chain from any state in the system.
49765 *
49766 * ---Transitions---
49767 * UI-Router Extras decorates the $state.transitionTo function.  While a transition is in progress, the toState and
49768 * fromState internal state representations are modified in order to coerce stock UI-Router's transitionTo() into performing
49769 * the appropriate operations.  When the transition promise is completed, the original toState and fromState values are
49770 * restored.
49771 *
49772 * Stock UI-Router's $state.transitionTo function uses toState.path and fromState.path to manage entering and exiting
49773 * states.  UI-Router Extras takes advantage of those internal implementation details and prepares a toState.path and
49774 * fromState.path which coerces UI-Router into entering and exiting the correct states, or more importantly, not entering
49775 * and not exiting inactive or sticky states.  It also replaces state.self.onEnter and state.self.onExit for elements in
49776 * the paths when they are being inactivated or reactivated.
49777 */
49778
49779
49780
49781// ------------------------ Sticky State module-level variables -----------------------------------------------
49782var _StickyState; // internal reference to $stickyStateProvider
49783var internalStates = {}; // Map { statename -> InternalStateObj } holds internal representation of all states
49784var root, // Root state, internal representation
49785  pendingTransitions = [], // One transition may supersede another.  This holds references to all pending transitions
49786  pendingRestore, // The restore function from the superseded transition
49787  inactivePseudoState, // This pseudo state holds all the inactive states' locals (resolved state data, such as views etc)
49788  reactivatingLocals = { }, // This is a prent locals to the inactivePseudoState locals, used to hold locals for states being reactivated
49789  versionHeuristics = { // Heuristics used to guess the current UI-Router Version
49790    hasParamSet: false
49791  };
49792
49793// Creates a blank surrogate state
49794function SurrogateState(type) {
49795  return {
49796    resolve: { },
49797    locals: {
49798      globals: root && root.locals && root.locals.globals
49799    },
49800    views: { },
49801    self: { },
49802    params: { },
49803    ownParams: ( versionHeuristics.hasParamSet ? { $$equals: function() { return true; } } : []),
49804    surrogateType: type
49805  };
49806}
49807
49808// ------------------------ Sticky State registration and initialization code ----------------------------------
49809// Grab a copy of the $stickyState service for use by the transition management code
49810angular.module("ct.ui.router.extras.sticky").run(["$stickyState", function ($stickyState) {
49811  _StickyState = $stickyState;
49812}]);
49813
49814angular.module("ct.ui.router.extras.sticky").config(
49815  [ "$provide", "$stateProvider", '$stickyStateProvider', '$urlMatcherFactoryProvi
49815der', 'uirextras_coreProvider',
49816    function ($provide, $stateProvider, $stickyStateProvider, $urlMatcherFactoryProvider, uirextras_coreProvider) {
49817      var core = uirextras_coreProvider;
49818      var internalStates = core.internalStates;
49819      var inherit = core.inherit;
49820      var inheritParams = core.inheritParams;
49821      var forEach = core.forEach;
49822      var map = core.map;
49823      var filterObj = core.filterObj;
49824
49825      versionHeuristics.hasParamSet = !!$urlMatcherFactoryProvider.ParamSet;
49826      // inactivePseudoState (__inactives) holds all the inactive locals which includes resolved states data, i.e., views, scope, etc
49827      inactivePseudoState = angular.extend(new SurrogateState("__inactives"), { self: {  name: '__inactives'  } });
49828      // Reset other module scoped variables.  This is to primarily to flush any previous state during karma runs.
49829      root = pendingRestore = undefined;
49830      pendingTransitions = [];
49831
49832      uirextras_coreProvider.onStateRegistered(function(state) {
49833        // Register the ones marked as "sticky"
49834        if (state.self.sticky === true) {
49835          $stickyStateProvider.registerStickyState(state.self);
49836        }
49837      });
49838
49839      var $state_transitionTo; // internal reference to the real $state.transitionTo function
49840      // Decorate the $state service, so we can decorate the $state.transitionTo() function with sticky state stuff.
49841      $provide.decorator("$state", ['$delegate', '$log', '$q', function ($state, $log, $q) {
49842        // Note: this code gets run only on the first state that is decorated
49843        root = $state.$current;
49844        internalStates[""] = root;
49845        root.parent = inactivePseudoState; // Make inactivePsuedoState the parent of root.  "wat"
49846        inactivePseudoState.parent = undefined; // Make inactivePsuedoState the real root.
49847        // Add another locals bucket, as a parent to inactivatePseudoState locals.
49848        // This is for temporary storage of locals of states being reactivated while a transition is pending
49849        // This is necessary in some cases where $viewContentLoading is triggered before the $state.$current is updated to the toState.
49850        inactivePseudoState.locals = inherit(reactivatingLocals, inactivePseudoState.locals);
49851        root.locals = inherit(inactivePseudoState.locals, root.locals); // make root locals extend the __inactives locals.
49852        delete inactivePseudoState.locals.globals;
49853
49854        // Hold on to the real $state.transitionTo in a module-scope variable.
49855        $state_transitionTo = $state.transitionTo;
49856
49857        // ------------------------ Decorated transitionTo implementation begins here ---------------------------
49858        $state.transitionTo = function (to, toParams, options) {
49859          var DEBUG = $stickyStateProvider.debugMode();
49860          // TODO: Move this to module.run?
49861          // TODO: I'd rather have root.locals prototypally inherit from inactivePseudoState.locals
49862          // Link root.locals and inactives.locals.  Do this at runtime, after root.locals has been set.
49863          if (!inactivePseudoState.locals)
49864            inactivePseudoState.locals = root.locals;
49865          var idx = pendingTransitions.length;
49866          if (pendingRestore) {
49867            pendingRestore();
49868            if (DEBUG) {
49869              $log.debug("Restored paths from pending transition");
49870            }
49871          }
49872
49873          var fromState = $state.$current, fromParams = $state.params;
49874          var rel = options && options.relative || $state.$current; // Not sure if/when $state.$current is appropriate here.
49875          var toStateSelf = $state.get(to, rel); // exposes findState relative path functionality, returns state.self
49876          var savedToStatePath, savedFromStatePath, stickyTransitions;
49877          var reactivated = [], exited = [], terminalReactivatedState;
49878          toParams = toParams || {};
49879          arguments[1] = toParams;
49880
49881          var noop = function () {
49882          };
49883          // Sticky states works by modifying the internal state objects of toState and fromState, especially their .path(s).
49884          // The restore() function is a closure scoped function that restores those states' definitions to their original values.
49885          var restore = function () {
49886            if (savedToStatePath) {
49887              toState.path = savedToStatePath;
49888              savedToStatePath = null;
49889            }
49890
49891            if (savedFromStatePath) {
49892              fromState.path = savedFromStatePath;
49893              savedFromStatePath = null;
49894            }
49895
49896            angular.forEach(restore.restoreFunctions, function (restoreFunction) {
49897              restoreFunction();
49898            });
49899            // Restore is done, now set the restore function to noop in case it gets called again.
49900            restore = noop;
49901            // pendingRestore keeps track of a transition that is in progress.  It allows the decorated transitionTo
49902            // method to be re-entrant (for example, when superceding a transition, i.e., redirect).  The decorated
49903            // transitionTo checks right away if there is a pending transition in progress and restores the paths
49904            // if so using pendingRestore.
49905            pendingRestore = null;
49906            pendingTransitions.splice(idx, 1); // Remove this transition from the list
49907          };
49908
49909          // All decorated transitions have their toState.path and fromState.path replaced.  Surrogate states also make
49910          // additional changes to the states definition before handing the transition off to UI-Router. In particular,
49911          // certain types of surrogate states modify the state.self object's onEnter or onExit callbacks.
49912          // Those surrogate states must then register additional restore steps using restore.addRestoreFunction(fn)
49913          restore.restoreFunctions = [];
49914          restore.addRestoreFunction = function addRestoreFunction(fn) {
49915            this.restoreFunctions.push(fn);
49916          };
49917
49918
49919          // --------------------- Surrogate State Functions ------------------------
49920          // During a transition, the .path arrays in toState and fromState are replaced.  Individual path elements
49921          // (states) which aren't being "kept" are replaced with surrogate elements (states).  This section of the code
49922          // has factory functions for all the different types of surrogate states.
49923
49924
49925          function stateReactivatedSurrogatePhase1(state) {
49926            var surrogate = angular.extend(new SurrogateState("reactivate_phase1"), { locals: state.locals });
49927            surrogate.self = angular.extend({}, state.self);
49928            return surrogate;
49929          }
49930
49931          function stateReactivatedSurrogatePhase2(state) {
49932            var surrogate = angular.extend(new SurrogateState("reactivate_phase2"), state);
49933            var oldOnEnter = surrogate.self.onEnter;
49934            surrogate.resolve = {}; // Don't re-resolve when reactivating states (fixes issue #22)
49935            // TODO: Not 100% sure if this is necessary.  I think resolveState will load the views if I don't do this.
49936            surrogate.views = {}; // Don't re-activate controllers when reactivating states (fixes issue #22)
49937            surrogate.self.onEnter = function () {
49938              // ui-router sets locals on the surrogate to a blank locals (because we gave it nothing to resolve)
49939              // Re-set it back to the already loaded state.locals here.
49940              surrogate.locals = state.locals;
49941              _StickyState.stateReactivated(state);
49942            };
49943            restore.addRestoreFunction(function () {
49944              state.self.onEnter = oldOnEnter;
49945            });
49946            return surrogate;
49947          }
49948
49949          function stateInactivatedSurrogate(state) {
49950            var surrogate = new SurrogateState("inactivate");
49951            surrogate.self = state.self;
49952            var oldOnExit = state.self.onExit;
49953            surrogate.self.onExit = function () {
49954              _StickyState.stateInactivated(state);
49955            };
49956            restore.addRestoreFunction(function () {
49957              state.self.onExit = oldOnExit;
49958            });
49959            return surrogate;
49960          }
49961
49962          function stateEnteredSurrogate(state, toParams) {
49963            var oldOnEnter = state.self.onEnter;
49964            state.self.onEnter = function () {
49965              _StickyState.stateEntering(state, toParams, oldOnEnter);
49966            };
49967            restore.addRestoreFunction(function () {
49968              state.self.onEnter = oldOnEnter;
49969            });
49970
49971            return state;
49972          }
49973
49974          // TODO: This may be completely unnecessary now that we're using $$uirouterextrasreload temp param
49975          function stateUpdateParamsSurrogate(state, toParams) {
49976            var oldOnEnter = state.self.onEnter;
49977            state.self.onEnter = function () {
49978              _StickyState.stateEntering(state, toParams, oldOnEnter, true);
49979            };
49980            restore.addRestoreFunction(function () {
49981              state.self.onEnter = oldOnEnter;
49982            });
49983
49984            return state;
49985          }
49986
49987          function stateExitedSurrogate(state) {
49988            var oldOnExit = state.self.onExit;
49989            state.self.onExit = function () {
49990              _StickyState.stateExiting(state, exited, oldOnExit);
49991            };
49992            restore.addRestoreFunction(function () {
49993              state.self.onExit = oldOnExit;
49994            });
49995
49996            return state;
49997          }
49998
49999
50000          // --------------------- decorated .transitionTo() logic starts here ------------------------
50001          if (toStateSelf) {
50002            var toState = internalStates[toStateSelf.name]; // have the state, now grab the internal state representation
50003            if (toState) {
50004              // Save the toState and fromState paths to be restored using restore(
50004)
50005              savedToStatePath = toState.path;
50006              savedFromStatePath = fromState.path;
50007
50008              // Try to resolve options.reload to a state.  If so, we'll reload only up to the given state.
50009              var reload = options && options.reload || false;
50010              var reloadStateTree = reload && (reload === true ? savedToStatePath[0].self : $state.get(reload, rel));
50011              // If options.reload is a string or a state, we want to handle reload ourselves and not
50012              // let ui-router reload the entire toPath.
50013              if (options && reload && reload !== true)
50014                delete options.reload;
50015
50016              var currentTransition = {
50017                toState: toState,
50018                toParams: toParams || {},
50019                fromState: fromState,
50020                fromParams: fromParams || {},
50021                options: options,
50022                reloadStateTree: reloadStateTree
50023              };
50024
50025              pendingTransitions.push(currentTransition); // TODO: See if a list of pending transitions is necessary.
50026              pendingRestore = restore;
50027
50028              // If we're reloading from a state and below, temporarily add a param to the top of the state tree
50029              // being reloaded, and add a param value to the transition.  This will cause the "has params changed
50030              // for state" check to return true, and the states will be reloaded.
50031              if (reloadStateTree) {
50032                currentTransition.toParams.$$uirouterextrasreload = Math.random();
50033                var params = reloadStateTree.$$state().params;
50034                var ownParams = reloadStateTree.$$state().ownParams;
50035
50036                if (versionHeuristics.hasParamSet) {
50037                  var tempParam = new $urlMatcherFactoryProvider.Param('$$uirouterextrasreload');
50038                  params.$$uirouterextrasreload = ownParams.$$uirouterextrasreload = tempParam;
50039                  restore.restoreFunctions.push(function() {
50040                    delete params.$$uirouterextrasreload;
50041                    delete ownParams.$$uirouterextrasreload;
50042                  });
50043                } else {
50044                  params.push('$$uirouterextrasreload');
50045                  ownParams.push('$$uirouterextrasreload');
50046                  restore.restoreFunctions.push(function() {
50047                    params.length = params.length -1;
50048                    ownParams.length = ownParams.length -1;
50049                  });
50050                }
50051              }
50052
50053              // $StickyStateProvider.processTransition analyzes the states involved in the pending transition.  It
50054              // returns an object that tells us:
50055              // 1) if we're involved in a sticky-type transition
50056              // 2) what types of exit transitions will occur for each "exited" path element
50057              // 3) what types of enter transitions will occur for each "entered" path element
50058              // 4) which states will be inactive if the transition succeeds.
50059              stickyTransitions = _StickyState.processTransition(currentTransition);
50060
50061              if (DEBUG) debugTransition($log, currentTransition, stickyTransitions);
50062
50063              // Begin processing of surrogate to and from paths.
50064              var surrogateToPath = toState.path.slice(0, stickyTransitions.keep);
50065              var surrogateFromPath = fromState.path.slice(0, stickyTransitions.keep);
50066
50067              // Clear out and reload inactivePseudoState.locals each time transitionTo is called
50068              angular.forEach(inactivePseudoState.locals, function (local, name) {
50069                if (name.indexOf("@") != -1) delete inactivePseudoState.locals[name];
50070              });
50071
50072              var saveViewsToLocals = function (targetObj) {
50073                return function(view, name) {
50074                  if (name.indexOf("@") !== -1) { // Only grab this state's "view" locals
50075                    targetObj[name] = view; // Add all inactive views not already included.
50076                  }
50077                }
50078              };
50079
50080              // For each state that will be inactive when the transition is complete, place its view-locals on the
50081              // __inactives pseudostate's .locals.  This allows the ui-view directive to access them and
50082              // render the inactive views.
50083              forEach(stickyTransitions.inactives, function(state) {
50084                forEach(state.locals, saveViewsToLocals(inactivePseudoState.locals))
50085              });
50086
50087              // For each state that will be reactivated during the transition, place its view-locals on a separate
50088              // locals object (prototypal parent of __inactives.locals, and remove them when the transition is complete.
50089              // This is necessary when we a transition will reactivate one state, but enter a second.
50090              // Gory details:
50091              //   - the entering of a new state causes $view.load() to fire $viewContentLoading while the transition is
50092              //     still in process
50093              //   - all ui-view(s) check if they should re-render themselves in response to this event.
50094              //   - ui-view checks if previousLocals is equal to currentLocals
50095              //     - it uses $state.$current.locals[myViewName] for previousLocals
50096              //   - Because the transition is not completed, $state.$current is set to the from state, and
50097              //     the ui-view for a reactivated state cannot find its previous locals.
50098              forEach(stickyTransitions.reactivatingStates, function(state) {
50099                forEach(state.locals, saveViewsToLocals(reactivatingLocals));
50100              });
50101
50102              // When the transition is complete, remove the copies of the view locals from reactivatingLocals.
50103              restore.addRestoreFunction(function clearReactivatingLocals() {
50104                forEach(reactivatingLocals, function (val, viewname) {
50105                  delete reactivatingLocals[viewname];
50106                })
50107              });
50108
50109              // Find all the states the transition will be entering.  For each entered state, check entered-state-transition-type
50110              // Depending on the entered-state transition type, place the proper surrogate state on the surrogate toPath.
50111              angular.forEach(stickyTransitions.enter, function (value, idx) {
50112                var surrogate;
50113                var enteringState = toState.path[idx];
50114                if (value === "reactivate") {
50115                  // Reactivated states require TWO surrogates.  The "phase 1 reactivated surrogates" are added to both
50116                  // to.path and from.path, and as such, are considered to be "kept" by UI-Router.
50117                  // This is required to get UI-Router to add the surrogate locals to the protoypal locals object
50118                  surrogate = stateReactivatedSurrogatePhase1(enteringState);
50119                  surrogateToPath.push(surrogate);
50120                  surrogateFromPath.push(surrogate);  // so toPath[i] === fromPath[i]
50121
50122                  // The "phase 2 reactivated surrogate" is added to the END of the .path, after all the phase 1
50123                  // surrogates have been added.
50124                  reactivated.push(stateReactivatedSurrogatePhase2(enteringState));
50125                  terminalReactivatedState = enteringState;
50126                } else if (value === "reload") {
50127                  // If the state params have been changed, we need to exit any inactive states and re-enter them.
50128                  surrogateToPath.push(stateUpdateParamsSurrogate(enteringState));
50129                  terminalReactivatedState = enteringState;
50130                } else if (value === "enter") {
50131                  // Standard enter transition.  We still wrap it in a surrogate.
50132                  surrogateToPath.push(stateEnteredSurrogate(enteringState));
50133                }
50134              });
50135
50136              // Find all the states the transition will be exiting.  For each exited state, check the exited-state-transition-type.
50137              // Depending on the exited-state transition type, place a surrogate state on the surrogate fromPath.
50138              angular.forEach(stickyTransitions.exit, function (value, idx) {
50139                var exiting = fromState.path[idx];
50140                if (value === "inactivate") {
50141                  surrogateFromPath.push(stateInactivatedSurrogate(exiting));
50142                  exited.push(exiting);
50143                } else if (value === "exit") {
50144                  surrogateFromPath.push(stateExitedSurrogate(exiting));
50145                  exited.push(exiting);
50146                }
50147              });
50148
50149              // Add surrogate states for reactivated to ToPath again (phase 2), this time without a matching FromPath entry
50150              // This is to get ui-router to call the surrogate's onEnter callback.
50151              if (reactivated.length) {
50152                angular.forEach(reactivated, function (surrogate) {
50153                  surrogateToPath.push(surrogate);
50154                });
50155              }
50156
50157              // We may transition directly to an inactivated state, reactivating it.  In this case, we should
50158              // exit all of that state's inactivated children.
50159              var orphans = stickyTransitions.orphans;
50160              // Add surrogate exited states for all orphaned descendants of the Deepest Reactivated State
50161              surrogateFromPath = surrogateFromPath.concat(map(orphans, function (exiting) {
50162                return stateExitedSurrogate(exiting);
50163              }));
50164              exited = exited.concat(orphans);
50165
50166              // Replace the .path variables.  toState.path and fromState.path are now ready for a sticky transition.
50167              fromState.path = surrogateFromPath;
50168              toState.path = surrogateToPath;
50169
50170              var pathMessage = function (state) {
50171                return (state.surrogateType ? state.surrogateType + ":" : "") + state.self.name;
50172              };
50173              if (DEBUG) $log.debug("SurrogateFromPath: ", map(surrogateFromPath, pathMessage));
50174              if (DEBUG) $log.debug("SurrogateToPath:   ", map(surrogateToPath, pathMessage));
50175            }
50176          }
50177
50178          // toState and fromState are all set up; now run stock UI-Router's $state.transitionTo().
50179          var transitionPromise = $state_transitionTo.apply($state, arguments);
50180
50181          // Add post-transition promise handlers, then return the promise to the original caller.
50182          return transitionPromise.then(function transitionSuccess(state) {
50183            // First, restore toState and fromState to their original values.
50184            restore();
50185            if (DEBUG)  debugViewsAfterSuccess($log, internalStates[state.name], $state);
50186
50187            state.status = 'active';  // TODO: This status is used in statevis.js, and almost certainly belongs elsewhere.
50188
50189            return state;
50190          }, function transitionFailed(err) {
50191            restore();
50192            if (DEBUG &&
50193              err.message !== "transition prevented" &&
50194              err.message !== "transition aborted" &&
50195              err.message !== "transition superseded") {
50196              $log.debug("transition failed", err);
50197              $log.debug(err.stack);
50198            }
50199            return $q.reject(err);
50200          });
50201        };
50202        return $state;
50203      }]);
50204
50205
50206
50207      function debugTransition($log, currentTransition, stickyTransition) {
50208        function message(path, index, state) {
50209          return (path[index] ? path[index].toUpperCase() + ": " + state.self.name : "(" + state.self.name + ")");
50210        }
50211
50212        var inactiveLogVar = map(stickyTransition.inactives, function (state) {
50213          return state.self.name;
50214        });
50215        var enterLogVar = map(currentTransition.toState.path, function (state, index) {
50216          return message(stickyTransition.enter, index, state);
50217        });
50218        var exitLogVar = map(currentTransition.fromState.path, function (state, index) {
50219          return message(stickyTransition.exit, index, state);
50220        });
50221
50222        var transitionMessage = currentTransition.fromState.self.name + ": " +
50223          angular.toJson(currentTransition.fromParams) + ": " +
50224          " -> " +
50225          currentTransition.toState.self.name + ": " +
50226          angular.toJson(currentTransition.toParams);
50227
50228        $log.debug("------------------------------------------------------");
50229        $log.debug("   Current transition: ", transitionMessage);
50230        $log.debug("Before transition, inactives are:   : ", map(_StickyState.getInactiveStates(), function (s) {
50231          return s.self.name;
50232        }));
50233        $log.debug("After transition,  inactives will be: ", inactiveLogVar);
50234        $log.debug("Transition will exit:  ", exitLogVar);
50235        $log.debug("Transition will enter: ", enterLogVar);
50236      }
50237
50238      function debugViewsAfterSuccess($log, currentState, $state) {
50239        $log.debug("Current state: " + currentState.self.name + ", inactive states: ", map(_StickyState.getInactiveStates(), function (s) {
50240          return s.self.name;
50241        }));
50242
50243        var statesOnly = function (local, name) {
50244          return name != 'globals' && name != 'resolve';
50245        };
50246
50247        var viewsForState = function (state) {
50248          var viewLocals = filterObj(state.locals, statesOnly);
50249
50250          if (!Object.keys(viewLocals).length) {
50251            viewLocals[''] = { $$state: { name: null } };
50252          }
50253
50254          return map(viewLocals, function(local, name) {
50255            return {
50256              localsFor: state.self.name ? state.self.name : "(root)",
50257              uiViewName: name || null,
50258              filledByState: local.$$state.name
50259            };
50260          });
50261        };
50262
50263        var viewsByState = viewsForState(currentState);
50264        var parent = currentState.parent;
50265        while (parent && parent !== currentState) {
50266          viewsByState = viewsByState.concat(viewsForState(parent));
50267          currentState = parent;
50268          parent = currentState.parent;
50269        }
50270
50271        $log.debug("Views active on each state:");
50272        console.table(viewsByState.reverse());
50273      }
50274    }
50275  ]
50276);
50277
50278(function(angular, undefined) {
50279  var app = angular.module('ct.ui.router.extras.future', [ 'ct.ui.router.extras.core' ]);
50280
50281  _futureStateProvider.$inject = [ '$stateProvider', '$urlRouterProvider', '$urlMatcherFactoryProvider', 'uirextras_coreProvider' ];
50282  function _futureStateProvider($stateProvider, $urlRouterProvider, $urlMatcherFactory, uirextras_coreProvider) {
50283    var core = uirextras_coreProvider;
50284    var internalStates = core.internalStates;
50285    var stateFactories = {}, futureStates = {};
50286    var lazyloadInProgress = false, resolveFunctions = [], initPromise, initDone = false;
50287    var provider = this;
50288
50289    // This function registers a promiseFn, to be resolved before the url/state matching code
50290    // will reject a route.  The promiseFn is injected/executed using the runtime $injector.
50291    // The function should return a promise.
50292    // When all registered promises are resolved, then the route is re-sync'ed.
50293
50294    // Example: function($http) {
50295    //  return $http.get('//server.com/api/DynamicFutureStates').then(function(data) {
50296    //    angular.forEach(data.futureStates, function(fstate) { $futureStateProvider.futureState(fstate); });
50297    //  };
50298    // }
50299    this.addResolve = function (promiseFn) {
50300      resolveFunctions.push(promiseFn);
50301    };
50302
50303    // Register a state factory function for a particular future-state type.  This factory, given a future-state object,
50304    // should create a ui-router state.
50305    // The factory function is injected/executed using the runtime $injector.  The future-state is injected as 'futureState'.
50306
50307    // Example:
50308    //    $futureStateProvider.stateFactory('test', function(futureState) {
50309    //      return {
50310    //        name: futureState.stateName,
50311    //        url: futureState.urlFragment,
50312    //        template: '<h3>Future State Template</h3>',
50313    //        controller: function() {
50314    //          console.log("Entered state " + futureState.stateName);
50315    //        }
50316    //      }
50317    //    });
50318    this.stateFactory = function (futureStateType, factory) {
50319      stateFactories[futureStateType] = factory;
50320    };
50321
50322    this.futureState = function (futureState) {
50323      if (futureState.stateName)  // backwards compat for now
50324        futureState.name = futureState.stateName;
50325      if (futureState.urlPrefix)  // backwards compat for now
50326        futureState.url = "^" + futureState.urlPrefix;
50327
50328      futureStates[futureState.name] = futureState;
50329      var parentMatcher,  parentName = futureState.name.split(/\./).slice(0, -1).join("."),
50330        realParent = findState(futureState.parent || parentName);
50331      if (realParent) {
50332        parentMatcher = realParent.url || realParent.navigable && realParent.navigable.url;
50333      } else if (parentName === "") {
50334        parentMatcher = $urlMatcherFactory.compile("");
50335      } else {
50336        var futureParent = findState((futureState.parent || parentName), true);
50337        if (!futureParent) throw new Error("Couldn't determine parent state of future state. FutureState:" + angular.toJson(futureState));
50338        var pattern;
50339        if (futureParent.urlMatcher) {
50340          pattern = futureParent.urlMatcher.source.replace(/\*rest$/, "");
50341        }
50342        else {
50343          // if the futureParent doesn't have a urlMatcher, then we are still
50344          // starting from the beginning of the path
50345          pattern = "";
50346        }
50347        parentMatcher = $urlMatcherFactory.compile(pattern);
50348        futureState.parentFutureState = futureParent;
50349      }
50350      if (futureState.url) {
50351        futureState.urlMatcher = futureState.url.charAt(0) === "^" ?
50352          $urlMatcherFactory.compile(futureState.url.substring(1) + "*rest") :
50353          parentMatcher.concat(futureState.url + "*rest");
50354      }
50355    };
50356
50357    this.get = function () {
50358      return angular.extend({}, futureStates);
50359    };
50360
50361    function findState(stateOrName, findFutureState) {
50362      var statename = angular.isObject(stateOrName) ? stateOrName.name : stateOrName;
50363      return !findFutureState ? internalStates[statename] : futureStates[statename];
50364    }
50365
50366    /* options is an object with at least a name or url attribute */
50367    function findFutureState($state, options) {
50368      if (options.name) {
50369        var nameComponents = options.name.split(/\./);
50370        if (options.name.charAt(0) === '.')
50371          nameComponents[0] = $state.current.name;
50372        while (nameComponents.length) {
50373          var stateName = nameComponents.join(".");
50374          if ($state.get(stateName, { relative: $state.current }))
50375            return null; // State is already defined; nothing to do
50376          if (futureStates[stateName])
50377            return futureStates[stateName];
50378          nameComponents.pop();
50379        }
50380      }
50381
50382      if (options.url) {
50383        var matches = [];
50384        for(var future in futureStates) {
50385          var matcher = futureStates[future].urlMatcher;
50386          if (matcher && matcher.exec(options.url)) {
50387            matches.push(futureStates[future]);
50388          }
50389        }
50390        // Find most specific by ignoring matching parents from matches
50391        var copy = matches.slice(0);
50392        for (var i = matches.length - 1; i >= 0; i--) {
50393          for (var j = 0; j < copy.length; j++) {
50394            if (matches[i] === copy[j].parentFutureState) matches.splice(i, 1);
50395          }
50396        }
50397        return matches[0];
50398      }
50399    }
50400
50401    function lazyLoadState($injector, futureState) {
50402      lazyloadInProgress = true;
50403      var $q = $injector.get("$q");
50404      if (!futureState) {
50405        var deferred = $q.defer();
50406        deferred.reject("No lazyState passed in " + futureState);
50407        return deferred.promise;
50408      }
50409
50410      var parentPromises = $q.when([]), parentFuture = futureState.parentFutureState;
50411      if (parentFuture && futureStates[parentFuture.name]) {
50412        parentPromises = lazyLoadState($injector, futureStates[parentFuture.name]);
50413      }
50414
50415      var type = futureState.type;
50416      var factory = stateFactories[type];
50417      if (!factory) throw Error("No state factory for futureState.type: " + (futureState && futureState.type));
50418
50419      var failedLoadPolicy = factory.$options && factory.$options.failedLazyLoadPolicy || "remove";
50420      function deregisterFutureState() { delete(futureStates[futureState.name]); }
50421      function errorHandler(err) {
50422        if (failedLoadPolicy === "remove") deregisterFutureState();
50423        return $q.reject(err);
50424      }
50425
50426      return parentPromises.then(function(array) {
50427        var factoryPromise = $injector.invoke(factory, factory, { futureState: futureState });
50428
50429        return factoryPromise.then(function(fullState) {
50430          deregisterFutureState(); // Success; remove future state
50431          if (fullState) { array.push(fullState); } // Pass a chain of realized states back
50432          return array;
50433        });
50434      }).catch(errorHandler)
50435    }
50436
50437    var otherwiseFunc = [ '$log', '$location',
50438      function otherwiseFunc($log, $location) {
50439        //$log.debug("Unable to map " + $location.path());
50440      }];
50441
50442    function futureState_otherwise($injector, $location) {
50443      var resyncing = false;
50444
50445      var lazyLoadMissingState =
50446        ['$rootScope', '$urlRouter', '$state',
50447          function lazyLoadMissingState($rootScope, $urlRouter, $state) {
50448            function resync() {
50449              resyncing = true; $urlRouter.sync(); resyncing = false;
50450            }
50451            if (!initDone) {
50452              // Asynchronously load state definitions, then resync URL
50453              initPromise().then(resync);
50454              initDone = true;
50455              return;
50456            }
50457
50458            var futureState = findFutureState($state, { url: $location.path() });
50459            if (!futureState) {
50460              return $injector.invoke(otherwiseFunc);
50461            }
50462
50463            // Config loaded.  Asynchronously lazy-load state definition from URL fragment, if mapped.
50464            lazyLoadState($injector, futureState).then(function lazyLoadedStateCallback(states) {
50465              states.forEach(function (state) {
50466                if (state && (!$state.get(state) || (state.name && !$state.get(state.name))))
50467                  $stateProvider.state(state);
50468              });
50469              lazyloadInProgress = false;
50470              resync();
50471            }, function lazyLoadStateAborted() {
50472              lazyloadInProgress = false;
50473              resync();
50474            });
50475          }];
50476      if (lazyloadInProgress) return;
50477
50478      var nextFn = resyncing ? otherwiseFunc : lazyLoadMissingState;
50479      return $injector.invoke(nextFn);
50480    }
50481
50482    $urlRouterProvider.otherwise(futureState_otherwise);
50483
50484    $urlRouterProvider.otherwise = function(rule) {
50485      if (angular.isString(rule)) {
50486        var redirect = rule;
50487        rule = function () { return redirect; };
50488      }
50489      else if (!angular.isFunction(rule)) throw new Error("'rule' must be a function");
50490      otherwiseFunc = ['$injector', '$location', rule];
50491      return $urlRouterProvider;
50492    };
50493
50494    var serviceObject = {
50495      getResolvePromise: function () {
50496        return initPromise();
50497      }
50498    };
50499
50500    // Used in .run() block to init
50501    this.$get = [ '$injector', '$state', '$q', '$rootScope', '$urlRouter', '$timeout', '$log',
50502      function futureStateProvider_get($injector, $state, $q, $rootScope, $urlRouter, $timeout, $log) {
50503        function init() {
50504          $rootScope.$on("$stateNotFound", function futureState_notFound(event, unfoundState, fromState, fromParams) {
50505            if (lazyloadInProgress) return;
50506            //$log.debug("event, unfoundState, fromState, fromParams", event, unfoundState, fromState, fromParams);
50507
50508            var futureState = findFutureState($state, { name: unfoundState.to });
50509            if (!futureState) return;
50510
50511            event.preventDefault();
50512            var promise = lazyLoadState($injector, futureState);
50513            promise.then(function (states) {
50514              states.forEach(function (state) {
50515                if (state && (!$state.get(state) || (state.name && !$state.get(state.name))))
50516                  $stateProvider.state(state);
50517              });
50518              $state.go(unfoundState.to, unfoundState.toParams, unfoundState.options);
50519              lazyloadInProgress = false;
50520            }, function (error) {
50521              console.log("failed to lazy load state ", error);
50522              if (fromState.name) $state.go(fromState, fromParams);
50523              lazyloadInProgress = false;
50524            });
50525          });
50526
50527          // Do this better.  Want to load remote config once, before everything else
50528          if (!initPromise) {
50529            var promises = [];
50530            angular.forEach(resolveFunctions, function (promiseFn) {
50531              promises.push($injector.invoke(promiseFn));
50532            });
50533            initPromise = function () {
50534              return $q.all(promises);
50535            };
50536          }
50537
50538          // TODO: analyze this. I'm calling $urlRouter.sync() in two places for retry-initial-transition.
50539          // TODO: I should only need to do this once.  Pick the better place and remove the extra resync.
50540          initPromise().then(function retryInitialState() {
50541            $timeout(function () {
50542              if ($state.transition) {
50543                $state.transition.then(retryInitialState, retryInitialState);
50544              } else {
50545                $urlRouter.sync();
50546              }
50547            });
50548          });
50549        }
50550
50551        init();
50552
50553        serviceObject.state = $stateProvider.state;
50554        serviceObject.futureState = provider.futureState;
50555        serviceObject.get = provider.get;
50556
50557        return serviceObject;
50558      }
50559    ];
50560  }
50561
50562  app.provider('$futureState', _futureStateProvider);
50563
50564  var statesAddedQueue = {
50565    state: function(state) {
50566      if (statesAddedQueue.$rootScope)
50567        statesAddedQueue.$rootScope.$broadcast("$stateAdded", state);
50568    },
50569    itsNowRuntimeOhWhatAHappyDay: function($rootScope) {
50570      statesAddedQueue.$rootScope = $rootScope;
50571    },
50572    $rootScope: undefined
50573  };
50574
50575  app.config([ '$stateProvider', function($stateProvider) {
50576    // decorate $stateProvider.state so we can broadcast when a real state was added
50577    var realStateFn = $stateProvider.state;
50578    $stateProvider.state = function state_announce() {
50579      var val = realStateFn.apply($stateProvider, arguments);
50580
50581      var state = angular.isObject(arguments[0]) ? arguments[0] : arguments[1];
50582      statesAddedQueue.state(state);
50583      return val;
50584    };
50585  }]);
50586
50587  // inject $futureState so the service gets initialized via $get();
50588  app.run(['$futureState', function ($futureState, $rootScope) {
50589    statesAddedQueue.itsNowRuntimeOhWhatAHappyDay($rootScope);
50590  } ]);
50591
50592})(angular);
50593
50594angular.module('ct.ui.router.extras.previous', [ 'ct.ui.router.extras.core', 'ct.ui.router.extras.transition' ]).service("$previousState",
50595  [ '$rootScope', '$state', '$q',
50596    function ($rootScope, $state, $q) {
50597      var previous = null, lastPrevious = null, memos = {};
50598
50599      $rootScope.$on("$transitionStart", function(evt, $transition$) {
50600        var from = $transition$.from;
50601        // Check if the fromState is navigable before tracking it.
50602        // Root state doesn't get decorated with $$state().  Doh.
50603        var fromState = from.state && from.state.$$state && from.state.$$state();
50604        function commit() { lastPrevious = null; }
50605        function revert() { previous = lastPrevious; }
50606        if (fromState) {
50607          lastPrevious = previous;
50608          previous = $transition$.from;
50609
50610          $transition$.promise.then(commit)['catch'](revert);
50611        }
50612      });
50613
50614      var $previousState = {
50615        get: function (memoName) {
50616          return memoName ? memos[memoName] : previous;
50617        },
50618        set: function (memoName, previousState, previousParams) {
50619          memos[memoName] = { state: $state.get(previousState), params: previousParams };
50620        },
50621        go: function (memoName, options) {
50622          var to = $previousState.get(memoName);
50623          if (!to) {
50624            return $q.reject(new Error('no previous state ' + (memoName ? 'for memo: ' + memoName : '')));
50625          }
50626          return $state.go(to.state, to.params, options);
50627        },
50628        memo: function (memoName, defaultStateName, defaultStateParams) {
50629          memos[memoName] = previous || { state: $state.get(defaultStateName), params: defaultStateParams };
50630        },
50631        forget: function (memoName) {
50632          if (memoName) {
50633            delete memos[memoName];
50634          } else {
50635            previous = undefined;
50636          }
50637        }
50638      };
50639
50640      return $previousState;
50641    }
50642  ]
50643);
50644
50645angular.module('ct.ui.router.extras.previous').run(['$previousState', function ($previousState) {
50646  // Inject $previousState so it can register $rootScope events
50647}]);
50648
50649
50650angular.module("ct.ui.router.extras.transition", [ 'ct.ui.router.extras.core' ]).config( [ "$provide",  function ($provide) {
50651      // Decorate the $state service, so we can replace $state.transitionTo()
50652      $provide.decorator("$state", ['$delegate', '$rootScope', '$q', '$injector',
50653        function ($state, $rootScope, $q, $injector) {
50654          // Keep an internal reference to the real $state.transitionTo function
50655          var $state_transitionTo = $state.transitionTo;
50656          // $state.transitionTo can be re-entered.  Keep track of re-entrant stack
50657          var transitionDepth = -1;
50658          var tDataStack = [];
50659          var restoreFnStack = [];
50660
50661          // This function decorates the $injector, adding { $transition$: tData } to invoke() and instantiate() locals.
50662          // It returns a function that restores $injector to its previous state.
50663          function decorateInjector(tData) {
50664            var oldinvoke = $injector.invoke;
50665            var oldinstantiate = $injector.instantiate;
50666            $injector.invoke = function (fn, self, locals) {
50667              return oldinvoke(fn, self, angular.extend({$transition$: tData}, locals));
50668            };
50669            $injector.instantiate = function (fn, locals) {
50670              return oldinstantiate(fn, angular.extend({$transition$: tData}, locals));
50671            };
50672
50673            return function restoreItems() {
50674              $injector.invoke = oldinvoke;
50675              $injector.instantiate = oldinstantiate;
50676            };
50677          }
50678
50679          function popStack() {
50680            restoreFnStack.pop()();
50681            tDataStack.pop();
50682            transitionDepth--;
50683          }
50684
50685          // This promise callback (for when the real transitionTo is successful) runs the restore function for the
50686          // current stack level, then broadcasts the $transitionSuccess event.
50687          function transitionSuccess(deferred, tSuccess) {
50688            return function successFn(data) {
50689              popStack();
50690              $rootScope.$broadcast("$transitionSuccess", tSuccess);
50691              deferred.resolve(data); // $transition$ deferred
50692              return data;
50693            };
50694          }
50695
50696          // This promise callback (for when the real transitionTo fails) runs the restore function for the
50697          // current stack level, then broadcasts the $transitionError event.
50698          function transitionFailure(deferred, tFail) {
50699            return function failureFn(error) {
50700              popStack();
50701              $rootScope.$broadcast("$transitionError", tFail, error);
50702              deferred.reject(error);  // $transition$ deferred
50703              return $q.reject(error);
50704            };
50705          }
50706
50707          // Decorate $state.transitionTo.
50708          $state.transitionTo = function (to, toParams, options) {
50709            // Create a deferred/promise which can be used earlier than UI-Router's transition promise.
50710            var deferred = $q.defer();
50711            // Place the promise in a transition data, and place it on the stack to be used in $stateChangeStart
50712            var tData = tDataStack[++transitionDepth] = {
50713              promise: deferred.promise
50714            };
50715            // placeholder restoreFn in case transitionTo doesn't reach $stateChangeStart (state not found, etc)
50716            restoreFnStack[transitionDepth] = function() { };
50717            // Invoke the real $state.transitionTo
50718            var tPromise = $state_transitionTo.apply($state, arguments);
50719
50720            // insert our promise callbacks into the chain.
50721            return tPromise.then(transitionSuccess(deferred, tData), transitionFailure(deferred, tData));
50722          };
50723
50724          // This event is handled synchronously in transitionTo call stack
50725          $rootScope.$on("$stateChangeStart", function (evt, toState, toParams, fromState, fromParams) {
50726              if (transitionDepth >= tDataStack.length) return;
50727              var depth = transitionDepth;
50728              // To/From is now normalized by ui-router.  Add this information to the transition data object.
50729              var tData = angular.extend(tDataStack[depth], {
50730                to: { state: toState, params: toParams },
50731                from: { state: fromState, params: fromParams }
50732              });
50733
50734              var restoreFn = decorateInjector(tData);
50735              restoreFnStack[depth] = restoreFn;
50736              $rootScope.$broadcast("$transitionStart", tData);
50737            }
50738          );
50739
50740          return $state;
50741        }]);
50742    }
50743  ]
50744);
50745
50746// statevis requires d3.
50747(function () {
50748  "use strict";
50749  var app = angular.module("ct.ui.router.extras.statevis", [ 'ct.ui.router.extras.core', 'ct.ui.router.extras.sticky'  ]);
50750
50751  app.directive('stateVis', [ '$state', '$timeout', '$interval', stateVisDirective ]);
50752
50753  /**
50754   * This directive gets all the current states using $state.get() and displays them in a tree using D3 lib.
50755   * It then listens for state events and updates the tree.
50756   *
50757   * Usage:
50758   * <state-vis height="1000px" width="1000px"></state-vis>
50759   */
50760  function stateVisDirective($state, $timeout, $interval) {
50761    return {
50762      scope: {
50763        width: '@',
50764        height: '@'
50765      },
50766      restrict: 'AE',
50767      template: '<svg></svg>',
50768      link: function (_scope, _elem, _attrs) {
50769        var stateMap = {};
50770        var width = _scope.width || 400,
50771          height = _scope.height || 400;
50772
50773        var tree = d3.layout.tree()
50774            .size([width - 20, height - 20])
50775            .separation(function (a, b) {
50776              return a.parent == b.parent ? 10 : 25;
50777            });
50778
50779        var root = $state.get().filter(function (state) { return state.name === ""; })[0];
50780        var nodes = tree(root);
50781
50782        root.parent = root;
50783        root.px = root.x = width / 2;
50784        root.py = root.y = height / 2;
50785
50786        var activeNode = { };
50787        activeNode.px = activeNode.x = root.px;
50788        activeNode.py = activeNode.y = root.py;
50789
50790        var diagonal = d3.svg.diagonal();
50791
50792        var svg = d3.select(_elem.find("svg")[0])
50793          .attr("width", width)
50794          .attr("height", height)
50795          .append("g")
50796          .attr("transform", "translate(10, 10)");
50797
50798        var node = svg.selectAll(".node"),
50799          link = svg.selectAll(".link"),
50800          active = svg.selectAll(".active")
50801          ;
50802
50803        var updateInterval = 200,
50804          transLength = 200,
50805          timer = setInterval(update, updateInterval);
50806
50807        function addStates(data) {
50808          // *********** Convert flat data into a nice tree ***************
50809          data = data.map(function (node) {
50810            return node.name === "" ? root : angular.copy(node);
50811          });
50812          angular.extend(stateMap, data.reduce(function (map, node) {
50813            map[node.name] = node;
50814            return map;
50815          }, {}));
50816
50817          data.forEach(function (node) {
50818            // add to parent
50819            var parentName = node.name.split(/\./).slice(0, -1).join(".");
50820            var parent = node.name != parentName && stateMap[parentName];
50821            if (parent) {
50822              (parent.children || (parent.children = [])).push(node); // create child array if it doesn't exist
50823              node.px = parent.px;
50824              node.py = parent.py;
50825              nodes.push(node);
50826            }
50827          });
50828        }
50829
50830        $interval(function () {
50831          _scope.states = $state.get();
50832          angular.forEach(nodes, function (n) {
50833            var s = $state.get(n.name);
50834            if (s) {
50835              n.status = s.status || 'exited';
50836            }
50837          });
50838//          _scope.futureStates = $futureState.get();
50839        }, 250);
50840
50841        _scope.$watchCollection("states", function (newval, oldval) {
50842          var oldstates = (oldval || []).map(function (s) { return s.name; });
50843          addStates((newval || []).filter(function(state) { return oldstates.indexOf(state.name) == -1; } ));
50844//          addStates(_.reject(newval, function (state) { return _.contains(oldstates, state.name); }));
50845        });
50846
50847//        addStates($state.get());
50848        update(updateInterval);
50849
50850        function update() {
50851          // Recompute the layout and data join.
50852          node = node.data(tree.nodes(root), function (d) { return d.name; });
50853          link = link.data(tree.links(nodes), function (d) { return d.target.name; });
50854          active = active.data(activeNode);
50855
50856          nodes.forEach(function (d) { d.y = d.depth * 70; });
50857
50858          // Add entering nodes in the parent’s old position.
50859          var nodeEnter = node.enter();
50860
50861          function stateName(node) {
50862            var name = node.name.split(".").pop();
50863            if (node.sticky) { name += " (STICKY)"; }
50864            if (node.deepStateRedirect) { name += " (DSR)"; }
50865            return name;
50866          }
50867
50868          active.enter()
50869            .append("circle")
50870            .attr("class", "active")
50871            .attr("r", 13)
50872            .attr("cx", function (d) { return d.parent.px || 100; })
50873            .attr("cy", function (d) { return d.parent.py || 100; })
50874          ;
50875
50876          nodeEnter.append("circle")
50877            .attr("class", "node")
50878            .attr("r", 9)
50879            .attr("cx", function (d) { return d.parent.px; })
50880            .attr("cy", function (d) { return d.parent.py; });
50881
50882          nodeEnter.append("text")
50883            .attr("class", "label")
50884            .attr("x", function (d) { return d.parent.px; })
50885            .attr("y", function (d) { return d.parent.py; })
50886            .attr("text-anchor", function (d) { return "middle"; })
50887            .text(stateName)
50888            .style("fill-opacity", 1);
50889
50890
50891          // Add entering links in the parent’s old position.
50892          link.enter().insert("path", ".node")
50893            .attr("class", "link")
50894            .attr("d", function (d) {
50895              var o = {x: d.source.px, y: d.source.py};
50896              return diagonal({source: o, target: o});
50897            });
50898
50899          // Transition nodes and links to their new positions.
50900          var t = svg.transition()
50901            .duration(transLength);
50902
50903          t.selectAll(".link")
50904            .attr("d", diagonal);
50905
50906          /* jshint -W093 */
50907          var circleColors = { entered: '#AF0', exited: '#777', active: '#0f0', inactive: '#55F', future: '#009' };
50908          t.selectAll(".node")
50909            .attr("cx", function (d) { return d.px = d.x; })
50910            .attr("cy", function (d) { return d.py = d.y; })
50911            .attr("r", function (d) { return d.status === 'active' ? 15 : 10; })
50912            .style("fill", function (d) { return circleColors[d.status] || "#FFF"; });
50913
50914          t.selectAll(".label")
50915            .attr("x", function (d) { return d.px = d.x; })
50916            .attr("y", function (d) { return d.py = d.y - 15; })
50917            .attr("transform", function (d) { return "rotate(-25 " + d.x + " " + d.y + ")"; })
50918          ;
50919
50920          t.selectAll(".active")
50921            .attr("x", function (d) { return d.px = d.x; })
50922            .attr("y", function (d) { return d.py = d.y - 15; });
50923        }
50924      }
50925    };
50926  }
50927})();
50928
50929
50930angular.module("ct.ui.router.extras",
50931  [
50932    'ct.ui.router.extras.core',
50933    'ct.ui.router.extras.dsr',
50934    'ct.ui.router.extras.future',
50935    'ct.ui.router.extras.previous',
50936    'ct.ui.router.extras.statevis',
50937    'ct.ui.router.extras.sticky',
50938    'ct.ui.router.extras.transition'
50939  ]);
50940
50941
50942}));
50943},{"angular":5}],13:[function(require,module,exports){
50944require('angular');
50945require('angular-ui-router');
50946require('ui-router-extras');
50947require('angular-marked');
50948window.CodeMirror = require('codemirror');
50949require('codemirror/mode/css/css.js');
50950require('codemirror/mode/javascript/javascript.js');
50951require('codemirror/mode/xml/xml.js');
50952require('codemirror/mode/htmlmixed/htmlmixed.js');
50953},{"angular":5,"angular-marked":1,"angular-ui-router":3,"codemirror":6,"codemirror/mode/css/css.js":7,"codemirror/mode/htmlmixed/htmlmixed.js":8,"codemirror/mode/javascript/javascript.js":9,"codemirror/mode/xml/xml.js":10,"ui-router-extras":12}]},{},[13]);

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