pyc-website

main website for pyc inc.

git clone https://9o.is/git/pyc-website.git

ui-router.js

(116488B)


      1 /**
      2  * State-based routing for AngularJS
      3  * @version v0.2.10
      4  * @link http://angular-ui.github.com/
      5  * @license MIT License, http://www.opensource.org/licenses/MIT
      6  */
      7 
      8 /* commonjs package manager support (eg componentjs) */
      9 if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
     10   module.exports = 'ui.router';
     11 }
     12 
     13 (function (window, angular, undefined) {
     14 /*jshint globalstrict:true*/
     15 /*global angular:false*/
     16 'use strict';
     17 
     18 var isDefined = angular.isDefined,
     19     isFunction = angular.isFunction,
     20     isString = angular.isString,
     21     isObject = angular.isObject,
     22     isArray = angular.isArray,
     23     forEach = angular.forEach,
     24     extend = angular.extend,
     25     copy = angular.copy;
     26 
     27 function inherit(parent, extra) {
     28   return extend(new (extend(function() {}, { prototype: parent }))(), extra);
     29 }
     30 
     31 function merge(dst) {
     32   forEach(arguments, function(obj) {
     33     if (obj !== dst) {
     34       forEach(obj, function(value, key) {
     35         if (!dst.hasOwnProperty(key)) dst[key] = value;
     36       });
     37     }
     38   });
     39   return dst;
     40 }
     41 
     42 /**
     43  * Finds the common ancestor path between two states.
     44  *
     45  * @param {Object} first The first state.
     46  * @param {Object} second The second state.
     47  * @return {Array} Returns an array of state names in descending order, not including the root.
     48  */
     49 function ancestors(first, second) {
     50   var path = [];
     51 
     52   for (var n in first.path) {
     53     if (first.path[n] !== second.path[n]) break;
     54     path.push(first.path[n]);
     55   }
     56   return path;
     57 }
     58 
     59 /**
     60  * IE8-safe wrapper for `Object.keys()`.
     61  *
     62  * @param {Object} object A JavaScript object.
     63  * @return {Array} Returns the keys of the object as an array.
     64  */
     65 function keys(object) {
     66   if (Object.keys) {
     67     return Object.keys(object);
     68   }
     69   var result = [];
     70 
     71   angular.forEach(object, function(val, key) {
     72     result.push(key);
     73   });
     74   return result;
     75 }
     76 
     77 /**
     78  * IE8-safe wrapper for `Array.prototype.indexOf()`.
     79  *
     80  * @param {Array} array A JavaScript array.
     81  * @param {*} value A value to search the array for.
     82  * @return {Number} Returns the array index value of `value`, or `-1` if not present.
     83  */
     84 function arraySearch(array, value) {
     85   if (Array.prototype.indexOf) {
     86     return array.indexOf(value, Number(arguments[2]) || 0);
     87   }
     88   var len = array.length >>> 0, from = Number(arguments[2]) || 0;
     89   from = (from < 0) ? Math.ceil(from) : Math.floor(from);
     90 
     91   if (from < 0) from += len;
     92 
     93   for (; from < len; from++) {
     94     if (from in array && array[from] === value) return from;
     95   }
     96   return -1;
     97 }
     98 
     99 /**
    100  * Merges a set of parameters with all parameters inherited between the common parents of the
    101  * current state and a given destination state.
    102  *
    103  * @param {Object} currentParams The value of the current state parameters ($stateParams).
    104  * @param {Object} newParams The set of parameters which will be composited with inherited params.
    105  * @param {Object} $current Internal definition of object representing the current state.
    106  * @param {Object} $to Internal definition of object representing state to transition to.
    107  */
    108 function inheritParams(currentParams, newParams, $current, $to) {
    109   var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
    110 
    111   for (var i in parents) {
    112     if (!parents[i].params || !parents[i].params.length) continue;
    113     parentParams = parents[i].params;
    114 
    115     for (var j in parentParams) {
    116       if (arraySearch(inheritList, parentParams[j]) >= 0) continue;
    117       inheritList.push(parentParams[j]);
    118       inherited[parentParams[j]] = currentParams[parentParams[j]];
    119     }
    120   }
    121   return extend({}, inherited, newParams);
    122 }
    123 
    124 /**
    125  * Normalizes a set of values to string or `null`, filtering them by a list of keys.
    126  *
    127  * @param {Array} keys The list of keys to normalize/return.
    128  * @param {Object} values An object hash of values to normalize.
    129  * @return {Object} Returns an object hash of normalized string values.
    130  */
    131 function normalize(keys, values) {
    132   var normalized = {};
    133 
    134   forEach(keys, function (name) {
    135     var value = values[name];
    136     normalized[name] = (value != null) ? String(value) : null;
    137   });
    138   return normalized;
    139 }
    140 
    141 /**
    142  * Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
    143  *
    144  * @param {Object} a The first object.
    145  * @param {Object} b The second object.
    146  * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
    147  *                     it defaults to the list of keys in `a`.
    148  * @return {Boolean} Returns `true` if the keys match, otherwise `false`.
    149  */
    150 function equalForKeys(a, b, keys) {
    151   if (!keys) {
    152     keys = [];
    153     for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
    154   }
    155 
    156   for (var i=0; i<keys.length; i++) {
    157     var k = keys[i];
    158     if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
    159   }
    160   return true;
    161 }
    162 
    163 /**
    164  * Returns the subset of an object, based on a list of keys.
    165  *
    166  * @param {Array} keys
    167  * @param {Object} values
    168  * @return {Boolean} Returns a subset of `values`.
    169  */
    170 function filterByKeys(keys, values) {
    171   var filtered = {};
    172 
    173   forEach(keys, function (name) {
    174     filtered[name] = values[name];
    175   });
    176   return filtered;
    177 }
    178 /**
    179  * @ngdoc overview
    180  * @name ui.router.util
    181  *
    182  * @description
    183  * # ui.router.util sub-module
    184  *
    185  * This module is a dependency of other sub-modules. Do not include this module as a dependency
    186  * in your angular app (use {@link ui.router} module instead).
    187  *
    188  */
    189 angular.module('ui.router.util', ['ng']);
    190 
    191 /**
    192  * @ngdoc overview
    193  * @name ui.router.router
    194  * 
    195  * @requires ui.router.util
    196  *
    197  * @description
    198  * # ui.router.router sub-module
    199  *
    200  * This module is a dependency of other sub-modules. Do not include this module as a dependency
    201  * in your angular app (use {@link ui.router} module instead).
    202  */
    203 angular.module('ui.router.router', ['ui.router.util']);
    204 
    205 /**
    206  * @ngdoc overview
    207  * @name ui.router.state
    208  * 
    209  * @requires ui.router.router
    210  * @requires ui.router.util
    211  *
    212  * @description
    213  * # ui.router.state sub-module
    214  *
    215  * This module is a dependency of the main ui.router module. Do not include this module as a dependency
    216  * in your angular app (use {@link ui.router} module instead).
    217  * 
    218  */
    219 angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
    220 
    221 /**
    222  * @ngdoc overview
    223  * @name ui.router
    224  *
    225  * @requires ui.router.state
    226  *
    227  * @description
    228  * # ui.router
    229  * 
    230  * ## The main module for ui.router 
    231  * There are several sub-modules included with the ui.router module, however only this module is needed
    232  * as a dependency within your angular app. The other modules are for organization purposes. 
    233  *
    234  * The modules are:
    235  * * ui.router - the main "umbrella" module
    236  * * ui.router.router - 
    237  * 
    238  * *You'll need to include **only** this module as the dependency within your angular app.*
    239  * 
    240  * <pre>
    241  * <!doctype html>
    242  * <html ng-app="myApp">
    243  * <head>
    244  *   <script src="js/angular.js"></script>
    245  *   <!-- Include the ui-router script -->
    246  *   <script src="js/angular-ui-router.min.js"></script>
    247  *   <script>
    248  *     // ...and add 'ui.router' as a dependency
    249  *     var myApp = angular.module('myApp', ['ui.router']);
    250  *   </script>
    251  * </head>
    252  * <body>
    253  * </body>
    254  * </html>
    255  * </pre>
    256  */
    257 angular.module('ui.router', ['ui.router.state']);
    258 
    259 angular.module('ui.router.compat', ['ui.router']);
    260 
    261 /**
    262  * @ngdoc object
    263  * @name ui.router.util.$resolve
    264  *
    265  * @requires $q
    266  * @requires $injector
    267  *
    268  * @description
    269  * Manages resolution of (acyclic) graphs of promises.
    270  */
    271 $Resolve.$inject = ['$q', '$injector'];
    272 function $Resolve(  $q,    $injector) {
    273   
    274   var VISIT_IN_PROGRESS = 1,
    275       VISIT_DONE = 2,
    276       NOTHING = {},
    277       NO_DEPENDENCIES = [],
    278       NO_LOCALS = NOTHING,
    279       NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
    280   
    281 
    282   /**
    283    * @ngdoc function
    284    * @name ui.router.util.$resolve#study
    285    * @methodOf ui.router.util.$resolve
    286    *
    287    * @description
    288    * Studies a set of invocables that are likely to be used multiple times.
    289    * <pre>
    290    * $resolve.study(invocables)(locals, parent, self)
    291    * </pre>
    292    * is equivalent to
    293    * <pre>
    294    * $resolve.resolve(invocables, locals, parent, self)
    295    * </pre>
    296    * but the former is more efficient (in fact `resolve` just calls `study` 
    297    * internally).
    298    *
    299    * @param {object} invocables Invocable objects
    300    * @return {function} a function to pass in locals, parent and self
    301    */
    302   this.study = function (invocables) {
    303     if (!isObject(invocables)) throw new Error("'invocables' must be an object");
    304     
    305     // Perform a topological sort of invocables to build an ordered plan
    306     var plan = [], cycle = [], visited = {};
    307     function visit(value, key) {
    308       if (visited[key] === VISIT_DONE) return;
    309       
    310       cycle.push(key);
    311       if (visited[key] === VISIT_IN_PROGRESS) {
    312         cycle.splice(0, cycle.indexOf(key));
    313         throw new Error("Cyclic dependency: " + cycle.join(" -> "));
    314       }
    315       visited[key] = VISIT_IN_PROGRESS;
    316       
    317       if (isString(value)) {
    318         plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
    319       } else {
    320         var params = $injector.annotate(value);
    321         forEach(params, function (param) {
    322           if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
    323         });
    324         plan.push(key, value, params);
    325       }
    326       
    327       cycle.pop();
    328       visited[key] = VISIT_DONE;
    329     }
    330     forEach(invocables, visit);
    331     invocables = cycle = visited = null; // plan is all that's required
    332     
    333     function isResolve(value) {
    334       return isObject(value) && value.then && value.$$promises;
    335     }
    336     
    337     return function (locals, parent, self) {
    338       if (isResolve(locals) && self === undefined) {
    339         self = parent; parent = locals; locals = null;
    340       }
    341       if (!locals) locals = NO_LOCALS;
    342       else if (!isObject(locals)) {
    343         throw new Error("'locals' must be an object");
    344       }       
    345       if (!parent) parent = NO_PARENT;
    346       else if (!isResolve(parent)) {
    347         throw new Error("'parent' must be a promise returned by $resolve.resolve()");
    348       }
    349       
    350       // To complete the overall resolution, we have to wait for the parent
    351       // promise and for the promise for each invokable in our plan.
    352       var resolution = $q.defer(),
    353           result = resolution.promise,
    354           promises = result.$$promises = {},
    355           values = extend({}, locals),
    356           wait = 1 + plan.length/3,
    357           merged = false;
    358           
    359       function done() {
    360         // Merge parent values we haven't got yet and publish our own $$values
    361         if (!--wait) {
    362           if (!merged) merge(values, parent.$$values); 
    363           result.$$values = values;
    364           result.$$promises = true; // keep for isResolve()
    365           resolution.resolve(values);
    366         }
    367       }
    368       
    369       function fail(reason) {
    370         result.$$failure = reason;
    371         resolution.reject(reason);
    372       }
    373       
    374       // Short-circuit if parent has already failed
    375       if (isDefined(parent.$$failure)) {
    376         fail(parent.$$failure);
    377         return result;
    378       }
    379       
    380       // Merge parent values if the parent has already resolved, or merge
    381       // parent promises and wait if the parent resolve is still in progress.
    382       if (parent.$$values) {
    383         merged = merge(values, parent.$$values);
    384         done();
    385       } else {
    386         extend(promises, parent.$$promises);
    387         parent.then(done, fail);
    388       }
    389       
    390       // Process each invocable in the plan, but ignore any where a local of the same name exists.
    391       for (var i=0, ii=plan.length; i<ii; i+=3) {
    392         if (locals.hasOwnProperty(plan[i])) done();
    393         else invoke(plan[i], plan[i+1], plan[i+2]);
    394       }
    395       
    396       function invoke(key, invocable, params) {
    397         // Create a deferred for this invocation. Failures will propagate to the resolution as well.
    398         var invocation = $q.defer(), waitParams = 0;
    399         function onfailure(reason) {
    400           invocation.reject(reason);
    401           fail(reason);
    402         }
    403         // Wait for any parameter that we have a promise for (either from parent or from this
    404         // resolve; in that case study() will have made sure it's ordered before us in the plan).
    405         forEach(params, function (dep) {
    406           if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
    407             waitParams++;
    408             promises[dep].then(function (result) {
    409               values[dep] = result;
    410               if (!(--waitParams)) proceed();
    411             }, onfailure);
    412           }
    413         });
    414         if (!waitParams) proceed();
    415         function proceed() {
    416           if (isDefined(result.$$failure)) return;
    417           try {
    418             invocation.resolve($injector.invoke(invocable, self, values));
    419             invocation.promise.then(function (result) {
    420               values[key] = result;
    421               done();
    422             }, onfailure);
    423           } catch (e) {
    424             onfailure(e);
    425           }
    426         }
    427         // Publish promise synchronously; invocations further down in the plan may depend on it.
    428         promises[key] = invocation.promise;
    429       }
    430       
    431       return result;
    432     };
    433   };
    434   
    435   /**
    436    * @ngdoc function
    437    * @name ui.router.util.$resolve#resolve
    438    * @methodOf ui.router.util.$resolve
    439    *
    440    * @description
    441    * Resolves a set of invocables. An invocable is a function to be invoked via 
    442    * `$injector.invoke()`, and can have an arbitrary number of dependencies. 
    443    * An invocable can either return a value directly,
    444    * or a `$q` promise. If a promise is returned it will be resolved and the 
    445    * resulting value will be used instead. Dependencies of invocables are resolved 
    446    * (in this order of precedence)
    447    *
    448    * - from the specified `locals`
    449    * - from another invocable that is part of this `$resolve` call
    450    * - from an invocable that is inherited from a `parent` call to `$resolve` 
    451    *   (or recursively
    452    * - from any ancestor `$resolve` of that parent).
    453    *
    454    * The return value of `$resolve` is a promise for an object that contains 
    455    * (in this order of precedence)
    456    *
    457    * - any `locals` (if specified)
    458    * - the resolved return values of all injectables
    459    * - any values inherited from a `parent` call to `$resolve` (if specified)
    460    *
    461    * The promise will resolve after the `parent` promise (if any) and all promises 
    462    * returned by injectables have been resolved. If any invocable 
    463    * (or `$injector.invoke`) throws an exception, or if a promise returned by an 
    464    * invocable is rejected, the `$resolve` promise is immediately rejected with the 
    465    * same error. A rejection of a `parent` promise (if specified) will likewise be 
    466    * propagated immediately. Once the `$resolve` promise has been rejected, no 
    467    * further invocables will be called.
    468    * 
    469    * Cyclic dependencies between invocables are not permitted and will caues `$resolve`
    470    * to throw an error. As a special case, an injectable can depend on a parameter 
    471    * with the same name as the injectable, which will be fulfilled from the `parent` 
    472    * injectable of the same name. This allows inherited values to be decorated. 
    473    * Note that in this case any other injectable in the same `$resolve` with the same
    474    * dependency would see the decorated value, not the inherited value.
    475    *
    476    * Note that missing dependencies -- unlike cyclic dependencies -- will cause an 
    477    * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous) 
    478    * exception.
    479    *
    480    * Invocables are invoked eagerly as soon as all dependencies are available. 
    481    * This is true even for dependencies inherited from a `parent` call to `$resolve`.
    482    *
    483    * As a special case, an invocable can be a string, in which case it is taken to 
    484    * be a service name to be passed to `$injector.get()`. This is supported primarily 
    485    * for backwards-compatibility with the `resolve` property of `$routeProvider` 
    486    * routes.
    487    *
    488    * @param {object} invocables functions to invoke or 
    489    * `$injector` services to fetch.
    490    * @param {object} locals  values to make available to the injectables
    491    * @param {object} parent  a promise returned by another call to `$resolve`.
    492    * @param {object} self  the `this` for the invoked methods
    493    * @return {object} Promise for an object that contains the resolved return value
    494    * of all invocables, as well as any inherited and local values.
    495    */
    496   this.resolve = function (invocables, locals, parent, self) {
    497     return this.study(invocables)(locals, parent, self);
    498   };
    499 }
    500 
    501 angular.module('ui.router.util').service('$resolve', $Resolve);
    502 
    503 
    504 /**
    505  * @ngdoc object
    506  * @name ui.router.util.$templateFactory
    507  *
    508  * @requires $http
    509  * @requires $templateCache
    510  * @requires $injector
    511  *
    512  * @description
    513  * Service. Manages loading of templates.
    514  */
    515 $TemplateFactory.$inject = ['$http', '$templateCache', '$injector'];
    516 function $TemplateFactory(  $http,   $templateCache,   $injector) {
    517 
    518   /**
    519    * @ngdoc function
    520    * @name ui.router.util.$templateFactory#fromConfig
    521    * @methodOf ui.router.util.$templateFactory
    522    *
    523    * @description
    524    * Creates a template from a configuration object. 
    525    *
    526    * @param {object} config Configuration object for which to load a template. 
    527    * The following properties are search in the specified order, and the first one 
    528    * that is defined is used to create the template:
    529    *
    530    * @param {string|object} config.template html string template or function to 
    531    * load via {@link ui.router.util.$templateFactory#fromString fromString}.
    532    * @param {string|object} config.templateUrl url to load or a function returning 
    533    * the url to load via {@link ui.router.util.$templateFactory#fromUrl fromUrl}.
    534    * @param {Function} config.templateProvider function to invoke via 
    535    * {@link ui.router.util.$templateFactory#fromProvider fromProvider}.
    536    * @param {object} params  Parameters to pass to the template function.
    537    * @param {object} locals Locals to pass to `invoke` if the template is loaded 
    538    * via a `templateProvider`. Defaults to `{ params: params }`.
    539    *
    540    * @return {string|object}  The template html as a string, or a promise for 
    541    * that string,or `null` if no template is configured.
    542    */
    543   this.fromConfig = function (config, params, locals) {
    544     return (
    545       isDefined(config.template) ? this.fromString(config.template, params) :
    546       isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
    547       isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
    548       null
    549     );
    550   };
    551 
    552   /**
    553    * @ngdoc function
    554    * @name ui.router.util.$templateFactory#fromString
    555    * @methodOf ui.router.util.$templateFactory
    556    *
    557    * @description
    558    * Creates a template from a string or a function returning a string.
    559    *
    560    * @param {string|object} template html template as a string or function that 
    561    * returns an html template as a string.
    562    * @param {object} params Parameters to pass to the template function.
    563    *
    564    * @return {string|object} The template html as a string, or a promise for that 
    565    * string.
    566    */
    567   this.fromString = function (template, params) {
    568     return isFunction(template) ? template(params) : template;
    569   };
    570 
    571   /**
    572    * @ngdoc function
    573    * @name ui.router.util.$templateFactory#fromUrl
    574    * @methodOf ui.router.util.$templateFactory
    575    * 
    576    * @description
    577    * Loads a template from the a URL via `$http` and `$templateCache`.
    578    *
    579    * @param {string|Function} url url of the template to load, or a function 
    580    * that returns a url.
    581    * @param {Object} params Parameters to pass to the url function.
    582    * @return {string|Promise.<string>} The template html as a string, or a promise 
    583    * for that string.
    584    */
    585   this.fromUrl = function (url, params) {
    586     if (isFunction(url)) url = url(params);
    587     if (url == null) return null;
    588     else return $http
    589         .get(url, { cache: $templateCache })
    590         .then(function(response) { return response.data; });
    591   };
    592 
    593   /**
    594    * @ngdoc function
    595    * @name ui.router.util.$templateFactory#fromUrl
    596    * @methodOf ui.router.util.$templateFactory
    597    *
    598    * @description
    599    * Creates a template by invoking an injectable provider function.
    600    *
    601    * @param {Function} provider Function to invoke via `$injector.invoke`
    602    * @param {Object} params Parameters for the template.
    603    * @param {Object} locals Locals to pass to `invoke`. Defaults to 
    604    * `{ params: params }`.
    605    * @return {string|Promise.<string>} The template html as a string, or a promise 
    606    * for that string.
    607    */
    608   this.fromProvider = function (provider, params, locals) {
    609     return $injector.invoke(provider, null, locals || { params: params });
    610   };
    611 }
    612 
    613 angular.module('ui.router.util').service('$templateFactory', $TemplateFactory);
    614 
    615 /**
    616  * @ngdoc object
    617  * @name ui.router.util.type:UrlMatcher
    618  *
    619  * @description
    620  * Matches URLs against patterns and extracts named parameters from the path or the search
    621  * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
    622  * of search parameters. Multiple search parameter names are separated by '&'. Search parameters
    623  * do not influence whether or not a URL is matched, but their values are passed through into
    624  * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.
    625  * 
    626  * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
    627  * syntax, which optionally allows a regular expression for the parameter to be specified:
    628  *
    629  * * `':'` name - colon placeholder
    630  * * `'*'` name - catch-all placeholder
    631  * * `'{' name '}'` - curly placeholder
    632  * * `'{' name ':' regexp '}'` - curly placeholder with regexp. Should the regexp itself contain
    633  *   curly braces, they must be in matched pairs or escaped with a backslash.
    634  *
    635  * Parameter names may contain only word characters (latin letters, digits, and underscore) and
    636  * must be unique within the pattern (across both path and search parameters). For colon 
    637  * placeholders or curly placeholders without an explicit regexp, a path parameter matches any
    638  * number of characters other than '/'. For catch-all placeholders the path parameter matches
    639  * any number of characters.
    640  * 
    641  * Examples:
    642  * 
    643  * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
    644  *   trailing slashes, and patterns have to match the entire path, not just a prefix.
    645  * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
    646  *   '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
    647  * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
    648  * * `'/user/{id:[^/]*}'` - Same as the previous example.
    649  * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
    650  *   parameter consists of 1 to 8 hex digits.
    651  * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
    652  *   path into the parameter 'path'.
    653  * * `'/files/*path'` - ditto.
    654  *
    655  * @param {string} pattern  the pattern to compile into a matcher.
    656  *
    657  * @property {string} prefix  A static prefix of this pattern. The matcher guarantees that any
    658  *   URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns
    659  *   non-null) will start with this prefix.
    660  *
    661  * @property {string} source  The pattern that was passed into the contructor
    662  *
    663  * @property {string} sourcePath  The path portion of the source property
    664  *
    665  * @property {string} sourceSearch  The search portion of the source property
    666  *
    667  * @property {string} regex  The constructed regex that will be used to match against the url when 
    668  *   it is time to determine which url will match.
    669  *
    670  * @returns {Object}  New UrlMatcher object
    671  */
    672 function UrlMatcher(pattern) {
    673 
    674   // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
    675   //   '*' name
    676   //   ':' name
    677   //   '{' name '}'
    678   //   '{' name ':' regexp '}'
    679   // The regular expression is somewhat complicated due to the need to allow curly braces
    680   // inside the regular expression. The placeholder regexp breaks down as follows:
    681   //    ([:*])(\w+)               classic placeholder ($1 / $2)
    682   //    \{(\w+)(?:\:( ... ))?\}   curly brace placeholder ($3) with optional regexp ... ($4)
    683   //    (?: ... | ... | ... )+    the regexp consists of any number of atoms, an atom being either
    684   //    [^{}\\]+                  - anything other than curly braces or backslash
    685   //    \\.                       - a backslash escape
    686   //    \{(?:[^{}\\]+|\\.)*\}     - a matched set of curly braces containing other atoms
    687   var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
    688       names = {}, compiled = '^', last = 0, m,
    689       segments = this.segments = [],
    690       params = this.params = [];
    691 
    692   function addParameter(id) {
    693     if (!/^\w+(-+\w+)*$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
    694     if (names[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
    695     names[id] = true;
    696     params.push(id);
    697   }
    698 
    699   function quoteRegExp(string) {
    700     return string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
    701   }
    702 
    703   this.source = pattern;
    704 
    705   // Split into static segments separated by path parameter placeholders.
    706   // The number of segments is always 1 more than the number of parameters.
    707   var id, regexp, segment;
    708   while ((m = placeholder.exec(pattern))) {
    709     id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
    710     regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*');
    711     segment = pattern.substring(last, m.index);
    712     if (segment.indexOf('?') >= 0) break; // we're into the search part
    713     compiled += quoteRegExp(segment) + '(' + regexp + ')';
    714     addParameter(id);
    715     segments.push(segment);
    716     last = placeholder.lastIndex;
    717   }
    718   segment = pattern.substring(last);
    719 
    720   // Find any search parameter names and remove them from the last segment
    721   var i = segment.indexOf('?');
    722   if (i >= 0) {
    723     var search = this.sourceSearch = segment.substring(i);
    724     segment = segment.substring(0, i);
    725     this.sourcePath = pattern.substring(0, last+i);
    726 
    727     // Allow parameters to be separated by '?' as well as '&' to make concat() easier
    728     forEach(search.substring(1).split(/[&?]/), addParameter);
    729   } else {
    730     this.sourcePath = pattern;
    731     this.sourceSearch = '';
    732   }
    733 
    734   compiled += quoteRegExp(segment) + '$';
    735   segments.push(segment);
    736   this.regexp = new RegExp(compiled);
    737   this.prefix = segments[0];
    738 }
    739 
    740 /**
    741  * @ngdoc function
    742  * @name ui.router.util.type:UrlMatcher#concat
    743  * @methodOf ui.router.util.type:UrlMatcher
    744  *
    745  * @description
    746  * Returns a new matcher for a pattern constructed by appending the path part and adding the
    747  * search parameters of the specified pattern to this pattern. The current pattern is not
    748  * modified. This can be understood as creating a pattern for URLs that are relative to (or
    749  * suffixes of) the current pattern.
    750  *
    751  * @example
    752  * The following two matchers are equivalent:
    753  * ```
    754  * new UrlMatcher('/user/{id}?q').concat('/details?date');
    755  * new UrlMatcher('/user/{id}/details?q&date');
    756  * ```
    757  *
    758  * @param {string} pattern  The pattern to append.
    759  * @returns {ui.router.util.type:UrlMatcher}  A matcher for the concatenated pattern.
    760  */
    761 UrlMatcher.prototype.concat = function (pattern) {
    762   // Because order of search parameters is irrelevant, we can add our own search
    763   // parameters to the end of the new pattern. Parse the new pattern by itself
    764   // and then join the bits together, but it's much easier to do this on a string level.
    765   return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch);
    766 };
    767 
    768 UrlMatcher.prototype.toString = function () {
    769   return this.source;
    770 };
    771 
    772 /**
    773  * @ngdoc function
    774  * @name ui.router.util.type:UrlMatcher#exec
    775  * @methodOf ui.router.util.type:UrlMatcher
    776  *
    777  * @description
    778  * Tests the specified path against this matcher, and returns an object containing the captured
    779  * parameter values, or null if the path does not match. The returned object contains the values
    780  * of any search parameters that are mentioned in the pattern, but their value may be null if
    781  * they are not present in `searchParams`. This means that search parameters are always treated
    782  * as optional.
    783  *
    784  * @example
    785  * ```
    786  * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', { x:'1', q:'hello' });
    787  * // returns { id:'bob', q:'hello', r:null }
    788  * ```
    789  *
    790  * @param {string} path  The URL path to match, e.g. `$location.path()`.
    791  * @param {Object} searchParams  URL search parameters, e.g. `$location.search()`.
    792  * @returns {Object}  The captured parameter values.
    793  */
    794 UrlMatcher.prototype.exec = function (path, searchParams) {
    795   var m = this.regexp.exec(path);
    796   if (!m) return null;
    797 
    798   var params = this.params, nTotal = params.length,
    799     nPath = this.segments.length-1,
    800     values = {}, i;
    801 
    802   if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
    803 
    804   for (i=0; i<nPath; i++) values[params[i]] = m[i+1];
    805   for (/**/; i<nTotal; i++) values[params[i]] = searchParams[params[i]];
    806 
    807   return values;
    808 };
    809 
    810 /**
    811  * @ngdoc function
    812  * @name ui.router.util.type:UrlMatcher#parameters
    813  * @methodOf ui.router.util.type:UrlMatcher
    814  *
    815  * @description
    816  * Returns the names of all path and search parameters of this pattern in an unspecified order.
    817  * 
    818  * @returns {Array.<string>}  An array of parameter names. Must be treated as read-only. If the
    819  *    pattern has no parameters, an empty array is returned.
    820  */
    821 UrlMatcher.prototype.parameters = function () {
    822   return this.params;
    823 };
    824 
    825 /**
    826  * @ngdoc function
    827  * @name ui.router.util.type:UrlMatcher#format
    828  * @methodOf ui.router.util.type:UrlMatcher
    829  *
    830  * @description
    831  * Creates a URL that matches this pattern by substituting the specified values
    832  * for the path and search parameters. Null values for path parameters are
    833  * treated as empty strings.
    834  *
    835  * @example
    836  * ```
    837  * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
    838  * // returns '/user/bob?q=yes'
    839  * ```
    840  *
    841  * @param {Object} values  the values to substitute for the parameters in this pattern.
    842  * @returns {string}  the formatted URL (path and optionally search part).
    843  */
    844 UrlMatcher.prototype.format = function (values) {
    845   var segments = this.segments, params = this.params;
    846   if (!values) return segments.join('');
    847 
    848   var nPath = segments.length-1, nTotal = params.length,
    849     result = segments[0], i, search, value;
    850 
    851   for (i=0; i<nPath; i++) {
    852     value = values[params[i]];
    853     // TODO: Maybe we should throw on null here? It's not really good style to use '' and null interchangeabley
    854     if (value != null) result += encodeURIComponent(value);
    855     result += segments[i+1];
    856   }
    857   for (/**/; i<nTotal; i++) {
    858     value = values[params[i]];
    859     if (value != null) {
    860       result += (search ? '&' : '?') + params[i] + '=' + encodeURIComponent(value);
    861       search = true;
    862     }
    863   }
    864 
    865   return result;
    866 };
    867 
    868 
    869 
    870 /**
    871  * @ngdoc object
    872  * @name ui.router.util.$urlMatcherFactory
    873  *
    874  * @description
    875  * Factory for {@link ui.router.util.type:UrlMatcher} instances. The factory is also available to providers
    876  * under the name `$urlMatcherFactoryProvider`.
    877  */
    878 function $UrlMatcherFactory() {
    879 
    880   /**
    881    * @ngdoc function
    882    * @name ui.router.util.$urlMatcherFactory#compile
    883    * @methodOf ui.router.util.$urlMatcherFactory
    884    *
    885    * @description
    886    * Creates a {@link ui.router.util.type:UrlMatcher} for the specified pattern.
    887    *   
    888    * @param {string} pattern  The URL pattern.
    889    * @returns {ui.router.util.type:UrlMatcher}  The UrlMatcher.
    890    */
    891   this.compile = function (pattern) {
    892     return new UrlMatcher(pattern);
    893   };
    894 
    895   /**
    896    * @ngdoc function
    897    * @name ui.router.util.$urlMatcherFactory#isMatcher
    898    * @methodOf ui.router.util.$urlMatcherFactory
    899    *
    900    * @description
    901    * Returns true if the specified object is a UrlMatcher, or false otherwise.
    902    *
    903    * @param {Object} object  The object to perform the type check against.
    904    * @returns {Boolean}  Returns `true` if the object has the following functions: `exec`, `format`, and `concat`.
    905    */
    906   this.isMatcher = function (o) {
    907     return isObject(o) && isFunction(o.exec) && isFunction(o.format) && isFunction(o.concat);
    908   };
    909   
    910   /* No need to document $get, since it returns this */
    911   this.$get = function () {
    912     return this;
    913   };
    914 }
    915 
    916 // Register as a provider so it's available to other providers
    917 angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
    918 
    919 /**
    920  * @ngdoc object
    921  * @name ui.router.router.$urlRouterProvider
    922  *
    923  * @requires ui.router.util.$urlMatcherFactoryProvider
    924  *
    925  * @description
    926  * `$urlRouterProvider` has the responsibility of watching `$location`. 
    927  * When `$location` changes it runs through a list of rules one by one until a 
    928  * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify 
    929  * a url in a state configuration. All urls are compiled into a UrlMatcher object.
    930  *
    931  * There are several methods on `$urlRouterProvider` that make it useful to use directly
    932  * in your module config.
    933  */
    934 $UrlRouterProvider.$inject = ['$urlMatcherFactoryProvider'];
    935 function $UrlRouterProvider(  $urlMatcherFactory) {
    936   var rules = [], 
    937       otherwise = null;
    938 
    939   // Returns a string that is a prefix of all strings matching the RegExp
    940   function regExpPrefix(re) {
    941     var prefix = /^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(re.source);
    942     return (prefix != null) ? prefix[1].replace(/\\(.)/g, "$1") : '';
    943   }
    944 
    945   // Interpolates matched values into a String.replace()-style pattern
    946   function interpolate(pattern, match) {
    947     return pattern.replace(/\$(\$|\d{1,2})/, function (m, what) {
    948       return match[what === '$' ? 0 : Number(what)];
    949     });
    950   }
    951 
    952   /**
    953    * @ngdoc function
    954    * @name ui.router.router.$urlRouterProvider#rule
    955    * @methodOf ui.router.router.$urlRouterProvider
    956    *
    957    * @description
    958    * Defines rules that are used by `$urlRouterProvider to find matches for
    959    * specific URLs.
    960    *
    961    * @example
    962    * <pre>
    963    * var app = angular.module('app', ['ui.router.router']);
    964    *
    965    * app.config(function ($urlRouterProvider) {
    966    *   // Here's an example of how you might allow case insensitive urls
    967    *   $urlRouterProvider.rule(function ($injector, $location) {
    968    *     var path = $location.path(),
    969    *         normalized = path.toLowerCase();
    970    *
    971    *     if (path !== normalized) {
    972    *       return normalized;
    973    *     }
    974    *   });
    975    * });
    976    * </pre>
    977    *
    978    * @param {object} rule Handler function that takes `$injector` and `$location`
    979    * services as arguments. You can use them to return a valid path as a string.
    980    *
    981    * @return {object} $urlRouterProvider - $urlRouterProvider instance
    982    */
    983   this.rule =
    984     function (rule) {
    985       if (!isFunction(rule)) throw new Error("'rule' must be a function");
    986       rules.push(rule);
    987       return this;
    988     };
    989 
    990   /**
    991    * @ngdoc object
    992    * @name ui.router.router.$urlRouterProvider#otherwise
    993    * @methodOf ui.router.router.$urlRouterProvider
    994    *
    995    * @description
    996    * Defines a path that is used when an invalied route is requested.
    997    *
    998    * @example
    999    * <pre>
   1000    * var app = angular.module('app', ['ui.router.router']);
   1001    *
   1002    * app.config(function ($urlRouterProvider) {
   1003    *   // if the path doesn't match any of the urls you configured
   1004    *   // otherwise will take care of routing the user to the
   1005    *   // specified url
   1006    *   $urlRouterProvider.otherwise('/index');
   1007    *
   1008    *   // Example of using function rule as param
   1009    *   $urlRouterProvider.otherwise(function ($injector, $location) {
   1010    *     ...
   1011    *   });
   1012    * });
   1013    * </pre>
   1014    *
   1015    * @param {string|object} rule The url path you want to redirect to or a function 
   1016    * rule that returns the url path. The function version is passed two params: 
   1017    * `$injector` and `$location` services.
   1018    *
   1019    * @return {object} $urlRouterProvider - $urlRouterProvider instance
   1020    */
   1021   this.otherwise =
   1022     function (rule) {
   1023       if (isString(rule)) {
   1024         var redirect = rule;
   1025         rule = function () { return redirect; };
   1026       }
   1027       else if (!isFunction(rule)) throw new Error("'rule' must be a function");
   1028       otherwise = rule;
   1029       return this;
   1030     };
   1031 
   1032 
   1033   function handleIfMatch($injector, handler, match) {
   1034     if (!match) return false;
   1035     var result = $injector.invoke(handler, handler, { $match: match });
   1036     return isDefined(result) ? result : true;
   1037   }
   1038 
   1039   /**
   1040    * @ngdoc function
   1041    * @name ui.router.router.$urlRouterProvider#when
   1042    * @methodOf ui.router.router.$urlRouterProvider
   1043    *
   1044    * @description
   1045    * Registers a handler for a given url matching. if handle is a string, it is
   1046    * treated as a redirect, and is interpolated according to the syyntax of match
   1047    * (i.e. like String.replace() for RegExp, or like a UrlMatcher pattern otherwise).
   1048    *
   1049    * If the handler is a function, it is injectable. It gets invoked if `$location`
   1050    * matches. You have the option of inject the match object as `$match`.
   1051    *
   1052    * The handler can return
   1053    *
   1054    * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter`
   1055    *   will continue trying to find another one that matches.
   1056    * - **string** which is treated as a redirect and passed to `$location.url()`
   1057    * - **void** or any **truthy** value tells `$urlRouter` that the url was handled.
   1058    *
   1059    * @example
   1060    * <pre>
   1061    * var app = angular.module('app', ['ui.router.router']);
   1062    *
   1063    * app.config(function ($urlRouterProvider) {
   1064    *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
   1065    *     if ($state.$current.navigable !== state ||
   1066    *         !equalForKeys($match, $stateParams) {
   1067    *      $state.transitionTo(state, $match, false);
   1068    *     }
   1069    *   });
   1070    * });
   1071    * </pre>
   1072    *
   1073    * @param {string|object} what The incoming path that you want to redirect.
   1074    * @param {string|object} handler The path you want to redirect your user to.
   1075    */
   1076   this.when =
   1077     function (what, handler) {
   1078       var redirect, handlerIsString = isString(handler);
   1079       if (isString(what)) what = $urlMatcherFactory.compile(what);
   1080 
   1081       if (!handlerIsString && !isFunction(handler) && !isArray(handler))
   1082         throw new Error("invalid 'handler' in when()");
   1083 
   1084       var strategies = {
   1085         matcher: function (what, handler) {
   1086           if (handlerIsString) {
   1087             redirect = $urlMatcherFactory.compile(handler);
   1088             handler = ['$match', function ($match) { return redirect.format($match); }];
   1089           }
   1090           return extend(function ($injector, $location) {
   1091             return handleIfMatch($injector, handler, what.exec($location.path(), $location.search()));
   1092           }, {
   1093             prefix: isString(what.prefix) ? what.prefix : ''
   1094           });
   1095         },
   1096         regex: function (what, handler) {
   1097           if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky");
   1098 
   1099           if (handlerIsString) {
   1100             redirect = handler;
   1101             handler = ['$match', function ($match) { return interpolate(redirect, $match); }];
   1102           }
   1103           return extend(function ($injector, $location) {
   1104             return handleIfMatch($injector, handler, what.exec($location.path()));
   1105           }, {
   1106             prefix: regExpPrefix(what)
   1107           });
   1108         }
   1109       };
   1110 
   1111       var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp };
   1112 
   1113       for (var n in check) {
   1114         if (check[n]) {
   1115           return this.rule(strategies[n](what, handler));
   1116         }
   1117       }
   1118 
   1119       throw new Error("invalid 'what' in when()");
   1120     };
   1121 
   1122   /**
   1123    * @ngdoc object
   1124    * @name ui.router.router.$urlRouter
   1125    *
   1126    * @requires $location
   1127    * @requires $rootScope
   1128    * @requires $injector
   1129    *
   1130    * @description
   1131    *
   1132    */
   1133   this.$get =
   1134     [        '$location', '$rootScope', '$injector',
   1135     function ($location,   $rootScope,   $injector) {
   1136       // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree
   1137       function update(evt) {
   1138         if (evt && evt.defaultPrevented) return;
   1139         function check(rule) {
   1140           var handled = rule($injector, $location);
   1141           if (handled) {
   1142             if (isString(handled)) $location.replace().url(handled);
   1143             return true;
   1144           }
   1145           return false;
   1146         }
   1147         var n=rules.length, i;
   1148         for (i=0; i<n; i++) {
   1149           if (check(rules[i])) return;
   1150         }
   1151         // always check otherwise last to allow dynamic updates to the set of rules
   1152         if (otherwise) check(otherwise);
   1153       }
   1154 
   1155       $rootScope.$on('$locationChangeSuccess', update);
   1156 
   1157       return {
   1158         /**
   1159          * @ngdoc function
   1160          * @name ui.router.router.$urlRouter#sync
   1161          * @methodOf ui.router.router.$urlRouter
   1162          *
   1163          * @description
   1164          * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`.
   1165          * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event, 
   1166          * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed 
   1167          * with the transition by calling `$urlRouter.sync()`.
   1168          *
   1169          * @example
   1170          * <pre>
   1171          * angular.module('app', ['ui.router']);
   1172          *   .run(function($rootScope, $urlRouter) {
   1173          *     $rootScope.$on('$locationChangeSuccess', function(evt) {
   1174          *       // Halt state change from even starting
   1175          *       evt.preventDefault();
   1176          *       // Perform custom logic
   1177          *       var meetsRequirement = ...
   1178          *       // Continue with the update and state transition if logic allows
   1179          *       if (meetsRequirement) $urlRouter.sync();
   1180          *     });
   1181          * });
   1182          * </pre>
   1183          */
   1184         sync: function () {
   1185           update();
   1186         }
   1187       };
   1188     }];
   1189 }
   1190 
   1191 angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);
   1192 
   1193 /**
   1194  * @ngdoc object
   1195  * @name ui.router.state.$stateProvider
   1196  *
   1197  * @requires ui.router.router.$urlRouterProvider
   1198  * @requires ui.router.util.$urlMatcherFactoryProvider
   1199  * @requires $locationProvider
   1200  *
   1201  * @description
   1202  * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely
   1203  * on state.
   1204  *
   1205  * A state corresponds to a "place" in the application in terms of the overall UI and
   1206  * navigation. A state describes (via the controller / template / view properties) what
   1207  * the UI looks like and does at that place.
   1208  *
   1209  * States often have things in common, and the primary way of factoring out these
   1210  * commonalities in this model is via the state hierarchy, i.e. parent/child states aka
   1211  * nested states.
   1212  *
   1213  * The `$stateProvider` provides interfaces to declare these states for your app.
   1214  */
   1215 $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider', '$locationProvider'];
   1216 function $StateProvider(   $urlRouterProvider,   $urlMatcherFactory,           $locationProvider) {
   1217 
   1218   var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
   1219 
   1220   // Builds state properties from definition passed to registerState()
   1221   var stateBuilder = {
   1222 
   1223     // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.
   1224     // state.children = [];
   1225     // if (parent) parent.children.push(state);
   1226     parent: function(state) {
   1227       if (isDefined(state.parent) && state.parent) return findState(state.parent);
   1228       // regex matches any valid composite state name
   1229       // would match "contact.list" but not "contacts"
   1230       var compositeName = /^(.+)\.[^.]+$/.exec(state.name);
   1231       return compositeName ? findState(compositeName[1]) : root;
   1232     },
   1233 
   1234     // inherit 'data' from parent and override by own values (if any)
   1235     data: function(state) {
   1236       if (state.parent && state.parent.data) {
   1237         state.data = state.self.data = extend({}, state.parent.data, state.data);
   1238       }
   1239       return state.data;
   1240     },
   1241 
   1242     // Build a URLMatcher if necessary, either via a relative or absolute URL
   1243     url: function(state) {
   1244       var url = state.url;
   1245 
   1246       if (isString(url)) {
   1247         if (url.charAt(0) == '^') {
   1248           return $urlMatcherFactory.compile(url.substring(1));
   1249         }
   1250         return (state.parent.navigable || root).url.concat(url);
   1251       }
   1252 
   1253       if ($urlMatcherFactory.isMatcher(url) || url == null) {
   1254         return url;
   1255       }
   1256       throw new Error("Invalid url '" + url + "' in state '" + state + "'");
   1257     },
   1258 
   1259     // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
   1260     navigable: function(state) {
   1261       return state.url ? state : (state.parent ? state.parent.navigable : null);
   1262     },
   1263 
   1264     // Derive parameters for this state and ensure they're a super-set of parent's parameters
   1265     params: function(state) {
   1266       if (!state.params) {
   1267         return state.url ? state.url.parameters() : state.parent.params;
   1268       }
   1269       if (!isArray(state.params)) throw new Error("Invalid params in state '" + state + "'");
   1270       if (state.url) throw new Error("Both params and url specicified in state '" + state + "'");
   1271       return state.params;
   1272     },
   1273 
   1274     // If there is no explicit multi-view configuration, make one up so we don't have
   1275     // to handle both cases in the view directive later. Note that having an explicit
   1276     // 'views' property will mean the default unnamed view properties are ignored. This
   1277     // is also a good time to resolve view names to absolute names, so everything is a
   1278     // straight lookup at link time.
   1279     views: function(state) {
   1280       var views = {};
   1281 
   1282       forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {
   1283         if (name.indexOf('@') < 0) name += '@' + state.parent.name;
   1284         views[name] = view;
   1285       });
   1286       return views;
   1287     },
   1288 
   1289     ownParams: function(state) {
   1290       if (!state.parent) {
   1291         return state.params;
   1292       }
   1293       var paramNames = {}; forEach(state.params, function (p) { paramNames[p] = true; });
   1294 
   1295       forEach(state.parent.params, function (p) {
   1296         if (!paramNames[p]) {
   1297           throw new Error("Missing required parameter '" + p + "' in state '" + state.name + "'");
   1298         }
   1299         paramNames[p] = false;
   1300       });
   1301       var ownParams = [];
   1302 
   1303       forEach(paramNames, function (own, p) {
   1304         if (own) ownParams.push(p);
   1305       });
   1306       return ownParams;
   1307     },
   1308 
   1309     // Keep a full path from the root down to this state as this is needed for state activation.
   1310     path: function(state) {
   1311       return state.parent ? state.parent.path.concat(state) : []; // exclude root from path
   1312     },
   1313 
   1314     // Speed up $state.contains() as it's used a lot
   1315     includes: function(state) {
   1316       var includes = state.parent ? extend({}, state.parent.includes) : {};
   1317       includes[state.name] = true;
   1318       return includes;
   1319     },
   1320 
   1321     $delegates: {}
   1322   };
   1323 
   1324   function isRelative(stateName) {
   1325     return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
   1326   }
   1327 
   1328   function findState(stateOrName, base) {
   1329     var isStr = isString(stateOrName),
   1330         name  = isStr ? stateOrName : stateOrName.name,
   1331         path  = isRelative(name);
   1332 
   1333     if (path) {
   1334       if (!base) throw new Error("No reference point given for path '"  + name + "'");
   1335       var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
   1336 
   1337       for (; i < pathLength; i++) {
   1338         if (rel[i] === "" && i === 0) {
   1339           current = base;
   1340           continue;
   1341         }
   1342         if (rel[i] === "^") {
   1343           if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
   1344           current = current.parent;
   1345           continue;
   1346         }
   1347         break;
   1348       }
   1349       rel = rel.slice(i).join(".");
   1350       name = current.name + (current.name && rel ? "." : "") + rel;
   1351     }
   1352     var state = states[name];
   1353 
   1354     if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {
   1355       return state;
   1356     }
   1357     return undefined;
   1358   }
   1359 
   1360   function queueState(parentName, state) {
   1361     if (!queue[parentName]) {
   1362       queue[parentName] = [];
   1363     }
   1364     queue[parentName].push(state);
   1365   }
   1366 
   1367   function registerState(state) {
   1368     // Wrap a new object around the state so we can store our private details easily.
   1369     state = inherit(state, {
   1370       self: state,
   1371       resolve: state.resolve || {},
   1372       toString: function() { return this.name; }
   1373     });
   1374 
   1375     var name = state.name;
   1376     if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name");
   1377     if (states.hasOwnProperty(name)) throw new Error("State '" + name + "'' is already defined");
   1378 
   1379     // Get parent name
   1380     var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))
   1381         : (isString(state.parent)) ? state.parent
   1382         : '';
   1383 
   1384     // If parent is not registered yet, add state to queue and register later
   1385     if (parentName && !states[parentName]) {
   1386       return queueState(parentName, state.self);
   1387     }
   1388 
   1389     for (var key in stateBuilder) {
   1390       if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);
   1391     }
   1392     states[name] = state;
   1393 
   1394     // Register the state in the global state list and with $urlRouter if necessary.
   1395     if (!state[abstractKey] && state.url) {
   1396       $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
   1397         if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
   1398           $state.transitionTo(state, $match, { location: false });
   1399         }
   1400       }]);
   1401     }
   1402 
   1403     // Register any queued children
   1404     if (queue[name]) {
   1405       for (var i = 0; i < queue[name].length; i++) {
   1406         registerState(queue[name][i]);
   1407       }
   1408     }
   1409 
   1410     return state;
   1411   }
   1412 
   1413   // Checks text to see if it looks like a glob.
   1414   function isGlob (text) {
   1415     return text.indexOf('*') > -1;
   1416   }
   1417 
   1418   // Returns true if glob matches current $state name.
   1419   function doesStateMatchGlob (glob) {
   1420     var globSegments = glob.split('.'),
   1421         segments = $state.$current.name.split('.');
   1422 
   1423     //match greedy starts
   1424     if (globSegments[0] === '**') {
   1425        segments = segments.slice(segments.indexOf(globSegments[1]));
   1426        segments.unshift('**');
   1427     }
   1428     //match greedy ends
   1429     if (globSegments[globSegments.length - 1] === '**') {
   1430        segments.splice(segments.indexOf(globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
   1431        segments.push('**');
   1432     }
   1433 
   1434     if (globSegments.length != segments.length) {
   1435       return false;
   1436     }
   1437 
   1438     //match single stars
   1439     for (var i = 0, l = globSegments.length; i < l; i++) {
   1440       if (globSegments[i] === '*') {
   1441         segments[i] = '*';
   1442       }
   1443     }
   1444 
   1445     return segments.join('') === globSegments.join('');
   1446   }
   1447 
   1448 
   1449   // Implicit root state that is always active
   1450   root = registerState({
   1451     name: '',
   1452     url: '^',
   1453     views: null,
   1454     'abstract': true
   1455   });
   1456   root.navigable = null;
   1457 
   1458 
   1459   /**
   1460    * @ngdoc function
   1461    * @name ui.router.state.$stateProvider#decorator
   1462    * @methodOf ui.router.state.$stateProvider
   1463    *
   1464    * @description
   1465    * Allows you to extend (carefully) or override (at your own peril) the 
   1466    * `stateBuilder` object used internally by `$stateProvider`. This can be used 
   1467    * to add custom functionality to ui-router, for example inferring templateUrl 
   1468    * based on the state name.
   1469    *
   1470    * When passing only a name, it returns the current (original or decorated) builder
   1471    * function that matches `name`.
   1472    *
   1473    * The builder functions that can be decorated are listed below. Though not all
   1474    * necessarily have a good use case for decoration, that is up to you to decide.
   1475    *
   1476    * In addition, users can attach custom decorators, which will generate new 
   1477    * properties within the state's internal definition. There is currently no clear 
   1478    * use-case for this beyond accessing internal states (i.e. $state.$current), 
   1479    * however, expect this to become increasingly relevant as we introduce additional 
   1480    * meta-programming features.
   1481    *
   1482    * **Warning**: Decorators should not be interdependent because the order of 
   1483    * execution of the builder functions in non-deterministic. Builder functions 
   1484    * should only be dependent on the state definition object and super function.
   1485    *
   1486    *
   1487    * Existing builder functions and current return values:
   1488    *
   1489    * - **parent** `{object}` - returns the parent state object.
   1490    * - **data** `{object}` - returns state data, including any inherited data that is not
   1491    *   overridden by own values (if any).
   1492    * - **url** `{object}` - returns a {link ui.router.util.type:UrlMatcher} or null.
   1493    * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is 
   1494    *   navigable).
   1495    * - **params** `{object}` - returns an array of state params that are ensured to 
   1496    *   be a super-set of parent's params.
   1497    * - **views** `{object}` - returns a views object where each key is an absolute view 
   1498    *   name (i.e. "viewName@stateName") and each value is the config object 
   1499    *   (template, controller) for the view. Even when you don't use the views object 
   1500    *   explicitly on a state config, one is still created for you internally.
   1501    *   So by decorating this builder function you have access to decorating template 
   1502    *   and controller properties.
   1503    * - **ownParams** `{object}` - returns an array of params that belong to the state, 
   1504    *   not including any params defined by ancestor states.
   1505    * - **path** `{string}` - returns the full path from the root down to this state. 
   1506    *   Needed for state activation.
   1507    * - **includes** `{object}` - returns an object that includes every state that 
   1508    *   would pass a '$state.includes()' test.
   1509    *
   1510    * @example
   1511    * <pre>
   1512    * // Override the internal 'views' builder with a function that takes the state
   1513    * // definition, and a reference to the internal function being overridden:
   1514    * $stateProvider.decorator('views', function ($state, parent) {
   1515    *   var result = {},
   1516    *       views = parent(state);
   1517    *
   1518    *   angular.forEach(view, function (config, name) {
   1519    *     var autoName = (state.name + '.' + name).replace('.', '/');
   1520    *     config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
   1521    *     result[name] = config;
   1522    *   });
   1523    *   return result;
   1524    * });
   1525    *
   1526    * $stateProvider.state('home', {
   1527    *   views: {
   1528    *     'contact.list': { controller: 'ListController' },
   1529    *     'contact.item': { controller: 'ItemController' }
   1530    *   }
   1531    * });
   1532    *
   1533    * // ...
   1534    *
   1535    * $state.go('home');
   1536    * // Auto-populates list and item views with /partials/home/contact/list.html,
   1537    * // and /partials/home/contact/item.html, respectively.
   1538    * </pre>
   1539    *
   1540    * @param {string} name The name of the builder function to decorate. 
   1541    * @param {object} func A function that is responsible for decorating the original 
   1542    * builder function. The function receives two parameters:
   1543    *
   1544    *   - `{object}` - state - The state config object.
   1545    *   - `{object}` - super - The original builder function.
   1546    *
   1547    * @return {object} $stateProvider - $stateProvider instance
   1548    */
   1549   this.decorator = decorator;
   1550   function decorator(name, func) {
   1551     /*jshint validthis: true */
   1552     if (isString(name) && !isDefined(func)) {
   1553       return stateBuilder[name];
   1554     }
   1555     if (!isFunction(func) || !isString(name)) {
   1556       return this;
   1557     }
   1558     if (stateBuilder[name] && !stateBuilder.$delegates[name]) {
   1559       stateBuilder.$delegates[name] = stateBuilder[name];
   1560     }
   1561     stateBuilder[name] = func;
   1562     return this;
   1563   }
   1564 
   1565   /**
   1566    * @ngdoc function
   1567    * @name ui.router.state.$stateProvider#state
   1568    * @methodOf ui.router.state.$stateProvider
   1569    *
   1570    * @description
   1571    * Registers a state configuration under a given state name. The stateConfig object
   1572    * has the following acceptable properties.
   1573    *
   1574    * <a id='template'></a>
   1575    *
   1576    * - **`template`** - {string|function=} - html template as a string or a function that returns
   1577    *   an html template as a string which should be used by the uiView directives. This property 
   1578    *   takes precedence over templateUrl.
   1579    *   
   1580    *   If `template` is a function, it will be called with the following parameters:
   1581    *
   1582    *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by
   1583    *     applying the current state
   1584    *
   1585    * <a id='templateUrl'></a>
   1586    *
   1587    * - **`templateUrl`** - {string|function=} - path or function that returns a path to an html 
   1588    *   template that should be used by uiView.
   1589    *   
   1590    *   If `templateUrl` is a function, it will be called with the following parameters:
   1591    *
   1592    *   - {array.&lt;object&gt;} - state parameters extracted from the current $location.path() by 
   1593    *     applying the current state
   1594    *
   1595    * <a id='templateProvider'></a>
   1596    *
   1597    * - **`templateProvider`** - {function=} - Provider function that returns HTML content
   1598    *   string.
   1599    *
   1600    * <a id='controller'></a>
   1601    *
   1602    * - **`controller`** - {string|function=} -  Controller fn that should be associated with newly 
   1603    *   related scope or the name of a registered controller if passed as a string.
   1604    *
   1605    * <a id='controllerProvider'></a>
   1606    *
   1607    * - **`controllerProvider`** - {function=} - Injectable provider function that returns
   1608    *   the actual controller or string.
   1609    *
   1610    * <a id='controllerAs'></a>
   1611    * 
   1612    * - **`controllerAs`** – {string=} – A controller alias name. If present the controller will be 
   1613    *   published to scope under the controllerAs name.
   1614    *
   1615    * <a id='resolve'></a>
   1616    *
   1617    * - **`resolve`** - {object.&lt;string, function&gt;=} - An optional map of dependencies which 
   1618    *   should be injected into the controller. If any of these dependencies are promises, 
   1619    *   the router will wait for them all to be resolved or one to be rejected before the 
   1620    *   controller is instantiated. If all the promises are resolved successfully, the values 
   1621    *   of the resolved promises are injected and $stateChangeSuccess event is fired. If any 
   1622    *   of the promises are rejected the $stateChangeError event is fired. The map object is:
   1623    *   
   1624    *   - key - {string}: name of dependency to be injected into controller
   1625    *   - factory - {string|function}: If string then it is alias for service. Otherwise if function, 
   1626    *     it is injected and return value it treated as dependency. If result is a promise, it is 
   1627    *     resolved before its value is injected into controller.
   1628    *
   1629    * <a id='url'></a>
   1630    *
   1631    * - **`url`** - {string=} - A url with optional parameters. When a state is navigated or
   1632    *   transitioned to, the `$stateParams` service will be populated with any 
   1633    *   parameters that were passed.
   1634    *
   1635    * <a id='params'></a>
   1636    *
   1637    * - **`params`** - {object=} - An array of parameter names or regular expressions. Only 
   1638    *   use this within a state if you are not using url. Otherwise you can specify your
   1639    *   parameters within the url. When a state is navigated or transitioned to, the 
   1640    *   $stateParams service will be populated with any parameters that were passed.
   1641    *
   1642    * <a id='views'></a>
   1643    *
   1644    * - **`views`** - {object=} - Use the views property to set up multiple views or to target views
   1645    *   manually/explicitly.
   1646    *
   1647    * <a id='abstract'></a>
   1648    *
   1649    * - **`abstract`** - {boolean=} - An abstract state will never be directly activated, 
   1650    *   but can provide inherited properties to its common children states.
   1651    *
   1652    * <a id='onEnter'></a>
   1653    *
   1654    * - **`onEnter`** - {object=} - Callback function for when a state is entered. Good way
   1655    *   to trigger an action or dispatch an event, such as opening a dialog.
   1656    *
   1657    * <a id='onExit'></a>
   1658    *
   1659    * - **`onExit`** - {object=} - Callback function for when a state is exited. Good way to
   1660    *   trigger an action or dispatch an event, such as opening a dialog.
   1661    *
   1662    * <a id='reloadOnSearch'></a>
   1663    *
   1664    * - **`reloadOnSearch = true`** - {boolean=} - If `false`, will not retrigger the same state 
   1665    *   just because a search/query parameter has changed (via $location.search() or $location.hash()). 
   1666    *   Useful for when you'd like to modify $location.search() without triggering a reload.
   1667    *
   1668    * <a id='data'></a>
   1669    *
   1670    * - **`data`** - {object=} - Arbitrary data object, useful for custom configuration.
   1671    *
   1672    * @example
   1673    * <pre>
   1674    * // Some state name examples
   1675    *
   1676    * // stateName can be a single top-level name (must be unique).
   1677    * $stateProvider.state("home", {});
   1678    *
   1679    * // Or it can be a nested state name. This state is a child of the 
   1680    * // above "home" state.
   1681    * $stateProvider.state("home.newest", {});
   1682    *
   1683    * // Nest states as deeply as needed.
   1684    * $stateProvider.state("home.newest.abc.xyz.inception", {});
   1685    *
   1686    * // state() returns $stateProvider, so you can chain state declarations.
   1687    * $stateProvider
   1688    *   .state("home", {})
   1689    *   .state("about", {})
   1690    *   .state("contacts", {});
   1691    * </pre>
   1692    *
   1693    * @param {string} name A unique state name, e.g. "home", "about", "contacts". 
   1694    * To create a parent/child state use a dot, e.g. "about.sales", "home.newest".
   1695    * @param {object} definition State configuration object.
   1696    */
   1697   this.state = state;
   1698   function state(name, definition) {
   1699     /*jshint validthis: true */
   1700     if (isObject(name)) definition = name;
   1701     else definition.name = name;
   1702     registerState(definition);
   1703     return this;
   1704   }
   1705 
   1706   /**
   1707    * @ngdoc object
   1708    * @name ui.router.state.$state
   1709    *
   1710    * @requires $rootScope
   1711    * @requires $q
   1712    * @requires ui.router.state.$view
   1713    * @requires $injector
   1714    * @requires ui.router.util.$resolve
   1715    * @requires ui.router.state.$stateParams
   1716    *
   1717    * @property {object} params A param object, e.g. {sectionId: section.id)}, that 
   1718    * you'd like to test against the current active state.
   1719    * @property {object} current A reference to the state's config object. However 
   1720    * you passed it in. Useful for accessing custom data.
   1721    * @property {object} transition Currently pending transition. A promise that'll 
   1722    * resolve or reject.
   1723    *
   1724    * @description
   1725    * `$state` service is responsible for representing states as well as transitioning
   1726    * between them. It also provides interfaces to ask for current state or even states
   1727    * you're coming from.
   1728    */
   1729   // $urlRouter is injected just to ensure it gets instantiated
   1730   this.$get = $get;
   1731   $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$location', '$urlRouter', '$browser'];
   1732   function $get(   $rootScope,   $q,   $view,   $injector,   $resolve,   $stateParams,   $location,   $urlRouter,   $browser) {
   1733 
   1734     var TransitionSuperseded = $q.reject(new Error('transition superseded'));
   1735     var TransitionPrevented = $q.reject(new Error('transition prevented'));
   1736     var TransitionAborted = $q.reject(new Error('transition aborted'));
   1737     var TransitionFailed = $q.reject(new Error('transition failed'));
   1738     var currentLocation = $location.url();
   1739     var baseHref = $browser.baseHref();
   1740 
   1741     function syncUrl() {
   1742       if ($location.url() !== currentLocation) {
   1743         $location.url(currentLocation);
   1744         $location.replace();
   1745       }
   1746     }
   1747 
   1748     root.locals = { resolve: null, globals: { $stateParams: {} } };
   1749     $state = {
   1750       params: {},
   1751       current: root.self,
   1752       $current: root,
   1753       transition: null
   1754     };
   1755 
   1756     /**
   1757      * @ngdoc function
   1758      * @name ui.router.state.$state#reload
   1759      * @methodOf ui.router.state.$state
   1760      *
   1761      * @description
   1762      * A method that force reloads the current state. All resolves are re-resolved, events are not re-fired, 
   1763      * and controllers reinstantiated (bug with controllers reinstantiating right now, fixing soon).
   1764      *
   1765      * @example
   1766      * <pre>
   1767      * var app angular.module('app', ['ui.router']);
   1768      *
   1769      * app.controller('ctrl', function ($scope, $state) {
   1770      *   $scope.reload = function(){
   1771      *     $state.reload();
   1772      *   }
   1773      * });
   1774      * </pre>
   1775      *
   1776      * `reload()` is just an alias for:
   1777      * <pre>
   1778      * $state.transitionTo($state.current, $stateParams, { 
   1779      *   reload: true, inherit: false, notify: false 
   1780      * });
   1781      * </pre>
   1782      */
   1783     $state.reload = function reload() {
   1784       $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: false });
   1785     };
   1786 
   1787     /**
   1788      * @ngdoc function
   1789      * @name ui.router.state.$state#go
   1790      * @methodOf ui.router.state.$state
   1791      *
   1792      * @description
   1793      * Convenience method for transitioning to a new state. `$state.go` calls 
   1794      * `$state.transitionTo` internally but automatically sets options to 
   1795      * `{ location: true, inherit: true, relative: $state.$current, notify: true }`. 
   1796      * This allows you to easily use an absolute or relative to path and specify 
   1797      * only the parameters you'd like to update (while letting unspecified parameters 
   1798      * inherit from the currently active ancestor states).
   1799      *
   1800      * @example
   1801      * <pre>
   1802      * var app = angular.module('app', ['ui.router']);
   1803      *
   1804      * app.controller('ctrl', function ($scope, $state) {
   1805      *   $scope.changeState = function () {
   1806      *     $state.go('contact.detail');
   1807      *   };
   1808      * });
   1809      * </pre>
   1810      * <img src='../ngdoc_assets/StateGoExamples.png'/>
   1811      *
   1812      * @param {string} to Absolute state name or relative state path. Some examples:
   1813      *
   1814      * - `$state.go('contact.detail')` - will go to the `contact.detail` state
   1815      * - `$state.go('^')` - will go to a parent state
   1816      * - `$state.go('^.sibling')` - will go to a sibling state
   1817      * - `$state.go('.child.grandchild')` - will go to grandchild state
   1818      *
   1819      * @param {object=} params A map of the parameters that will be sent to the state, 
   1820      * will populate $stateParams. Any parameters that are not specified will be inherited from currently 
   1821      * defined parameters. This allows, for example, going to a sibling state that shares parameters
   1822      * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e.
   1823      * transitioning to a sibling will get you the parameters for all parents, transitioning to a child
   1824      * will get you all current parameters, etc.
   1825      * @param {object=} options Options object. The options are:
   1826      *
   1827      * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
   1828      *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
   1829      * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url.
   1830      * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
   1831      *    defines which state to be relative from.
   1832      * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
   1833      * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params 
   1834      *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
   1835      *    use this when you want to force a reload when *everything* is the same, including search params.
   1836      *
   1837      * @returns {promise} A promise representing the state of the new transition.
   1838      *
   1839      * Possible success values:
   1840      *
   1841      * - $state.current
   1842      *
   1843      * <br/>Possible rejection values:
   1844      *
   1845      * - 'transition superseded' - when a newer transition has been started after this one
   1846      * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener
   1847      * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or
   1848      *   when a `$stateNotFound` `event.retry` promise errors.
   1849      * - 'transition failed' - when a state has been unsuccessfully found after 2 tries.
   1850      * - *resolve error* - when an error has occurred with a `resolve`
   1851      *
   1852      */
   1853     $state.go = function go(to, params, options) {
   1854       return this.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options));
   1855     };
   1856 
   1857     /**
   1858      * @ngdoc function
   1859      * @name ui.router.state.$state#transitionTo
   1860      * @methodOf ui.router.state.$state
   1861      *
   1862      * @description
   1863      * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go}
   1864      * uses `transitionTo` internally. `$state.go` is recommended in most situations.
   1865      *
   1866      * @example
   1867      * <pre>
   1868      * var app = angular.module('app', ['ui.router']);
   1869      *
   1870      * app.controller('ctrl', function ($scope, $state) {
   1871      *   $scope.changeState = function () {
   1872      *     $state.transitionTo('contact.detail');
   1873      *   };
   1874      * });
   1875      * </pre>
   1876      *
   1877      * @param {string} to State name.
   1878      * @param {object=} toParams A map of the parameters that will be sent to the state,
   1879      * will populate $stateParams.
   1880      * @param {object=} options Options object. The options are:
   1881      *
   1882      * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false`
   1883      *    will not. If string, must be `"replace"`, which will update url and also replace last history record.
   1884      * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
   1885      * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), 
   1886      *    defines which state to be relative from.
   1887      * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events.
   1888      * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params 
   1889      *    have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd
   1890      *    use this when you want to force a reload when *everything* is the same, including search params.
   1891      *
   1892      * @returns {promise} A promise representing the state of the new transition. See
   1893      * {@link ui.router.state.$state#methods_go $state.go}.
   1894      */
   1895     $state.transitionTo = function transitionTo(to, toParams, options) {
   1896       toParams = toParams || {};
   1897       options = extend({
   1898         location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false
   1899       }, options || {});
   1900 
   1901       var from = $state.$current, fromParams = $state.params, fromPath = from.path;
   1902       var evt, toState = findState(to, options.relative);
   1903 
   1904       if (!isDefined(toState)) {
   1905         // Broadcast not found event and abort the transition if prevented
   1906         var redirect = { to: to, toParams: toParams, options: options };
   1907 
   1908         /**
   1909          * @ngdoc event
   1910          * @name ui.router.state.$state#$stateNotFound
   1911          * @eventOf ui.router.state.$state
   1912          * @eventType broadcast on root scope
   1913          * @description
   1914          * Fired when a requested state **cannot be found** using the provided state name during transition.
   1915          * The event is broadcast allowing any handlers a single chance to deal with the error (usually by
   1916          * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler,
   1917          * you can see its three properties in the example. You can use `event.preventDefault()` to abort the
   1918          * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value.
   1919          *
   1920          * @param {Object} event Event object.
   1921          * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties.
   1922          * @param {State} fromState Current state object.
   1923          * @param {Object} fromParams Current state params.
   1924          *
   1925          * @example
   1926          *
   1927          * <pre>
   1928          * // somewhere, assume lazy.state has not been defined
   1929          * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
   1930          *
   1931          * // somewhere else
   1932          * $scope.$on('$stateNotFound',
   1933          * function(event, unfoundState, fromState, fromParams){
   1934          *     console.log(unfoundState.to); // "lazy.state"
   1935          *     console.log(unfoundState.toParams); // {a:1, b:2}
   1936          *     console.log(unfoundState.options); // {inherit:false} + default options
   1937          * })
   1938          * </pre>
   1939          */
   1940         evt = $rootScope.$broadcast('$stateNotFound', redirect, from.self, fromParams);
   1941         if (evt.defaultPrevented) {
   1942           syncUrl();
   1943           return TransitionAborted;
   1944         }
   1945 
   1946         // Allow the handler to return a promise to defer state lookup retry
   1947         if (evt.retry) {
   1948           if (options.$retry) {
   1949             syncUrl();
   1950             return TransitionFailed;
   1951           }
   1952           var retryTransition = $state.transition = $q.when(evt.retry);
   1953           retryTransition.then(function() {
   1954             if (retryTransition !== $state.transition) return TransitionSuperseded;
   1955             redirect.options.$retry = true;
   1956             return $state.transitionTo(redirect.to, redirect.toParams, redirect.options);
   1957           }, function() {
   1958             return TransitionAborted;
   1959           });
   1960           syncUrl();
   1961           return retryTransition;
   1962         }
   1963 
   1964         // Always retry once if the $stateNotFound was not prevented
   1965         // (handles either redirect changed or state lazy-definition)
   1966         to = redirect.to;
   1967         toParams = redirect.toParams;
   1968         options = redirect.options;
   1969         toState = findState(to, options.relative);
   1970         if (!isDefined(toState)) {
   1971           if (options.relative) throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
   1972           throw new Error("No such state '" + to + "'");
   1973         }
   1974       }
   1975       if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
   1976       if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
   1977       to = toState;
   1978 
   1979       var toPath = to.path;
   1980 
   1981       // Starting from the root of the path, keep all levels that haven't changed
   1982       var keep, state, locals = root.locals, toLocals = [];
   1983       for (keep = 0, state = toPath[keep];
   1984            state && state === fromPath[keep] && equalForKeys(toParams, fromParams, state.ownParams) && !options.reload;
   1985            keep++, state = toPath[keep]) {
   1986         locals = toLocals[keep] = state.locals;
   1987       }
   1988 
   1989       // If we're going to the same state and all locals are kept, we've got nothing to do.
   1990       // But clear 'transition', as we still want to cancel any other pending transitions.
   1991       // TODO: We may not want to bump 'transition' if we're called from a location change that we've initiated ourselves,
   1992       // because we might accidentally abort a legitimate transition initiated from code?
   1993       if (shouldTriggerReload(to, from, locals, options) ) {
   1994         if ( to.self.reloadOnSearch !== false )
   1995           syncUrl();
   1996         $state.transition = null;
   1997         return $q.when($state.current);
   1998       }
   1999 
   2000       // Normalize/filter parameters before we pass them to event handlers etc.
   2001       toParams = normalize(to.params, toParams || {});
   2002 
   2003       // Broadcast start event and cancel the transition if requested
   2004       if (options.notify) {
   2005         /**
   2006          * @ngdoc event
   2007          * @name ui.router.state.$state#$stateChangeStart
   2008          * @eventOf ui.router.state.$state
   2009          * @eventType broadcast on root scope
   2010          * @description
   2011          * Fired when the state transition **begins**. You can use `event.preventDefault()`
   2012          * to prevent the transition from happening and then the transition promise will be
   2013          * rejected with a `'transition prevented'` value.
   2014          *
   2015          * @param {Object} event Event object.
   2016          * @param {State} toState The state being transitioned to.
   2017          * @param {Object} toParams The params supplied to the `toState`.
   2018          * @param {State} fromState The current state, pre-transition.
   2019          * @param {Object} fromParams The params supplied to the `fromState`.
   2020          *
   2021          * @example
   2022          *
   2023          * <pre>
   2024          * $rootScope.$on('$stateChangeStart',
   2025          * function(event, toState, toParams, fromState, fromParams){
   2026          *     event.preventDefault();
   2027          *     // transitionTo() promise will be rejected with
   2028          *     // a 'transition prevented' error
   2029          * })
   2030          * </pre>
   2031          */
   2032         evt = $rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams);
   2033         if (evt.defaultPrevented) {
   2034           syncUrl();
   2035           return TransitionPrevented;
   2036         }
   2037       }
   2038 
   2039       // Resolve locals for the remaining states, but don't update any global state just
   2040       // yet -- if anything fails to resolve the current state needs to remain untouched.
   2041       // We also set up an inheritance chain for the locals here. This allows the view directive
   2042       // to quickly look up the correct definition for each view in the current state. Even
   2043       // though we create the locals object itself outside resolveState(), it is initially
   2044       // empty and gets filled asynchronously. We need to keep track of the promise for the
   2045       // (fully resolved) current locals, and pass this down the chain.
   2046       var resolved = $q.when(locals);
   2047       for (var l=keep; l<toPath.length; l++, state=toPath[l]) {
   2048         locals = toLocals[l] = inherit(locals);
   2049         resolved = resolveState(state, toParams, state===to, resolved, locals);
   2050       }
   2051 
   2052       // Once everything is resolved, we are ready to perform the actual transition
   2053       // and return a promise for the new state. We also keep track of what the
   2054       // current promise is, so that we can detect overlapping transitions and
   2055       // keep only the outcome of the last transition.
   2056       var transition = $state.transition = resolved.then(function () {
   2057         var l, entering, exiting;
   2058 
   2059         if ($state.transition !== transition) return TransitionSuperseded;
   2060 
   2061         // Exit 'from' states not kept
   2062         for (l=fromPath.length-1; l>=keep; l--) {
   2063           exiting = fromPath[l];
   2064           if (exiting.self.onExit) {
   2065             $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals);
   2066           }
   2067           exiting.locals = null;
   2068         }
   2069 
   2070         // Enter 'to' states not kept
   2071         for (l=keep; l<toPath.length; l++) {
   2072           entering = toPath[l];
   2073           entering.locals = toLocals[l];
   2074           if (entering.self.onEnter) {
   2075             $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals);
   2076           }
   2077         }
   2078 
   2079         // Run it again, to catch any transitions in callbacks
   2080         if ($state.transition !== transition) return TransitionSuperseded;
   2081 
   2082         // Update globals in $state
   2083         $state.$current = to;
   2084         $state.current = to.self;
   2085         $state.params = toParams;
   2086         copy($state.params, $stateParams);
   2087         $state.transition = null;
   2088 
   2089         // Update $location
   2090         var toNav = to.navigable;
   2091         if (options.location && toNav) {
   2092           $location.url(toNav.url.format(toNav.locals.globals.$stateParams));
   2093 
   2094           if (options.location === 'replace') {
   2095             $location.replace();
   2096           }
   2097         }
   2098 
   2099         if (options.notify) {
   2100         /**
   2101          * @ngdoc event
   2102          * @name ui.router.state.$state#$stateChangeSuccess
   2103          * @eventOf ui.router.state.$state
   2104          * @eventType broadcast on root scope
   2105          * @description
   2106          * Fired once the state transition is **complete**.
   2107          *
   2108          * @param {Object} event Event object.
   2109          * @param {State} toState The state being transitioned to.
   2110          * @param {Object} toParams The params supplied to the `toState`.
   2111          * @param {State} fromState The current state, pre-transition.
   2112          * @param {Object} fromParams The params supplied to the `fromState`.
   2113          */
   2114           $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams);
   2115         }
   2116         currentLocation = $location.url();
   2117 
   2118         return $state.current;
   2119       }, function (error) {
   2120         if ($state.transition !== transition) return TransitionSuperseded;
   2121 
   2122         $state.transition = null;
   2123         /**
   2124          * @ngdoc event
   2125          * @name ui.router.state.$state#$stateChangeError
   2126          * @eventOf ui.router.state.$state
   2127          * @eventType broadcast on root scope
   2128          * @description
   2129          * Fired when an **error occurs** during transition. It's important to note that if you
   2130          * have any errors in your resolve functions (javascript errors, non-existent services, etc)
   2131          * they will not throw traditionally. You must listen for this $stateChangeError event to
   2132          * catch **ALL** errors.
   2133          *
   2134          * @param {Object} event Event object.
   2135          * @param {State} toState The state being transitioned to.
   2136          * @param {Object} toParams The params supplied to the `toState`.
   2137          * @param {State} fromState The current state, pre-transition.
   2138          * @param {Object} fromParams The params supplied to the `fromState`.
   2139          * @param {Error} error The resolve error object.
   2140          */
   2141         $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error);
   2142         syncUrl();
   2143 
   2144         return $q.reject(error);
   2145       });
   2146 
   2147       return transition;
   2148     };
   2149 
   2150     /**
   2151      * @ngdoc function
   2152      * @name ui.router.state.$state#is
   2153      * @methodOf ui.router.state.$state
   2154      *
   2155      * @description
   2156      * Similar to {@link ui.router.state.$state#methods_includes $state.includes},
   2157      * but only checks for the full state name. If params is supplied then it will be 
   2158      * tested for strict equality against the current active params object, so all params 
   2159      * must match with none missing and no extras.
   2160      *
   2161      * @example
   2162      * <pre>
   2163      * $state.is('contact.details.item'); // returns true
   2164      * $state.is(contactDetailItemStateObject); // returns true
   2165      *
   2166      * // everything else would return false
   2167      * </pre>
   2168      *
   2169      * @param {string|object} stateName The state name or state object you'd like to check.
   2170      * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like 
   2171      * to test against the current active state.
   2172      * @returns {boolean} Returns true if it is the state.
   2173      */
   2174     $state.is = function is(stateOrName, params) {
   2175       var state = findState(stateOrName);
   2176 
   2177       if (!isDefined(state)) {
   2178         return undefined;
   2179       }
   2180 
   2181       if ($state.$current !== state) {
   2182         return false;
   2183       }
   2184 
   2185       return isDefined(params) && params !== null ? angular.equals($stateParams, params) : true;
   2186     };
   2187 
   2188     /**
   2189      * @ngdoc function
   2190      * @name ui.router.state.$state#includes
   2191      * @methodOf ui.router.state.$state
   2192      *
   2193      * @description
   2194      * A method to determine if the current active state is equal to or is the child of the 
   2195      * state stateName. If any params are passed then they will be tested for a match as well.
   2196      * Not all the parameters need to be passed, just the ones you'd like to test for equality.
   2197      *
   2198      * @example
   2199      * <pre>
   2200      * $state.$current.name = 'contacts.details.item';
   2201      *
   2202      * $state.includes("contacts"); // returns true
   2203      * $state.includes("contacts.details"); // returns true
   2204      * $state.includes("contacts.details.item"); // returns true
   2205      * $state.includes("contacts.list"); // returns false
   2206      * $state.includes("about"); // returns false
   2207      * </pre>
   2208      *
   2209      * @description
   2210      * Basic globing patterns will also work.
   2211      *
   2212      * @example
   2213      * <pre>
   2214      * $state.$current.name = 'contacts.details.item.url';
   2215      *
   2216      * $state.includes("*.details.*.*"); // returns true
   2217      * $state.includes("*.details.**"); // returns true
   2218      * $state.includes("**.item.**"); // returns true
   2219      * $state.includes("*.details.item.url"); // returns true
   2220      * $state.includes("*.details.*.url"); // returns true
   2221      * $state.includes("*.details.*"); // returns false
   2222      * $state.includes("item.**"); // returns false
   2223      * </pre>
   2224      *
   2225      * @param {string} stateOrName A partial name to be searched for within the current state name.
   2226      * @param {object} params A param object, e.g. `{sectionId: section.id}`, 
   2227      * that you'd like to test against the current active state.
   2228      * @returns {boolean} Returns true if it does include the state
   2229      */
   2230 
   2231     $state.includes = function includes(stateOrName, params) {
   2232       if (isString(stateOrName) && isGlob(stateOrName)) {
   2233         if (doesStateMatchGlob(stateOrName)) {
   2234           stateOrName = $state.$current.name;
   2235         } else {
   2236           return false;
   2237         }
   2238       }
   2239 
   2240       var state = findState(stateOrName);
   2241       if (!isDefined(state)) {
   2242         return undefined;
   2243       }
   2244 
   2245       if (!isDefined($state.$current.includes[state.name])) {
   2246         return false;
   2247       }
   2248 
   2249       var validParams = true;
   2250       angular.forEach(params, function(value, key) {
   2251         if (!isDefined($stateParams[key]) || $stateParams[key] !== value) {
   2252           validParams = false;
   2253         }
   2254       });
   2255       return validParams;
   2256     };
   2257 
   2258 
   2259     /**
   2260      * @ngdoc function
   2261      * @name ui.router.state.$state#href
   2262      * @methodOf ui.router.state.$state
   2263      *
   2264      * @description
   2265      * A url generation method that returns the compiled url for the given state populated with the given params.
   2266      *
   2267      * @example
   2268      * <pre>
   2269      * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
   2270      * </pre>
   2271      *
   2272      * @param {string|object} stateOrName The state name or state object you'd like to generate a url from.
   2273      * @param {object=} params An object of parameter values to fill the state's required parameters.
   2274      * @param {object=} options Options object. The options are:
   2275      *
   2276      * - **`lossy`** - {boolean=true} -  If true, and if there is no url associated with the state provided in the
   2277      *    first parameter, then the constructed href url will be built from the first navigable ancestor (aka
   2278      *    ancestor with a valid url).
   2279      * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url.
   2280      * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), 
   2281      *    defines which state to be relative from.
   2282      * - **`absolute`** - {boolean=false},  If true will generate an absolute url, e.g. "http://www.example.com/fullurl".
   2283      * 
   2284      * @returns {string} compiled state url
   2285      */
   2286     $state.href = function href(stateOrName, params, options) {
   2287       options = extend({ lossy: true, inherit: false, absolute: false, relative: $state.$current }, options || {});
   2288       var state = findState(stateOrName, options.relative);
   2289       if (!isDefined(state)) return null;
   2290 
   2291       params = inheritParams($stateParams, params || {}, $state.$current, state);
   2292       var nav = (state && options.lossy) ? state.navigable : state;
   2293       var url = (nav && nav.url) ? nav.url.format(normalize(state.params, params || {})) : null;
   2294       if (!$locationProvider.html5Mode() && url) {
   2295         url = "#" + $locationProvider.hashPrefix() + url;
   2296       }
   2297 
   2298       if (baseHref !== '/') {
   2299         if ($locationProvider.html5Mode()) {
   2300           url = baseHref.slice(0, -1) + url;
   2301         } else if (options.absolute){
   2302           url = baseHref.slice(1) + url;
   2303         }
   2304       }
   2305 
   2306       if (options.absolute && url) {
   2307         url = $location.protocol() + '://' + 
   2308               $location.host() + 
   2309               ($location.port() == 80 || $location.port() == 443 ? '' : ':' + $location.port()) + 
   2310               (!$locationProvider.html5Mode() && url ? '/' : '') + 
   2311               url;
   2312       }
   2313       return url;
   2314     };
   2315 
   2316     /**
   2317      * @ngdoc function
   2318      * @name ui.router.state.$state#get
   2319      * @methodOf ui.router.state.$state
   2320      *
   2321      * @description
   2322      * Returns the state configuration object for any specific state or all states.
   2323      *
   2324      * @param {string|object=} stateOrName If provided, will only get the config for
   2325      * the requested state. If not provided, returns an array of ALL state configs.
   2326      * @returns {object|array} State configuration object or array of all objects.
   2327      */
   2328     $state.get = function (stateOrName, context) {
   2329       if (!isDefined(stateOrName)) {
   2330         var list = [];
   2331         forEach(states, function(state) { list.push(state.self); });
   2332         return list;
   2333       }
   2334       var state = findState(stateOrName, context);
   2335       return (state && state.self) ? state.self : null;
   2336     };
   2337 
   2338     function resolveState(state, params, paramsAreFiltered, inherited, dst) {
   2339       // Make a restricted $stateParams with only the parameters that apply to this state if
   2340       // necessary. In addition to being available to the controller and onEnter/onExit callbacks,
   2341       // we also need $stateParams to be available for any $injector calls we make during the
   2342       // dependency resolution process.
   2343       var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params, params);
   2344       var locals = { $stateParams: $stateParams };
   2345 
   2346       // Resolve 'global' dependencies for the state, i.e. those not specific to a view.
   2347       // We're also including $stateParams in this; that way the parameters are restricted
   2348       // to the set that should be visible to the state, and are independent of when we update
   2349       // the global $state and $stateParams values.
   2350       dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state);
   2351       var promises = [ dst.resolve.then(function (globals) {
   2352         dst.globals = globals;
   2353       }) ];
   2354       if (inherited) promises.push(inherited);
   2355 
   2356       // Resolve template and dependencies for all views.
   2357       forEach(state.views, function (view, name) {
   2358         var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {});
   2359         injectables.$template = [ function () {
   2360           return $view.load(name, { view: view, locals: locals, params: $stateParams, notify: false }) || '';
   2361         }];
   2362 
   2363         promises.push($resolve.resolve(injectables, locals, dst.resolve, state).then(function (result) {
   2364           // References to the controller (only instantiated at link time)
   2365           if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) {
   2366             var injectLocals = angular.extend({}, injectables, locals);
   2367             result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals);
   2368           } else {
   2369             result.$$controller = view.controller;
   2370           }
   2371           // Provide access to the state itself for internal use
   2372           result.$$state = state;
   2373           result.$$controllerAs = view.controllerAs;
   2374           dst[name] = result;
   2375         }));
   2376       });
   2377 
   2378       // Wait for all the promises and then return the activation object
   2379       return $q.all(promises).then(function (values) {
   2380         return dst;
   2381       });
   2382     }
   2383 
   2384     return $state;
   2385   }
   2386 
   2387   function shouldTriggerReload(to, from, locals, options) {
   2388     if ( to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false)) ) {
   2389       return true;
   2390     }
   2391   }
   2392 }
   2393 
   2394 angular.module('ui.router.state')
   2395   .value('$stateParams', {})
   2396   .provider('$state', $StateProvider);
   2397 
   2398 
   2399 $ViewProvider.$inject = [];
   2400 function $ViewProvider() {
   2401 
   2402   this.$get = $get;
   2403   /**
   2404    * @ngdoc object
   2405    * @name ui.router.state.$view
   2406    *
   2407    * @requires ui.router.util.$templateFactory
   2408    * @requires $rootScope
   2409    *
   2410    * @description
   2411    *
   2412    */
   2413   $get.$inject = ['$rootScope', '$templateFactory'];
   2414   function $get(   $rootScope,   $templateFactory) {
   2415     return {
   2416       // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... })
   2417       /**
   2418        * @ngdoc function
   2419        * @name ui.router.state.$view#load
   2420        * @methodOf ui.router.state.$view
   2421        *
   2422        * @description
   2423        *
   2424        * @param {string} name name
   2425        * @param {object} options option object.
   2426        */
   2427       load: function load(name, options) {
   2428         var result, defaults = {
   2429           template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {}
   2430         };
   2431         options = extend(defaults, options);
   2432 
   2433         if (options.view) {
   2434           result = $templateFactory.fromConfig(options.view, options.params, options.locals);
   2435         }
   2436         if (result && options.notify) {
   2437         /**
   2438          * @ngdoc event
   2439          * @name ui.router.state.$state#$viewContentLoading
   2440          * @eventOf ui.router.state.$view
   2441          * @eventType broadcast on root scope
   2442          * @description
   2443          *
   2444          * Fired once the view **begins loading**, *before* the DOM is rendered.
   2445          *
   2446          * @param {Object} event Event object.
   2447          * @param {Object} viewConfig The view config properties (template, controller, etc).
   2448          *
   2449          * @example
   2450          *
   2451          * <pre>
   2452          * $scope.$on('$viewContentLoading',
   2453          * function(event, viewConfig){
   2454          *     // Access to all the view config properties.
   2455          *     // and one special property 'targetView'
   2456          *     // viewConfig.targetView
   2457          * });
   2458          * </pre>
   2459          */
   2460           $rootScope.$broadcast('$viewContentLoading', options);
   2461         }
   2462         return result;
   2463       }
   2464     };
   2465   }
   2466 }
   2467 
   2468 angular.module('ui.router.state').provider('$view', $ViewProvider);
   2469 
   2470 /**
   2471  * @ngdoc object
   2472  * @name ui.router.state.$uiViewScrollProvider
   2473  *
   2474  * @description
   2475  * Provider that returns the {@link ui.router.state.$uiViewScroll} service function.
   2476  */
   2477 function $ViewScrollProvider() {
   2478 
   2479   var useAnchorScroll = false;
   2480 
   2481   /**
   2482    * @ngdoc function
   2483    * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll
   2484    * @methodOf ui.router.state.$uiViewScrollProvider
   2485    *
   2486    * @description
   2487    * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for
   2488    * scrolling based on the url anchor.
   2489    */
   2490   this.useAnchorScroll = function () {
   2491     useAnchorScroll = true;
   2492   };
   2493 
   2494   /**
   2495    * @ngdoc object
   2496    * @name ui.router.state.$uiViewScroll
   2497    *
   2498    * @requires $anchorScroll
   2499    * @requires $timeout
   2500    *
   2501    * @description
   2502    * When called with a jqLite element, it scrolls the element into view (after a
   2503    * `$timeout` so the DOM has time to refresh).
   2504    *
   2505    * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor,
   2506    * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}.
   2507    */
   2508   this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) {
   2509     if (useAnchorScroll) {
   2510       return $anchorScroll;
   2511     }
   2512 
   2513     return function ($element) {
   2514       $timeout(function () {
   2515         $element[0].scrollIntoView();
   2516       }, 0, false);
   2517     };
   2518   }];
   2519 }
   2520 
   2521 angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider);
   2522 
   2523 /**
   2524  * @ngdoc directive
   2525  * @name ui.router.state.directive:ui-view
   2526  *
   2527  * @requires ui.router.state.$state
   2528  * @requires $compile
   2529  * @requires $controller
   2530  * @requires $injector
   2531  * @requires ui.router.state.$uiViewScroll
   2532  * @requires $document
   2533  *
   2534  * @restrict ECA
   2535  *
   2536  * @description
   2537  * The ui-view directive tells $state where to place your templates.
   2538  *
   2539  * @param {string=} ui-view A view name. The name should be unique amongst the other views in the
   2540  * same state. You can have views of the same name that live in different states.
   2541  *
   2542  * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window
   2543  * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll
   2544  * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you
   2545  * scroll ui-view elements into view when they are populated during a state activation.
   2546  *
   2547  * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll)
   2548  * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.*
   2549  *
   2550  * @param {string=} onload Expression to evaluate whenever the view updates.
   2551  * 
   2552  * @example
   2553  * A view can be unnamed or named. 
   2554  * <pre>
   2555  * <!-- Unnamed -->
   2556  * <div ui-view></div> 
   2557  * 
   2558  * <!-- Named -->
   2559  * <div ui-view="viewName"></div>
   2560  * </pre>
   2561  *
   2562  * You can only have one unnamed view within any template (or root html). If you are only using a 
   2563  * single view and it is unnamed then you can populate it like so:
   2564  * <pre>
   2565  * <div ui-view></div> 
   2566  * $stateProvider.state("home", {
   2567  *   template: "<h1>HELLO!</h1>"
   2568  * })
   2569  * </pre>
   2570  * 
   2571  * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#views `views`}
   2572  * config property, by name, in this case an empty name:
   2573  * <pre>
   2574  * $stateProvider.state("home", {
   2575  *   views: {
   2576  *     "": {
   2577  *       template: "<h1>HELLO!</h1>"
   2578  *     }
   2579  *   }    
   2580  * })
   2581  * </pre>
   2582  * 
   2583  * But typically you'll only use the views property if you name your view or have more than one view 
   2584  * in the same template. There's not really a compelling reason to name a view if its the only one, 
   2585  * but you could if you wanted, like so:
   2586  * <pre>
   2587  * <div ui-view="main"></div>
   2588  * </pre> 
   2589  * <pre>
   2590  * $stateProvider.state("home", {
   2591  *   views: {
   2592  *     "main": {
   2593  *       template: "<h1>HELLO!</h1>"
   2594  *     }
   2595  *   }    
   2596  * })
   2597  * </pre>
   2598  * 
   2599  * Really though, you'll use views to set up multiple views:
   2600  * <pre>
   2601  * <div ui-view></div>
   2602  * <div ui-view="chart"></div> 
   2603  * <div ui-view="data"></div> 
   2604  * </pre>
   2605  * 
   2606  * <pre>
   2607  * $stateProvider.state("home", {
   2608  *   views: {
   2609  *     "": {
   2610  *       template: "<h1>HELLO!</h1>"
   2611  *     },
   2612  *     "chart": {
   2613  *       template: "<chart_thing/>"
   2614  *     },
   2615  *     "data": {
   2616  *       template: "<data_thing/>"
   2617  *     }
   2618  *   }    
   2619  * })
   2620  * </pre>
   2621  *
   2622  * Examples for `autoscroll`:
   2623  *
   2624  * <pre>
   2625  * <!-- If autoscroll present with no expression,
   2626  *      then scroll ui-view into view -->
   2627  * <ui-view autoscroll/>
   2628  *
   2629  * <!-- If autoscroll present with valid expression,
   2630  *      then scroll ui-view into view if expression evaluates to true -->
   2631  * <ui-view autoscroll='true'/>
   2632  * <ui-view autoscroll='false'/>
   2633  * <ui-view autoscroll='scopeVariable'/>
   2634  * </pre>
   2635  */
   2636 $ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll'];
   2637 function $ViewDirective(   $state,   $injector,   $uiViewScroll) {
   2638 
   2639   function getService() {
   2640     return ($injector.has) ? function(service) {
   2641       return $injector.has(service) ? $injector.get(service) : null;
   2642     } : function(service) {
   2643       try {
   2644         return $injector.get(service);
   2645       } catch (e) {
   2646         return null;
   2647       }
   2648     };
   2649   }
   2650 
   2651   var service = getService(),
   2652       $animator = service('$animator'),
   2653       $animate = service('$animate');
   2654 
   2655   // Returns a set of DOM manipulation functions based on which Angular version
   2656   // it should use
   2657   function getRenderer(attrs, scope) {
   2658     var statics = function() {
   2659       return {
   2660         enter: function (element, target, cb) { target.after(element); cb(); },
   2661         leave: function (element, cb) { element.remove(); cb(); }
   2662       };
   2663     };
   2664 
   2665     if ($animate) {
   2666       return {
   2667         enter: function(element, target, cb) { $animate.enter(element, null, target, cb); },
   2668         leave: function(element, cb) { $animate.leave(element, cb); }
   2669       };
   2670     }
   2671 
   2672     if ($animator) {
   2673       var animate = $animator && $animator(scope, attrs);
   2674 
   2675       return {
   2676         enter: function(element, target, cb) {animate.enter(element, null, target); cb(); },
   2677         leave: function(element, cb) { animate.leave(element); cb(); }
   2678       };
   2679     }
   2680 
   2681     return statics();
   2682   }
   2683 
   2684   var directive = {
   2685     restrict: 'ECA',
   2686     terminal: true,
   2687     priority: 400,
   2688     transclude: 'element',
   2689     compile: function (tElement, tAttrs, $transclude) {
   2690       return function (scope, $element, attrs) {
   2691         var previousEl, currentEl, currentScope, latestLocals,
   2692             onloadExp     = attrs.onload || '',
   2693             autoScrollExp = attrs.autoscroll,
   2694             renderer      = getRenderer(attrs, scope);
   2695 
   2696         scope.$on('$stateChangeSuccess', function() {
   2697           updateView(false);
   2698         });
   2699         scope.$on('$viewContentLoading', function() {
   2700           updateView(false);
   2701         });
   2702 
   2703         updateView(true);
   2704 
   2705         function cleanupLastView() {
   2706           if (previousEl) {
   2707             previousEl.remove();
   2708             previousEl = null;
   2709           }
   2710 
   2711           if (currentScope) {
   2712             currentScope.$destroy();
   2713             currentScope = null;
   2714           }
   2715 
   2716           if (currentEl) {
   2717             renderer.leave(currentEl, function() {
   2718               previousEl = null;
   2719             });
   2720 
   2721             previousEl = currentEl;
   2722             currentEl = null;
   2723           }
   2724         }
   2725 
   2726         function updateView(firstTime) {
   2727           var newScope        = scope.$new(),
   2728               name            = currentEl && currentEl.data('$uiViewName'),
   2729               previousLocals  = name && $state.$current && $state.$current.locals[name];
   2730 
   2731           if (!firstTime && previousLocals === latestLocals) return; // nothing to do
   2732 
   2733           var clone = $transclude(newScope, function(clone) {
   2734             renderer.enter(clone, $element, function onUiViewEnter() {
   2735               if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) {
   2736                 $uiViewScroll(clone);
   2737               }
   2738             });
   2739             cleanupLastView();
   2740           });
   2741 
   2742           latestLocals = $state.$current.locals[clone.data('$uiViewName')];
   2743 
   2744           currentEl = clone;
   2745           currentScope = newScope;
   2746           /**
   2747            * @ngdoc event
   2748            * @name ui.router.state.directive:ui-view#$viewContentLoaded
   2749            * @eventOf ui.router.state.directive:ui-view
   2750            * @eventType emits on ui-view directive scope
   2751            * @description           *
   2752            * Fired once the view is **loaded**, *after* the DOM is rendered.
   2753            *
   2754            * @param {Object} event Event object.
   2755            */
   2756           currentScope.$emit('$viewContentLoaded');
   2757           currentScope.$eval(onloadExp);
   2758         }
   2759       };
   2760     }
   2761   };
   2762 
   2763   return directive;
   2764 }
   2765 
   2766 $ViewDirectiveFill.$inject = ['$compile', '$controller', '$state'];
   2767 function $ViewDirectiveFill ($compile, $controller, $state) {
   2768   return {
   2769     restrict: 'ECA',
   2770     priority: -400,
   2771     compile: function (tElement) {
   2772       var initial = tElement.html();
   2773       return function (scope, $element, attrs) {
   2774         var name      = attrs.uiView || attrs.name || '',
   2775             inherited = $element.inheritedData('$uiView');
   2776 
   2777         if (name.indexOf('@') < 0) {
   2778           name = name + '@' + (inherited ? inherited.state.name : '');
   2779         }
   2780 
   2781         $element.data('$uiViewName', name);
   2782 
   2783         var current = $state.$current,
   2784             locals  = current && current.locals[name];
   2785 
   2786         if (! locals) {
   2787           return;
   2788         }
   2789 
   2790         $element.data('$uiView', { name: name, state: locals.$$state });
   2791         $element.html(locals.$template ? locals.$template : initial);
   2792 
   2793         var link = $compile($element.contents());
   2794 
   2795         if (locals.$$controller) {
   2796           locals.$scope = scope;
   2797           var controller = $controller(locals.$$controller, locals);
   2798           if (locals.$$controllerAs) {
   2799             scope[locals.$$controllerAs] = controller;
   2800           }
   2801           $element.data('$ngControllerController', controller);
   2802           $element.children().data('$ngControllerController', controller);
   2803         }
   2804 
   2805         link(scope);
   2806       };
   2807     }
   2808   };
   2809 }
   2810 
   2811 angular.module('ui.router.state').directive('uiView', $ViewDirective);
   2812 angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);
   2813 
   2814 function parseStateRef(ref) {
   2815   var parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
   2816   if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
   2817   return { state: parsed[1], paramExpr: parsed[3] || null };
   2818 }
   2819 
   2820 function stateContext(el) {
   2821   var stateData = el.parent().inheritedData('$uiView');
   2822 
   2823   if (stateData && stateData.state && stateData.state.name) {
   2824     return stateData.state;
   2825   }
   2826 }
   2827 
   2828 /**
   2829  * @ngdoc directive
   2830  * @name ui.router.state.directive:ui-sref
   2831  *
   2832  * @requires ui.router.state.$state
   2833  * @requires $timeout
   2834  *
   2835  * @restrict A
   2836  *
   2837  * @description
   2838  * A directive that binds a link (`<a>` tag) to a state. If the state has an associated 
   2839  * URL, the directive will automatically generate & update the `href` attribute via 
   2840  * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking 
   2841  * the link will trigger a state transition with optional parameters. 
   2842  *
   2843  * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be 
   2844  * handled natively by the browser.
   2845  *
   2846  * You can also use relative state paths within ui-sref, just like the relative 
   2847  * paths passed to `$state.go()`. You just need to be aware that the path is relative
   2848  * to the state that the link lives in, in other words the state that loaded the 
   2849  * template containing the link.
   2850  *
   2851  * You can specify options to pass to {@link ui.router.state.$state#go $state.go()}
   2852  * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`,
   2853  * and `reload`.
   2854  *
   2855  * @example
   2856  * Here's an example of how you'd use ui-sref and how it would compile. If you have the 
   2857  * following template:
   2858  * <pre>
   2859  * <a ui-sref="home">Home</a> | <a ui-sref="about">About</a>
   2860  * 
   2861  * <ul>
   2862  *     <li ng-repeat="contact in contacts">
   2863  *         <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a>
   2864  *     </li>
   2865  * </ul>
   2866  * </pre>
   2867  * 
   2868  * Then the compiled html would be (assuming Html5Mode is off):
   2869  * <pre>
   2870  * <a href="#/home" ui-sref="home">Home</a> | <a href="#/about" ui-sref="about">About</a>
   2871  * 
   2872  * <ul>
   2873  *     <li ng-repeat="contact in contacts">
   2874  *         <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a>
   2875  *     </li>
   2876  *     <li ng-repeat="contact in contacts">
   2877  *         <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a>
   2878  *     </li>
   2879  *     <li ng-repeat="contact in contacts">
   2880  *         <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a>
   2881  *     </li>
   2882  * </ul>
   2883  *
   2884  * <a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
   2885  * </pre>
   2886  *
   2887  * @param {string} ui-sref 'stateName' can be any valid absolute or relative state
   2888  * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#go $state.go()}
   2889  */
   2890 $StateRefDirective.$inject = ['$state', '$timeout'];
   2891 function $StateRefDirective($state, $timeout) {
   2892   var allowedOptions = ['location', 'inherit', 'reload'];
   2893 
   2894   return {
   2895     restrict: 'A',
   2896     require: '?^uiSrefActive',
   2897     link: function(scope, element, attrs, uiSrefActive) {
   2898       var ref = parseStateRef(attrs.uiSref);
   2899       var params = null, url = null, base = stateContext(element) || $state.$current;
   2900       var isForm = element[0].nodeName === "FORM";
   2901       var attr = isForm ? "action" : "href", nav = true;
   2902 
   2903       var options = {
   2904         relative: base
   2905       };
   2906       var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {};
   2907       angular.forEach(allowedOptions, function(option) {
   2908         if (option in optionsOverride) {
   2909           options[option] = optionsOverride[option];
   2910         }
   2911       });
   2912 
   2913       var update = function(newVal) {
   2914         if (newVal) params = newVal;
   2915         if (!nav) return;
   2916 
   2917         var newHref = $state.href(ref.state, params, options);
   2918 
   2919         if (uiSrefActive) {
   2920           uiSrefActive.$$setStateInfo(ref.state, params);
   2921         }
   2922         if (!newHref) {
   2923           nav = false;
   2924           return false;
   2925         }
   2926         element[0][attr] = newHref;
   2927       };
   2928 
   2929       if (ref.paramExpr) {
   2930         scope.$watch(ref.paramExpr, function(newVal, oldVal) {
   2931           if (newVal !== params) update(newVal);
   2932         }, true);
   2933         params = scope.$eval(ref.paramExpr);
   2934       }
   2935       update();
   2936 
   2937       if (isForm) return;
   2938 
   2939       element.bind("click", function(e) {
   2940         var button = e.which || e.button;
   2941         if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) {
   2942           // HACK: This is to allow ng-clicks to be processed before the transition is initiated:
   2943           $timeout(function() {
   2944             $state.go(ref.state, params, options);
   2945           });
   2946           e.preventDefault();
   2947         }
   2948       });
   2949     }
   2950   };
   2951 }
   2952 
   2953 /**
   2954  * @ngdoc directive
   2955  * @name ui.router.state.directive:ui-sref-active
   2956  *
   2957  * @requires ui.router.state.$state
   2958  * @requires ui.router.state.$stateParams
   2959  * @requires $interpolate
   2960  *
   2961  * @restrict A
   2962  *
   2963  * @description
   2964  * A directive working alongside ui-sref to add classes to an element when the 
   2965  * related ui-sref directive's state is active, and removing them when it is inactive.
   2966  * The primary use-case is to simplify the special appearance of navigation menus 
   2967  * relying on `ui-sref`, by having the "active" state's menu button appear different,
   2968  * distinguishing it from the inactive menu items.
   2969  *
   2970  * @example
   2971  * Given the following template:
   2972  * <pre>
   2973  * <ul>
   2974  *   <li ui-sref-active="active" class="item">
   2975  *     <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
   2976  *   </li>
   2977  * </ul>
   2978  * </pre>
   2979  * 
   2980  * When the app state is "app.user", and contains the state parameter "user" with value "bilbobaggins", 
   2981  * the resulting HTML will appear as (note the 'active' class):
   2982  * <pre>
   2983  * <ul>
   2984  *   <li ui-sref-active="active" class="item active">
   2985  *     <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
   2986  *   </li>
   2987  * </ul>
   2988  * </pre>
   2989  * 
   2990  * The class name is interpolated **once** during the directives link time (any further changes to the 
   2991  * interpolated value are ignored). 
   2992  * 
   2993  * Multiple classes may be specified in a space-separated format:
   2994  * <pre>
   2995  * <ul>
   2996  *   <li ui-sref-active='class1 class2 class3'>
   2997  *     <a ui-sref="app.user">link</a>
   2998  *   </li>
   2999  * </ul>
   3000  * </pre>
   3001  */
   3002 $StateActiveDirective.$inject = ['$state', '$stateParams', '$interpolate'];
   3003 function $StateActiveDirective($state, $stateParams, $interpolate) {
   3004   return {
   3005     restrict: "A",
   3006     controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
   3007       var state, params, activeClass;
   3008 
   3009       // There probably isn't much point in $observing this
   3010       activeClass = $interpolate($attrs.uiSrefActive || '', false)($scope);
   3011 
   3012       // Allow uiSref to communicate with uiSrefActive
   3013       this.$$setStateInfo = function(newState, newParams) {
   3014         state = $state.get(newState, stateContext($element));
   3015         params = newParams;
   3016         update();
   3017       };
   3018 
   3019       $scope.$on('$stateChangeSuccess', update);
   3020 
   3021       // Update route state
   3022       function update() {
   3023         if ($state.$current.self === state && matchesParams()) {
   3024           $element.addClass(activeClass);
   3025         } else {
   3026           $element.removeClass(activeClass);
   3027         }
   3028       }
   3029 
   3030       function matchesParams() {
   3031         return !params || equalForKeys(params, $stateParams);
   3032       }
   3033     }]
   3034   };
   3035 }
   3036 
   3037 angular.module('ui.router.state')
   3038   .directive('uiSref', $StateRefDirective)
   3039   .directive('uiSrefActive', $StateActiveDirective);
   3040 
   3041 /**
   3042  * @ngdoc filter
   3043  * @name ui.router.state.filter:isState
   3044  *
   3045  * @requires ui.router.state.$state
   3046  *
   3047  * @description
   3048  * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}.
   3049  */
   3050 $IsStateFilter.$inject = ['$state'];
   3051 function $IsStateFilter($state) {
   3052   return function(state) {
   3053     return $state.is(state);
   3054   };
   3055 }
   3056 
   3057 /**
   3058  * @ngdoc filter
   3059  * @name ui.router.state.filter:includedByState
   3060  *
   3061  * @requires ui.router.state.$state
   3062  *
   3063  * @description
   3064  * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}.
   3065  */
   3066 $IncludedByStateFilter.$inject = ['$state'];
   3067 function $IncludedByStateFilter($state) {
   3068   return function(state) {
   3069     return $state.includes(state);
   3070   };
   3071 }
   3072 
   3073 angular.module('ui.router.state')
   3074   .filter('isState', $IsStateFilter)
   3075   .filter('includedByState', $IncludedByStateFilter);
   3076 
   3077 /*
   3078  * @ngdoc object
   3079  * @name ui.router.compat.$routeProvider
   3080  *
   3081  * @requires ui.router.state.$stateProvider
   3082  * @requires ui.router.router.$urlRouterProvider
   3083  *
   3084  * @description
   3085  * `$routeProvider` of the `ui.router.compat` module overwrites the existing
   3086  * `routeProvider` from the core. This is done to provide compatibility between
   3087  * the UI Router and the core router.
   3088  *
   3089  * It also provides a `when()` method to register routes that map to certain urls.
   3090  * Behind the scenes it actually delegates either to 
   3091  * {@link ui.router.router.$urlRouterProvider $urlRouterProvider} or to the 
   3092  * {@link ui.router.state.$stateProvider $stateProvider} to postprocess the given 
   3093  * router definition object.
   3094  */
   3095 $RouteProvider.$inject = ['$stateProvider', '$urlRouterProvider'];
   3096 function $RouteProvider(  $stateProvider,    $urlRouterProvider) {
   3097 
   3098   var routes = [];
   3099 
   3100   onEnterRoute.$inject = ['$$state'];
   3101   function onEnterRoute(   $$state) {
   3102     /*jshint validthis: true */
   3103     this.locals = $$state.locals.globals;
   3104     this.params = this.locals.$stateParams;
   3105   }
   3106 
   3107   function onExitRoute() {
   3108     /*jshint validthis: true */
   3109     this.locals = null;
   3110     this.params = null;
   3111   }
   3112 
   3113   this.when = when;
   3114   /*
   3115    * @ngdoc function
   3116    * @name ui.router.compat.$routeProvider#when
   3117    * @methodOf ui.router.compat.$routeProvider
   3118    *
   3119    * @description
   3120    * Registers a route with a given route definition object. The route definition
   3121    * object has the same interface the angular core route definition object has.
   3122    * 
   3123    * @example
   3124    * <pre>
   3125    * var app = angular.module('app', ['ui.router.compat']);
   3126    *
   3127    * app.config(function ($routeProvider) {
   3128    *   $routeProvider.when('home', {
   3129    *     controller: function () { ... },
   3130    *     templateUrl: 'path/to/template'
   3131    *   });
   3132    * });
   3133    * </pre>
   3134    *
   3135    * @param {string} url URL as string
   3136    * @param {object} route Route definition object
   3137    *
   3138    * @return {object} $routeProvider - $routeProvider instance
   3139    */
   3140   function when(url, route) {
   3141     /*jshint validthis: true */
   3142     if (route.redirectTo != null) {
   3143       // Redirect, configure directly on $urlRouterProvider
   3144       var redirect = route.redirectTo, handler;
   3145       if (isString(redirect)) {
   3146         handler = redirect; // leave $urlRouterProvider to handle
   3147       } else if (isFunction(redirect)) {
   3148         // Adapt to $urlRouterProvider API
   3149         handler = function (params, $location) {
   3150           return redirect(params, $location.path(), $location.search());
   3151         };
   3152       } else {
   3153         throw new Error("Invalid 'redirectTo' in when()");
   3154       }
   3155       $urlRouterProvider.when(url, handler);
   3156     } else {
   3157       // Regular route, configure as state
   3158       $stateProvider.state(inherit(route, {
   3159         parent: null,
   3160         name: 'route:' + encodeURIComponent(url),
   3161         url: url,
   3162         onEnter: onEnterRoute,
   3163         onExit: onExitRoute
   3164       }));
   3165     }
   3166     routes.push(route);
   3167     return this;
   3168   }
   3169 
   3170   /*
   3171    * @ngdoc object
   3172    * @name ui.router.compat.$route
   3173    *
   3174    * @requires ui.router.state.$state
   3175    * @requires $rootScope
   3176    * @requires $routeParams
   3177    *
   3178    * @property {object} routes - Array of registered routes.
   3179    * @property {object} params - Current route params as object.
   3180    * @property {string} current - Name of the current route.
   3181    *
   3182    * @description
   3183    * The `$route` service provides interfaces to access defined routes. It also let's
   3184    * you access route params through `$routeParams` service, so you have fully
   3185    * control over all the stuff you would actually get from angular's core `$route`
   3186    * service.
   3187    */
   3188   this.$get = $get;
   3189   $get.$inject = ['$state', '$rootScope', '$routeParams'];
   3190   function $get(   $state,   $rootScope,   $routeParams) {
   3191 
   3192     var $route = {
   3193       routes: routes,
   3194       params: $routeParams,
   3195       current: undefined
   3196     };
   3197 
   3198     function stateAsRoute(state) {
   3199       return (state.name !== '') ? state : undefined;
   3200     }
   3201 
   3202     $rootScope.$on('$stateChangeStart', function (ev, to, toParams, from, fromParams) {
   3203       $rootScope.$broadcast('$routeChangeStart', stateAsRoute(to), stateAsRoute(from));
   3204     });
   3205 
   3206     $rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
   3207       $route.current = stateAsRoute(to);
   3208       $rootScope.$broadcast('$routeChangeSuccess', stateAsRoute(to), stateAsRoute(from));
   3209       copy(toParams, $route.params);
   3210     });
   3211 
   3212     $rootScope.$on('$stateChangeError', function (ev, to, toParams, from, fromParams, error) {
   3213       $rootScope.$broadcast('$routeChangeError', stateAsRoute(to), stateAsRoute(from), error);
   3214     });
   3215 
   3216     return $route;
   3217   }
   3218 }
   3219 
   3220 angular.module('ui.router.compat')
   3221   .provider('$route', $RouteProvider)
   3222   .directive('ngView', $ViewDirective);
   3223 })(window, window.angular);