text: /**
   * @ngdoc object
   * @name ui.router.util.type:UrlMatcher
   *
   * @description
   * Matches URLs against patterns and extracts named parameters from the path or the search
   * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
   * of search parameters. Multiple search parameter names are separated by '&'. Search parameters
   * do not influence whether or not a URL is matched, but their values are passed through into
   * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.
   * 
   * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
   * syntax, which optionally allows a regular expression for the parameter to be specified:
   *
   * * `':'` name - colon placeholder
   * * `'*'` name - catch-all placeholder
   * * `'{' name '}'` - curly placeholder
   * * `'{' name ':' regexp '}'` - curly placeholder with regexp. Should the regexp itself contain
   *   curly braces, they must be in matched pairs or escaped with a backslash.
   *
   * Parameter names may contain only word characters (latin letters, digits, and underscore) and
   * must be unique within the pattern (across both path and search parameters). For colon 
   * placeholders or curly placeholders without an explicit regexp, a path parameter matches any
   * number of characters other than '/'. For catch-all placeholders the path parameter matches
   * any number of characters.
   * 
   * Examples:
   * 
   * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
   *   trailing slashes, and patterns have to match the entire path, not just a prefix.
   * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
   *   '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
   * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
   * * `'/user/{id:[^/]*}'` - Same as the previous example.
   * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
   *   parameter consists of 1 to 8 hex digits.
   * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
   *   path into the parameter 'path'.
   * * `'/files/*path'` - ditto.
   *
   * @param {string} pattern  The pattern to compile into a matcher.
   * @param {Object} config  A configuration object hash:
   *
   * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.
   * * `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`.
   *
   * @property {string} prefix  A static prefix of this pattern. The matcher guarantees that any
   *   URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns
   *   non-null) will start with this prefix.
   *
   * @property {string} source  The pattern that was passed into the constructor
   *
   * @property {string} sourcePath  The path portion of the source property
   *
   * @property {string} sourceSearch  The search portion of the source property
   *
   * @property {string} regex  The constructed regex that will be used to match against the url when 
   *   it is time to determine which url will match.
   *
   * @returns {Object}  New `UrlMatcher` object
   */
  function UrlMatcher(pattern, config) {
    config = angular.isObject(config) ? config : {};
  
    // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
    //   '*' name
    //   ':' name
    //   '{' name '}'
    //   '{' name ':' regexp '}'
    // The regular expression is somewhat complicated due to the need to allow curly braces
    // inside the regular expression. The placeholder regexp breaks down as follows:
    //    ([:*])(\w+)               classic placeholder ($1 / $2)
    //    \{(\w+)(?:\:( ... ))?\}   curly brace placeholder ($3) with optional regexp ... ($4)
    //    (?: ... | ... | ... )+    the regexp consists of any number of atoms, an atom being either
    //    [^{}\\]+                  - anything other than curly braces or backslash
    //    \\.                       - a backslash escape
    //    \{(?:[^{}\\]+|\\.)*\}     - a matched set of curly braces containing other atoms
    var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
        compiled = '^', last = 0, m,
        segments = this.segments = [],
        params = this.params = {};
  
    /**
     * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the
     * default value, which may be the result of an injectable function.
     */
    function $value(value) {
      /*jshint validthis: true */
      return isDefined(value) ? this.type.decode(value) : $UrlMatcherFactory.$$getDefaultValue(this);
    }
  
    function addParameter(id, type, config) {
      if (!/^\w+(-+\w+)*$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
      if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
      params[id] = extend({ type: type || new Type(), $value: $value }, config);
    }
  
    function quoteRegExp(string, pattern, isOptional) {
      var result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
      if (!pattern) return result;
      var flag = isOptional ? '?' : '';
      return result + flag + '(' + pattern + ')' + flag;
    }
  
    function paramConfig(param) {
      if (!config.params || !config.params[param]) return {};
      var cfg = config.params[param];
      return isObject(cfg) ? cfg : { value: cfg };
    }
  
    this.source = pattern;
  
    // Split into static segments separated by path parameter placeholders.
    // The number of segments is always 1 more than the number of parameters.
    var id, regexp, segment, type, cfg;
  
    while ((m = placeholder.exec(pattern))) {
      id      = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
      regexp  = m[4] || (m[1] == '*' ? '.*' : '[^/]*');
      segment = pattern.substring(last, m.index);
      type    = this.$types[regexp] || new Type({ pattern: new RegExp(regexp) });
      cfg     = paramConfig(id);
  
      if (segment.indexOf('?') >= 0) break; // we're into the search part
  
      compiled += quoteRegExp(segment, type.$subPattern(), isDefined(cfg.value));
      addParameter(id, type, cfg);
      segments.push(segment);
      last = placeholder.lastIndex;
    }
    segment = pattern.substring(last);
  
    // Find any search parameter names and remove them from the last segment
    var i = segment.indexOf('?');
  
    if (i >= 0) {
      var search = this.sourceSearch = segment.substring(i);
      segment = segment.substring(0, i);
      this.sourcePath = pattern.substring(0, last + i);
  
      // Allow parameters to be separated by '?' as well as '&' to make concat() easier
      forEach(search.substring(1).split(/[&?]/), function(key) {
        addParameter(key, null, paramConfig(key));
      });
    } else {
      this.sourcePath = pattern;
      this.sourceSearch = '';
    }
  
    compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$';
    segments.push(segment);
  
    this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
    this.prefix = segments[0];
  }
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:UrlMatcher#concat
   * @methodOf ui.router.util.type:UrlMatcher
   *
   * @description
   * Returns a new matcher for a pattern constructed by appending the path part and adding the
   * search parameters of the specified pattern to this pattern. The current pattern is not
   * modified. This can be understood as creating a pattern for URLs that are relative to (or
   * suffixes of) the current pattern.
   *
   * @example
   * The following two matchers are equivalent:
   * <pre>
   * new UrlMatcher('/user/{id}?q').concat('/details?date');
   * new UrlMatcher('/user/{id}/details?q&date');
   * </pre>
   *
   * @param {string} pattern  The pattern to append.
   * @param {Object} config  An object hash of the configuration for the matcher.
   * @returns {UrlMatcher}  A matcher for the concatenated pattern.
   */
  UrlMatcher.prototype.concat = function (pattern, config) {
    // Because order of search parameters is irrelevant, we can add our own search
    // parameters to the end of the new pattern. Parse the new pattern by itself
    // and then join the bits together, but it's much easier to do this on a string level.
    return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, config);
  };
  
  UrlMatcher.prototype.toString = function () {
    return this.source;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:UrlMatcher#exec
   * @methodOf ui.router.util.type:UrlMatcher
   *
   * @description
   * Tests the specified path against this matcher, and returns an object containing the captured
   * parameter values, or null if the path does not match. The returned object contains the values
   * of any search parameters that are mentioned in the pattern, but their value may be null if
   * they are not present in `searchParams`. This means that search parameters are always treated
   * as optional.
   *
   * @example
   * <pre>
   * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
   *   x: '1', q: 'hello'
   * });
   * // returns { id: 'bob', q: 'hello', r: null }
   * </pre>
   *
   * @param {string} path  The URL path to match, e.g. `$location.path()`.
   * @param {Object} searchParams  URL search parameters, e.g. `$location.search()`.
   * @returns {Object}  The captured parameter values.
   */
  UrlMatcher.prototype.exec = function (path, searchParams) {
    var m = this.regexp.exec(path);
    if (!m) return null;
    searchParams = searchParams || {};
  
    var params = this.parameters(), nTotal = params.length,
      nPath = this.segments.length - 1,
      values = {}, i, cfg, param;
  
    if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
  
    for (i = 0; i < nPath; i++) {
      param = params[i];
      cfg = this.params[param];
      values[param] = cfg.$value(m[i + 1]);
    }
    for (/**/; i < nTotal; i++) {
      param = params[i];
      cfg = this.params[param];
      values[param] = cfg.$value(searchParams[param]);
    }
  
    return values;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:UrlMatcher#parameters
   * @methodOf ui.router.util.type:UrlMatcher
   *
   * @description
   * Returns the names of all path and search parameters of this pattern in an unspecified order.
   * 
   * @returns {Array.<string>}  An array of parameter names. Must be treated as read-only. If the
   *    pattern has no parameters, an empty array is returned.
   */
  UrlMatcher.prototype.parameters = function (param) {
    if (!isDefined(param)) return objectKeys(this.params);
    return this.params[param] || null;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:UrlMatcher#validate
   * @methodOf ui.router.util.type:UrlMatcher
   *
   * @description
   * Checks an object hash of parameters to validate their correctness according to the parameter
   * types of this `UrlMatcher`.
   *
   * @param {Object} params The object hash of parameters to validate.
   * @returns {boolean} Returns `true` if `params` validates, otherwise `false`.
   */
  UrlMatcher.prototype.validates = function (params) {
    var result = true, isOptional, cfg, self = this;
  
    forEach(params, function(val, key) {
      if (!self.params[key]) return;
      cfg = self.params[key];
      isOptional = !val && isDefined(cfg.value);
      result = result && (isOptional || cfg.type.is(val));
    });
    return result;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:UrlMatcher#format
   * @methodOf ui.router.util.type:UrlMatcher
   *
   * @description
   * Creates a URL that matches this pattern by substituting the specified values
   * for the path and search parameters. Null values for path parameters are
   * treated as empty strings.
   *
   * @example
   * <pre>
   * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
   * // returns '/user/bob?q=yes'
   * </pre>
   *
   * @param {Object} values  the values to substitute for the parameters in this pattern.
   * @returns {string}  the formatted URL (path and optionally search part).
   */
  UrlMatcher.prototype.format = function (values) {
    var segments = this.segments, params = this.parameters();
  
    if (!values) return segments.join('').replace('//', '/');
  
    var nPath = segments.length - 1, nTotal = params.length,
      result = segments[0], i, search, value, param, cfg, array;
  
    if (!this.validates(values)) return null;
  
    for (i = 0; i < nPath; i++) {
      param = params[i];
      value = values[param];
      cfg   = this.params[param];
  
      if (!isDefined(value) && (segments[i] === '/' || segments[i + 1] === '/')) continue;
      if (value != null) result += encodeURIComponent(cfg.type.encode(value));
      result += segments[i + 1];
    }
  
    for (/**/; i < nTotal; i++) {
      param = params[i];
      value = values[param];
      if (value == null) continue;
      array = isArray(value);
  
      if (array) {
        value = value.map(encodeURIComponent).join('&' + param + '=');
      }
      result += (search ? '&' : '?') + param + '=' + (array ? value : encodeURIComponent(value));
      search = true;
    }
    return result;
  };
  
  UrlMatcher.prototype.$types = {};
  
  /**
   * @ngdoc object
   * @name ui.router.util.type:Type
   *
   * @description
   * Implements an interface to define custom parameter types that can be decoded from and encoded to
   * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`}
   * objects when matching or formatting URLs, or comparing or validating parameter values.
   *
   * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more
   * information on registering custom types.
   *
   * @param {Object} config  A configuration object hash that includes any method in `Type`'s public
   *        interface, and/or `pattern`, which should contain a custom regular expression used to match
   *        string parameters originating from a URL.
   *
   * @property {RegExp} pattern The regular expression pattern used to match values of this type when
   *           coming from a substring of a URL.
   *
   * @returns {Object}  Returns a new `Type` object.
   */
  function Type(config) {
    extend(this, config);
  }
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:Type#is
   * @methodOf ui.router.util.type:Type
   *
   * @description
   * Detects whether a value is of a particular type. Accepts a native (decoded) value
   * and determines whether it matches the current `Type` object.
   *
   * @param {*} val  The value to check.
   * @param {string} key  Optional. If the type check is happening in the context of a specific
   *        {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the
   *        parameter in which `val` is stored. Can be used for meta-programming of `Type` objects.
   * @returns {Boolean}  Returns `true` if the value matches the type, otherwise `false`.
   */
  Type.prototype.is = function(val, key) {
    return true;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:Type#encode
   * @methodOf ui.router.util.type:Type
   *
   * @description
   * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the
   * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it
   * only needs to be a representation of `val` that has been coerced to a string.
   *
   * @param {*} val  The value to encode.
   * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
   *        meta-programming of `Type` objects.
   * @returns {string}  Returns a string representation of `val` that can be encoded in a URL.
   */
  Type.prototype.encode = function(val, key) {
    return val;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:Type#decode
   * @methodOf ui.router.util.type:Type
   *
   * @description
   * Converts a string URL parameter value to a custom/native value.
   *
   * @param {string} val  The URL parameter value to decode.
   * @param {string} key  The name of the parameter in which `val` is stored. Can be used for
   *        meta-programming of `Type` objects.
   * @returns {*}  Returns a custom representation of the URL parameter value.
   */
  Type.prototype.decode = function(val, key) {
    return val;
  };
  
  /**
   * @ngdoc function
   * @name ui.router.util.type:Type#equals
   * @methodOf ui.router.util.type:Type
   *
   * @description
   * Determines whether two decoded values are equivalent.
   *
   * @param {*} a  A value to compare against.
   * @param {*} b  A value to compare against.
   * @returns {Boolean}  Returns `true` if the values are equivalent/equal, otherwise `false`.
   */
  Type.prototype.equals = function(a, b) {
    return a == b;
  };
  
  Type.prototype.$subPattern = function() {
    var sub = this.pattern.toString();
    return sub.substr(1, sub.length - 2);
  };
  
  Type.prototype.pattern = /.*/;
  
  /**
   * @ngdoc object
   * @name ui.router.util.$urlMatcherFactory
   *
   * @description
   * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory
   * is also available to providers under the name `$urlMatcherFactoryProvider`.
   */
  function $UrlMatcherFactory() {
  
    var isCaseInsensitive = false, isStrictMode = true;
  
    var enqueue = true, typeQueue = [], injector, defaultTypes = {
      int: {
        decode: function(val) {
          return parseInt(val, 10);
        },
        is: function(val) {
          if (!isDefined(val)) return false;
          return this.decode(val.toString()) === val;
        },
        pattern: /\d+/
      },
      bool: {
        encode: function(val) {
          return val ? 1 : 0;
        },
        decode: function(val) {
          return parseInt(val, 10) === 0 ? false : true;
        },
        is: function(val) {
          return val === true || val === false;
        },
        pattern: /0|1/
      },
      string: {
        pattern: /[^\/]*/
      },
      date: {
        equals: function (a, b) {
          return a.toISOString() === b.toISOString();
        },
        decode: function (val) {
          return new Date(val);
        },
        encode: function (val) {
          return [
            val.getFullYear(),
            ('0' + (val.getMonth() + 1)).slice(-2),
            ('0' + val.getDate()).slice(-2)
          ].join("-");
        },
        pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/
      }
    };
  
    function getDefaultConfig() {
      return {
        strict: isStrictMode,
        caseInsensitive: isCaseInsensitive
      };
    }
  
    function isInjectable(value) {
      return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));
    }
  
    /**
     * [Internal] Get the default value of a parameter, which may be an injectable function.
     */
    $UrlMatcherFactory.$$getDefaultValue = function(config) {
      if (!isInjectable(config.value)) return config.value;
      if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
      return injector.invoke(config.value);
    };
  
    /**
     * @ngdoc function
     * @name ui.router.util.$urlMatcherFactory#caseInsensitive
     * @methodOf ui.router.util.$urlMatcherFactory
     *
     * @description
     * Defines whether URL matching should be case sensitive (the default behavior), or not.
     *
     * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`;
     */
    this.caseInsensitive = function(value) {
      isCaseInsensitive = value;
    };
  
    /**
     * @ngdoc function
     * @name ui.router.util.$urlMatcherFactory#strictMode
     * @methodOf ui.router.util.$urlMatcherFactory
     *
     * @description
     * Defines whether URLs should match trailing slashes, or not (the default behavior).
     *
     * @param {boolean} value `false` to match trailing slashes in URLs, otherwise `true`.
     */
    this.strictMode = function(value) {
      isStrictMode = value;
    };
  
    /**
     * @ngdoc function
     * @name ui.router.util.$urlMatcherFactory#compile
     * @methodOf ui.router.util.$urlMatcherFactory
     *
     * @description
     * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern.
     *   
     * @param {string} pattern  The URL pattern.
     * @param {Object} config  The config object hash.
     * @returns {UrlMatcher}  The UrlMatcher.
     */
    this.compile = function (pattern, config) {
      return new UrlMatcher(pattern, extend(getDefaultConfig(), config));
    };
  
    /**
     * @ngdoc function
     * @name ui.router.util.$urlMatcherFactory#isMatcher
     * @methodOf ui.router.util.$urlMatcherFactory
     *
     * @description
     * Returns true if the specified object is a `UrlMatcher`, or false otherwise.
     *
     * @param {Object} object  The object to perform the type check against.
     * @returns {Boolean}  Returns `true` if the object matches the `UrlMatcher` interface, by
     *          implementing all the same methods.
     */
    this.isMatcher = function (o) {
      if (!isObject(o)) return false;
      var result = true;
  
      forEach(UrlMatcher.prototype, function(val, name) {
        if (isFunction(val)) {
          result = result && (isDefined(o[name]) && isFunction(o[name]));
        }
      });
      return result;
    };
  
    /**
     * @ngdoc function
     * @name ui.router.util.$urlMatcherFactory#type
     * @methodOf ui.router.util.$urlMatcherFactory
     *
     * @description
     * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to
     * generate URLs with typed parameters.
     *
     * @param {string} name  The type name.
     * @param {Object|Function} def  The type definition. See
     *        {@link ui.router.util.type:Type `Type`} for information on the values accepted.
     *
     * @returns {Object}  Returns `$urlMatcherFactoryProvider`.
     *
     * @example
     * This is a simple example of a custom type that encodes and decodes items from an
     * array, using the array index as the URL-encoded value:
     *
     * <pre>
     * var list = ['John', 'Paul', 'George', 'Ringo'];
     *
     * $urlMatcherFactoryProvider.type('listItem', {
     *   encode: function(item) {
     *     // Represent the list item in the URL using its corresponding index
     *     return list.indexOf(item);
     *   },
     *   decode: function(item) {
     *     // Look up the list item by index
     *     return list[parseInt(item, 10)];
     *   },
     *   is: function(item) {
     *     // Ensure the item is valid by checking to see that it appears
     *     // in the list
     *     return list.indexOf(item) > -1;
     *   }
     * });
     *
     * $stateProvider.state('list', {
     *   url: "/list/{item:listItem}",
     *   controller: function($scope, $stateParams) {
     *     console.log($stateParams.item);
     *   }
     * });
     *
     * // ...
     *
     * // Changes URL to '/list/3', logs "Ringo" to the console
     * $state.go('list', { item: "Ringo" });
     * </pre>
     *
     * This is a more complex example of a type that relies on dependency injection to
     * interact with services, and uses the parameter name from the URL to infer how to
     * handle encoding and decoding parameter values:
     *
     * <pre>
     * // Defines a custom type that gets a value from a service,
     * // where each service gets different types of values from
     * // a backend API:
     * $urlMatcherFactoryProvider.type('dbObject', function(Users, Posts) {
     *
     *   // Matches up services to URL parameter names
     *   var services = {
     *     user: Users,
     *     post: Posts
     *   };
     *
     *   return {
     *     encode: function(object) {
     *       // Represent the object in the URL using its unique ID
     *       return object.id;
     *     },
     *     decode: function(value, key) {
     *       // Look up the object by ID, using the parameter
     *       // name (key) to call the correct service
     *       return services[key].findById(value);
     *     },
     *     is: function(object, key) {
     *       // Check that object is a valid dbObject
     *       return angular.isObject(object) && object.id && services[key];
     *     }
     *     equals: function(a, b) {
     *       // Check the equality of decoded objects by comparing
     *       // their unique IDs
     *       return a.id === b.id;
     *     }
     *   };
     * });
     *
     * // In a config() block, you can then attach URLs with
     * // type-annotated parameters:
     * $stateProvider.state('users', {
     *   url: "/users",
     *   // ...
     * }).state('users.item', {
     *   url: "/{user:dbObject}",
     *   controller: function($scope, $stateParams) {
     *     // $stateParams.user will now be an object returned from
     *     // the Users service
     *   },
     *   // ...
     * });
     * </pre>
     */
    this.type = function (name, def) {
      if (!isDefined(def)) return UrlMatcher.prototype.$types[name];
      typeQueue.push({ name: name, def: def });
      if (!enqueue) flushTypeQueue();
      return this;
    };
  
    /* No need to document $get, since it returns this */
    this.$get = ['$injector', function ($injector) {
      injector = $injector;
      enqueue = false;
      UrlMatcher.prototype.$types = {};
      flushTypeQueue();
  
      forEach(defaultTypes, function(type, name) {
        if (!UrlMatcher.prototype.$types[name]) UrlMatcher.prototype.$types[name] = new Type(type);
      });
      return this;
    }];
  
    // To ensure proper order of operations in object configuration, and to allow internal
    // types to be overridden, `flushTypeQueue()` waits until `$urlMatcherFactory` is injected
    // before actually wiring up and assigning type definitions
    function flushTypeQueue() {
      forEach(typeQueue, function(type) {
        if (UrlMatcher.prototype.$types[type.name]) {
          throw new Error("A type named '" + type.name + "' has already been defined.");
        }
        var def = new Type(isInjectable(type.def) ? injector.invoke(type.def) : type.def);
        UrlMatcher.prototype.$types[type.name] = def;
      });
    }
  }
  
  // Register as a provider so it's available to other providers
  angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
  