29efe468827650f4cba1effca5da5533f4b480b78cf7be23eb3f52edc1a8ee14.json raw

   1  {"ast":null,"code":"/**\n * @license Angular v19.2.20\n * (c) 2010-2025 Google LLC. https://angular.io/\n * License: MIT\n */\n\nimport { DOCUMENT, Location } from '@angular/common';\nimport * as i0 from '@angular/core';\nimport { ɵisPromise as _isPromise, ɵRuntimeError as _RuntimeError, Injectable, ɵisNgModule as _isNgModule, isStandalone, createEnvironmentInjector, InjectionToken, EventEmitter, input, inject, ViewContainerRef, ChangeDetectorRef, Output, Input, Directive, reflectComponentType, Component, ɵisInjectable as _isInjectable, runInInjectionContext, NgModuleFactory, Compiler, NgZone, afterNextRender, EnvironmentInjector, DestroyRef, ɵConsole as _Console, ɵPendingTasksInternal as _PendingTasksInternal } from '@angular/core';\nimport { isObservable, from, of, BehaviorSubject, combineLatest, EmptyError, concat, defer, pipe, throwError, EMPTY, ConnectableObservable, Subject, Subscription } from 'rxjs';\nimport { map, switchMap, take, startWith, filter, mergeMap, first, concatMap, tap, catchError, scan, defaultIfEmpty, last as last$1, takeLast, finalize, refCount, takeUntil } from 'rxjs/operators';\nimport * as i1 from '@angular/platform-browser';\n\n/**\n * The primary routing outlet.\n *\n * @publicApi\n */\nconst PRIMARY_OUTLET = 'primary';\n/**\n * A private symbol used to store the value of `Route.title` inside the `Route.data` if it is a\n * static string or `Route.resolve` if anything else. This allows us to reuse the existing route\n * data/resolvers to support the title feature without new instrumentation in the `Router` pipeline.\n */\nconst RouteTitleKey = /* @__PURE__ */Symbol('RouteTitle');\nclass ParamsAsMap {\n  params;\n  constructor(params) {\n    this.params = params || {};\n  }\n  has(name) {\n    return Object.prototype.hasOwnProperty.call(this.params, name);\n  }\n  get(name) {\n    if (this.has(name)) {\n      const v = this.params[name];\n      return Array.isArray(v) ? v[0] : v;\n    }\n    return null;\n  }\n  getAll(name) {\n    if (this.has(name)) {\n      const v = this.params[name];\n      return Array.isArray(v) ? v : [v];\n    }\n    return [];\n  }\n  get keys() {\n    return Object.keys(this.params);\n  }\n}\n/**\n * Converts a `Params` instance to a `ParamMap`.\n * @param params The instance to convert.\n * @returns The new map instance.\n *\n * @publicApi\n */\nfunction convertToParamMap(params) {\n  return new ParamsAsMap(params);\n}\n/**\n * Matches the route configuration (`route`) against the actual URL (`segments`).\n *\n * When no matcher is defined on a `Route`, this is the matcher used by the Router by default.\n *\n * @param segments The remaining unmatched segments in the current navigation\n * @param segmentGroup The current segment group being matched\n * @param route The `Route` to match against.\n *\n * @see {@link UrlMatchResult}\n * @see {@link Route}\n *\n * @returns The resulting match information or `null` if the `route` should not match.\n * @publicApi\n */\nfunction defaultUrlMatcher(segments, segmentGroup, route) {\n  const parts = route.path.split('/');\n  if (parts.length > segments.length) {\n    // The actual URL is shorter than the config, no match\n    return null;\n  }\n  if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || parts.length < segments.length)) {\n    // The config is longer than the actual URL but we are looking for a full match, return null\n    return null;\n  }\n  const posParams = {};\n  // Check each config part against the actual URL\n  for (let index = 0; index < parts.length; index++) {\n    const part = parts[index];\n    const segment = segments[index];\n    const isParameter = part[0] === ':';\n    if (isParameter) {\n      posParams[part.substring(1)] = segment;\n    } else if (part !== segment.path) {\n      // The actual URL part does not match the config, no match\n      return null;\n    }\n  }\n  return {\n    consumed: segments.slice(0, parts.length),\n    posParams\n  };\n}\nfunction shallowEqualArrays(a, b) {\n  if (a.length !== b.length) return false;\n  for (let i = 0; i < a.length; ++i) {\n    if (!shallowEqual(a[i], b[i])) return false;\n  }\n  return true;\n}\nfunction shallowEqual(a, b) {\n  // While `undefined` should never be possible, it would sometimes be the case in IE 11\n  // and pre-chromium Edge. The check below accounts for this edge case.\n  const k1 = a ? getDataKeys(a) : undefined;\n  const k2 = b ? getDataKeys(b) : undefined;\n  if (!k1 || !k2 || k1.length != k2.length) {\n    return false;\n  }\n  let key;\n  for (let i = 0; i < k1.length; i++) {\n    key = k1[i];\n    if (!equalArraysOrString(a[key], b[key])) {\n      return false;\n    }\n  }\n  return true;\n}\n/**\n * Gets the keys of an object, including `symbol` keys.\n */\nfunction getDataKeys(obj) {\n  return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];\n}\n/**\n * Test equality for arrays of strings or a string.\n */\nfunction equalArraysOrString(a, b) {\n  if (Array.isArray(a) && Array.isArray(b)) {\n    if (a.length !== b.length) return false;\n    const aSorted = [...a].sort();\n    const bSorted = [...b].sort();\n    return aSorted.every((val, index) => bSorted[index] === val);\n  } else {\n    return a === b;\n  }\n}\n/**\n * Return the last element of an array.\n */\nfunction last(a) {\n  return a.length > 0 ? a[a.length - 1] : null;\n}\nfunction wrapIntoObservable(value) {\n  if (isObservable(value)) {\n    return value;\n  }\n  if (_isPromise(value)) {\n    // Use `Promise.resolve()` to wrap promise-like instances.\n    // Required ie when a Resolver returns a AngularJS `$q` promise to correctly trigger the\n    // change detection.\n    return from(Promise.resolve(value));\n  }\n  return of(value);\n}\nconst pathCompareMap = {\n  'exact': equalSegmentGroups,\n  'subset': containsSegmentGroup\n};\nconst paramCompareMap = {\n  'exact': equalParams,\n  'subset': containsParams,\n  'ignored': () => true\n};\nfunction containsTree(container, containee, options) {\n  return pathCompareMap[options.paths](container.root, containee.root, options.matrixParams) && paramCompareMap[options.queryParams](container.queryParams, containee.queryParams) && !(options.fragment === 'exact' && container.fragment !== containee.fragment);\n}\nfunction equalParams(container, containee) {\n  // TODO: This does not handle array params correctly.\n  return shallowEqual(container, containee);\n}\nfunction equalSegmentGroups(container, containee, matrixParams) {\n  if (!equalPath(container.segments, containee.segments)) return false;\n  if (!matrixParamsMatch(container.segments, containee.segments, matrixParams)) {\n    return false;\n  }\n  if (container.numberOfChildren !== containee.numberOfChildren) return false;\n  for (const c in containee.children) {\n    if (!container.children[c]) return false;\n    if (!equalSegmentGroups(container.children[c], containee.children[c], matrixParams)) return false;\n  }\n  return true;\n}\nfunction containsParams(container, containee) {\n  return Object.keys(containee).length <= Object.keys(container).length && Object.keys(containee).every(key => equalArraysOrString(container[key], containee[key]));\n}\nfunction containsSegmentGroup(container, containee, matrixParams) {\n  return containsSegmentGroupHelper(container, containee, containee.segments, matrixParams);\n}\nfunction containsSegmentGroupHelper(container, containee, containeePaths, matrixParams) {\n  if (container.segments.length > containeePaths.length) {\n    const current = container.segments.slice(0, containeePaths.length);\n    if (!equalPath(current, containeePaths)) return false;\n    if (containee.hasChildren()) return false;\n    if (!matrixParamsMatch(current, containeePaths, matrixParams)) return false;\n    return true;\n  } else if (container.segments.length === containeePaths.length) {\n    if (!equalPath(container.segments, containeePaths)) return false;\n    if (!matrixParamsMatch(container.segments, containeePaths, matrixParams)) return false;\n    for (const c in containee.children) {\n      if (!container.children[c]) return false;\n      if (!containsSegmentGroup(container.children[c], containee.children[c], matrixParams)) {\n        return false;\n      }\n    }\n    return true;\n  } else {\n    const current = containeePaths.slice(0, container.segments.length);\n    const next = containeePaths.slice(container.segments.length);\n    if (!equalPath(container.segments, current)) return false;\n    if (!matrixParamsMatch(container.segments, current, matrixParams)) return false;\n    if (!container.children[PRIMARY_OUTLET]) return false;\n    return containsSegmentGroupHelper(container.children[PRIMARY_OUTLET], containee, next, matrixParams);\n  }\n}\nfunction matrixParamsMatch(containerPaths, containeePaths, options) {\n  return containeePaths.every((containeeSegment, i) => {\n    return paramCompareMap[options](containerPaths[i].parameters, containeeSegment.parameters);\n  });\n}\n/**\n * @description\n *\n * Represents the parsed URL.\n *\n * Since a router state is a tree, and the URL is nothing but a serialized state, the URL is a\n * serialized tree.\n * UrlTree is a data structure that provides a lot of affordances in dealing with URLs\n *\n * @usageNotes\n * ### Example\n *\n * ```ts\n * @Component({templateUrl:'template.html'})\n * class MyComponent {\n *   constructor(router: Router) {\n *     const tree: UrlTree =\n *       router.parseUrl('/team/33/(user/victor//support:help)?debug=true#fragment');\n *     const f = tree.fragment; // return 'fragment'\n *     const q = tree.queryParams; // returns {debug: 'true'}\n *     const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET];\n *     const s: UrlSegment[] = g.segments; // returns 2 segments 'team' and '33'\n *     g.children[PRIMARY_OUTLET].segments; // returns 2 segments 'user' and 'victor'\n *     g.children['support'].segments; // return 1 segment 'help'\n *   }\n * }\n * ```\n *\n * @publicApi\n */\nclass UrlTree {\n  root;\n  queryParams;\n  fragment;\n  /** @internal */\n  _queryParamMap;\n  constructor(/** The root segment group of the URL tree */\n  root = new UrlSegmentGroup([], {}), /** The query params of the URL */\n  queryParams = {}, /** The fragment of the URL */\n  fragment = null) {\n    this.root = root;\n    this.queryParams = queryParams;\n    this.fragment = fragment;\n    if (typeof ngDevMode === 'undefined' || ngDevMode) {\n      if (root.segments.length > 0) {\n        throw new _RuntimeError(4015 /* RuntimeErrorCode.INVALID_ROOT_URL_SEGMENT */, 'The root `UrlSegmentGroup` should not contain `segments`. ' + 'Instead, these segments belong in the `children` so they can be associated with a named outlet.');\n      }\n    }\n  }\n  get queryParamMap() {\n    this._queryParamMap ??= convertToParamMap(this.queryParams);\n    return this._queryParamMap;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return DEFAULT_SERIALIZER.serialize(this);\n  }\n}\n/**\n * @description\n *\n * Represents the parsed URL segment group.\n *\n * See `UrlTree` for more information.\n *\n * @publicApi\n */\nclass UrlSegmentGroup {\n  segments;\n  children;\n  /** The parent node in the url tree */\n  parent = null;\n  constructor(/** The URL segments of this group. See `UrlSegment` for more information */\n  segments, /** The list of children of this group */\n  children) {\n    this.segments = segments;\n    this.children = children;\n    Object.values(children).forEach(v => v.parent = this);\n  }\n  /** Whether the segment has child segments */\n  hasChildren() {\n    return this.numberOfChildren > 0;\n  }\n  /** Number of child segments */\n  get numberOfChildren() {\n    return Object.keys(this.children).length;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return serializePaths(this);\n  }\n}\n/**\n * @description\n *\n * Represents a single URL segment.\n *\n * A UrlSegment is a part of a URL between the two slashes. It contains a path and the matrix\n * parameters associated with the segment.\n *\n * @usageNotes\n * ### Example\n *\n * ```ts\n * @Component({templateUrl:'template.html'})\n * class MyComponent {\n *   constructor(router: Router) {\n *     const tree: UrlTree = router.parseUrl('/team;id=33');\n *     const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET];\n *     const s: UrlSegment[] = g.segments;\n *     s[0].path; // returns 'team'\n *     s[0].parameters; // returns {id: 33}\n *   }\n * }\n * ```\n *\n * @publicApi\n */\nclass UrlSegment {\n  path;\n  parameters;\n  /** @internal */\n  _parameterMap;\n  constructor(/** The path part of a URL segment */\n  path, /** The matrix parameters associated with a segment */\n  parameters) {\n    this.path = path;\n    this.parameters = parameters;\n  }\n  get parameterMap() {\n    this._parameterMap ??= convertToParamMap(this.parameters);\n    return this._parameterMap;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return serializePath(this);\n  }\n}\nfunction equalSegments(as, bs) {\n  return equalPath(as, bs) && as.every((a, i) => shallowEqual(a.parameters, bs[i].parameters));\n}\nfunction equalPath(as, bs) {\n  if (as.length !== bs.length) return false;\n  return as.every((a, i) => a.path === bs[i].path);\n}\nfunction mapChildrenIntoArray(segment, fn) {\n  let res = [];\n  Object.entries(segment.children).forEach(([childOutlet, child]) => {\n    if (childOutlet === PRIMARY_OUTLET) {\n      res = res.concat(fn(child, childOutlet));\n    }\n  });\n  Object.entries(segment.children).forEach(([childOutlet, child]) => {\n    if (childOutlet !== PRIMARY_OUTLET) {\n      res = res.concat(fn(child, childOutlet));\n    }\n  });\n  return res;\n}\n/**\n * @description\n *\n * Serializes and deserializes a URL string into a URL tree.\n *\n * The url serialization strategy is customizable. You can\n * make all URLs case insensitive by providing a custom UrlSerializer.\n *\n * See `DefaultUrlSerializer` for an example of a URL serializer.\n *\n * @publicApi\n */\nlet UrlSerializer = /*#__PURE__*/(() => {\n  class UrlSerializer {\n    static ɵfac = function UrlSerializer_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || UrlSerializer)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: UrlSerializer,\n      factory: () => (() => new DefaultUrlSerializer())(),\n      providedIn: 'root'\n    });\n  }\n  return UrlSerializer;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n/**\n * @description\n *\n * A default implementation of the `UrlSerializer`.\n *\n * Example URLs:\n *\n * ```\n * /inbox/33(popup:compose)\n * /inbox/33;open=true/messages/44\n * ```\n *\n * DefaultUrlSerializer uses parentheses to serialize secondary segments (e.g., popup:compose), the\n * colon syntax to specify the outlet, and the ';parameter=value' syntax (e.g., open=true) to\n * specify route specific parameters.\n *\n * @publicApi\n */\nclass DefaultUrlSerializer {\n  /** Parses a url into a `UrlTree` */\n  parse(url) {\n    const p = new UrlParser(url);\n    return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());\n  }\n  /** Converts a `UrlTree` into a url */\n  serialize(tree) {\n    const segment = `/${serializeSegment(tree.root, true)}`;\n    const query = serializeQueryParams(tree.queryParams);\n    const fragment = typeof tree.fragment === `string` ? `#${encodeUriFragment(tree.fragment)}` : '';\n    return `${segment}${query}${fragment}`;\n  }\n}\nconst DEFAULT_SERIALIZER = /*#__PURE__*/new DefaultUrlSerializer();\nfunction serializePaths(segment) {\n  return segment.segments.map(p => serializePath(p)).join('/');\n}\nfunction serializeSegment(segment, root) {\n  if (!segment.hasChildren()) {\n    return serializePaths(segment);\n  }\n  if (root) {\n    const primary = segment.children[PRIMARY_OUTLET] ? serializeSegment(segment.children[PRIMARY_OUTLET], false) : '';\n    const children = [];\n    Object.entries(segment.children).forEach(([k, v]) => {\n      if (k !== PRIMARY_OUTLET) {\n        children.push(`${k}:${serializeSegment(v, false)}`);\n      }\n    });\n    return children.length > 0 ? `${primary}(${children.join('//')})` : primary;\n  } else {\n    const children = mapChildrenIntoArray(segment, (v, k) => {\n      if (k === PRIMARY_OUTLET) {\n        return [serializeSegment(segment.children[PRIMARY_OUTLET], false)];\n      }\n      return [`${k}:${serializeSegment(v, false)}`];\n    });\n    // use no parenthesis if the only child is a primary outlet route\n    if (Object.keys(segment.children).length === 1 && segment.children[PRIMARY_OUTLET] != null) {\n      return `${serializePaths(segment)}/${children[0]}`;\n    }\n    return `${serializePaths(segment)}/(${children.join('//')})`;\n  }\n}\n/**\n * Encodes a URI string with the default encoding. This function will only ever be called from\n * `encodeUriQuery` or `encodeUriSegment` as it's the base set of encodings to be used. We need\n * a custom encoding because encodeURIComponent is too aggressive and encodes stuff that doesn't\n * have to be encoded per https://url.spec.whatwg.org.\n */\nfunction encodeUriString(s) {\n  return encodeURIComponent(s).replace(/%40/g, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',');\n}\n/**\n * This function should be used to encode both keys and values in a query string key/value. In\n * the following URL, you need to call encodeUriQuery on \"k\" and \"v\":\n *\n * http://www.site.org/html;mk=mv?k=v#f\n */\nfunction encodeUriQuery(s) {\n  return encodeUriString(s).replace(/%3B/gi, ';');\n}\n/**\n * This function should be used to encode a URL fragment. In the following URL, you need to call\n * encodeUriFragment on \"f\":\n *\n * http://www.site.org/html;mk=mv?k=v#f\n */\nfunction encodeUriFragment(s) {\n  return encodeURI(s);\n}\n/**\n * This function should be run on any URI segment as well as the key and value in a key/value\n * pair for matrix params. In the following URL, you need to call encodeUriSegment on \"html\",\n * \"mk\", and \"mv\":\n *\n * http://www.site.org/html;mk=mv?k=v#f\n */\nfunction encodeUriSegment(s) {\n  return encodeUriString(s).replace(/\\(/g, '%28').replace(/\\)/g, '%29').replace(/%26/gi, '&');\n}\nfunction decode(s) {\n  return decodeURIComponent(s);\n}\n// Query keys/values should have the \"+\" replaced first, as \"+\" in a query string is \" \".\n// decodeURIComponent function will not decode \"+\" as a space.\nfunction decodeQuery(s) {\n  return decode(s.replace(/\\+/g, '%20'));\n}\nfunction serializePath(path) {\n  return `${encodeUriSegment(path.path)}${serializeMatrixParams(path.parameters)}`;\n}\nfunction serializeMatrixParams(params) {\n  return Object.entries(params).map(([key, value]) => `;${encodeUriSegment(key)}=${encodeUriSegment(value)}`).join('');\n}\nfunction serializeQueryParams(params) {\n  const strParams = Object.entries(params).map(([name, value]) => {\n    return Array.isArray(value) ? value.map(v => `${encodeUriQuery(name)}=${encodeUriQuery(v)}`).join('&') : `${encodeUriQuery(name)}=${encodeUriQuery(value)}`;\n  }).filter(s => s);\n  return strParams.length ? `?${strParams.join('&')}` : '';\n}\nconst SEGMENT_RE = /^[^\\/()?;#]+/;\nfunction matchSegments(str) {\n  const match = str.match(SEGMENT_RE);\n  return match ? match[0] : '';\n}\nconst MATRIX_PARAM_SEGMENT_RE = /^[^\\/()?;=#]+/;\nfunction matchMatrixKeySegments(str) {\n  const match = str.match(MATRIX_PARAM_SEGMENT_RE);\n  return match ? match[0] : '';\n}\nconst QUERY_PARAM_RE = /^[^=?&#]+/;\n// Return the name of the query param at the start of the string or an empty string\nfunction matchQueryParams(str) {\n  const match = str.match(QUERY_PARAM_RE);\n  return match ? match[0] : '';\n}\nconst QUERY_PARAM_VALUE_RE = /^[^&#]+/;\n// Return the value of the query param at the start of the string or an empty string\nfunction matchUrlQueryParamValue(str) {\n  const match = str.match(QUERY_PARAM_VALUE_RE);\n  return match ? match[0] : '';\n}\nclass UrlParser {\n  url;\n  remaining;\n  constructor(url) {\n    this.url = url;\n    this.remaining = url;\n  }\n  parseRootSegment() {\n    this.consumeOptional('/');\n    if (this.remaining === '' || this.peekStartsWith('?') || this.peekStartsWith('#')) {\n      return new UrlSegmentGroup([], {});\n    }\n    // The root segment group never has segments\n    return new UrlSegmentGroup([], this.parseChildren());\n  }\n  parseQueryParams() {\n    const params = {};\n    if (this.consumeOptional('?')) {\n      do {\n        this.parseQueryParam(params);\n      } while (this.consumeOptional('&'));\n    }\n    return params;\n  }\n  parseFragment() {\n    return this.consumeOptional('#') ? decodeURIComponent(this.remaining) : null;\n  }\n  parseChildren() {\n    if (this.remaining === '') {\n      return {};\n    }\n    this.consumeOptional('/');\n    const segments = [];\n    if (!this.peekStartsWith('(')) {\n      segments.push(this.parseSegment());\n    }\n    while (this.peekStartsWith('/') && !this.peekStartsWith('//') && !this.peekStartsWith('/(')) {\n      this.capture('/');\n      segments.push(this.parseSegment());\n    }\n    let children = {};\n    if (this.peekStartsWith('/(')) {\n      this.capture('/');\n      children = this.parseParens(true);\n    }\n    let res = {};\n    if (this.peekStartsWith('(')) {\n      res = this.parseParens(false);\n    }\n    if (segments.length > 0 || Object.keys(children).length > 0) {\n      res[PRIMARY_OUTLET] = new UrlSegmentGroup(segments, children);\n    }\n    return res;\n  }\n  // parse a segment with its matrix parameters\n  // ie `name;k1=v1;k2`\n  parseSegment() {\n    const path = matchSegments(this.remaining);\n    if (path === '' && this.peekStartsWith(';')) {\n      throw new _RuntimeError(4009 /* RuntimeErrorCode.EMPTY_PATH_WITH_PARAMS */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Empty path url segment cannot have parameters: '${this.remaining}'.`);\n    }\n    this.capture(path);\n    return new UrlSegment(decode(path), this.parseMatrixParams());\n  }\n  parseMatrixParams() {\n    const params = {};\n    while (this.consumeOptional(';')) {\n      this.parseParam(params);\n    }\n    return params;\n  }\n  parseParam(params) {\n    const key = matchMatrixKeySegments(this.remaining);\n    if (!key) {\n      return;\n    }\n    this.capture(key);\n    let value = '';\n    if (this.consumeOptional('=')) {\n      const valueMatch = matchSegments(this.remaining);\n      if (valueMatch) {\n        value = valueMatch;\n        this.capture(value);\n      }\n    }\n    params[decode(key)] = decode(value);\n  }\n  // Parse a single query parameter `name[=value]`\n  parseQueryParam(params) {\n    const key = matchQueryParams(this.remaining);\n    if (!key) {\n      return;\n    }\n    this.capture(key);\n    let value = '';\n    if (this.consumeOptional('=')) {\n      const valueMatch = matchUrlQueryParamValue(this.remaining);\n      if (valueMatch) {\n        value = valueMatch;\n        this.capture(value);\n      }\n    }\n    const decodedKey = decodeQuery(key);\n    const decodedVal = decodeQuery(value);\n    if (params.hasOwnProperty(decodedKey)) {\n      // Append to existing values\n      let currentVal = params[decodedKey];\n      if (!Array.isArray(currentVal)) {\n        currentVal = [currentVal];\n        params[decodedKey] = currentVal;\n      }\n      currentVal.push(decodedVal);\n    } else {\n      // Create a new value\n      params[decodedKey] = decodedVal;\n    }\n  }\n  // parse `(a/b//outlet_name:c/d)`\n  parseParens(allowPrimary) {\n    const segments = {};\n    this.capture('(');\n    while (!this.consumeOptional(')') && this.remaining.length > 0) {\n      const path = matchSegments(this.remaining);\n      const next = this.remaining[path.length];\n      // if is is not one of these characters, then the segment was unescaped\n      // or the group was not closed\n      if (next !== '/' && next !== ')' && next !== ';') {\n        throw new _RuntimeError(4010 /* RuntimeErrorCode.UNPARSABLE_URL */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Cannot parse url '${this.url}'`);\n      }\n      let outletName = undefined;\n      if (path.indexOf(':') > -1) {\n        outletName = path.slice(0, path.indexOf(':'));\n        this.capture(outletName);\n        this.capture(':');\n      } else if (allowPrimary) {\n        outletName = PRIMARY_OUTLET;\n      }\n      const children = this.parseChildren();\n      segments[outletName] = Object.keys(children).length === 1 ? children[PRIMARY_OUTLET] : new UrlSegmentGroup([], children);\n      this.consumeOptional('//');\n    }\n    return segments;\n  }\n  peekStartsWith(str) {\n    return this.remaining.startsWith(str);\n  }\n  // Consumes the prefix when it is present and returns whether it has been consumed\n  consumeOptional(str) {\n    if (this.peekStartsWith(str)) {\n      this.remaining = this.remaining.substring(str.length);\n      return true;\n    }\n    return false;\n  }\n  capture(str) {\n    if (!this.consumeOptional(str)) {\n      throw new _RuntimeError(4011 /* RuntimeErrorCode.UNEXPECTED_VALUE_IN_URL */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Expected \"${str}\".`);\n    }\n  }\n}\nfunction createRoot(rootCandidate) {\n  return rootCandidate.segments.length > 0 ? new UrlSegmentGroup([], {\n    [PRIMARY_OUTLET]: rootCandidate\n  }) : rootCandidate;\n}\n/**\n * Recursively\n * - merges primary segment children into their parents\n * - drops empty children (those which have no segments and no children themselves). This latter\n * prevents serializing a group into something like `/a(aux:)`, where `aux` is an empty child\n * segment.\n * - merges named outlets without a primary segment sibling into the children. This prevents\n * serializing a URL like `//(a:a)(b:b) instead of `/(a:a//b:b)` when the aux b route lives on the\n * root but the `a` route lives under an empty path primary route.\n */\nfunction squashSegmentGroup(segmentGroup) {\n  const newChildren = {};\n  for (const [childOutlet, child] of Object.entries(segmentGroup.children)) {\n    const childCandidate = squashSegmentGroup(child);\n    // moves named children in an empty path primary child into this group\n    if (childOutlet === PRIMARY_OUTLET && childCandidate.segments.length === 0 && childCandidate.hasChildren()) {\n      for (const [grandChildOutlet, grandChild] of Object.entries(childCandidate.children)) {\n        newChildren[grandChildOutlet] = grandChild;\n      }\n    } // don't add empty children\n    else if (childCandidate.segments.length > 0 || childCandidate.hasChildren()) {\n      newChildren[childOutlet] = childCandidate;\n    }\n  }\n  const s = new UrlSegmentGroup(segmentGroup.segments, newChildren);\n  return mergeTrivialChildren(s);\n}\n/**\n * When possible, merges the primary outlet child into the parent `UrlSegmentGroup`.\n *\n * When a segment group has only one child which is a primary outlet, merges that child into the\n * parent. That is, the child segment group's segments are merged into the `s` and the child's\n * children become the children of `s`. Think of this like a 'squash', merging the child segment\n * group into the parent.\n */\nfunction mergeTrivialChildren(s) {\n  if (s.numberOfChildren === 1 && s.children[PRIMARY_OUTLET]) {\n    const c = s.children[PRIMARY_OUTLET];\n    return new UrlSegmentGroup(s.segments.concat(c.segments), c.children);\n  }\n  return s;\n}\nfunction isUrlTree(v) {\n  return v instanceof UrlTree;\n}\n\n/**\n * Creates a `UrlTree` relative to an `ActivatedRouteSnapshot`.\n *\n * @publicApi\n *\n *\n * @param relativeTo The `ActivatedRouteSnapshot` to apply the commands to\n * @param commands An array of URL fragments with which to construct the new URL tree.\n * If the path is static, can be the literal URL string. For a dynamic path, pass an array of path\n * segments, followed by the parameters for each segment.\n * The fragments are applied to the one provided in the `relativeTo` parameter.\n * @param queryParams The query parameters for the `UrlTree`. `null` if the `UrlTree` does not have\n *     any query parameters.\n * @param fragment The fragment for the `UrlTree`. `null` if the `UrlTree` does not have a fragment.\n *\n * @usageNotes\n *\n * ```ts\n * // create /team/33/user/11\n * createUrlTreeFromSnapshot(snapshot, ['/team', 33, 'user', 11]);\n *\n * // create /team/33;expand=true/user/11\n * createUrlTreeFromSnapshot(snapshot, ['/team', 33, {expand: true}, 'user', 11]);\n *\n * // you can collapse static segments like this (this works only with the first passed-in value):\n * createUrlTreeFromSnapshot(snapshot, ['/team/33/user', userId]);\n *\n * // If the first segment can contain slashes, and you do not want the router to split it,\n * // you can do the following:\n * createUrlTreeFromSnapshot(snapshot, [{segmentPath: '/one/two'}]);\n *\n * // create /team/33/(user/11//right:chat)\n * createUrlTreeFromSnapshot(snapshot, ['/team', 33, {outlets: {primary: 'user/11', right:\n * 'chat'}}], null, null);\n *\n * // remove the right secondary node\n * createUrlTreeFromSnapshot(snapshot, ['/team', 33, {outlets: {primary: 'user/11', right: null}}]);\n *\n * // For the examples below, assume the current URL is for the `/team/33/user/11` and the\n * `ActivatedRouteSnapshot` points to `user/11`:\n *\n * // navigate to /team/33/user/11/details\n * createUrlTreeFromSnapshot(snapshot, ['details']);\n *\n * // navigate to /team/33/user/22\n * createUrlTreeFromSnapshot(snapshot, ['../22']);\n *\n * // navigate to /team/44/user/22\n * createUrlTreeFromSnapshot(snapshot, ['../../team/44/user/22']);\n * ```\n */\nfunction createUrlTreeFromSnapshot(relativeTo, commands, queryParams = null, fragment = null) {\n  const relativeToUrlSegmentGroup = createSegmentGroupFromRoute(relativeTo);\n  return createUrlTreeFromSegmentGroup(relativeToUrlSegmentGroup, commands, queryParams, fragment);\n}\nfunction createSegmentGroupFromRoute(route) {\n  let targetGroup;\n  function createSegmentGroupFromRouteRecursive(currentRoute) {\n    const childOutlets = {};\n    for (const childSnapshot of currentRoute.children) {\n      const root = createSegmentGroupFromRouteRecursive(childSnapshot);\n      childOutlets[childSnapshot.outlet] = root;\n    }\n    const segmentGroup = new UrlSegmentGroup(currentRoute.url, childOutlets);\n    if (currentRoute === route) {\n      targetGroup = segmentGroup;\n    }\n    return segmentGroup;\n  }\n  const rootCandidate = createSegmentGroupFromRouteRecursive(route.root);\n  const rootSegmentGroup = createRoot(rootCandidate);\n  return targetGroup ?? rootSegmentGroup;\n}\nfunction createUrlTreeFromSegmentGroup(relativeTo, commands, queryParams, fragment) {\n  let root = relativeTo;\n  while (root.parent) {\n    root = root.parent;\n  }\n  // There are no commands so the `UrlTree` goes to the same path as the one created from the\n  // `UrlSegmentGroup`. All we need to do is update the `queryParams` and `fragment` without\n  // applying any other logic.\n  if (commands.length === 0) {\n    return tree(root, root, root, queryParams, fragment);\n  }\n  const nav = computeNavigation(commands);\n  if (nav.toRoot()) {\n    return tree(root, root, new UrlSegmentGroup([], {}), queryParams, fragment);\n  }\n  const position = findStartingPositionForTargetGroup(nav, root, relativeTo);\n  const newSegmentGroup = position.processChildren ? updateSegmentGroupChildren(position.segmentGroup, position.index, nav.commands) : updateSegmentGroup(position.segmentGroup, position.index, nav.commands);\n  return tree(root, position.segmentGroup, newSegmentGroup, queryParams, fragment);\n}\nfunction isMatrixParams(command) {\n  return typeof command === 'object' && command != null && !command.outlets && !command.segmentPath;\n}\n/**\n * Determines if a given command has an `outlets` map. When we encounter a command\n * with an outlets k/v map, we need to apply each outlet individually to the existing segment.\n */\nfunction isCommandWithOutlets(command) {\n  return typeof command === 'object' && command != null && command.outlets;\n}\nfunction tree(oldRoot, oldSegmentGroup, newSegmentGroup, queryParams, fragment) {\n  let qp = {};\n  if (queryParams) {\n    Object.entries(queryParams).forEach(([name, value]) => {\n      qp[name] = Array.isArray(value) ? value.map(v => `${v}`) : `${value}`;\n    });\n  }\n  let rootCandidate;\n  if (oldRoot === oldSegmentGroup) {\n    rootCandidate = newSegmentGroup;\n  } else {\n    rootCandidate = replaceSegment(oldRoot, oldSegmentGroup, newSegmentGroup);\n  }\n  const newRoot = createRoot(squashSegmentGroup(rootCandidate));\n  return new UrlTree(newRoot, qp, fragment);\n}\n/**\n * Replaces the `oldSegment` which is located in some child of the `current` with the `newSegment`.\n * This also has the effect of creating new `UrlSegmentGroup` copies to update references. This\n * shouldn't be necessary but the fallback logic for an invalid ActivatedRoute in the creation uses\n * the Router's current url tree. If we don't create new segment groups, we end up modifying that\n * value.\n */\nfunction replaceSegment(current, oldSegment, newSegment) {\n  const children = {};\n  Object.entries(current.children).forEach(([outletName, c]) => {\n    if (c === oldSegment) {\n      children[outletName] = newSegment;\n    } else {\n      children[outletName] = replaceSegment(c, oldSegment, newSegment);\n    }\n  });\n  return new UrlSegmentGroup(current.segments, children);\n}\nclass Navigation {\n  isAbsolute;\n  numberOfDoubleDots;\n  commands;\n  constructor(isAbsolute, numberOfDoubleDots, commands) {\n    this.isAbsolute = isAbsolute;\n    this.numberOfDoubleDots = numberOfDoubleDots;\n    this.commands = commands;\n    if (isAbsolute && commands.length > 0 && isMatrixParams(commands[0])) {\n      throw new _RuntimeError(4003 /* RuntimeErrorCode.ROOT_SEGMENT_MATRIX_PARAMS */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Root segment cannot have matrix parameters');\n    }\n    const cmdWithOutlet = commands.find(isCommandWithOutlets);\n    if (cmdWithOutlet && cmdWithOutlet !== last(commands)) {\n      throw new _RuntimeError(4004 /* RuntimeErrorCode.MISPLACED_OUTLETS_COMMAND */, (typeof ngDevMode === 'undefined' || ngDevMode) && '{outlets:{}} has to be the last command');\n    }\n  }\n  toRoot() {\n    return this.isAbsolute && this.commands.length === 1 && this.commands[0] == '/';\n  }\n}\n/** Transforms commands to a normalized `Navigation` */\nfunction computeNavigation(commands) {\n  if (typeof commands[0] === 'string' && commands.length === 1 && commands[0] === '/') {\n    return new Navigation(true, 0, commands);\n  }\n  let numberOfDoubleDots = 0;\n  let isAbsolute = false;\n  const res = commands.reduce((res, cmd, cmdIdx) => {\n    if (typeof cmd === 'object' && cmd != null) {\n      if (cmd.outlets) {\n        const outlets = {};\n        Object.entries(cmd.outlets).forEach(([name, commands]) => {\n          outlets[name] = typeof commands === 'string' ? commands.split('/') : commands;\n        });\n        return [...res, {\n          outlets\n        }];\n      }\n      if (cmd.segmentPath) {\n        return [...res, cmd.segmentPath];\n      }\n    }\n    if (!(typeof cmd === 'string')) {\n      return [...res, cmd];\n    }\n    if (cmdIdx === 0) {\n      cmd.split('/').forEach((urlPart, partIndex) => {\n        if (partIndex == 0 && urlPart === '.') ;else if (partIndex == 0 && urlPart === '') {\n          //  '/a'\n          isAbsolute = true;\n        } else if (urlPart === '..') {\n          //  '../a'\n          numberOfDoubleDots++;\n        } else if (urlPart != '') {\n          res.push(urlPart);\n        }\n      });\n      return res;\n    }\n    return [...res, cmd];\n  }, []);\n  return new Navigation(isAbsolute, numberOfDoubleDots, res);\n}\nclass Position {\n  segmentGroup;\n  processChildren;\n  index;\n  constructor(segmentGroup, processChildren, index) {\n    this.segmentGroup = segmentGroup;\n    this.processChildren = processChildren;\n    this.index = index;\n  }\n}\nfunction findStartingPositionForTargetGroup(nav, root, target) {\n  if (nav.isAbsolute) {\n    return new Position(root, true, 0);\n  }\n  if (!target) {\n    // `NaN` is used only to maintain backwards compatibility with incorrectly mocked\n    // `ActivatedRouteSnapshot` in tests. In prior versions of this code, the position here was\n    // determined based on an internal property that was rarely mocked, resulting in `NaN`. In\n    // reality, this code path should _never_ be touched since `target` is not allowed to be falsey.\n    return new Position(root, false, NaN);\n  }\n  if (target.parent === null) {\n    return new Position(target, true, 0);\n  }\n  const modifier = isMatrixParams(nav.commands[0]) ? 0 : 1;\n  const index = target.segments.length - 1 + modifier;\n  return createPositionApplyingDoubleDots(target, index, nav.numberOfDoubleDots);\n}\nfunction createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) {\n  let g = group;\n  let ci = index;\n  let dd = numberOfDoubleDots;\n  while (dd > ci) {\n    dd -= ci;\n    g = g.parent;\n    if (!g) {\n      throw new _RuntimeError(4005 /* RuntimeErrorCode.INVALID_DOUBLE_DOTS */, (typeof ngDevMode === 'undefined' || ngDevMode) && \"Invalid number of '../'\");\n    }\n    ci = g.segments.length;\n  }\n  return new Position(g, false, ci - dd);\n}\nfunction getOutlets(commands) {\n  if (isCommandWithOutlets(commands[0])) {\n    return commands[0].outlets;\n  }\n  return {\n    [PRIMARY_OUTLET]: commands\n  };\n}\nfunction updateSegmentGroup(segmentGroup, startIndex, commands) {\n  segmentGroup ??= new UrlSegmentGroup([], {});\n  if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {\n    return updateSegmentGroupChildren(segmentGroup, startIndex, commands);\n  }\n  const m = prefixedWith(segmentGroup, startIndex, commands);\n  const slicedCommands = commands.slice(m.commandIndex);\n  if (m.match && m.pathIndex < segmentGroup.segments.length) {\n    const g = new UrlSegmentGroup(segmentGroup.segments.slice(0, m.pathIndex), {});\n    g.children[PRIMARY_OUTLET] = new UrlSegmentGroup(segmentGroup.segments.slice(m.pathIndex), segmentGroup.children);\n    return updateSegmentGroupChildren(g, 0, slicedCommands);\n  } else if (m.match && slicedCommands.length === 0) {\n    return new UrlSegmentGroup(segmentGroup.segments, {});\n  } else if (m.match && !segmentGroup.hasChildren()) {\n    return createNewSegmentGroup(segmentGroup, startIndex, commands);\n  } else if (m.match) {\n    return updateSegmentGroupChildren(segmentGroup, 0, slicedCommands);\n  } else {\n    return createNewSegmentGroup(segmentGroup, startIndex, commands);\n  }\n}\nfunction updateSegmentGroupChildren(segmentGroup, startIndex, commands) {\n  if (commands.length === 0) {\n    return new UrlSegmentGroup(segmentGroup.segments, {});\n  } else {\n    const outlets = getOutlets(commands);\n    const children = {};\n    // If the set of commands applies to anything other than the primary outlet and the child\n    // segment is an empty path primary segment on its own, we want to apply the commands to the\n    // empty child path rather than here. The outcome is that the empty primary child is effectively\n    // removed from the final output UrlTree. Imagine the following config:\n    //\n    // {path: '', children: [{path: '**', outlet: 'popup'}]}.\n    //\n    // Navigation to /(popup:a) will activate the child outlet correctly Given a follow-up\n    // navigation with commands\n    // ['/', {outlets: {'popup': 'b'}}], we _would not_ want to apply the outlet commands to the\n    // root segment because that would result in\n    // //(popup:a)(popup:b) since the outlet command got applied one level above where it appears in\n    // the `ActivatedRoute` rather than updating the existing one.\n    //\n    // Because empty paths do not appear in the URL segments and the fact that the segments used in\n    // the output `UrlTree` are squashed to eliminate these empty paths where possible\n    // https://github.com/angular/angular/blob/13f10de40e25c6900ca55bd83b36bd533dacfa9e/packages/router/src/url_tree.ts#L755\n    // it can be hard to determine what is the right thing to do when applying commands to a\n    // `UrlSegmentGroup` that is created from an \"unsquashed\"/expanded `ActivatedRoute` tree.\n    // This code effectively \"squashes\" empty path primary routes when they have no siblings on\n    // the same level of the tree.\n    if (Object.keys(outlets).some(o => o !== PRIMARY_OUTLET) && segmentGroup.children[PRIMARY_OUTLET] && segmentGroup.numberOfChildren === 1 && segmentGroup.children[PRIMARY_OUTLET].segments.length === 0) {\n      const childrenOfEmptyChild = updateSegmentGroupChildren(segmentGroup.children[PRIMARY_OUTLET], startIndex, commands);\n      return new UrlSegmentGroup(segmentGroup.segments, childrenOfEmptyChild.children);\n    }\n    Object.entries(outlets).forEach(([outlet, commands]) => {\n      if (typeof commands === 'string') {\n        commands = [commands];\n      }\n      if (commands !== null) {\n        children[outlet] = updateSegmentGroup(segmentGroup.children[outlet], startIndex, commands);\n      }\n    });\n    Object.entries(segmentGroup.children).forEach(([childOutlet, child]) => {\n      if (outlets[childOutlet] === undefined) {\n        children[childOutlet] = child;\n      }\n    });\n    return new UrlSegmentGroup(segmentGroup.segments, children);\n  }\n}\nfunction prefixedWith(segmentGroup, startIndex, commands) {\n  let currentCommandIndex = 0;\n  let currentPathIndex = startIndex;\n  const noMatch = {\n    match: false,\n    pathIndex: 0,\n    commandIndex: 0\n  };\n  while (currentPathIndex < segmentGroup.segments.length) {\n    if (currentCommandIndex >= commands.length) return noMatch;\n    const path = segmentGroup.segments[currentPathIndex];\n    const command = commands[currentCommandIndex];\n    // Do not try to consume command as part of the prefixing if it has outlets because it can\n    // contain outlets other than the one being processed. Consuming the outlets command would\n    // result in other outlets being ignored.\n    if (isCommandWithOutlets(command)) {\n      break;\n    }\n    const curr = `${command}`;\n    const next = currentCommandIndex < commands.length - 1 ? commands[currentCommandIndex + 1] : null;\n    if (currentPathIndex > 0 && curr === undefined) break;\n    if (curr && next && typeof next === 'object' && next.outlets === undefined) {\n      if (!compare(curr, next, path)) return noMatch;\n      currentCommandIndex += 2;\n    } else {\n      if (!compare(curr, {}, path)) return noMatch;\n      currentCommandIndex++;\n    }\n    currentPathIndex++;\n  }\n  return {\n    match: true,\n    pathIndex: currentPathIndex,\n    commandIndex: currentCommandIndex\n  };\n}\nfunction createNewSegmentGroup(segmentGroup, startIndex, commands) {\n  const paths = segmentGroup.segments.slice(0, startIndex);\n  let i = 0;\n  while (i < commands.length) {\n    const command = commands[i];\n    if (isCommandWithOutlets(command)) {\n      const children = createNewSegmentChildren(command.outlets);\n      return new UrlSegmentGroup(paths, children);\n    }\n    // if we start with an object literal, we need to reuse the path part from the segment\n    if (i === 0 && isMatrixParams(commands[0])) {\n      const p = segmentGroup.segments[startIndex];\n      paths.push(new UrlSegment(p.path, stringify(commands[0])));\n      i++;\n      continue;\n    }\n    const curr = isCommandWithOutlets(command) ? command.outlets[PRIMARY_OUTLET] : `${command}`;\n    const next = i < commands.length - 1 ? commands[i + 1] : null;\n    if (curr && next && isMatrixParams(next)) {\n      paths.push(new UrlSegment(curr, stringify(next)));\n      i += 2;\n    } else {\n      paths.push(new UrlSegment(curr, {}));\n      i++;\n    }\n  }\n  return new UrlSegmentGroup(paths, {});\n}\nfunction createNewSegmentChildren(outlets) {\n  const children = {};\n  Object.entries(outlets).forEach(([outlet, commands]) => {\n    if (typeof commands === 'string') {\n      commands = [commands];\n    }\n    if (commands !== null) {\n      children[outlet] = createNewSegmentGroup(new UrlSegmentGroup([], {}), 0, commands);\n    }\n  });\n  return children;\n}\nfunction stringify(params) {\n  const res = {};\n  Object.entries(params).forEach(([k, v]) => res[k] = `${v}`);\n  return res;\n}\nfunction compare(path, params, segment) {\n  return path == segment.path && shallowEqual(params, segment.parameters);\n}\nconst IMPERATIVE_NAVIGATION = 'imperative';\n/**\n * Identifies the type of a router event.\n *\n * @publicApi\n */\nvar EventType = /*#__PURE__*/function (EventType) {\n  EventType[EventType[\"NavigationStart\"] = 0] = \"NavigationStart\";\n  EventType[EventType[\"NavigationEnd\"] = 1] = \"NavigationEnd\";\n  EventType[EventType[\"NavigationCancel\"] = 2] = \"NavigationCancel\";\n  EventType[EventType[\"NavigationError\"] = 3] = \"NavigationError\";\n  EventType[EventType[\"RoutesRecognized\"] = 4] = \"RoutesRecognized\";\n  EventType[EventType[\"ResolveStart\"] = 5] = \"ResolveStart\";\n  EventType[EventType[\"ResolveEnd\"] = 6] = \"ResolveEnd\";\n  EventType[EventType[\"GuardsCheckStart\"] = 7] = \"GuardsCheckStart\";\n  EventType[EventType[\"GuardsCheckEnd\"] = 8] = \"GuardsCheckEnd\";\n  EventType[EventType[\"RouteConfigLoadStart\"] = 9] = \"RouteConfigLoadStart\";\n  EventType[EventType[\"RouteConfigLoadEnd\"] = 10] = \"RouteConfigLoadEnd\";\n  EventType[EventType[\"ChildActivationStart\"] = 11] = \"ChildActivationStart\";\n  EventType[EventType[\"ChildActivationEnd\"] = 12] = \"ChildActivationEnd\";\n  EventType[EventType[\"ActivationStart\"] = 13] = \"ActivationStart\";\n  EventType[EventType[\"ActivationEnd\"] = 14] = \"ActivationEnd\";\n  EventType[EventType[\"Scroll\"] = 15] = \"Scroll\";\n  EventType[EventType[\"NavigationSkipped\"] = 16] = \"NavigationSkipped\";\n  return EventType;\n}(EventType || {});\n/**\n * Base for events the router goes through, as opposed to events tied to a specific\n * route. Fired one time for any given navigation.\n *\n * The following code shows how a class subscribes to router events.\n *\n * ```ts\n * import {Event, RouterEvent, Router} from '@angular/router';\n *\n * class MyService {\n *   constructor(public router: Router) {\n *     router.events.pipe(\n *        filter((e: Event | RouterEvent): e is RouterEvent => e instanceof RouterEvent)\n *     ).subscribe((e: RouterEvent) => {\n *       // Do something\n *     });\n *   }\n * }\n * ```\n *\n * @see {@link Event}\n * @see [Router events summary](guide/routing/router-reference#router-events)\n * @publicApi\n */\nclass RouterEvent {\n  id;\n  url;\n  constructor(/** A unique ID that the router assigns to every router navigation. */\n  id, /** The URL that is the destination for this navigation. */\n  url) {\n    this.id = id;\n    this.url = url;\n  }\n}\n/**\n * An event triggered when a navigation starts.\n *\n * @publicApi\n */\nclass NavigationStart extends RouterEvent {\n  type = EventType.NavigationStart;\n  /**\n   * Identifies the call or event that triggered the navigation.\n   * An `imperative` trigger is a call to `router.navigateByUrl()` or `router.navigate()`.\n   *\n   * @see {@link NavigationEnd}\n   * @see {@link NavigationCancel}\n   * @see {@link NavigationError}\n   */\n  navigationTrigger;\n  /**\n   * The navigation state that was previously supplied to the `pushState` call,\n   * when the navigation is triggered by a `popstate` event. Otherwise null.\n   *\n   * The state object is defined by `NavigationExtras`, and contains any\n   * developer-defined state value, as well as a unique ID that\n   * the router assigns to every router transition/navigation.\n   *\n   * From the perspective of the router, the router never \"goes back\".\n   * When the user clicks on the back button in the browser,\n   * a new navigation ID is created.\n   *\n   * Use the ID in this previous-state object to differentiate between a newly created\n   * state and one returned to by a `popstate` event, so that you can restore some\n   * remembered state, such as scroll position.\n   *\n   */\n  restoredState;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  navigationTrigger = 'imperative', /** @docsNotRequired */\n  restoredState = null) {\n    super(id, url);\n    this.navigationTrigger = navigationTrigger;\n    this.restoredState = restoredState;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return `NavigationStart(id: ${this.id}, url: '${this.url}')`;\n  }\n}\n/**\n * An event triggered when a navigation ends successfully.\n *\n * @see {@link NavigationStart}\n * @see {@link NavigationCancel}\n * @see {@link NavigationError}\n *\n * @publicApi\n */\nclass NavigationEnd extends RouterEvent {\n  urlAfterRedirects;\n  type = EventType.NavigationEnd;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  urlAfterRedirects) {\n    super(id, url);\n    this.urlAfterRedirects = urlAfterRedirects;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`;\n  }\n}\n/**\n * A code for the `NavigationCancel` event of the `Router` to indicate the\n * reason a navigation failed.\n *\n * @publicApi\n */\nvar NavigationCancellationCode = /*#__PURE__*/function (NavigationCancellationCode) {\n  /**\n   * A navigation failed because a guard returned a `UrlTree` to redirect.\n   */\n  NavigationCancellationCode[NavigationCancellationCode[\"Redirect\"] = 0] = \"Redirect\";\n  /**\n   * A navigation failed because a more recent navigation started.\n   */\n  NavigationCancellationCode[NavigationCancellationCode[\"SupersededByNewNavigation\"] = 1] = \"SupersededByNewNavigation\";\n  /**\n   * A navigation failed because one of the resolvers completed without emitting a value.\n   */\n  NavigationCancellationCode[NavigationCancellationCode[\"NoDataFromResolver\"] = 2] = \"NoDataFromResolver\";\n  /**\n   * A navigation failed because a guard returned `false`.\n   */\n  NavigationCancellationCode[NavigationCancellationCode[\"GuardRejected\"] = 3] = \"GuardRejected\";\n  return NavigationCancellationCode;\n}(NavigationCancellationCode || {});\n/**\n * A code for the `NavigationSkipped` event of the `Router` to indicate the\n * reason a navigation was skipped.\n *\n * @publicApi\n */\nvar NavigationSkippedCode = /*#__PURE__*/function (NavigationSkippedCode) {\n  /**\n   * A navigation was skipped because the navigation URL was the same as the current Router URL.\n   */\n  NavigationSkippedCode[NavigationSkippedCode[\"IgnoredSameUrlNavigation\"] = 0] = \"IgnoredSameUrlNavigation\";\n  /**\n   * A navigation was skipped because the configured `UrlHandlingStrategy` return `false` for both\n   * the current Router URL and the target of the navigation.\n   *\n   * @see {@link UrlHandlingStrategy}\n   */\n  NavigationSkippedCode[NavigationSkippedCode[\"IgnoredByUrlHandlingStrategy\"] = 1] = \"IgnoredByUrlHandlingStrategy\";\n  return NavigationSkippedCode;\n}(NavigationSkippedCode || {});\n/**\n * An event triggered when a navigation is canceled, directly or indirectly.\n * This can happen for several reasons including when a route guard\n * returns `false` or initiates a redirect by returning a `UrlTree`.\n *\n * @see {@link NavigationStart}\n * @see {@link NavigationEnd}\n * @see {@link NavigationError}\n *\n * @publicApi\n */\nclass NavigationCancel extends RouterEvent {\n  reason;\n  code;\n  type = EventType.NavigationCancel;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url,\n  /**\n   * A description of why the navigation was cancelled. For debug purposes only. Use `code`\n   * instead for a stable cancellation reason that can be used in production.\n   */\n  reason,\n  /**\n   * A code to indicate why the navigation was canceled. This cancellation code is stable for\n   * the reason and can be relied on whereas the `reason` string could change and should not be\n   * used in production.\n   */\n  code) {\n    super(id, url);\n    this.reason = reason;\n    this.code = code;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return `NavigationCancel(id: ${this.id}, url: '${this.url}')`;\n  }\n}\n/**\n * An event triggered when a navigation is skipped.\n * This can happen for a couple reasons including onSameUrlHandling\n * is set to `ignore` and the navigation URL is not different than the\n * current state.\n *\n * @publicApi\n */\nclass NavigationSkipped extends RouterEvent {\n  reason;\n  code;\n  type = EventType.NavigationSkipped;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url,\n  /**\n   * A description of why the navigation was skipped. For debug purposes only. Use `code`\n   * instead for a stable skipped reason that can be used in production.\n   */\n  reason,\n  /**\n   * A code to indicate why the navigation was skipped. This code is stable for\n   * the reason and can be relied on whereas the `reason` string could change and should not be\n   * used in production.\n   */\n  code) {\n    super(id, url);\n    this.reason = reason;\n    this.code = code;\n  }\n}\n/**\n * An event triggered when a navigation fails due to an unexpected error.\n *\n * @see {@link NavigationStart}\n * @see {@link NavigationEnd}\n * @see {@link NavigationCancel}\n *\n * @publicApi\n */\nclass NavigationError extends RouterEvent {\n  error;\n  target;\n  type = EventType.NavigationError;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  error,\n  /**\n   * The target of the navigation when the error occurred.\n   *\n   * Note that this can be `undefined` because an error could have occurred before the\n   * `RouterStateSnapshot` was created for the navigation.\n   */\n  target) {\n    super(id, url);\n    this.error = error;\n    this.target = target;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return `NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`;\n  }\n}\n/**\n * An event triggered when routes are recognized.\n *\n * @publicApi\n */\nclass RoutesRecognized extends RouterEvent {\n  urlAfterRedirects;\n  state;\n  type = EventType.RoutesRecognized;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  urlAfterRedirects, /** @docsNotRequired */\n  state) {\n    super(id, url);\n    this.urlAfterRedirects = urlAfterRedirects;\n    this.state = state;\n  }\n  /** @docsNotRequired */\n  toString() {\n    return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;\n  }\n}\n/**\n * An event triggered at the start of the Guard phase of routing.\n *\n * @see {@link GuardsCheckEnd}\n *\n * @publicApi\n */\nclass GuardsCheckStart extends RouterEvent {\n  urlAfterRedirects;\n  state;\n  type = EventType.GuardsCheckStart;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  urlAfterRedirects, /** @docsNotRequired */\n  state) {\n    super(id, url);\n    this.urlAfterRedirects = urlAfterRedirects;\n    this.state = state;\n  }\n  toString() {\n    return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;\n  }\n}\n/**\n * An event triggered at the end of the Guard phase of routing.\n *\n * @see {@link GuardsCheckStart}\n *\n * @publicApi\n */\nclass GuardsCheckEnd extends RouterEvent {\n  urlAfterRedirects;\n  state;\n  shouldActivate;\n  type = EventType.GuardsCheckEnd;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  urlAfterRedirects, /** @docsNotRequired */\n  state, /** @docsNotRequired */\n  shouldActivate) {\n    super(id, url);\n    this.urlAfterRedirects = urlAfterRedirects;\n    this.state = state;\n    this.shouldActivate = shouldActivate;\n  }\n  toString() {\n    return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;\n  }\n}\n/**\n * An event triggered at the start of the Resolve phase of routing.\n *\n * Runs in the \"resolve\" phase whether or not there is anything to resolve.\n * In future, may change to only run when there are things to be resolved.\n *\n * @see {@link ResolveEnd}\n *\n * @publicApi\n */\nclass ResolveStart extends RouterEvent {\n  urlAfterRedirects;\n  state;\n  type = EventType.ResolveStart;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  urlAfterRedirects, /** @docsNotRequired */\n  state) {\n    super(id, url);\n    this.urlAfterRedirects = urlAfterRedirects;\n    this.state = state;\n  }\n  toString() {\n    return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;\n  }\n}\n/**\n * An event triggered at the end of the Resolve phase of routing.\n * @see {@link ResolveStart}\n *\n * @publicApi\n */\nclass ResolveEnd extends RouterEvent {\n  urlAfterRedirects;\n  state;\n  type = EventType.ResolveEnd;\n  constructor(/** @docsNotRequired */\n  id, /** @docsNotRequired */\n  url, /** @docsNotRequired */\n  urlAfterRedirects, /** @docsNotRequired */\n  state) {\n    super(id, url);\n    this.urlAfterRedirects = urlAfterRedirects;\n    this.state = state;\n  }\n  toString() {\n    return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;\n  }\n}\n/**\n * An event triggered before lazy loading a route configuration.\n *\n * @see {@link RouteConfigLoadEnd}\n *\n * @publicApi\n */\nclass RouteConfigLoadStart {\n  route;\n  type = EventType.RouteConfigLoadStart;\n  constructor(/** @docsNotRequired */\n  route) {\n    this.route = route;\n  }\n  toString() {\n    return `RouteConfigLoadStart(path: ${this.route.path})`;\n  }\n}\n/**\n * An event triggered when a route has been lazy loaded.\n *\n * @see {@link RouteConfigLoadStart}\n *\n * @publicApi\n */\nclass RouteConfigLoadEnd {\n  route;\n  type = EventType.RouteConfigLoadEnd;\n  constructor(/** @docsNotRequired */\n  route) {\n    this.route = route;\n  }\n  toString() {\n    return `RouteConfigLoadEnd(path: ${this.route.path})`;\n  }\n}\n/**\n * An event triggered at the start of the child-activation\n * part of the Resolve phase of routing.\n * @see {@link ChildActivationEnd}\n * @see {@link ResolveStart}\n *\n * @publicApi\n */\nclass ChildActivationStart {\n  snapshot;\n  type = EventType.ChildActivationStart;\n  constructor(/** @docsNotRequired */\n  snapshot) {\n    this.snapshot = snapshot;\n  }\n  toString() {\n    const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';\n    return `ChildActivationStart(path: '${path}')`;\n  }\n}\n/**\n * An event triggered at the end of the child-activation part\n * of the Resolve phase of routing.\n * @see {@link ChildActivationStart}\n * @see {@link ResolveStart}\n * @publicApi\n */\nclass ChildActivationEnd {\n  snapshot;\n  type = EventType.ChildActivationEnd;\n  constructor(/** @docsNotRequired */\n  snapshot) {\n    this.snapshot = snapshot;\n  }\n  toString() {\n    const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';\n    return `ChildActivationEnd(path: '${path}')`;\n  }\n}\n/**\n * An event triggered at the start of the activation part\n * of the Resolve phase of routing.\n * @see {@link ActivationEnd}\n * @see {@link ResolveStart}\n *\n * @publicApi\n */\nclass ActivationStart {\n  snapshot;\n  type = EventType.ActivationStart;\n  constructor(/** @docsNotRequired */\n  snapshot) {\n    this.snapshot = snapshot;\n  }\n  toString() {\n    const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';\n    return `ActivationStart(path: '${path}')`;\n  }\n}\n/**\n * An event triggered at the end of the activation part\n * of the Resolve phase of routing.\n * @see {@link ActivationStart}\n * @see {@link ResolveStart}\n *\n * @publicApi\n */\nclass ActivationEnd {\n  snapshot;\n  type = EventType.ActivationEnd;\n  constructor(/** @docsNotRequired */\n  snapshot) {\n    this.snapshot = snapshot;\n  }\n  toString() {\n    const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';\n    return `ActivationEnd(path: '${path}')`;\n  }\n}\n/**\n * An event triggered by scrolling.\n *\n * @publicApi\n */\nclass Scroll {\n  routerEvent;\n  position;\n  anchor;\n  type = EventType.Scroll;\n  constructor(/** @docsNotRequired */\n  routerEvent, /** @docsNotRequired */\n  position, /** @docsNotRequired */\n  anchor) {\n    this.routerEvent = routerEvent;\n    this.position = position;\n    this.anchor = anchor;\n  }\n  toString() {\n    const pos = this.position ? `${this.position[0]}, ${this.position[1]}` : null;\n    return `Scroll(anchor: '${this.anchor}', position: '${pos}')`;\n  }\n}\nclass BeforeActivateRoutes {}\nclass RedirectRequest {\n  url;\n  navigationBehaviorOptions;\n  constructor(url, navigationBehaviorOptions) {\n    this.url = url;\n    this.navigationBehaviorOptions = navigationBehaviorOptions;\n  }\n}\nfunction stringifyEvent(routerEvent) {\n  switch (routerEvent.type) {\n    case EventType.ActivationEnd:\n      return `ActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;\n    case EventType.ActivationStart:\n      return `ActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;\n    case EventType.ChildActivationEnd:\n      return `ChildActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;\n    case EventType.ChildActivationStart:\n      return `ChildActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;\n    case EventType.GuardsCheckEnd:\n      return `GuardsCheckEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state}, shouldActivate: ${routerEvent.shouldActivate})`;\n    case EventType.GuardsCheckStart:\n      return `GuardsCheckStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;\n    case EventType.NavigationCancel:\n      return `NavigationCancel(id: ${routerEvent.id}, url: '${routerEvent.url}')`;\n    case EventType.NavigationSkipped:\n      return `NavigationSkipped(id: ${routerEvent.id}, url: '${routerEvent.url}')`;\n    case EventType.NavigationEnd:\n      return `NavigationEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}')`;\n    case EventType.NavigationError:\n      return `NavigationError(id: ${routerEvent.id}, url: '${routerEvent.url}', error: ${routerEvent.error})`;\n    case EventType.NavigationStart:\n      return `NavigationStart(id: ${routerEvent.id}, url: '${routerEvent.url}')`;\n    case EventType.ResolveEnd:\n      return `ResolveEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;\n    case EventType.ResolveStart:\n      return `ResolveStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;\n    case EventType.RouteConfigLoadEnd:\n      return `RouteConfigLoadEnd(path: ${routerEvent.route.path})`;\n    case EventType.RouteConfigLoadStart:\n      return `RouteConfigLoadStart(path: ${routerEvent.route.path})`;\n    case EventType.RoutesRecognized:\n      return `RoutesRecognized(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;\n    case EventType.Scroll:\n      const pos = routerEvent.position ? `${routerEvent.position[0]}, ${routerEvent.position[1]}` : null;\n      return `Scroll(anchor: '${routerEvent.anchor}', position: '${pos}')`;\n  }\n}\n\n/**\n * Creates an `EnvironmentInjector` if the `Route` has providers and one does not already exist\n * and returns the injector. Otherwise, if the `Route` does not have `providers`, returns the\n * `currentInjector`.\n *\n * @param route The route that might have providers\n * @param currentInjector The parent injector of the `Route`\n */\nfunction getOrCreateRouteInjectorIfNeeded(route, currentInjector) {\n  if (route.providers && !route._injector) {\n    route._injector = createEnvironmentInjector(route.providers, currentInjector, `Route: ${route.path}`);\n  }\n  return route._injector ?? currentInjector;\n}\nfunction validateConfig(config, parentPath = '', requireStandaloneComponents = false) {\n  // forEach doesn't iterate undefined values\n  for (let i = 0; i < config.length; i++) {\n    const route = config[i];\n    const fullPath = getFullPath(parentPath, route);\n    validateNode(route, fullPath, requireStandaloneComponents);\n  }\n}\nfunction assertStandalone(fullPath, component) {\n  if (component && _isNgModule(component)) {\n    throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}'. You are using 'loadComponent' with a module, ` + `but it must be used with standalone components. Use 'loadChildren' instead.`);\n  } else if (component && !isStandalone(component)) {\n    throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}'. The component must be standalone.`);\n  }\n}\nfunction validateNode(route, fullPath, requireStandaloneComponents) {\n  if (typeof ngDevMode === 'undefined' || ngDevMode) {\n    if (!route) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `\n      Invalid configuration of route '${fullPath}': Encountered undefined route.\n      The reason might be an extra comma.\n\n      Example:\n      const routes: Routes = [\n        { path: '', redirectTo: '/dashboard', pathMatch: 'full' },\n        { path: 'dashboard',  component: DashboardComponent },, << two commas\n        { path: 'detail/:id', component: HeroDetailComponent }\n      ];\n    `);\n    }\n    if (Array.isArray(route)) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': Array cannot be specified`);\n    }\n    if (!route.redirectTo && !route.component && !route.loadComponent && !route.children && !route.loadChildren && route.outlet && route.outlet !== PRIMARY_OUTLET) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);\n    }\n    if (route.redirectTo && route.children) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);\n    }\n    if (route.redirectTo && route.loadChildren) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);\n    }\n    if (route.children && route.loadChildren) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);\n    }\n    if (route.redirectTo && (route.component || route.loadComponent)) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': redirectTo and component/loadComponent cannot be used together`);\n    }\n    if (route.component && route.loadComponent) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': component and loadComponent cannot be used together`);\n    }\n    if (route.redirectTo && route.canActivate) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation ` + `so canActivate will never be executed.`);\n    }\n    if (route.path && route.matcher) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);\n    }\n    if (route.redirectTo === void 0 && !route.component && !route.loadComponent && !route.children && !route.loadChildren) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}'. One of the following must be provided: component, loadComponent, redirectTo, children or loadChildren`);\n    }\n    if (route.path === void 0 && route.matcher === void 0) {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);\n    }\n    if (typeof route.path === 'string' && route.path.charAt(0) === '/') {\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '${fullPath}': path cannot start with a slash`);\n    }\n    if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {\n      const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;\n      throw new _RuntimeError(4014 /* RuntimeErrorCode.INVALID_ROUTE_CONFIG */, `Invalid configuration of route '{path: \"${fullPath}\", redirectTo: \"${route.redirectTo}\"}': please provide 'pathMatch'. ${exp}`);\n    }\n    if (requireStandaloneComponents) {\n      assertStandalone(fullPath, route.component);\n    }\n  }\n  if (route.children) {\n    validateConfig(route.children, fullPath, requireStandaloneComponents);\n  }\n}\nfunction getFullPath(parentPath, currentRoute) {\n  if (!currentRoute) {\n    return parentPath;\n  }\n  if (!parentPath && !currentRoute.path) {\n    return '';\n  } else if (parentPath && !currentRoute.path) {\n    return `${parentPath}/`;\n  } else if (!parentPath && currentRoute.path) {\n    return currentRoute.path;\n  } else {\n    return `${parentPath}/${currentRoute.path}`;\n  }\n}\n/** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */\nfunction getOutlet(route) {\n  return route.outlet || PRIMARY_OUTLET;\n}\n/**\n * Sorts the `routes` such that the ones with an outlet matching `outletName` come first.\n * The order of the configs is otherwise preserved.\n */\nfunction sortByMatchingOutlets(routes, outletName) {\n  const sortedConfig = routes.filter(r => getOutlet(r) === outletName);\n  sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));\n  return sortedConfig;\n}\n/**\n * Gets the first injector in the snapshot's parent tree.\n *\n * If the `Route` has a static list of providers, the returned injector will be the one created from\n * those. If it does not exist, the returned injector may come from the parents, which may be from a\n * loaded config or their static providers.\n *\n * Returns `null` if there is neither this nor any parents have a stored injector.\n *\n * Generally used for retrieving the injector to use for getting tokens for guards/resolvers and\n * also used for getting the correct injector to use for creating components.\n */\nfunction getClosestRouteInjector(snapshot) {\n  if (!snapshot) return null;\n  // If the current route has its own injector, which is created from the static providers on the\n  // route itself, we should use that. Otherwise, we start at the parent since we do not want to\n  // include the lazy loaded injector from this route.\n  if (snapshot.routeConfig?._injector) {\n    return snapshot.routeConfig._injector;\n  }\n  for (let s = snapshot.parent; s; s = s.parent) {\n    const route = s.routeConfig;\n    // Note that the order here is important. `_loadedInjector` stored on the route with\n    // `loadChildren: () => NgModule` so it applies to child routes with priority. The `_injector`\n    // is created from the static providers on that parent route, so it applies to the children as\n    // well, but only if there is no lazy loaded NgModuleRef injector.\n    if (route?._loadedInjector) return route._loadedInjector;\n    if (route?._injector) return route._injector;\n  }\n  return null;\n}\n\n/**\n * Store contextual information about a `RouterOutlet`\n *\n * @publicApi\n */\nclass OutletContext {\n  rootInjector;\n  outlet = null;\n  route = null;\n  children;\n  attachRef = null;\n  get injector() {\n    return getClosestRouteInjector(this.route?.snapshot) ?? this.rootInjector;\n  }\n  constructor(rootInjector) {\n    this.rootInjector = rootInjector;\n    this.children = new ChildrenOutletContexts(this.rootInjector);\n  }\n}\n/**\n * Store contextual information about the children (= nested) `RouterOutlet`\n *\n * @publicApi\n */\nlet ChildrenOutletContexts = /*#__PURE__*/(() => {\n  class ChildrenOutletContexts {\n    rootInjector;\n    // contexts for child outlets, by name.\n    contexts = new Map();\n    /** @docs-private */\n    constructor(rootInjector) {\n      this.rootInjector = rootInjector;\n    }\n    /** Called when a `RouterOutlet` directive is instantiated */\n    onChildOutletCreated(childName, outlet) {\n      const context = this.getOrCreateContext(childName);\n      context.outlet = outlet;\n      this.contexts.set(childName, context);\n    }\n    /**\n     * Called when a `RouterOutlet` directive is destroyed.\n     * We need to keep the context as the outlet could be destroyed inside a NgIf and might be\n     * re-created later.\n     */\n    onChildOutletDestroyed(childName) {\n      const context = this.getContext(childName);\n      if (context) {\n        context.outlet = null;\n        context.attachRef = null;\n      }\n    }\n    /**\n     * Called when the corresponding route is deactivated during navigation.\n     * Because the component get destroyed, all children outlet are destroyed.\n     */\n    onOutletDeactivated() {\n      const contexts = this.contexts;\n      this.contexts = new Map();\n      return contexts;\n    }\n    onOutletReAttached(contexts) {\n      this.contexts = contexts;\n    }\n    getOrCreateContext(childName) {\n      let context = this.getContext(childName);\n      if (!context) {\n        context = new OutletContext(this.rootInjector);\n        this.contexts.set(childName, context);\n      }\n      return context;\n    }\n    getContext(childName) {\n      return this.contexts.get(childName) || null;\n    }\n    static ɵfac = function ChildrenOutletContexts_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || ChildrenOutletContexts)(i0.ɵɵinject(i0.EnvironmentInjector));\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: ChildrenOutletContexts,\n      factory: ChildrenOutletContexts.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return ChildrenOutletContexts;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nclass Tree {\n  /** @internal */\n  _root;\n  constructor(root) {\n    this._root = root;\n  }\n  get root() {\n    return this._root.value;\n  }\n  /**\n   * @internal\n   */\n  parent(t) {\n    const p = this.pathFromRoot(t);\n    return p.length > 1 ? p[p.length - 2] : null;\n  }\n  /**\n   * @internal\n   */\n  children(t) {\n    const n = findNode(t, this._root);\n    return n ? n.children.map(t => t.value) : [];\n  }\n  /**\n   * @internal\n   */\n  firstChild(t) {\n    const n = findNode(t, this._root);\n    return n && n.children.length > 0 ? n.children[0].value : null;\n  }\n  /**\n   * @internal\n   */\n  siblings(t) {\n    const p = findPath(t, this._root);\n    if (p.length < 2) return [];\n    const c = p[p.length - 2].children.map(c => c.value);\n    return c.filter(cc => cc !== t);\n  }\n  /**\n   * @internal\n   */\n  pathFromRoot(t) {\n    return findPath(t, this._root).map(s => s.value);\n  }\n}\n// DFS for the node matching the value\nfunction findNode(value, node) {\n  if (value === node.value) return node;\n  for (const child of node.children) {\n    const node = findNode(value, child);\n    if (node) return node;\n  }\n  return null;\n}\n// Return the path to the node with the given value using DFS\nfunction findPath(value, node) {\n  if (value === node.value) return [node];\n  for (const child of node.children) {\n    const path = findPath(value, child);\n    if (path.length) {\n      path.unshift(node);\n      return path;\n    }\n  }\n  return [];\n}\nclass TreeNode {\n  value;\n  children;\n  constructor(value, children) {\n    this.value = value;\n    this.children = children;\n  }\n  toString() {\n    return `TreeNode(${this.value})`;\n  }\n}\n// Return the list of T indexed by outlet name\nfunction nodeChildrenAsMap(node) {\n  const map = {};\n  if (node) {\n    node.children.forEach(child => map[child.value.outlet] = child);\n  }\n  return map;\n}\n\n/**\n * Represents the state of the router as a tree of activated routes.\n *\n * @usageNotes\n *\n * Every node in the route tree is an `ActivatedRoute` instance\n * that knows about the \"consumed\" URL segments, the extracted parameters,\n * and the resolved data.\n * Use the `ActivatedRoute` properties to traverse the tree from any node.\n *\n * The following fragment shows how a component gets the root node\n * of the current state to establish its own route tree:\n *\n * ```ts\n * @Component({templateUrl:'template.html'})\n * class MyComponent {\n *   constructor(router: Router) {\n *     const state: RouterState = router.routerState;\n *     const root: ActivatedRoute = state.root;\n *     const child = root.firstChild;\n *     const id: Observable<string> = child.params.map(p => p.id);\n *     //...\n *   }\n * }\n * ```\n *\n * @see {@link ActivatedRoute}\n * @see [Getting route information](guide/routing/common-router-tasks#getting-route-information)\n *\n * @publicApi\n */\nclass RouterState extends Tree {\n  snapshot;\n  /** @internal */\n  constructor(root, /** The current snapshot of the router state */\n  snapshot) {\n    super(root);\n    this.snapshot = snapshot;\n    setRouterState(this, root);\n  }\n  toString() {\n    return this.snapshot.toString();\n  }\n}\nfunction createEmptyState(rootComponent) {\n  const snapshot = createEmptyStateSnapshot(rootComponent);\n  const emptyUrl = new BehaviorSubject([new UrlSegment('', {})]);\n  const emptyParams = new BehaviorSubject({});\n  const emptyData = new BehaviorSubject({});\n  const emptyQueryParams = new BehaviorSubject({});\n  const fragment = new BehaviorSubject('');\n  const activated = new ActivatedRoute(emptyUrl, emptyParams, emptyQueryParams, fragment, emptyData, PRIMARY_OUTLET, rootComponent, snapshot.root);\n  activated.snapshot = snapshot.root;\n  return new RouterState(new TreeNode(activated, []), snapshot);\n}\nfunction createEmptyStateSnapshot(rootComponent) {\n  const emptyParams = {};\n  const emptyData = {};\n  const emptyQueryParams = {};\n  const fragment = '';\n  const activated = new ActivatedRouteSnapshot([], emptyParams, emptyQueryParams, fragment, emptyData, PRIMARY_OUTLET, rootComponent, null, {});\n  return new RouterStateSnapshot('', new TreeNode(activated, []));\n}\n/**\n * Provides access to information about a route associated with a component\n * that is loaded in an outlet.\n * Use to traverse the `RouterState` tree and extract information from nodes.\n *\n * The following example shows how to construct a component using information from a\n * currently activated route.\n *\n * Note: the observables in this class only emit when the current and previous values differ based\n * on shallow equality. For example, changing deeply nested properties in resolved `data` will not\n * cause the `ActivatedRoute.data` `Observable` to emit a new value.\n *\n * {@example router/activated-route/module.ts region=\"activated-route\"\n *     header=\"activated-route.component.ts\"}\n *\n * @see [Getting route information](guide/routing/common-router-tasks#getting-route-information)\n *\n * @publicApi\n */\nclass ActivatedRoute {\n  urlSubject;\n  paramsSubject;\n  queryParamsSubject;\n  fragmentSubject;\n  dataSubject;\n  outlet;\n  component;\n  /** The current snapshot of this route */\n  snapshot;\n  /** @internal */\n  _futureSnapshot;\n  /** @internal */\n  _routerState;\n  /** @internal */\n  _paramMap;\n  /** @internal */\n  _queryParamMap;\n  /** An Observable of the resolved route title */\n  title;\n  /** An observable of the URL segments matched by this route. */\n  url;\n  /** An observable of the matrix parameters scoped to this route. */\n  params;\n  /** An observable of the query parameters shared by all the routes. */\n  queryParams;\n  /** An observable of the URL fragment shared by all the routes. */\n  fragment;\n  /** An observable of the static and resolved data of this route. */\n  data;\n  /** @internal */\n  constructor(/** @internal */\n  urlSubject, /** @internal */\n  paramsSubject, /** @internal */\n  queryParamsSubject, /** @internal */\n  fragmentSubject, /** @internal */\n  dataSubject, /** The outlet name of the route, a constant. */\n  outlet, /** The component of the route, a constant. */\n  component, futureSnapshot) {\n    this.urlSubject = urlSubject;\n    this.paramsSubject = paramsSubject;\n    this.queryParamsSubject = queryParamsSubject;\n    this.fragmentSubject = fragmentSubject;\n    this.dataSubject = dataSubject;\n    this.outlet = outlet;\n    this.component = component;\n    this._futureSnapshot = futureSnapshot;\n    this.title = this.dataSubject?.pipe(map(d => d[RouteTitleKey])) ?? of(undefined);\n    // TODO(atscott): Verify that these can be changed to `.asObservable()` with TGP.\n    this.url = urlSubject;\n    this.params = paramsSubject;\n    this.queryParams = queryParamsSubject;\n    this.fragment = fragmentSubject;\n    this.data = dataSubject;\n  }\n  /** The configuration used to match this route. */\n  get routeConfig() {\n    return this._futureSnapshot.routeConfig;\n  }\n  /** The root of the router state. */\n  get root() {\n    return this._routerState.root;\n  }\n  /** The parent of this route in the router state tree. */\n  get parent() {\n    return this._routerState.parent(this);\n  }\n  /** The first child of this route in the router state tree. */\n  get firstChild() {\n    return this._routerState.firstChild(this);\n  }\n  /** The children of this route in the router state tree. */\n  get children() {\n    return this._routerState.children(this);\n  }\n  /** The path from the root of the router state tree to this route. */\n  get pathFromRoot() {\n    return this._routerState.pathFromRoot(this);\n  }\n  /**\n   * An Observable that contains a map of the required and optional parameters\n   * specific to the route.\n   * The map supports retrieving single and multiple values from the same parameter.\n   */\n  get paramMap() {\n    this._paramMap ??= this.params.pipe(map(p => convertToParamMap(p)));\n    return this._paramMap;\n  }\n  /**\n   * An Observable that contains a map of the query parameters available to all routes.\n   * The map supports retrieving single and multiple values from the query parameter.\n   */\n  get queryParamMap() {\n    this._queryParamMap ??= this.queryParams.pipe(map(p => convertToParamMap(p)));\n    return this._queryParamMap;\n  }\n  toString() {\n    return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;\n  }\n}\n/**\n * Returns the inherited params, data, and resolve for a given route.\n *\n * By default, we do not inherit parent data unless the current route is path-less or the parent\n * route is component-less.\n */\nfunction getInherited(route, parent, paramsInheritanceStrategy = 'emptyOnly') {\n  let inherited;\n  const {\n    routeConfig\n  } = route;\n  if (parent !== null && (paramsInheritanceStrategy === 'always' ||\n  // inherit parent data if route is empty path\n  routeConfig?.path === '' ||\n  // inherit parent data if parent was componentless\n  !parent.component && !parent.routeConfig?.loadComponent)) {\n    inherited = {\n      params: {\n        ...parent.params,\n        ...route.params\n      },\n      data: {\n        ...parent.data,\n        ...route.data\n      },\n      resolve: {\n        // Snapshots are created with data inherited from parent and guards (i.e. canActivate) can\n        // change data because it's not frozen...\n        // This first line could be deleted chose to break/disallow mutating the `data` object in\n        // guards.\n        // Note that data from parents still override this mutated data so anyone relying on this\n        // might be surprised that it doesn't work if parent data is inherited but otherwise does.\n        ...route.data,\n        // Ensure inherited resolved data overrides inherited static data\n        ...parent.data,\n        // static data from the current route overrides any inherited data\n        ...routeConfig?.data,\n        // resolved data from current route overrides everything\n        ...route._resolvedData\n      }\n    };\n  } else {\n    inherited = {\n      params: {\n        ...route.params\n      },\n      data: {\n        ...route.data\n      },\n      resolve: {\n        ...route.data,\n        ...(route._resolvedData ?? {})\n      }\n    };\n  }\n  if (routeConfig && hasStaticTitle(routeConfig)) {\n    inherited.resolve[RouteTitleKey] = routeConfig.title;\n  }\n  return inherited;\n}\n/**\n * @description\n *\n * Contains the information about a route associated with a component loaded in an\n * outlet at a particular moment in time. ActivatedRouteSnapshot can also be used to\n * traverse the router state tree.\n *\n * The following example initializes a component with route information extracted\n * from the snapshot of the root node at the time of creation.\n *\n * ```ts\n * @Component({templateUrl:'./my-component.html'})\n * class MyComponent {\n *   constructor(route: ActivatedRoute) {\n *     const id: string = route.snapshot.params.id;\n *     const url: string = route.snapshot.url.join('');\n *     const user = route.snapshot.data.user;\n *   }\n * }\n * ```\n *\n * @publicApi\n */\nclass ActivatedRouteSnapshot {\n  url;\n  params;\n  queryParams;\n  fragment;\n  data;\n  outlet;\n  component;\n  /** The configuration used to match this route **/\n  routeConfig;\n  /** @internal */\n  _resolve;\n  /** @internal */\n  _resolvedData;\n  /** @internal */\n  _routerState;\n  /** @internal */\n  _paramMap;\n  /** @internal */\n  _queryParamMap;\n  /** The resolved route title */\n  get title() {\n    // Note: This _must_ be a getter because the data is mutated in the resolvers. Title will not be\n    // available at the time of class instantiation.\n    return this.data?.[RouteTitleKey];\n  }\n  /** @internal */\n  constructor(/** The URL segments matched by this route */\n  url,\n  /**\n   *  The matrix parameters scoped to this route.\n   *\n   *  You can compute all params (or data) in the router state or to get params outside\n   *  of an activated component by traversing the `RouterState` tree as in the following\n   *  example:\n   *  ```ts\n   *  collectRouteParams(router: Router) {\n   *    let params = {};\n   *    let stack: ActivatedRouteSnapshot[] = [router.routerState.snapshot.root];\n   *    while (stack.length > 0) {\n   *      const route = stack.pop()!;\n   *      params = {...params, ...route.params};\n   *      stack.push(...route.children);\n   *    }\n   *    return params;\n   *  }\n   *  ```\n   */\n  params, /** The query parameters shared by all the routes */\n  queryParams, /** The URL fragment shared by all the routes */\n  fragment, /** The static and resolved data of this route */\n  data, /** The outlet name of the route */\n  outlet, /** The component of the route */\n  component, routeConfig, resolve) {\n    this.url = url;\n    this.params = params;\n    this.queryParams = queryParams;\n    this.fragment = fragment;\n    this.data = data;\n    this.outlet = outlet;\n    this.component = component;\n    this.routeConfig = routeConfig;\n    this._resolve = resolve;\n  }\n  /** The root of the router state */\n  get root() {\n    return this._routerState.root;\n  }\n  /** The parent of this route in the router state tree */\n  get parent() {\n    return this._routerState.parent(this);\n  }\n  /** The first child of this route in the router state tree */\n  get firstChild() {\n    return this._routerState.firstChild(this);\n  }\n  /** The children of this route in the router state tree */\n  get children() {\n    return this._routerState.children(this);\n  }\n  /** The path from the root of the router state tree to this route */\n  get pathFromRoot() {\n    return this._routerState.pathFromRoot(this);\n  }\n  get paramMap() {\n    this._paramMap ??= convertToParamMap(this.params);\n    return this._paramMap;\n  }\n  get queryParamMap() {\n    this._queryParamMap ??= convertToParamMap(this.queryParams);\n    return this._queryParamMap;\n  }\n  toString() {\n    const url = this.url.map(segment => segment.toString()).join('/');\n    const matched = this.routeConfig ? this.routeConfig.path : '';\n    return `Route(url:'${url}', path:'${matched}')`;\n  }\n}\n/**\n * @description\n *\n * Represents the state of the router at a moment in time.\n *\n * This is a tree of activated route snapshots. Every node in this tree knows about\n * the \"consumed\" URL segments, the extracted parameters, and the resolved data.\n *\n * The following example shows how a component is initialized with information\n * from the snapshot of the root node's state at the time of creation.\n *\n * ```ts\n * @Component({templateUrl:'template.html'})\n * class MyComponent {\n *   constructor(router: Router) {\n *     const state: RouterState = router.routerState;\n *     const snapshot: RouterStateSnapshot = state.snapshot;\n *     const root: ActivatedRouteSnapshot = snapshot.root;\n *     const child = root.firstChild;\n *     const id: Observable<string> = child.params.map(p => p.id);\n *     //...\n *   }\n * }\n * ```\n *\n * @publicApi\n */\nclass RouterStateSnapshot extends Tree {\n  url;\n  /** @internal */\n  constructor(/** The url from which this snapshot was created */\n  url, root) {\n    super(root);\n    this.url = url;\n    setRouterState(this, root);\n  }\n  toString() {\n    return serializeNode(this._root);\n  }\n}\nfunction setRouterState(state, node) {\n  node.value._routerState = state;\n  node.children.forEach(c => setRouterState(state, c));\n}\nfunction serializeNode(node) {\n  const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(', ')} } ` : '';\n  return `${node.value}${c}`;\n}\n/**\n * The expectation is that the activate route is created with the right set of parameters.\n * So we push new values into the observables only when they are not the initial values.\n * And we detect that by checking if the snapshot field is set.\n */\nfunction advanceActivatedRoute(route) {\n  if (route.snapshot) {\n    const currentSnapshot = route.snapshot;\n    const nextSnapshot = route._futureSnapshot;\n    route.snapshot = nextSnapshot;\n    if (!shallowEqual(currentSnapshot.queryParams, nextSnapshot.queryParams)) {\n      route.queryParamsSubject.next(nextSnapshot.queryParams);\n    }\n    if (currentSnapshot.fragment !== nextSnapshot.fragment) {\n      route.fragmentSubject.next(nextSnapshot.fragment);\n    }\n    if (!shallowEqual(currentSnapshot.params, nextSnapshot.params)) {\n      route.paramsSubject.next(nextSnapshot.params);\n    }\n    if (!shallowEqualArrays(currentSnapshot.url, nextSnapshot.url)) {\n      route.urlSubject.next(nextSnapshot.url);\n    }\n    if (!shallowEqual(currentSnapshot.data, nextSnapshot.data)) {\n      route.dataSubject.next(nextSnapshot.data);\n    }\n  } else {\n    route.snapshot = route._futureSnapshot;\n    // this is for resolved data\n    route.dataSubject.next(route._futureSnapshot.data);\n  }\n}\nfunction equalParamsAndUrlSegments(a, b) {\n  const equalUrlParams = shallowEqual(a.params, b.params) && equalSegments(a.url, b.url);\n  const parentsMismatch = !a.parent !== !b.parent;\n  return equalUrlParams && !parentsMismatch && (!a.parent || equalParamsAndUrlSegments(a.parent, b.parent));\n}\nfunction hasStaticTitle(config) {\n  return typeof config.title === 'string' || config.title === null;\n}\n\n/**\n * An `InjectionToken` provided by the `RouterOutlet` and can be set using the `routerOutletData`\n * input.\n *\n * When unset, this value is `null` by default.\n *\n * @usageNotes\n *\n * To set the data from the template of the component with `router-outlet`:\n * ```html\n * <router-outlet [routerOutletData]=\"{name: 'Angular'}\" />\n * ```\n *\n * To read the data in the routed component:\n * ```ts\n * data = inject(ROUTER_OUTLET_DATA) as Signal<{name: string}>;\n * ```\n *\n * @publicApi\n */\nconst ROUTER_OUTLET_DATA = /*#__PURE__*/new InjectionToken(ngDevMode ? 'RouterOutlet data' : '');\n/**\n * @description\n *\n * Acts as a placeholder that Angular dynamically fills based on the current router state.\n *\n * Each outlet can have a unique name, determined by the optional `name` attribute.\n * The name cannot be set or changed dynamically. If not set, default value is \"primary\".\n *\n * ```html\n * <router-outlet></router-outlet>\n * <router-outlet name='left'></router-outlet>\n * <router-outlet name='right'></router-outlet>\n * ```\n *\n * Named outlets can be the targets of secondary routes.\n * The `Route` object for a secondary route has an `outlet` property to identify the target outlet:\n *\n * `{path: <base-path>, component: <component>, outlet: <target_outlet_name>}`\n *\n * Using named outlets and secondary routes, you can target multiple outlets in\n * the same `RouterLink` directive.\n *\n * The router keeps track of separate branches in a navigation tree for each named outlet and\n * generates a representation of that tree in the URL.\n * The URL for a secondary route uses the following syntax to specify both the primary and secondary\n * routes at the same time:\n *\n * `http://base-path/primary-route-path(outlet-name:route-path)`\n *\n * A router outlet emits an activate event when a new component is instantiated,\n * deactivate event when a component is destroyed.\n * An attached event emits when the `RouteReuseStrategy` instructs the outlet to reattach the\n * subtree, and the detached event emits when the `RouteReuseStrategy` instructs the outlet to\n * detach the subtree.\n *\n * ```html\n * <router-outlet\n *   (activate)='onActivate($event)'\n *   (deactivate)='onDeactivate($event)'\n *   (attach)='onAttach($event)'\n *   (detach)='onDetach($event)'></router-outlet>\n * ```\n *\n * @see {@link RouterLink}\n * @see {@link Route}\n * @ngModule RouterModule\n *\n * @publicApi\n */\nlet RouterOutlet = /*#__PURE__*/(() => {\n  class RouterOutlet {\n    activated = null;\n    /** @internal */\n    get activatedComponentRef() {\n      return this.activated;\n    }\n    _activatedRoute = null;\n    /**\n     * The name of the outlet\n     *\n     */\n    name = PRIMARY_OUTLET;\n    activateEvents = new EventEmitter();\n    deactivateEvents = new EventEmitter();\n    /**\n     * Emits an attached component instance when the `RouteReuseStrategy` instructs to re-attach a\n     * previously detached subtree.\n     **/\n    attachEvents = new EventEmitter();\n    /**\n     * Emits a detached component instance when the `RouteReuseStrategy` instructs to detach the\n     * subtree.\n     */\n    detachEvents = new EventEmitter();\n    /**\n     * Data that will be provided to the child injector through the `ROUTER_OUTLET_DATA` token.\n     *\n     * When unset, the value of the token is `undefined` by default.\n     */\n    routerOutletData = input(undefined);\n    parentContexts = inject(ChildrenOutletContexts);\n    location = inject(ViewContainerRef);\n    changeDetector = inject(ChangeDetectorRef);\n    inputBinder = inject(INPUT_BINDER, {\n      optional: true\n    });\n    /** @docs-private */\n    supportsBindingToComponentInputs = true;\n    /** @docs-private */\n    ngOnChanges(changes) {\n      if (changes['name']) {\n        const {\n          firstChange,\n          previousValue\n        } = changes['name'];\n        if (firstChange) {\n          // The first change is handled by ngOnInit. Because ngOnChanges doesn't get called when no\n          // input is set at all, we need to centrally handle the first change there.\n          return;\n        }\n        // unregister with the old name\n        if (this.isTrackedInParentContexts(previousValue)) {\n          this.deactivate();\n          this.parentContexts.onChildOutletDestroyed(previousValue);\n        }\n        // register the new name\n        this.initializeOutletWithName();\n      }\n    }\n    /** @docs-private */\n    ngOnDestroy() {\n      // Ensure that the registered outlet is this one before removing it on the context.\n      if (this.isTrackedInParentContexts(this.name)) {\n        this.parentContexts.onChildOutletDestroyed(this.name);\n      }\n      this.inputBinder?.unsubscribeFromRouteData(this);\n    }\n    isTrackedInParentContexts(outletName) {\n      return this.parentContexts.getContext(outletName)?.outlet === this;\n    }\n    /** @docs-private */\n    ngOnInit() {\n      this.initializeOutletWithName();\n    }\n    initializeOutletWithName() {\n      this.parentContexts.onChildOutletCreated(this.name, this);\n      if (this.activated) {\n        return;\n      }\n      // If the outlet was not instantiated at the time the route got activated we need to populate\n      // the outlet when it is initialized (ie inside a NgIf)\n      const context = this.parentContexts.getContext(this.name);\n      if (context?.route) {\n        if (context.attachRef) {\n          // `attachRef` is populated when there is an existing component to mount\n          this.attach(context.attachRef, context.route);\n        } else {\n          // otherwise the component defined in the configuration is created\n          this.activateWith(context.route, context.injector);\n        }\n      }\n    }\n    get isActivated() {\n      return !!this.activated;\n    }\n    /**\n     * @returns The currently activated component instance.\n     * @throws An error if the outlet is not activated.\n     */\n    get component() {\n      if (!this.activated) throw new _RuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Outlet is not activated');\n      return this.activated.instance;\n    }\n    get activatedRoute() {\n      if (!this.activated) throw new _RuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Outlet is not activated');\n      return this._activatedRoute;\n    }\n    get activatedRouteData() {\n      if (this._activatedRoute) {\n        return this._activatedRoute.snapshot.data;\n      }\n      return {};\n    }\n    /**\n     * Called when the `RouteReuseStrategy` instructs to detach the subtree\n     */\n    detach() {\n      if (!this.activated) throw new _RuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Outlet is not activated');\n      this.location.detach();\n      const cmp = this.activated;\n      this.activated = null;\n      this._activatedRoute = null;\n      this.detachEvents.emit(cmp.instance);\n      return cmp;\n    }\n    /**\n     * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree\n     */\n    attach(ref, activatedRoute) {\n      this.activated = ref;\n      this._activatedRoute = activatedRoute;\n      this.location.insert(ref.hostView);\n      this.inputBinder?.bindActivatedRouteToOutletComponent(this);\n      this.attachEvents.emit(ref.instance);\n    }\n    deactivate() {\n      if (this.activated) {\n        const c = this.component;\n        this.activated.destroy();\n        this.activated = null;\n        this._activatedRoute = null;\n        this.deactivateEvents.emit(c);\n      }\n    }\n    activateWith(activatedRoute, environmentInjector) {\n      if (this.isActivated) {\n        throw new _RuntimeError(4013 /* RuntimeErrorCode.OUTLET_ALREADY_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Cannot activate an already activated outlet');\n      }\n      this._activatedRoute = activatedRoute;\n      const location = this.location;\n      const snapshot = activatedRoute.snapshot;\n      const component = snapshot.component;\n      const childContexts = this.parentContexts.getOrCreateContext(this.name).children;\n      const injector = new OutletInjector(activatedRoute, childContexts, location.injector, this.routerOutletData);\n      this.activated = location.createComponent(component, {\n        index: location.length,\n        injector,\n        environmentInjector: environmentInjector\n      });\n      // Calling `markForCheck` to make sure we will run the change detection when the\n      // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.\n      this.changeDetector.markForCheck();\n      this.inputBinder?.bindActivatedRouteToOutletComponent(this);\n      this.activateEvents.emit(this.activated.instance);\n    }\n    static ɵfac = function RouterOutlet_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || RouterOutlet)();\n    };\n    static ɵdir = /* @__PURE__ */i0.ɵɵdefineDirective({\n      type: RouterOutlet,\n      selectors: [[\"router-outlet\"]],\n      inputs: {\n        name: \"name\",\n        routerOutletData: [1, \"routerOutletData\"]\n      },\n      outputs: {\n        activateEvents: \"activate\",\n        deactivateEvents: \"deactivate\",\n        attachEvents: \"attach\",\n        detachEvents: \"detach\"\n      },\n      exportAs: [\"outlet\"],\n      features: [i0.ɵɵNgOnChangesFeature]\n    });\n  }\n  return RouterOutlet;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nclass OutletInjector {\n  route;\n  childContexts;\n  parent;\n  outletData;\n  constructor(route, childContexts, parent, outletData) {\n    this.route = route;\n    this.childContexts = childContexts;\n    this.parent = parent;\n    this.outletData = outletData;\n  }\n  get(token, notFoundValue) {\n    if (token === ActivatedRoute) {\n      return this.route;\n    }\n    if (token === ChildrenOutletContexts) {\n      return this.childContexts;\n    }\n    if (token === ROUTER_OUTLET_DATA) {\n      return this.outletData;\n    }\n    return this.parent.get(token, notFoundValue);\n  }\n}\nconst INPUT_BINDER = /*#__PURE__*/new InjectionToken('');\n/**\n * Injectable used as a tree-shakable provider for opting in to binding router data to component\n * inputs.\n *\n * The RouterOutlet registers itself with this service when an `ActivatedRoute` is attached or\n * activated. When this happens, the service subscribes to the `ActivatedRoute` observables (params,\n * queryParams, data) and sets the inputs of the component using `ComponentRef.setInput`.\n * Importantly, when an input does not have an item in the route data with a matching key, this\n * input is set to `undefined`. If it were not done this way, the previous information would be\n * retained if the data got removed from the route (i.e. if a query parameter is removed).\n *\n * The `RouterOutlet` should unregister itself when destroyed via `unsubscribeFromRouteData` so that\n * the subscriptions are cleaned up.\n */\nlet RoutedComponentInputBinder = /*#__PURE__*/(() => {\n  class RoutedComponentInputBinder {\n    outletDataSubscriptions = new Map();\n    bindActivatedRouteToOutletComponent(outlet) {\n      this.unsubscribeFromRouteData(outlet);\n      this.subscribeToRouteData(outlet);\n    }\n    unsubscribeFromRouteData(outlet) {\n      this.outletDataSubscriptions.get(outlet)?.unsubscribe();\n      this.outletDataSubscriptions.delete(outlet);\n    }\n    subscribeToRouteData(outlet) {\n      const {\n        activatedRoute\n      } = outlet;\n      const dataSubscription = combineLatest([activatedRoute.queryParams, activatedRoute.params, activatedRoute.data]).pipe(switchMap(([queryParams, params, data], index) => {\n        data = {\n          ...queryParams,\n          ...params,\n          ...data\n        };\n        // Get the first result from the data subscription synchronously so it's available to\n        // the component as soon as possible (and doesn't require a second change detection).\n        if (index === 0) {\n          return of(data);\n        }\n        // Promise.resolve is used to avoid synchronously writing the wrong data when\n        // two of the Observables in the `combineLatest` stream emit one after\n        // another.\n        return Promise.resolve(data);\n      })).subscribe(data => {\n        // Outlet may have been deactivated or changed names to be associated with a different\n        // route\n        if (!outlet.isActivated || !outlet.activatedComponentRef || outlet.activatedRoute !== activatedRoute || activatedRoute.component === null) {\n          this.unsubscribeFromRouteData(outlet);\n          return;\n        }\n        const mirror = reflectComponentType(activatedRoute.component);\n        if (!mirror) {\n          this.unsubscribeFromRouteData(outlet);\n          return;\n        }\n        for (const {\n          templateName\n        } of mirror.inputs) {\n          outlet.activatedComponentRef.setInput(templateName, data[templateName]);\n        }\n      });\n      this.outletDataSubscriptions.set(outlet, dataSubscription);\n    }\n    static ɵfac = function RoutedComponentInputBinder_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || RoutedComponentInputBinder)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: RoutedComponentInputBinder,\n      factory: RoutedComponentInputBinder.ɵfac\n    });\n  }\n  return RoutedComponentInputBinder;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n\n/**\n * This component is used internally within the router to be a placeholder when an empty\n * router-outlet is needed. For example, with a config such as:\n *\n * `{path: 'parent', outlet: 'nav', children: [...]}`\n *\n * In order to render, there needs to be a component on this config, which will default\n * to this `EmptyOutletComponent`.\n */\nlet ɵEmptyOutletComponent = /*#__PURE__*/(() => {\n  class ɵEmptyOutletComponent {\n    static ɵfac = function ɵEmptyOutletComponent_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || ɵEmptyOutletComponent)();\n    };\n    static ɵcmp = /* @__PURE__ */i0.ɵɵdefineComponent({\n      type: ɵEmptyOutletComponent,\n      selectors: [[\"ng-component\"]],\n      exportAs: [\"emptyRouterOutlet\"],\n      decls: 1,\n      vars: 0,\n      template: function _EmptyOutletComponent_Template(rf, ctx) {\n        if (rf & 1) {\n          i0.ɵɵelement(0, \"router-outlet\");\n        }\n      },\n      dependencies: [RouterOutlet],\n      encapsulation: 2\n    });\n  }\n  return ɵEmptyOutletComponent;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n/**\n * Makes a copy of the config and adds any default required properties.\n */\nfunction standardizeConfig(r) {\n  const children = r.children && r.children.map(standardizeConfig);\n  const c = children ? {\n    ...r,\n    children\n  } : {\n    ...r\n  };\n  if (!c.component && !c.loadComponent && (children || c.loadChildren) && c.outlet && c.outlet !== PRIMARY_OUTLET) {\n    c.component = ɵEmptyOutletComponent;\n  }\n  return c;\n}\nfunction createRouterState(routeReuseStrategy, curr, prevState) {\n  const root = createNode(routeReuseStrategy, curr._root, prevState ? prevState._root : undefined);\n  return new RouterState(root, curr);\n}\nfunction createNode(routeReuseStrategy, curr, prevState) {\n  // reuse an activated route that is currently displayed on the screen\n  if (prevState && routeReuseStrategy.shouldReuseRoute(curr.value, prevState.value.snapshot)) {\n    const value = prevState.value;\n    value._futureSnapshot = curr.value;\n    const children = createOrReuseChildren(routeReuseStrategy, curr, prevState);\n    return new TreeNode(value, children);\n  } else {\n    if (routeReuseStrategy.shouldAttach(curr.value)) {\n      // retrieve an activated route that is used to be displayed, but is not currently displayed\n      const detachedRouteHandle = routeReuseStrategy.retrieve(curr.value);\n      if (detachedRouteHandle !== null) {\n        const tree = detachedRouteHandle.route;\n        tree.value._futureSnapshot = curr.value;\n        tree.children = curr.children.map(c => createNode(routeReuseStrategy, c));\n        return tree;\n      }\n    }\n    const value = createActivatedRoute(curr.value);\n    const children = curr.children.map(c => createNode(routeReuseStrategy, c));\n    return new TreeNode(value, children);\n  }\n}\nfunction createOrReuseChildren(routeReuseStrategy, curr, prevState) {\n  return curr.children.map(child => {\n    for (const p of prevState.children) {\n      if (routeReuseStrategy.shouldReuseRoute(child.value, p.value.snapshot)) {\n        return createNode(routeReuseStrategy, child, p);\n      }\n    }\n    return createNode(routeReuseStrategy, child);\n  });\n}\nfunction createActivatedRoute(c) {\n  return new ActivatedRoute(new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams), new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);\n}\n\n/**\n * Can be returned by a `Router` guard to instruct the `Router` to redirect rather than continue\n * processing the path of the in-flight navigation. The `redirectTo` indicates _where_ the new\n * navigation should go to and the optional `navigationBehaviorOptions` can provide more information\n * about _how_ to perform the navigation.\n *\n * ```ts\n * const route: Route = {\n *   path: \"user/:userId\",\n *   component: User,\n *   canActivate: [\n *     () => {\n *       const router = inject(Router);\n *       const authService = inject(AuthenticationService);\n *\n *       if (!authService.isLoggedIn()) {\n *         const loginPath = router.parseUrl(\"/login\");\n *         return new RedirectCommand(loginPath, {\n *           skipLocationChange: \"true\",\n *         });\n *       }\n *\n *       return true;\n *     },\n *   ],\n * };\n * ```\n * @see [Routing guide](guide/routing/common-router-tasks#preventing-unauthorized-access)\n *\n * @publicApi\n */\nclass RedirectCommand {\n  redirectTo;\n  navigationBehaviorOptions;\n  constructor(redirectTo, navigationBehaviorOptions) {\n    this.redirectTo = redirectTo;\n    this.navigationBehaviorOptions = navigationBehaviorOptions;\n  }\n}\nconst NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';\nfunction redirectingNavigationError(urlSerializer, redirect) {\n  const {\n    redirectTo,\n    navigationBehaviorOptions\n  } = isUrlTree(redirect) ? {\n    redirectTo: redirect,\n    navigationBehaviorOptions: undefined\n  } : redirect;\n  const error = navigationCancelingError(ngDevMode && `Redirecting to \"${urlSerializer.serialize(redirectTo)}\"`, NavigationCancellationCode.Redirect);\n  error.url = redirectTo;\n  error.navigationBehaviorOptions = navigationBehaviorOptions;\n  return error;\n}\nfunction navigationCancelingError(message, code) {\n  const error = new Error(`NavigationCancelingError: ${message || ''}`);\n  error[NAVIGATION_CANCELING_ERROR] = true;\n  error.cancellationCode = code;\n  return error;\n}\nfunction isRedirectingNavigationCancelingError(error) {\n  return isNavigationCancelingError(error) && isUrlTree(error.url);\n}\nfunction isNavigationCancelingError(error) {\n  return !!error && error[NAVIGATION_CANCELING_ERROR];\n}\nlet warnedAboutUnsupportedInputBinding = false;\nconst activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent, inputBindingEnabled) => map(t => {\n  new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent, inputBindingEnabled).activate(rootContexts);\n  return t;\n});\nclass ActivateRoutes {\n  routeReuseStrategy;\n  futureState;\n  currState;\n  forwardEvent;\n  inputBindingEnabled;\n  constructor(routeReuseStrategy, futureState, currState, forwardEvent, inputBindingEnabled) {\n    this.routeReuseStrategy = routeReuseStrategy;\n    this.futureState = futureState;\n    this.currState = currState;\n    this.forwardEvent = forwardEvent;\n    this.inputBindingEnabled = inputBindingEnabled;\n  }\n  activate(parentContexts) {\n    const futureRoot = this.futureState._root;\n    const currRoot = this.currState ? this.currState._root : null;\n    this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);\n    advanceActivatedRoute(this.futureState.root);\n    this.activateChildRoutes(futureRoot, currRoot, parentContexts);\n  }\n  // De-activate the child route that are not re-used for the future state\n  deactivateChildRoutes(futureNode, currNode, contexts) {\n    const children = nodeChildrenAsMap(currNode);\n    // Recurse on the routes active in the future state to de-activate deeper children\n    futureNode.children.forEach(futureChild => {\n      const childOutletName = futureChild.value.outlet;\n      this.deactivateRoutes(futureChild, children[childOutletName], contexts);\n      delete children[childOutletName];\n    });\n    // De-activate the routes that will not be re-used\n    Object.values(children).forEach(v => {\n      this.deactivateRouteAndItsChildren(v, contexts);\n    });\n  }\n  deactivateRoutes(futureNode, currNode, parentContext) {\n    const future = futureNode.value;\n    const curr = currNode ? currNode.value : null;\n    if (future === curr) {\n      // Reusing the node, check to see if the children need to be de-activated\n      if (future.component) {\n        // If we have a normal route, we need to go through an outlet.\n        const context = parentContext.getContext(future.outlet);\n        if (context) {\n          this.deactivateChildRoutes(futureNode, currNode, context.children);\n        }\n      } else {\n        // if we have a componentless route, we recurse but keep the same outlet map.\n        this.deactivateChildRoutes(futureNode, currNode, parentContext);\n      }\n    } else {\n      if (curr) {\n        // Deactivate the current route which will not be re-used\n        this.deactivateRouteAndItsChildren(currNode, parentContext);\n      }\n    }\n  }\n  deactivateRouteAndItsChildren(route, parentContexts) {\n    // If there is no component, the Route is never attached to an outlet (because there is no\n    // component to attach).\n    if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {\n      this.detachAndStoreRouteSubtree(route, parentContexts);\n    } else {\n      this.deactivateRouteAndOutlet(route, parentContexts);\n    }\n  }\n  detachAndStoreRouteSubtree(route, parentContexts) {\n    const context = parentContexts.getContext(route.value.outlet);\n    const contexts = context && route.value.component ? context.children : parentContexts;\n    const children = nodeChildrenAsMap(route);\n    for (const treeNode of Object.values(children)) {\n      this.deactivateRouteAndItsChildren(treeNode, contexts);\n    }\n    if (context && context.outlet) {\n      const componentRef = context.outlet.detach();\n      const contexts = context.children.onOutletDeactivated();\n      this.routeReuseStrategy.store(route.value.snapshot, {\n        componentRef,\n        route,\n        contexts\n      });\n    }\n  }\n  deactivateRouteAndOutlet(route, parentContexts) {\n    const context = parentContexts.getContext(route.value.outlet);\n    // The context could be `null` if we are on a componentless route but there may still be\n    // children that need deactivating.\n    const contexts = context && route.value.component ? context.children : parentContexts;\n    const children = nodeChildrenAsMap(route);\n    for (const treeNode of Object.values(children)) {\n      this.deactivateRouteAndItsChildren(treeNode, contexts);\n    }\n    if (context) {\n      if (context.outlet) {\n        // Destroy the component\n        context.outlet.deactivate();\n        // Destroy the contexts for all the outlets that were in the component\n        context.children.onOutletDeactivated();\n      }\n      // Clear the information about the attached component on the context but keep the reference to\n      // the outlet. Clear even if outlet was not yet activated to avoid activating later with old\n      // info\n      context.attachRef = null;\n      context.route = null;\n    }\n  }\n  activateChildRoutes(futureNode, currNode, contexts) {\n    const children = nodeChildrenAsMap(currNode);\n    futureNode.children.forEach(c => {\n      this.activateRoutes(c, children[c.value.outlet], contexts);\n      this.forwardEvent(new ActivationEnd(c.value.snapshot));\n    });\n    if (futureNode.children.length) {\n      this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));\n    }\n  }\n  activateRoutes(futureNode, currNode, parentContexts) {\n    const future = futureNode.value;\n    const curr = currNode ? currNode.value : null;\n    advanceActivatedRoute(future);\n    // reusing the node\n    if (future === curr) {\n      if (future.component) {\n        // If we have a normal route, we need to go through an outlet.\n        const context = parentContexts.getOrCreateContext(future.outlet);\n        this.activateChildRoutes(futureNode, currNode, context.children);\n      } else {\n        // if we have a componentless route, we recurse but keep the same outlet map.\n        this.activateChildRoutes(futureNode, currNode, parentContexts);\n      }\n    } else {\n      if (future.component) {\n        // if we have a normal route, we need to place the component into the outlet and recurse.\n        const context = parentContexts.getOrCreateContext(future.outlet);\n        if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {\n          const stored = this.routeReuseStrategy.retrieve(future.snapshot);\n          this.routeReuseStrategy.store(future.snapshot, null);\n          context.children.onOutletReAttached(stored.contexts);\n          context.attachRef = stored.componentRef;\n          context.route = stored.route.value;\n          if (context.outlet) {\n            // Attach right away when the outlet has already been instantiated\n            // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated\n            context.outlet.attach(stored.componentRef, stored.route.value);\n          }\n          advanceActivatedRoute(stored.route.value);\n          this.activateChildRoutes(futureNode, null, context.children);\n        } else {\n          context.attachRef = null;\n          context.route = future;\n          if (context.outlet) {\n            // Activate the outlet when it has already been instantiated\n            // Otherwise it will get activated from its `ngOnInit` when instantiated\n            context.outlet.activateWith(future, context.injector);\n          }\n          this.activateChildRoutes(futureNode, null, context.children);\n        }\n      } else {\n        // if we have a componentless route, we recurse but keep the same outlet map.\n        this.activateChildRoutes(futureNode, null, parentContexts);\n      }\n    }\n    if (typeof ngDevMode === 'undefined' || ngDevMode) {\n      const context = parentContexts.getOrCreateContext(future.outlet);\n      const outlet = context.outlet;\n      if (outlet && this.inputBindingEnabled && !outlet.supportsBindingToComponentInputs && !warnedAboutUnsupportedInputBinding) {\n        console.warn(`'withComponentInputBinding' feature is enabled but ` + `this application is using an outlet that may not support binding to component inputs.`);\n        warnedAboutUnsupportedInputBinding = true;\n      }\n    }\n  }\n}\nclass CanActivate {\n  path;\n  route;\n  constructor(path) {\n    this.path = path;\n    this.route = this.path[this.path.length - 1];\n  }\n}\nclass CanDeactivate {\n  component;\n  route;\n  constructor(component, route) {\n    this.component = component;\n    this.route = route;\n  }\n}\nfunction getAllRouteGuards(future, curr, parentContexts) {\n  const futureRoot = future._root;\n  const currRoot = curr ? curr._root : null;\n  return getChildRouteGuards(futureRoot, currRoot, parentContexts, [futureRoot.value]);\n}\nfunction getCanActivateChild(p) {\n  const canActivateChild = p.routeConfig ? p.routeConfig.canActivateChild : null;\n  if (!canActivateChild || canActivateChild.length === 0) return null;\n  return {\n    node: p,\n    guards: canActivateChild\n  };\n}\nfunction getTokenOrFunctionIdentity(tokenOrFunction, injector) {\n  const NOT_FOUND = Symbol();\n  const result = injector.get(tokenOrFunction, NOT_FOUND);\n  if (result === NOT_FOUND) {\n    if (typeof tokenOrFunction === 'function' && !_isInjectable(tokenOrFunction)) {\n      // We think the token is just a function so return it as-is\n      return tokenOrFunction;\n    } else {\n      // This will throw the not found error\n      return injector.get(tokenOrFunction);\n    }\n  }\n  return result;\n}\nfunction getChildRouteGuards(futureNode, currNode, contexts, futurePath, checks = {\n  canDeactivateChecks: [],\n  canActivateChecks: []\n}) {\n  const prevChildren = nodeChildrenAsMap(currNode);\n  // Process the children of the future route\n  futureNode.children.forEach(c => {\n    getRouteGuards(c, prevChildren[c.value.outlet], contexts, futurePath.concat([c.value]), checks);\n    delete prevChildren[c.value.outlet];\n  });\n  // Process any children left from the current route (not active for the future route)\n  Object.entries(prevChildren).forEach(([k, v]) => deactivateRouteAndItsChildren(v, contexts.getContext(k), checks));\n  return checks;\n}\nfunction getRouteGuards(futureNode, currNode, parentContexts, futurePath, checks = {\n  canDeactivateChecks: [],\n  canActivateChecks: []\n}) {\n  const future = futureNode.value;\n  const curr = currNode ? currNode.value : null;\n  const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null;\n  // reusing the node\n  if (curr && future.routeConfig === curr.routeConfig) {\n    const shouldRun = shouldRunGuardsAndResolvers(curr, future, future.routeConfig.runGuardsAndResolvers);\n    if (shouldRun) {\n      checks.canActivateChecks.push(new CanActivate(futurePath));\n    } else {\n      // we need to set the data\n      future.data = curr.data;\n      future._resolvedData = curr._resolvedData;\n    }\n    // If we have a component, we need to go through an outlet.\n    if (future.component) {\n      getChildRouteGuards(futureNode, currNode, context ? context.children : null, futurePath, checks);\n      // if we have a componentless route, we recurse but keep the same outlet map.\n    } else {\n      getChildRouteGuards(futureNode, currNode, parentContexts, futurePath, checks);\n    }\n    if (shouldRun && context && context.outlet && context.outlet.isActivated) {\n      checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, curr));\n    }\n  } else {\n    if (curr) {\n      deactivateRouteAndItsChildren(currNode, context, checks);\n    }\n    checks.canActivateChecks.push(new CanActivate(futurePath));\n    // If we have a component, we need to go through an outlet.\n    if (future.component) {\n      getChildRouteGuards(futureNode, null, context ? context.children : null, futurePath, checks);\n      // if we have a componentless route, we recurse but keep the same outlet map.\n    } else {\n      getChildRouteGuards(futureNode, null, parentContexts, futurePath, checks);\n    }\n  }\n  return checks;\n}\nfunction shouldRunGuardsAndResolvers(curr, future, mode) {\n  if (typeof mode === 'function') {\n    return mode(curr, future);\n  }\n  switch (mode) {\n    case 'pathParamsChange':\n      return !equalPath(curr.url, future.url);\n    case 'pathParamsOrQueryParamsChange':\n      return !equalPath(curr.url, future.url) || !shallowEqual(curr.queryParams, future.queryParams);\n    case 'always':\n      return true;\n    case 'paramsOrQueryParamsChange':\n      return !equalParamsAndUrlSegments(curr, future) || !shallowEqual(curr.queryParams, future.queryParams);\n    case 'paramsChange':\n    default:\n      return !equalParamsAndUrlSegments(curr, future);\n  }\n}\nfunction deactivateRouteAndItsChildren(route, context, checks) {\n  const children = nodeChildrenAsMap(route);\n  const r = route.value;\n  Object.entries(children).forEach(([childName, node]) => {\n    if (!r.component) {\n      deactivateRouteAndItsChildren(node, context, checks);\n    } else if (context) {\n      deactivateRouteAndItsChildren(node, context.children.getContext(childName), checks);\n    } else {\n      deactivateRouteAndItsChildren(node, null, checks);\n    }\n  });\n  if (!r.component) {\n    checks.canDeactivateChecks.push(new CanDeactivate(null, r));\n  } else if (context && context.outlet && context.outlet.isActivated) {\n    checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, r));\n  } else {\n    checks.canDeactivateChecks.push(new CanDeactivate(null, r));\n  }\n}\n\n/**\n * Simple function check, but generic so type inference will flow. Example:\n *\n * function product(a: number, b: number) {\n *   return a * b;\n * }\n *\n * if (isFunction<product>(fn)) {\n *   return fn(1, 2);\n * } else {\n *   throw \"Must provide the `product` function\";\n * }\n */\nfunction isFunction(v) {\n  return typeof v === 'function';\n}\nfunction isBoolean(v) {\n  return typeof v === 'boolean';\n}\nfunction isCanLoad(guard) {\n  return guard && isFunction(guard.canLoad);\n}\nfunction isCanActivate(guard) {\n  return guard && isFunction(guard.canActivate);\n}\nfunction isCanActivateChild(guard) {\n  return guard && isFunction(guard.canActivateChild);\n}\nfunction isCanDeactivate(guard) {\n  return guard && isFunction(guard.canDeactivate);\n}\nfunction isCanMatch(guard) {\n  return guard && isFunction(guard.canMatch);\n}\nfunction isEmptyError(e) {\n  return e instanceof EmptyError || e?.name === 'EmptyError';\n}\nconst INITIAL_VALUE = /* @__PURE__ */Symbol('INITIAL_VALUE');\nfunction prioritizedGuardValue() {\n  return switchMap(obs => {\n    return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE)))).pipe(map(results => {\n      for (const result of results) {\n        if (result === true) {\n          // If result is true, check the next one\n          continue;\n        } else if (result === INITIAL_VALUE) {\n          // If guard has not finished, we need to stop processing.\n          return INITIAL_VALUE;\n        } else if (result === false || isRedirect(result)) {\n          // Result finished and was not true. Return the result.\n          // Note that we only allow false/UrlTree/RedirectCommand. Other values are considered invalid and\n          // ignored.\n          return result;\n        }\n      }\n      // Everything resolved to true. Return true.\n      return true;\n    }), filter(item => item !== INITIAL_VALUE), take(1));\n  });\n}\nfunction isRedirect(val) {\n  return isUrlTree(val) || val instanceof RedirectCommand;\n}\nfunction checkGuards(injector, forwardEvent) {\n  return mergeMap(t => {\n    const {\n      targetSnapshot,\n      currentSnapshot,\n      guards: {\n        canActivateChecks,\n        canDeactivateChecks\n      }\n    } = t;\n    if (canDeactivateChecks.length === 0 && canActivateChecks.length === 0) {\n      return of({\n        ...t,\n        guardsResult: true\n      });\n    }\n    return runCanDeactivateChecks(canDeactivateChecks, targetSnapshot, currentSnapshot, injector).pipe(mergeMap(canDeactivate => {\n      return canDeactivate && isBoolean(canDeactivate) ? runCanActivateChecks(targetSnapshot, canActivateChecks, injector, forwardEvent) : of(canDeactivate);\n    }), map(guardsResult => ({\n      ...t,\n      guardsResult\n    })));\n  });\n}\nfunction runCanDeactivateChecks(checks, futureRSS, currRSS, injector) {\n  return from(checks).pipe(mergeMap(check => runCanDeactivate(check.component, check.route, currRSS, futureRSS, injector)), first(result => {\n    return result !== true;\n  }, true));\n}\nfunction runCanActivateChecks(futureSnapshot, checks, injector, forwardEvent) {\n  return from(checks).pipe(concatMap(check => {\n    return concat(fireChildActivationStart(check.route.parent, forwardEvent), fireActivationStart(check.route, forwardEvent), runCanActivateChild(futureSnapshot, check.path, injector), runCanActivate(futureSnapshot, check.route, injector));\n  }), first(result => {\n    return result !== true;\n  }, true));\n}\n/**\n * This should fire off `ActivationStart` events for each route being activated at this\n * level.\n * In other words, if you're activating `a` and `b` below, `path` will contain the\n * `ActivatedRouteSnapshot`s for both and we will fire `ActivationStart` for both. Always\n * return\n * `true` so checks continue to run.\n */\nfunction fireActivationStart(snapshot, forwardEvent) {\n  if (snapshot !== null && forwardEvent) {\n    forwardEvent(new ActivationStart(snapshot));\n  }\n  return of(true);\n}\n/**\n * This should fire off `ChildActivationStart` events for each route being activated at this\n * level.\n * In other words, if you're activating `a` and `b` below, `path` will contain the\n * `ActivatedRouteSnapshot`s for both and we will fire `ChildActivationStart` for both. Always\n * return\n * `true` so checks continue to run.\n */\nfunction fireChildActivationStart(snapshot, forwardEvent) {\n  if (snapshot !== null && forwardEvent) {\n    forwardEvent(new ChildActivationStart(snapshot));\n  }\n  return of(true);\n}\nfunction runCanActivate(futureRSS, futureARS, injector) {\n  const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;\n  if (!canActivate || canActivate.length === 0) return of(true);\n  const canActivateObservables = canActivate.map(canActivate => {\n    return defer(() => {\n      const closestInjector = getClosestRouteInjector(futureARS) ?? injector;\n      const guard = getTokenOrFunctionIdentity(canActivate, closestInjector);\n      const guardVal = isCanActivate(guard) ? guard.canActivate(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => guard(futureARS, futureRSS));\n      return wrapIntoObservable(guardVal).pipe(first());\n    });\n  });\n  return of(canActivateObservables).pipe(prioritizedGuardValue());\n}\nfunction runCanActivateChild(futureRSS, path, injector) {\n  const futureARS = path[path.length - 1];\n  const canActivateChildGuards = path.slice(0, path.length - 1).reverse().map(p => getCanActivateChild(p)).filter(_ => _ !== null);\n  const canActivateChildGuardsMapped = canActivateChildGuards.map(d => {\n    return defer(() => {\n      const guardsMapped = d.guards.map(canActivateChild => {\n        const closestInjector = getClosestRouteInjector(d.node) ?? injector;\n        const guard = getTokenOrFunctionIdentity(canActivateChild, closestInjector);\n        const guardVal = isCanActivateChild(guard) ? guard.canActivateChild(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => guard(futureARS, futureRSS));\n        return wrapIntoObservable(guardVal).pipe(first());\n      });\n      return of(guardsMapped).pipe(prioritizedGuardValue());\n    });\n  });\n  return of(canActivateChildGuardsMapped).pipe(prioritizedGuardValue());\n}\nfunction runCanDeactivate(component, currARS, currRSS, futureRSS, injector) {\n  const canDeactivate = currARS && currARS.routeConfig ? currARS.routeConfig.canDeactivate : null;\n  if (!canDeactivate || canDeactivate.length === 0) return of(true);\n  const canDeactivateObservables = canDeactivate.map(c => {\n    const closestInjector = getClosestRouteInjector(currARS) ?? injector;\n    const guard = getTokenOrFunctionIdentity(c, closestInjector);\n    const guardVal = isCanDeactivate(guard) ? guard.canDeactivate(component, currARS, currRSS, futureRSS) : runInInjectionContext(closestInjector, () => guard(component, currARS, currRSS, futureRSS));\n    return wrapIntoObservable(guardVal).pipe(first());\n  });\n  return of(canDeactivateObservables).pipe(prioritizedGuardValue());\n}\nfunction runCanLoadGuards(injector, route, segments, urlSerializer) {\n  const canLoad = route.canLoad;\n  if (canLoad === undefined || canLoad.length === 0) {\n    return of(true);\n  }\n  const canLoadObservables = canLoad.map(injectionToken => {\n    const guard = getTokenOrFunctionIdentity(injectionToken, injector);\n    const guardVal = isCanLoad(guard) ? guard.canLoad(route, segments) : runInInjectionContext(injector, () => guard(route, segments));\n    return wrapIntoObservable(guardVal);\n  });\n  return of(canLoadObservables).pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));\n}\nfunction redirectIfUrlTree(urlSerializer) {\n  return pipe(tap(result => {\n    if (typeof result === 'boolean') return;\n    throw redirectingNavigationError(urlSerializer, result);\n  }), map(result => result === true));\n}\nfunction runCanMatchGuards(injector, route, segments, urlSerializer) {\n  const canMatch = route.canMatch;\n  if (!canMatch || canMatch.length === 0) return of(true);\n  const canMatchObservables = canMatch.map(injectionToken => {\n    const guard = getTokenOrFunctionIdentity(injectionToken, injector);\n    const guardVal = isCanMatch(guard) ? guard.canMatch(route, segments) : runInInjectionContext(injector, () => guard(route, segments));\n    return wrapIntoObservable(guardVal);\n  });\n  return of(canMatchObservables).pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));\n}\nclass NoMatch {\n  segmentGroup;\n  constructor(segmentGroup) {\n    this.segmentGroup = segmentGroup || null;\n  }\n}\nclass AbsoluteRedirect extends Error {\n  urlTree;\n  constructor(urlTree) {\n    super();\n    this.urlTree = urlTree;\n  }\n}\nfunction noMatch$1(segmentGroup) {\n  return throwError(new NoMatch(segmentGroup));\n}\nfunction namedOutletsRedirect(redirectTo) {\n  return throwError(new _RuntimeError(4000 /* RuntimeErrorCode.NAMED_OUTLET_REDIRECT */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Only absolute redirects can have named outlets. redirectTo: '${redirectTo}'`));\n}\nfunction canLoadFails(route) {\n  return throwError(navigationCancelingError((typeof ngDevMode === 'undefined' || ngDevMode) && `Cannot load children because the guard of the route \"path: '${route.path}'\" returned false`, NavigationCancellationCode.GuardRejected));\n}\nclass ApplyRedirects {\n  urlSerializer;\n  urlTree;\n  constructor(urlSerializer, urlTree) {\n    this.urlSerializer = urlSerializer;\n    this.urlTree = urlTree;\n  }\n  lineralizeSegments(route, urlTree) {\n    let res = [];\n    let c = urlTree.root;\n    while (true) {\n      res = res.concat(c.segments);\n      if (c.numberOfChildren === 0) {\n        return of(res);\n      }\n      if (c.numberOfChildren > 1 || !c.children[PRIMARY_OUTLET]) {\n        return namedOutletsRedirect(`${route.redirectTo}`);\n      }\n      c = c.children[PRIMARY_OUTLET];\n    }\n  }\n  applyRedirectCommands(segments, redirectTo, posParams, currentSnapshot, injector) {\n    if (typeof redirectTo !== 'string') {\n      const redirectToFn = redirectTo;\n      const {\n        queryParams,\n        fragment,\n        routeConfig,\n        url,\n        outlet,\n        params,\n        data,\n        title\n      } = currentSnapshot;\n      const newRedirect = runInInjectionContext(injector, () => redirectToFn({\n        params,\n        data,\n        queryParams,\n        fragment,\n        routeConfig,\n        url,\n        outlet,\n        title\n      }));\n      if (newRedirect instanceof UrlTree) {\n        throw new AbsoluteRedirect(newRedirect);\n      }\n      redirectTo = newRedirect;\n    }\n    const newTree = this.applyRedirectCreateUrlTree(redirectTo, this.urlSerializer.parse(redirectTo), segments, posParams);\n    if (redirectTo[0] === '/') {\n      throw new AbsoluteRedirect(newTree);\n    }\n    return newTree;\n  }\n  applyRedirectCreateUrlTree(redirectTo, urlTree, segments, posParams) {\n    const newRoot = this.createSegmentGroup(redirectTo, urlTree.root, segments, posParams);\n    return new UrlTree(newRoot, this.createQueryParams(urlTree.queryParams, this.urlTree.queryParams), urlTree.fragment);\n  }\n  createQueryParams(redirectToParams, actualParams) {\n    const res = {};\n    Object.entries(redirectToParams).forEach(([k, v]) => {\n      const copySourceValue = typeof v === 'string' && v[0] === ':';\n      if (copySourceValue) {\n        const sourceName = v.substring(1);\n        res[k] = actualParams[sourceName];\n      } else {\n        res[k] = v;\n      }\n    });\n    return res;\n  }\n  createSegmentGroup(redirectTo, group, segments, posParams) {\n    const updatedSegments = this.createSegments(redirectTo, group.segments, segments, posParams);\n    let children = {};\n    Object.entries(group.children).forEach(([name, child]) => {\n      children[name] = this.createSegmentGroup(redirectTo, child, segments, posParams);\n    });\n    return new UrlSegmentGroup(updatedSegments, children);\n  }\n  createSegments(redirectTo, redirectToSegments, actualSegments, posParams) {\n    return redirectToSegments.map(s => s.path[0] === ':' ? this.findPosParam(redirectTo, s, posParams) : this.findOrReturn(s, actualSegments));\n  }\n  findPosParam(redirectTo, redirectToUrlSegment, posParams) {\n    const pos = posParams[redirectToUrlSegment.path.substring(1)];\n    if (!pos) throw new _RuntimeError(4001 /* RuntimeErrorCode.MISSING_REDIRECT */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Cannot redirect to '${redirectTo}'. Cannot find '${redirectToUrlSegment.path}'.`);\n    return pos;\n  }\n  findOrReturn(redirectToUrlSegment, actualSegments) {\n    let idx = 0;\n    for (const s of actualSegments) {\n      if (s.path === redirectToUrlSegment.path) {\n        actualSegments.splice(idx);\n        return s;\n      }\n      idx++;\n    }\n    return redirectToUrlSegment;\n  }\n}\nconst noMatch = {\n  matched: false,\n  consumedSegments: [],\n  remainingSegments: [],\n  parameters: {},\n  positionalParamSegments: {}\n};\nfunction matchWithChecks(segmentGroup, route, segments, injector, urlSerializer) {\n  const result = match(segmentGroup, route, segments);\n  if (!result.matched) {\n    return of(result);\n  }\n  // Only create the Route's `EnvironmentInjector` if it matches the attempted\n  // navigation\n  injector = getOrCreateRouteInjectorIfNeeded(route, injector);\n  return runCanMatchGuards(injector, route, segments, urlSerializer).pipe(map(v => v === true ? result : {\n    ...noMatch\n  }));\n}\nfunction match(segmentGroup, route, segments) {\n  if (route.path === '**') {\n    return createWildcardMatchResult(segments);\n  }\n  if (route.path === '') {\n    if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || segments.length > 0)) {\n      return {\n        ...noMatch\n      };\n    }\n    return {\n      matched: true,\n      consumedSegments: [],\n      remainingSegments: segments,\n      parameters: {},\n      positionalParamSegments: {}\n    };\n  }\n  const matcher = route.matcher || defaultUrlMatcher;\n  const res = matcher(segments, segmentGroup, route);\n  if (!res) return {\n    ...noMatch\n  };\n  const posParams = {};\n  Object.entries(res.posParams ?? {}).forEach(([k, v]) => {\n    posParams[k] = v.path;\n  });\n  const parameters = res.consumed.length > 0 ? {\n    ...posParams,\n    ...res.consumed[res.consumed.length - 1].parameters\n  } : posParams;\n  return {\n    matched: true,\n    consumedSegments: res.consumed,\n    remainingSegments: segments.slice(res.consumed.length),\n    // TODO(atscott): investigate combining parameters and positionalParamSegments\n    parameters,\n    positionalParamSegments: res.posParams ?? {}\n  };\n}\nfunction createWildcardMatchResult(segments) {\n  return {\n    matched: true,\n    parameters: segments.length > 0 ? last(segments).parameters : {},\n    consumedSegments: segments,\n    remainingSegments: [],\n    positionalParamSegments: {}\n  };\n}\nfunction split(segmentGroup, consumedSegments, slicedSegments, config) {\n  if (slicedSegments.length > 0 && containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {\n    const s = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));\n    return {\n      segmentGroup: s,\n      slicedSegments: []\n    };\n  }\n  if (slicedSegments.length === 0 && containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {\n    const s = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, slicedSegments, config, segmentGroup.children));\n    return {\n      segmentGroup: s,\n      slicedSegments\n    };\n  }\n  const s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);\n  return {\n    segmentGroup: s,\n    slicedSegments\n  };\n}\nfunction addEmptyPathsToChildrenIfNeeded(segmentGroup, slicedSegments, routes, children) {\n  const res = {};\n  for (const r of routes) {\n    if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {\n      const s = new UrlSegmentGroup([], {});\n      res[getOutlet(r)] = s;\n    }\n  }\n  return {\n    ...children,\n    ...res\n  };\n}\nfunction createChildrenForEmptyPaths(routes, primarySegment) {\n  const res = {};\n  res[PRIMARY_OUTLET] = primarySegment;\n  for (const r of routes) {\n    if (r.path === '' && getOutlet(r) !== PRIMARY_OUTLET) {\n      const s = new UrlSegmentGroup([], {});\n      res[getOutlet(r)] = s;\n    }\n  }\n  return res;\n}\nfunction containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {\n  return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET);\n}\nfunction containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {\n  return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r));\n}\nfunction emptyPathMatch(segmentGroup, slicedSegments, r) {\n  if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full') {\n    return false;\n  }\n  return r.path === '';\n}\nfunction noLeftoversInUrl(segmentGroup, segments, outlet) {\n  return segments.length === 0 && !segmentGroup.children[outlet];\n}\n\n/**\n * Class used to indicate there were no additional route config matches but that all segments of\n * the URL were consumed during matching so the route was URL matched. When this happens, we still\n * try to match child configs in case there are empty path children.\n */\nclass NoLeftoversInUrl {}\nfunction recognize$1(injector, configLoader, rootComponentType, config, urlTree, urlSerializer, paramsInheritanceStrategy = 'emptyOnly') {\n  return new Recognizer(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer).recognize();\n}\nconst MAX_ALLOWED_REDIRECTS = 31;\nclass Recognizer {\n  injector;\n  configLoader;\n  rootComponentType;\n  config;\n  urlTree;\n  paramsInheritanceStrategy;\n  urlSerializer;\n  applyRedirects;\n  absoluteRedirectCount = 0;\n  allowRedirects = true;\n  constructor(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer) {\n    this.injector = injector;\n    this.configLoader = configLoader;\n    this.rootComponentType = rootComponentType;\n    this.config = config;\n    this.urlTree = urlTree;\n    this.paramsInheritanceStrategy = paramsInheritanceStrategy;\n    this.urlSerializer = urlSerializer;\n    this.applyRedirects = new ApplyRedirects(this.urlSerializer, this.urlTree);\n  }\n  noMatchError(e) {\n    return new _RuntimeError(4002 /* RuntimeErrorCode.NO_MATCH */, typeof ngDevMode === 'undefined' || ngDevMode ? `Cannot match any routes. URL Segment: '${e.segmentGroup}'` : `'${e.segmentGroup}'`);\n  }\n  recognize() {\n    const rootSegmentGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;\n    return this.match(rootSegmentGroup).pipe(map(({\n      children,\n      rootSnapshot\n    }) => {\n      const rootNode = new TreeNode(rootSnapshot, children);\n      const routeState = new RouterStateSnapshot('', rootNode);\n      const tree = createUrlTreeFromSnapshot(rootSnapshot, [], this.urlTree.queryParams, this.urlTree.fragment);\n      // https://github.com/angular/angular/issues/47307\n      // Creating the tree stringifies the query params\n      // We don't want to do this here so reassign them to the original.\n      tree.queryParams = this.urlTree.queryParams;\n      routeState.url = this.urlSerializer.serialize(tree);\n      return {\n        state: routeState,\n        tree\n      };\n    }));\n  }\n  match(rootSegmentGroup) {\n    // Use Object.freeze to prevent readers of the Router state from modifying it outside\n    // of a navigation, resulting in the router being out of sync with the browser.\n    const rootSnapshot = new ActivatedRouteSnapshot([], Object.freeze({}), Object.freeze({\n      ...this.urlTree.queryParams\n    }), this.urlTree.fragment, Object.freeze({}), PRIMARY_OUTLET, this.rootComponentType, null, {});\n    return this.processSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET, rootSnapshot).pipe(map(children => {\n      return {\n        children,\n        rootSnapshot\n      };\n    }), catchError(e => {\n      if (e instanceof AbsoluteRedirect) {\n        this.urlTree = e.urlTree;\n        return this.match(e.urlTree.root);\n      }\n      if (e instanceof NoMatch) {\n        throw this.noMatchError(e);\n      }\n      throw e;\n    }));\n  }\n  processSegmentGroup(injector, config, segmentGroup, outlet, parentRoute) {\n    if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {\n      return this.processChildren(injector, config, segmentGroup, parentRoute);\n    }\n    return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet, true, parentRoute).pipe(map(child => child instanceof TreeNode ? [child] : []));\n  }\n  /**\n   * Matches every child outlet in the `segmentGroup` to a `Route` in the config. Returns `null` if\n   * we cannot find a match for _any_ of the children.\n   *\n   * @param config - The `Routes` to match against\n   * @param segmentGroup - The `UrlSegmentGroup` whose children need to be matched against the\n   *     config.\n   */\n  processChildren(injector, config, segmentGroup, parentRoute) {\n    // Expand outlets one at a time, starting with the primary outlet. We need to do it this way\n    // because an absolute redirect from the primary outlet takes precedence.\n    const childOutlets = [];\n    for (const child of Object.keys(segmentGroup.children)) {\n      if (child === 'primary') {\n        childOutlets.unshift(child);\n      } else {\n        childOutlets.push(child);\n      }\n    }\n    return from(childOutlets).pipe(concatMap(childOutlet => {\n      const child = segmentGroup.children[childOutlet];\n      // Sort the config so that routes with outlets that match the one being activated\n      // appear first, followed by routes for other outlets, which might match if they have\n      // an empty path.\n      const sortedConfig = sortByMatchingOutlets(config, childOutlet);\n      return this.processSegmentGroup(injector, sortedConfig, child, childOutlet, parentRoute);\n    }), scan((children, outletChildren) => {\n      children.push(...outletChildren);\n      return children;\n    }), defaultIfEmpty(null), last$1(), mergeMap(children => {\n      if (children === null) return noMatch$1(segmentGroup);\n      // Because we may have matched two outlets to the same empty path segment, we can have\n      // multiple activated results for the same outlet. We should merge the children of\n      // these results so the final return value is only one `TreeNode` per outlet.\n      const mergedChildren = mergeEmptyPathMatches(children);\n      if (typeof ngDevMode === 'undefined' || ngDevMode) {\n        // This should really never happen - we are only taking the first match for each\n        // outlet and merge the empty path matches.\n        checkOutletNameUniqueness(mergedChildren);\n      }\n      sortActivatedRouteSnapshots(mergedChildren);\n      return of(mergedChildren);\n    }));\n  }\n  processSegment(injector, routes, segmentGroup, segments, outlet, allowRedirects, parentRoute) {\n    return from(routes).pipe(concatMap(r => {\n      return this.processSegmentAgainstRoute(r._injector ?? injector, routes, r, segmentGroup, segments, outlet, allowRedirects, parentRoute).pipe(catchError(e => {\n        if (e instanceof NoMatch) {\n          return of(null);\n        }\n        throw e;\n      }));\n    }), first(x => !!x), catchError(e => {\n      if (isEmptyError(e)) {\n        if (noLeftoversInUrl(segmentGroup, segments, outlet)) {\n          return of(new NoLeftoversInUrl());\n        }\n        return noMatch$1(segmentGroup);\n      }\n      throw e;\n    }));\n  }\n  processSegmentAgainstRoute(injector, routes, route, rawSegment, segments, outlet, allowRedirects, parentRoute) {\n    // We allow matches to empty paths when the outlets differ so we can match a url like `/(b:b)` to\n    // a config like\n    // * `{path: '', children: [{path: 'b', outlet: 'b'}]}`\n    // or even\n    // * `{path: '', outlet: 'a', children: [{path: 'b', outlet: 'b'}]`\n    //\n    // The exception here is when the segment outlet is for the primary outlet. This would\n    // result in a match inside the named outlet because all children there are written as primary\n    // outlets. So we need to prevent child named outlet matches in a url like `/b` in a config like\n    // * `{path: '', outlet: 'x' children: [{path: 'b'}]}`\n    // This should only match if the url is `/(x:b)`.\n    if (getOutlet(route) !== outlet && (outlet === PRIMARY_OUTLET || !emptyPathMatch(rawSegment, segments, route))) {\n      return noMatch$1(rawSegment);\n    }\n    if (route.redirectTo === undefined) {\n      return this.matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet, parentRoute);\n    }\n    if (this.allowRedirects && allowRedirects) {\n      return this.expandSegmentAgainstRouteUsingRedirect(injector, rawSegment, routes, route, segments, outlet, parentRoute);\n    }\n    return noMatch$1(rawSegment);\n  }\n  expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet, parentRoute) {\n    const {\n      matched,\n      parameters,\n      consumedSegments,\n      positionalParamSegments,\n      remainingSegments\n    } = match(segmentGroup, route, segments);\n    if (!matched) return noMatch$1(segmentGroup);\n    // TODO(atscott): Move all of this under an if(ngDevMode) as a breaking change and allow stack\n    // size exceeded in production\n    if (typeof route.redirectTo === 'string' && route.redirectTo[0] === '/') {\n      this.absoluteRedirectCount++;\n      if (this.absoluteRedirectCount > MAX_ALLOWED_REDIRECTS) {\n        if (ngDevMode) {\n          throw new _RuntimeError(4016 /* RuntimeErrorCode.INFINITE_REDIRECT */, `Detected possible infinite redirect when redirecting from '${this.urlTree}' to '${route.redirectTo}'.\\n` + `This is currently a dev mode only error but will become a` + ` call stack size exceeded error in production in a future major version.`);\n        }\n        this.allowRedirects = false;\n      }\n    }\n    const currentSnapshot = new ActivatedRouteSnapshot(segments, parameters, Object.freeze({\n      ...this.urlTree.queryParams\n    }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));\n    const inherited = getInherited(currentSnapshot, parentRoute, this.paramsInheritanceStrategy);\n    currentSnapshot.params = Object.freeze(inherited.params);\n    currentSnapshot.data = Object.freeze(inherited.data);\n    const newTree = this.applyRedirects.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments, currentSnapshot, injector);\n    return this.applyRedirects.lineralizeSegments(route, newTree).pipe(mergeMap(newSegments => {\n      return this.processSegment(injector, routes, segmentGroup, newSegments.concat(remainingSegments), outlet, false, parentRoute);\n    }));\n  }\n  matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet, parentRoute) {\n    const matchResult = matchWithChecks(rawSegment, route, segments, injector, this.urlSerializer);\n    if (route.path === '**') {\n      // Prior versions of the route matching algorithm would stop matching at the wildcard route.\n      // We should investigate a better strategy for any existing children. Otherwise, these\n      // child segments are silently dropped from the navigation.\n      // https://github.com/angular/angular/issues/40089\n      rawSegment.children = {};\n    }\n    return matchResult.pipe(switchMap(result => {\n      if (!result.matched) {\n        return noMatch$1(rawSegment);\n      }\n      // If the route has an injector created from providers, we should start using that.\n      injector = route._injector ?? injector;\n      return this.getChildConfig(injector, route, segments).pipe(switchMap(({\n        routes: childConfig\n      }) => {\n        const childInjector = route._loadedInjector ?? injector;\n        const {\n          parameters,\n          consumedSegments,\n          remainingSegments\n        } = result;\n        const snapshot = new ActivatedRouteSnapshot(consumedSegments, parameters, Object.freeze({\n          ...this.urlTree.queryParams\n        }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));\n        const inherited = getInherited(snapshot, parentRoute, this.paramsInheritanceStrategy);\n        snapshot.params = Object.freeze(inherited.params);\n        snapshot.data = Object.freeze(inherited.data);\n        const {\n          segmentGroup,\n          slicedSegments\n        } = split(rawSegment, consumedSegments, remainingSegments, childConfig);\n        if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {\n          return this.processChildren(childInjector, childConfig, segmentGroup, snapshot).pipe(map(children => {\n            return new TreeNode(snapshot, children);\n          }));\n        }\n        if (childConfig.length === 0 && slicedSegments.length === 0) {\n          return of(new TreeNode(snapshot, []));\n        }\n        const matchedOnOutlet = getOutlet(route) === outlet;\n        // If we matched a config due to empty path match on a different outlet, we need to\n        // continue passing the current outlet for the segment rather than switch to PRIMARY.\n        // Note that we switch to primary when we have a match because outlet configs look like\n        // this: {path: 'a', outlet: 'a', children: [\n        //  {path: 'b', component: B},\n        //  {path: 'c', component: C},\n        // ]}\n        // Notice that the children of the named outlet are configured with the primary outlet\n        return this.processSegment(childInjector, childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true, snapshot).pipe(map(child => {\n          return new TreeNode(snapshot, child instanceof TreeNode ? [child] : []);\n        }));\n      }));\n    }));\n  }\n  getChildConfig(injector, route, segments) {\n    if (route.children) {\n      // The children belong to the same module\n      return of({\n        routes: route.children,\n        injector\n      });\n    }\n    if (route.loadChildren) {\n      // lazy children belong to the loaded module\n      if (route._loadedRoutes !== undefined) {\n        return of({\n          routes: route._loadedRoutes,\n          injector: route._loadedInjector\n        });\n      }\n      return runCanLoadGuards(injector, route, segments, this.urlSerializer).pipe(mergeMap(shouldLoadResult => {\n        if (shouldLoadResult) {\n          return this.configLoader.loadChildren(injector, route).pipe(tap(cfg => {\n            route._loadedRoutes = cfg.routes;\n            route._loadedInjector = cfg.injector;\n          }));\n        }\n        return canLoadFails(route);\n      }));\n    }\n    return of({\n      routes: [],\n      injector\n    });\n  }\n}\nfunction sortActivatedRouteSnapshots(nodes) {\n  nodes.sort((a, b) => {\n    if (a.value.outlet === PRIMARY_OUTLET) return -1;\n    if (b.value.outlet === PRIMARY_OUTLET) return 1;\n    return a.value.outlet.localeCompare(b.value.outlet);\n  });\n}\nfunction hasEmptyPathConfig(node) {\n  const config = node.value.routeConfig;\n  return config && config.path === '';\n}\n/**\n * Finds `TreeNode`s with matching empty path route configs and merges them into `TreeNode` with\n * the children from each duplicate. This is necessary because different outlets can match a\n * single empty path route config and the results need to then be merged.\n */\nfunction mergeEmptyPathMatches(nodes) {\n  const result = [];\n  // The set of nodes which contain children that were merged from two duplicate empty path nodes.\n  const mergedNodes = new Set();\n  for (const node of nodes) {\n    if (!hasEmptyPathConfig(node)) {\n      result.push(node);\n      continue;\n    }\n    const duplicateEmptyPathNode = result.find(resultNode => node.value.routeConfig === resultNode.value.routeConfig);\n    if (duplicateEmptyPathNode !== undefined) {\n      duplicateEmptyPathNode.children.push(...node.children);\n      mergedNodes.add(duplicateEmptyPathNode);\n    } else {\n      result.push(node);\n    }\n  }\n  // For each node which has children from multiple sources, we need to recompute a new `TreeNode`\n  // by also merging those children. This is necessary when there are multiple empty path configs\n  // in a row. Put another way: whenever we combine children of two nodes, we need to also check\n  // if any of those children can be combined into a single node as well.\n  for (const mergedNode of mergedNodes) {\n    const mergedChildren = mergeEmptyPathMatches(mergedNode.children);\n    result.push(new TreeNode(mergedNode.value, mergedChildren));\n  }\n  return result.filter(n => !mergedNodes.has(n));\n}\nfunction checkOutletNameUniqueness(nodes) {\n  const names = {};\n  nodes.forEach(n => {\n    const routeWithSameOutletName = names[n.value.outlet];\n    if (routeWithSameOutletName) {\n      const p = routeWithSameOutletName.url.map(s => s.toString()).join('/');\n      const c = n.value.url.map(s => s.toString()).join('/');\n      throw new _RuntimeError(4006 /* RuntimeErrorCode.TWO_SEGMENTS_WITH_SAME_OUTLET */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Two segments cannot have the same outlet name: '${p}' and '${c}'.`);\n    }\n    names[n.value.outlet] = n.value;\n  });\n}\nfunction getData(route) {\n  return route.data || {};\n}\nfunction getResolve(route) {\n  return route.resolve || {};\n}\nfunction recognize(injector, configLoader, rootComponentType, config, serializer, paramsInheritanceStrategy) {\n  return mergeMap(t => recognize$1(injector, configLoader, rootComponentType, config, t.extractedUrl, serializer, paramsInheritanceStrategy).pipe(map(({\n    state: targetSnapshot,\n    tree: urlAfterRedirects\n  }) => {\n    return {\n      ...t,\n      targetSnapshot,\n      urlAfterRedirects\n    };\n  })));\n}\nfunction resolveData(paramsInheritanceStrategy, injector) {\n  return mergeMap(t => {\n    const {\n      targetSnapshot,\n      guards: {\n        canActivateChecks\n      }\n    } = t;\n    if (!canActivateChecks.length) {\n      return of(t);\n    }\n    // Iterating a Set in javascript  happens in insertion order so it is safe to use a `Set` to\n    // preserve the correct order that the resolvers should run in.\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#description\n    const routesWithResolversToRun = new Set(canActivateChecks.map(check => check.route));\n    const routesNeedingDataUpdates = new Set();\n    for (const route of routesWithResolversToRun) {\n      if (routesNeedingDataUpdates.has(route)) {\n        continue;\n      }\n      // All children under the route with a resolver to run need to recompute inherited data.\n      for (const newRoute of flattenRouteTree(route)) {\n        routesNeedingDataUpdates.add(newRoute);\n      }\n    }\n    let routesProcessed = 0;\n    return from(routesNeedingDataUpdates).pipe(concatMap(route => {\n      if (routesWithResolversToRun.has(route)) {\n        return runResolve(route, targetSnapshot, paramsInheritanceStrategy, injector);\n      } else {\n        route.data = getInherited(route, route.parent, paramsInheritanceStrategy).resolve;\n        return of(void 0);\n      }\n    }), tap(() => routesProcessed++), takeLast(1), mergeMap(_ => routesProcessed === routesNeedingDataUpdates.size ? of(t) : EMPTY));\n  });\n}\n/**\n *  Returns the `ActivatedRouteSnapshot` tree as an array, using DFS to traverse the route tree.\n */\nfunction flattenRouteTree(route) {\n  const descendants = route.children.map(child => flattenRouteTree(child)).flat();\n  return [route, ...descendants];\n}\nfunction runResolve(futureARS, futureRSS, paramsInheritanceStrategy, injector) {\n  const config = futureARS.routeConfig;\n  const resolve = futureARS._resolve;\n  if (config?.title !== undefined && !hasStaticTitle(config)) {\n    resolve[RouteTitleKey] = config.title;\n  }\n  return resolveNode(resolve, futureARS, futureRSS, injector).pipe(map(resolvedData => {\n    futureARS._resolvedData = resolvedData;\n    futureARS.data = getInherited(futureARS, futureARS.parent, paramsInheritanceStrategy).resolve;\n    return null;\n  }));\n}\nfunction resolveNode(resolve, futureARS, futureRSS, injector) {\n  const keys = getDataKeys(resolve);\n  if (keys.length === 0) {\n    return of({});\n  }\n  const data = {};\n  return from(keys).pipe(mergeMap(key => getResolver(resolve[key], futureARS, futureRSS, injector).pipe(first(), tap(value => {\n    if (value instanceof RedirectCommand) {\n      throw redirectingNavigationError(new DefaultUrlSerializer(), value);\n    }\n    data[key] = value;\n  }))), takeLast(1), map(() => data), catchError(e => isEmptyError(e) ? EMPTY : throwError(e)));\n}\nfunction getResolver(injectionToken, futureARS, futureRSS, injector) {\n  const closestInjector = getClosestRouteInjector(futureARS) ?? injector;\n  const resolver = getTokenOrFunctionIdentity(injectionToken, closestInjector);\n  const resolverValue = resolver.resolve ? resolver.resolve(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => resolver(futureARS, futureRSS));\n  return wrapIntoObservable(resolverValue);\n}\n\n/**\n * Perform a side effect through a switchMap for every emission on the source Observable,\n * but return an Observable that is identical to the source. It's essentially the same as\n * the `tap` operator, but if the side effectful `next` function returns an ObservableInput,\n * it will wait before continuing with the original value.\n */\nfunction switchTap(next) {\n  return switchMap(v => {\n    const nextResult = next(v);\n    if (nextResult) {\n      return from(nextResult).pipe(map(() => v));\n    }\n    return of(v);\n  });\n}\n\n/**\n * Provides a strategy for setting the page title after a router navigation.\n *\n * The built-in implementation traverses the router state snapshot and finds the deepest primary\n * outlet with `title` property. Given the `Routes` below, navigating to\n * `/base/child(popup:aux)` would result in the document title being set to \"child\".\n * ```ts\n * [\n *   {path: 'base', title: 'base', children: [\n *     {path: 'child', title: 'child'},\n *   ],\n *   {path: 'aux', outlet: 'popup', title: 'popupTitle'}\n * ]\n * ```\n *\n * This class can be used as a base class for custom title strategies. That is, you can create your\n * own class that extends the `TitleStrategy`. Note that in the above example, the `title`\n * from the named outlet is never used. However, a custom strategy might be implemented to\n * incorporate titles in named outlets.\n *\n * @publicApi\n * @see [Page title guide](guide/routing/common-router-tasks#setting-the-page-title)\n */\nlet TitleStrategy = /*#__PURE__*/(() => {\n  class TitleStrategy {\n    /**\n     * @returns The `title` of the deepest primary route.\n     */\n    buildTitle(snapshot) {\n      let pageTitle;\n      let route = snapshot.root;\n      while (route !== undefined) {\n        pageTitle = this.getResolvedTitleForRoute(route) ?? pageTitle;\n        route = route.children.find(child => child.outlet === PRIMARY_OUTLET);\n      }\n      return pageTitle;\n    }\n    /**\n     * Given an `ActivatedRouteSnapshot`, returns the final value of the\n     * `Route.title` property, which can either be a static string or a resolved value.\n     */\n    getResolvedTitleForRoute(snapshot) {\n      return snapshot.data[RouteTitleKey];\n    }\n    static ɵfac = function TitleStrategy_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || TitleStrategy)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: TitleStrategy,\n      factory: () => (() => inject(DefaultTitleStrategy))(),\n      providedIn: 'root'\n    });\n  }\n  return TitleStrategy;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n/**\n * The default `TitleStrategy` used by the router that updates the title using the `Title` service.\n */\nlet DefaultTitleStrategy = /*#__PURE__*/(() => {\n  class DefaultTitleStrategy extends TitleStrategy {\n    title;\n    constructor(title) {\n      super();\n      this.title = title;\n    }\n    /**\n     * Sets the title of the browser to the given value.\n     *\n     * @param title The `pageTitle` from the deepest primary route.\n     */\n    updateTitle(snapshot) {\n      const title = this.buildTitle(snapshot);\n      if (title !== undefined) {\n        this.title.setTitle(title);\n      }\n    }\n    static ɵfac = function DefaultTitleStrategy_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || DefaultTitleStrategy)(i0.ɵɵinject(i1.Title));\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: DefaultTitleStrategy,\n      factory: DefaultTitleStrategy.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return DefaultTitleStrategy;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n\n/**\n * A DI token for the router service.\n *\n * @publicApi\n */\nconst ROUTER_CONFIGURATION = /*#__PURE__*/new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'router config' : '', {\n  providedIn: 'root',\n  factory: () => ({})\n});\n\n/**\n * The DI token for a router configuration.\n *\n * `ROUTES` is a low level API for router configuration via dependency injection.\n *\n * We recommend that in almost all cases to use higher level APIs such as `RouterModule.forRoot()`,\n * `provideRouter`, or `Router.resetConfig()`.\n *\n * @publicApi\n */\nconst ROUTES = /*#__PURE__*/new InjectionToken(ngDevMode ? 'ROUTES' : '');\nlet RouterConfigLoader = /*#__PURE__*/(() => {\n  class RouterConfigLoader {\n    componentLoaders = new WeakMap();\n    childrenLoaders = new WeakMap();\n    onLoadStartListener;\n    onLoadEndListener;\n    compiler = inject(Compiler);\n    loadComponent(route) {\n      if (this.componentLoaders.get(route)) {\n        return this.componentLoaders.get(route);\n      } else if (route._loadedComponent) {\n        return of(route._loadedComponent);\n      }\n      if (this.onLoadStartListener) {\n        this.onLoadStartListener(route);\n      }\n      const loadRunner = wrapIntoObservable(route.loadComponent()).pipe(map(maybeUnwrapDefaultExport), tap(component => {\n        if (this.onLoadEndListener) {\n          this.onLoadEndListener(route);\n        }\n        (typeof ngDevMode === 'undefined' || ngDevMode) && assertStandalone(route.path ?? '', component);\n        route._loadedComponent = component;\n      }), finalize(() => {\n        this.componentLoaders.delete(route);\n      }));\n      // Use custom ConnectableObservable as share in runners pipe increasing the bundle size too much\n      const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());\n      this.componentLoaders.set(route, loader);\n      return loader;\n    }\n    loadChildren(parentInjector, route) {\n      if (this.childrenLoaders.get(route)) {\n        return this.childrenLoaders.get(route);\n      } else if (route._loadedRoutes) {\n        return of({\n          routes: route._loadedRoutes,\n          injector: route._loadedInjector\n        });\n      }\n      if (this.onLoadStartListener) {\n        this.onLoadStartListener(route);\n      }\n      const moduleFactoryOrRoutes$ = loadChildren(route, this.compiler, parentInjector, this.onLoadEndListener);\n      const loadRunner = moduleFactoryOrRoutes$.pipe(finalize(() => {\n        this.childrenLoaders.delete(route);\n      }));\n      // Use custom ConnectableObservable as share in runners pipe increasing the bundle size too much\n      const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());\n      this.childrenLoaders.set(route, loader);\n      return loader;\n    }\n    static ɵfac = function RouterConfigLoader_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || RouterConfigLoader)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: RouterConfigLoader,\n      factory: RouterConfigLoader.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return RouterConfigLoader;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n/**\n * Executes a `route.loadChildren` callback and converts the result to an array of child routes and\n * an injector if that callback returned a module.\n *\n * This function is used for the route discovery during prerendering\n * in @angular-devkit/build-angular. If there are any updates to the contract here, it will require\n * an update to the extractor.\n */\nfunction loadChildren(route, compiler, parentInjector, onLoadEndListener) {\n  return wrapIntoObservable(route.loadChildren()).pipe(map(maybeUnwrapDefaultExport), mergeMap(t => {\n    if (t instanceof NgModuleFactory || Array.isArray(t)) {\n      return of(t);\n    } else {\n      return from(compiler.compileModuleAsync(t));\n    }\n  }), map(factoryOrRoutes => {\n    if (onLoadEndListener) {\n      onLoadEndListener(route);\n    }\n    // This injector comes from the `NgModuleRef` when lazy loading an `NgModule`. There is\n    // no injector associated with lazy loading a `Route` array.\n    let injector;\n    let rawRoutes;\n    let requireStandaloneComponents = false;\n    if (Array.isArray(factoryOrRoutes)) {\n      rawRoutes = factoryOrRoutes;\n      requireStandaloneComponents = true;\n    } else {\n      injector = factoryOrRoutes.create(parentInjector).injector;\n      // When loading a module that doesn't provide `RouterModule.forChild()` preloader\n      // will get stuck in an infinite loop. The child module's Injector will look to\n      // its parent `Injector` when it doesn't find any ROUTES so it will return routes\n      // for it's parent module instead.\n      rawRoutes = injector.get(ROUTES, [], {\n        optional: true,\n        self: true\n      }).flat();\n    }\n    const routes = rawRoutes.map(standardizeConfig);\n    (typeof ngDevMode === 'undefined' || ngDevMode) && validateConfig(routes, route.path, requireStandaloneComponents);\n    return {\n      routes,\n      injector\n    };\n  }));\n}\nfunction isWrappedDefaultExport(value) {\n  // We use `in` here with a string key `'default'`, because we expect `DefaultExport` objects to be\n  // dynamically imported ES modules with a spec-mandated `default` key. Thus we don't expect that\n  // `default` will be a renamed property.\n  return value && typeof value === 'object' && 'default' in value;\n}\nfunction maybeUnwrapDefaultExport(input) {\n  // As per `isWrappedDefaultExport`, the `default` key here is generated by the browser and not\n  // subject to property renaming, so we reference it with bracket access.\n  return isWrappedDefaultExport(input) ? input['default'] : input;\n}\n\n/**\n * @description\n *\n * Provides a way to migrate AngularJS applications to Angular.\n *\n * @publicApi\n */\nlet UrlHandlingStrategy = /*#__PURE__*/(() => {\n  class UrlHandlingStrategy {\n    static ɵfac = function UrlHandlingStrategy_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || UrlHandlingStrategy)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: UrlHandlingStrategy,\n      factory: () => (() => inject(DefaultUrlHandlingStrategy))(),\n      providedIn: 'root'\n    });\n  }\n  return UrlHandlingStrategy;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n/**\n * @publicApi\n */\nlet DefaultUrlHandlingStrategy = /*#__PURE__*/(() => {\n  class DefaultUrlHandlingStrategy {\n    shouldProcessUrl(url) {\n      return true;\n    }\n    extract(url) {\n      return url;\n    }\n    merge(newUrlPart, wholeUrl) {\n      return newUrlPart;\n    }\n    static ɵfac = function DefaultUrlHandlingStrategy_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || DefaultUrlHandlingStrategy)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: DefaultUrlHandlingStrategy,\n      factory: DefaultUrlHandlingStrategy.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return DefaultUrlHandlingStrategy;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n\n/// <reference types=\"dom-view-transitions\" />\nconst CREATE_VIEW_TRANSITION = /*#__PURE__*/new InjectionToken(ngDevMode ? 'view transition helper' : '');\nconst VIEW_TRANSITION_OPTIONS = /*#__PURE__*/new InjectionToken(ngDevMode ? 'view transition options' : '');\n/**\n * A helper function for using browser view transitions. This function skips the call to\n * `startViewTransition` if the browser does not support it.\n *\n * @returns A Promise that resolves when the view transition callback begins.\n */\nfunction createViewTransition(injector, from, to) {\n  const transitionOptions = injector.get(VIEW_TRANSITION_OPTIONS);\n  const document = injector.get(DOCUMENT);\n  // Create promises outside the Angular zone to avoid causing extra change detections\n  return injector.get(NgZone).runOutsideAngular(() => {\n    if (!document.startViewTransition || transitionOptions.skipNextTransition) {\n      transitionOptions.skipNextTransition = false;\n      // The timing of `startViewTransition` is closer to a macrotask. It won't be called\n      // until the current event loop exits so we use a promise resolved in a timeout instead\n      // of Promise.resolve().\n      return new Promise(resolve => setTimeout(resolve));\n    }\n    let resolveViewTransitionStarted;\n    const viewTransitionStarted = new Promise(resolve => {\n      resolveViewTransitionStarted = resolve;\n    });\n    const transition = document.startViewTransition(() => {\n      resolveViewTransitionStarted();\n      // We don't actually update dom within the transition callback. The resolving of the above\n      // promise unblocks the Router navigation, which synchronously activates and deactivates\n      // routes (the DOM update). This view transition waits for the next change detection to\n      // complete (below), which includes the update phase of the routed components.\n      return createRenderPromise(injector);\n      // TODO(atscott): Types in DefinitelyTyped are not up-to-date\n    });\n    const {\n      onViewTransitionCreated\n    } = transitionOptions;\n    if (onViewTransitionCreated) {\n      runInInjectionContext(injector, () => onViewTransitionCreated({\n        transition,\n        from,\n        to\n      }));\n    }\n    return viewTransitionStarted;\n  });\n}\n/**\n * Creates a promise that resolves after next render.\n */\nfunction createRenderPromise(injector) {\n  return new Promise(resolve => {\n    // Wait for the microtask queue to empty after the next render happens (by waiting a macrotask).\n    // This ensures any follow-up renders in the microtask queue are completed before the\n    // view transition starts animating.\n    afterNextRender({\n      read: () => setTimeout(resolve)\n    }, {\n      injector\n    });\n  });\n}\nconst NAVIGATION_ERROR_HANDLER = /*#__PURE__*/new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'navigation error handler' : '');\nlet NavigationTransitions = /*#__PURE__*/(() => {\n  class NavigationTransitions {\n    currentNavigation = null;\n    currentTransition = null;\n    lastSuccessfulNavigation = null;\n    /**\n     * These events are used to communicate back to the Router about the state of the transition. The\n     * Router wants to respond to these events in various ways. Because the `NavigationTransition`\n     * class is not public, this event subject is not publicly exposed.\n     */\n    events = new Subject();\n    /**\n     * Used to abort the current transition with an error.\n     */\n    transitionAbortSubject = new Subject();\n    configLoader = inject(RouterConfigLoader);\n    environmentInjector = inject(EnvironmentInjector);\n    destroyRef = inject(DestroyRef);\n    urlSerializer = inject(UrlSerializer);\n    rootContexts = inject(ChildrenOutletContexts);\n    location = inject(Location);\n    inputBindingEnabled = inject(INPUT_BINDER, {\n      optional: true\n    }) !== null;\n    titleStrategy = inject(TitleStrategy);\n    options = inject(ROUTER_CONFIGURATION, {\n      optional: true\n    }) || {};\n    paramsInheritanceStrategy = this.options.paramsInheritanceStrategy || 'emptyOnly';\n    urlHandlingStrategy = inject(UrlHandlingStrategy);\n    createViewTransition = inject(CREATE_VIEW_TRANSITION, {\n      optional: true\n    });\n    navigationErrorHandler = inject(NAVIGATION_ERROR_HANDLER, {\n      optional: true\n    });\n    navigationId = 0;\n    get hasRequestedNavigation() {\n      return this.navigationId !== 0;\n    }\n    transitions;\n    /**\n     * Hook that enables you to pause navigation after the preactivation phase.\n     * Used by `RouterModule`.\n     *\n     * @internal\n     */\n    afterPreactivation = () => of(void 0);\n    /** @internal */\n    rootComponentType = null;\n    destroyed = false;\n    constructor() {\n      const onLoadStart = r => this.events.next(new RouteConfigLoadStart(r));\n      const onLoadEnd = r => this.events.next(new RouteConfigLoadEnd(r));\n      this.configLoader.onLoadEndListener = onLoadEnd;\n      this.configLoader.onLoadStartListener = onLoadStart;\n      this.destroyRef.onDestroy(() => {\n        this.destroyed = true;\n      });\n    }\n    complete() {\n      this.transitions?.complete();\n    }\n    handleNavigationRequest(request) {\n      const id = ++this.navigationId;\n      this.transitions?.next({\n        ...request,\n        extractedUrl: this.urlHandlingStrategy.extract(request.rawUrl),\n        targetSnapshot: null,\n        targetRouterState: null,\n        guards: {\n          canActivateChecks: [],\n          canDeactivateChecks: []\n        },\n        guardsResult: null,\n        id\n      });\n    }\n    setupNavigations(router) {\n      this.transitions = new BehaviorSubject(null);\n      return this.transitions.pipe(filter(t => t !== null),\n      // Using switchMap so we cancel executing navigations when a new one comes in\n      switchMap(overallTransitionState => {\n        let completed = false;\n        let errored = false;\n        return of(overallTransitionState).pipe(switchMap(t => {\n          // It is possible that `switchMap` fails to cancel previous navigations if a new one happens synchronously while the operator\n          // is processing the `next` notification of that previous navigation. This can happen when a new navigation (say 2) cancels a\n          // previous one (1) and yet another navigation (3) happens synchronously in response to the `NavigationCancel` event for (1).\n          // https://github.com/ReactiveX/rxjs/issues/7455\n          if (this.navigationId > overallTransitionState.id) {\n            const cancellationReason = typeof ngDevMode === 'undefined' || ngDevMode ? `Navigation ID ${overallTransitionState.id} is not equal to the current navigation id ${this.navigationId}` : '';\n            this.cancelNavigationTransition(overallTransitionState, cancellationReason, NavigationCancellationCode.SupersededByNewNavigation);\n            return EMPTY;\n          }\n          this.currentTransition = overallTransitionState;\n          // Store the Navigation object\n          this.currentNavigation = {\n            id: t.id,\n            initialUrl: t.rawUrl,\n            extractedUrl: t.extractedUrl,\n            targetBrowserUrl: typeof t.extras.browserUrl === 'string' ? this.urlSerializer.parse(t.extras.browserUrl) : t.extras.browserUrl,\n            trigger: t.source,\n            extras: t.extras,\n            previousNavigation: !this.lastSuccessfulNavigation ? null : {\n              ...this.lastSuccessfulNavigation,\n              previousNavigation: null\n            }\n          };\n          const urlTransition = !router.navigated || this.isUpdatingInternalState() || this.isUpdatedBrowserUrl();\n          const onSameUrlNavigation = t.extras.onSameUrlNavigation ?? router.onSameUrlNavigation;\n          if (!urlTransition && onSameUrlNavigation !== 'reload') {\n            const reason = typeof ngDevMode === 'undefined' || ngDevMode ? `Navigation to ${t.rawUrl} was ignored because it is the same as the current Router URL.` : '';\n            this.events.next(new NavigationSkipped(t.id, this.urlSerializer.serialize(t.rawUrl), reason, NavigationSkippedCode.IgnoredSameUrlNavigation));\n            t.resolve(false);\n            return EMPTY;\n          }\n          if (this.urlHandlingStrategy.shouldProcessUrl(t.rawUrl)) {\n            return of(t).pipe(\n            // Fire NavigationStart event\n            switchMap(t => {\n              this.events.next(new NavigationStart(t.id, this.urlSerializer.serialize(t.extractedUrl), t.source, t.restoredState));\n              if (t.id !== this.navigationId) {\n                return EMPTY;\n              }\n              // This delay is required to match old behavior that forced\n              // navigation to always be async\n              return Promise.resolve(t);\n            }),\n            // Recognize\n            recognize(this.environmentInjector, this.configLoader, this.rootComponentType, router.config, this.urlSerializer, this.paramsInheritanceStrategy),\n            // Update URL if in `eager` update mode\n            tap(t => {\n              overallTransitionState.targetSnapshot = t.targetSnapshot;\n              overallTransitionState.urlAfterRedirects = t.urlAfterRedirects;\n              this.currentNavigation = {\n                ...this.currentNavigation,\n                finalUrl: t.urlAfterRedirects\n              };\n              // Fire RoutesRecognized\n              const routesRecognized = new RoutesRecognized(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot);\n              this.events.next(routesRecognized);\n            }));\n          } else if (urlTransition && this.urlHandlingStrategy.shouldProcessUrl(t.currentRawUrl)) {\n            /* When the current URL shouldn't be processed, but the previous one\n             * was, we handle this \"error condition\" by navigating to the\n             * previously successful URL, but leaving the URL intact.*/\n            const {\n              id,\n              extractedUrl,\n              source,\n              restoredState,\n              extras\n            } = t;\n            const navStart = new NavigationStart(id, this.urlSerializer.serialize(extractedUrl), source, restoredState);\n            this.events.next(navStart);\n            const targetSnapshot = createEmptyState(this.rootComponentType).snapshot;\n            this.currentTransition = overallTransitionState = {\n              ...t,\n              targetSnapshot,\n              urlAfterRedirects: extractedUrl,\n              extras: {\n                ...extras,\n                skipLocationChange: false,\n                replaceUrl: false\n              }\n            };\n            this.currentNavigation.finalUrl = extractedUrl;\n            return of(overallTransitionState);\n          } else {\n            /* When neither the current or previous URL can be processed, do\n             * nothing other than update router's internal reference to the\n             * current \"settled\" URL. This way the next navigation will be coming\n             * from the current URL in the browser.\n             */\n            const reason = typeof ngDevMode === 'undefined' || ngDevMode ? `Navigation was ignored because the UrlHandlingStrategy` + ` indicated neither the current URL ${t.currentRawUrl} nor target URL ${t.rawUrl} should be processed.` : '';\n            this.events.next(new NavigationSkipped(t.id, this.urlSerializer.serialize(t.extractedUrl), reason, NavigationSkippedCode.IgnoredByUrlHandlingStrategy));\n            t.resolve(false);\n            return EMPTY;\n          }\n        }),\n        // --- GUARDS ---\n        tap(t => {\n          const guardsStart = new GuardsCheckStart(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot);\n          this.events.next(guardsStart);\n        }), map(t => {\n          this.currentTransition = overallTransitionState = {\n            ...t,\n            guards: getAllRouteGuards(t.targetSnapshot, t.currentSnapshot, this.rootContexts)\n          };\n          return overallTransitionState;\n        }), checkGuards(this.environmentInjector, evt => this.events.next(evt)), tap(t => {\n          overallTransitionState.guardsResult = t.guardsResult;\n          if (t.guardsResult && typeof t.guardsResult !== 'boolean') {\n            throw redirectingNavigationError(this.urlSerializer, t.guardsResult);\n          }\n          const guardsEnd = new GuardsCheckEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot, !!t.guardsResult);\n          this.events.next(guardsEnd);\n        }), filter(t => {\n          if (!t.guardsResult) {\n            this.cancelNavigationTransition(t, '', NavigationCancellationCode.GuardRejected);\n            return false;\n          }\n          return true;\n        }),\n        // --- RESOLVE ---\n        switchTap(t => {\n          if (t.guards.canActivateChecks.length === 0) {\n            return undefined;\n          }\n          return of(t).pipe(tap(t => {\n            const resolveStart = new ResolveStart(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot);\n            this.events.next(resolveStart);\n          }), switchMap(t => {\n            let dataResolved = false;\n            return of(t).pipe(resolveData(this.paramsInheritanceStrategy, this.environmentInjector), tap({\n              next: () => dataResolved = true,\n              complete: () => {\n                if (!dataResolved) {\n                  this.cancelNavigationTransition(t, typeof ngDevMode === 'undefined' || ngDevMode ? `At least one route resolver didn't emit any value.` : '', NavigationCancellationCode.NoDataFromResolver);\n                }\n              }\n            }));\n          }), tap(t => {\n            const resolveEnd = new ResolveEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot);\n            this.events.next(resolveEnd);\n          }));\n        }),\n        // --- LOAD COMPONENTS ---\n        switchTap(t => {\n          const loadComponents = route => {\n            const loaders = [];\n            if (route.routeConfig?.loadComponent && !route.routeConfig._loadedComponent) {\n              loaders.push(this.configLoader.loadComponent(route.routeConfig).pipe(tap(loadedComponent => {\n                route.component = loadedComponent;\n              }), map(() => void 0)));\n            }\n            for (const child of route.children) {\n              loaders.push(...loadComponents(child));\n            }\n            return loaders;\n          };\n          return combineLatest(loadComponents(t.targetSnapshot.root)).pipe(defaultIfEmpty(null), take(1));\n        }), switchTap(() => this.afterPreactivation()), switchMap(() => {\n          const {\n            currentSnapshot,\n            targetSnapshot\n          } = overallTransitionState;\n          const viewTransitionStarted = this.createViewTransition?.(this.environmentInjector, currentSnapshot.root, targetSnapshot.root);\n          // If view transitions are enabled, block the navigation until the view\n          // transition callback starts. Otherwise, continue immediately.\n          return viewTransitionStarted ? from(viewTransitionStarted).pipe(map(() => overallTransitionState)) : of(overallTransitionState);\n        }), map(t => {\n          const targetRouterState = createRouterState(router.routeReuseStrategy, t.targetSnapshot, t.currentRouterState);\n          this.currentTransition = overallTransitionState = {\n            ...t,\n            targetRouterState\n          };\n          this.currentNavigation.targetRouterState = targetRouterState;\n          return overallTransitionState;\n        }), tap(() => {\n          this.events.next(new BeforeActivateRoutes());\n        }), activateRoutes(this.rootContexts, router.routeReuseStrategy, evt => this.events.next(evt), this.inputBindingEnabled),\n        // Ensure that if some observable used to drive the transition doesn't\n        // complete, the navigation still finalizes This should never happen, but\n        // this is done as a safety measure to avoid surfacing this error (#49567).\n        take(1), tap({\n          next: t => {\n            completed = true;\n            this.lastSuccessfulNavigation = this.currentNavigation;\n            this.events.next(new NavigationEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects)));\n            this.titleStrategy?.updateTitle(t.targetRouterState.snapshot);\n            t.resolve(true);\n          },\n          complete: () => {\n            completed = true;\n          }\n        }),\n        // There used to be a lot more logic happening directly within the\n        // transition Observable. Some of this logic has been refactored out to\n        // other places but there may still be errors that happen there. This gives\n        // us a way to cancel the transition from the outside. This may also be\n        // required in the future to support something like the abort signal of the\n        // Navigation API where the navigation gets aborted from outside the\n        // transition.\n        takeUntil(this.transitionAbortSubject.pipe(tap(err => {\n          throw err;\n        }))), finalize(() => {\n          /* When the navigation stream finishes either through error or success,\n           * we set the `completed` or `errored` flag. However, there are some\n           * situations where we could get here without either of those being set.\n           * For instance, a redirect during NavigationStart. Therefore, this is a\n           * catch-all to make sure the NavigationCancel event is fired when a\n           * navigation gets cancelled but not caught by other means. */\n          if (!completed && !errored) {\n            const cancelationReason = typeof ngDevMode === 'undefined' || ngDevMode ? `Navigation ID ${overallTransitionState.id} is not equal to the current navigation id ${this.navigationId}` : '';\n            this.cancelNavigationTransition(overallTransitionState, cancelationReason, NavigationCancellationCode.SupersededByNewNavigation);\n          }\n          // Only clear current navigation if it is still set to the one that\n          // finalized.\n          if (this.currentTransition?.id === overallTransitionState.id) {\n            this.currentNavigation = null;\n            this.currentTransition = null;\n          }\n        }), catchError(e => {\n          // If the application is already destroyed, the catch block should not\n          // execute anything in practice because other resources have already\n          // been released and destroyed.\n          if (this.destroyed) {\n            overallTransitionState.resolve(false);\n            return EMPTY;\n          }\n          errored = true;\n          /* This error type is issued during Redirect, and is handled as a\n           * cancellation rather than an error. */\n          if (isNavigationCancelingError(e)) {\n            this.events.next(new NavigationCancel(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), e.message, e.cancellationCode));\n            // When redirecting, we need to delay resolving the navigation\n            // promise and push it to the redirect navigation\n            if (!isRedirectingNavigationCancelingError(e)) {\n              overallTransitionState.resolve(false);\n            } else {\n              this.events.next(new RedirectRequest(e.url, e.navigationBehaviorOptions));\n            }\n            /* All other errors should reset to the router's internal URL reference\n             * to the pre-error state. */\n          } else {\n            const navigationError = new NavigationError(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), e, overallTransitionState.targetSnapshot ?? undefined);\n            try {\n              const navigationErrorHandlerResult = runInInjectionContext(this.environmentInjector, () => this.navigationErrorHandler?.(navigationError));\n              if (navigationErrorHandlerResult instanceof RedirectCommand) {\n                const {\n                  message,\n                  cancellationCode\n                } = redirectingNavigationError(this.urlSerializer, navigationErrorHandlerResult);\n                this.events.next(new NavigationCancel(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), message, cancellationCode));\n                this.events.next(new RedirectRequest(navigationErrorHandlerResult.redirectTo, navigationErrorHandlerResult.navigationBehaviorOptions));\n              } else {\n                this.events.next(navigationError);\n                throw e;\n              }\n            } catch (ee) {\n              // TODO(atscott): consider flipping the default behavior of\n              // resolveNavigationPromiseOnError to be `resolve(false)` when\n              // undefined. This is the most sane thing to do given that\n              // applications very rarely handle the promise rejection and, as a\n              // result, would get \"unhandled promise rejection\" console logs.\n              // The vast majority of applications would not be affected by this\n              // change so omitting a migration seems reasonable. Instead,\n              // applications that rely on rejection can specifically opt-in to the\n              // old behavior.\n              if (this.options.resolveNavigationPromiseOnError) {\n                overallTransitionState.resolve(false);\n              } else {\n                overallTransitionState.reject(ee);\n              }\n            }\n          }\n          return EMPTY;\n        }));\n        // casting because `pipe` returns observable({}) when called with 8+ arguments\n      }));\n    }\n    cancelNavigationTransition(t, reason, code) {\n      const navCancel = new NavigationCancel(t.id, this.urlSerializer.serialize(t.extractedUrl), reason, code);\n      this.events.next(navCancel);\n      t.resolve(false);\n    }\n    /**\n     * @returns Whether we're navigating to somewhere that is not what the Router is\n     * currently set to.\n     */\n    isUpdatingInternalState() {\n      // TODO(atscott): The serializer should likely be used instead of\n      // `UrlTree.toString()`. Custom serializers are often written to handle\n      // things better than the default one (objects, for example will be\n      // [Object object] with the custom serializer and be \"the same\" when they\n      // aren't).\n      // (Same for isUpdatedBrowserUrl)\n      return this.currentTransition?.extractedUrl.toString() !== this.currentTransition?.currentUrlTree.toString();\n    }\n    /**\n     * @returns Whether we're updating the browser URL to something new (navigation is going\n     * to somewhere not displayed in the URL bar and we will update the URL\n     * bar if navigation succeeds).\n     */\n    isUpdatedBrowserUrl() {\n      // The extracted URL is the part of the URL that this application cares about. `extract` may\n      // return only part of the browser URL and that part may have not changed even if some other\n      // portion of the URL did.\n      const currentBrowserUrl = this.urlHandlingStrategy.extract(this.urlSerializer.parse(this.location.path(true)));\n      const targetBrowserUrl = this.currentNavigation?.targetBrowserUrl ?? this.currentNavigation?.extractedUrl;\n      return currentBrowserUrl.toString() !== targetBrowserUrl?.toString() && !this.currentNavigation?.extras.skipLocationChange;\n    }\n    static ɵfac = function NavigationTransitions_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || NavigationTransitions)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: NavigationTransitions,\n      factory: NavigationTransitions.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return NavigationTransitions;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nfunction isBrowserTriggeredNavigation(source) {\n  return source !== IMPERATIVE_NAVIGATION;\n}\n\n/**\n * @description\n *\n * Provides a way to customize when activated routes get reused.\n *\n * @publicApi\n */\nlet RouteReuseStrategy = /*#__PURE__*/(() => {\n  class RouteReuseStrategy {\n    static ɵfac = function RouteReuseStrategy_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || RouteReuseStrategy)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: RouteReuseStrategy,\n      factory: () => (() => inject(DefaultRouteReuseStrategy))(),\n      providedIn: 'root'\n    });\n  }\n  return RouteReuseStrategy;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n/**\n * @description\n *\n * This base route reuse strategy only reuses routes when the matched router configs are\n * identical. This prevents components from being destroyed and recreated\n * when just the route parameters, query parameters or fragment change\n * (that is, the existing component is _reused_).\n *\n * This strategy does not store any routes for later reuse.\n *\n * Angular uses this strategy by default.\n *\n *\n * It can be used as a base class for custom route reuse strategies, i.e. you can create your own\n * class that extends the `BaseRouteReuseStrategy` one.\n * @publicApi\n */\nclass BaseRouteReuseStrategy {\n  /**\n   * Whether the given route should detach for later reuse.\n   * Always returns false for `BaseRouteReuseStrategy`.\n   * */\n  shouldDetach(route) {\n    return false;\n  }\n  /**\n   * A no-op; the route is never stored since this strategy never detaches routes for later re-use.\n   */\n  store(route, detachedTree) {}\n  /** Returns `false`, meaning the route (and its subtree) is never reattached */\n  shouldAttach(route) {\n    return false;\n  }\n  /** Returns `null` because this strategy does not store routes for later re-use. */\n  retrieve(route) {\n    return null;\n  }\n  /**\n   * Determines if a route should be reused.\n   * This strategy returns `true` when the future route config and current route config are\n   * identical.\n   */\n  shouldReuseRoute(future, curr) {\n    return future.routeConfig === curr.routeConfig;\n  }\n}\nlet DefaultRouteReuseStrategy = /*#__PURE__*/(() => {\n  class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {\n    static ɵfac = /* @__PURE__ */(() => {\n      let ɵDefaultRouteReuseStrategy_BaseFactory;\n      return function DefaultRouteReuseStrategy_Factory(__ngFactoryType__) {\n        return (ɵDefaultRouteReuseStrategy_BaseFactory || (ɵDefaultRouteReuseStrategy_BaseFactory = i0.ɵɵgetInheritedFactory(DefaultRouteReuseStrategy)))(__ngFactoryType__ || DefaultRouteReuseStrategy);\n      };\n    })();\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: DefaultRouteReuseStrategy,\n      factory: DefaultRouteReuseStrategy.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return DefaultRouteReuseStrategy;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nlet StateManager = /*#__PURE__*/(() => {\n  class StateManager {\n    urlSerializer = inject(UrlSerializer);\n    options = inject(ROUTER_CONFIGURATION, {\n      optional: true\n    }) || {};\n    canceledNavigationResolution = this.options.canceledNavigationResolution || 'replace';\n    location = inject(Location);\n    urlHandlingStrategy = inject(UrlHandlingStrategy);\n    urlUpdateStrategy = this.options.urlUpdateStrategy || 'deferred';\n    currentUrlTree = new UrlTree();\n    /**\n     * Returns the currently activated `UrlTree`.\n     *\n     * This `UrlTree` shows only URLs that the `Router` is configured to handle (through\n     * `UrlHandlingStrategy`).\n     *\n     * The value is set after finding the route config tree to activate but before activating the\n     * route.\n     */\n    getCurrentUrlTree() {\n      return this.currentUrlTree;\n    }\n    rawUrlTree = this.currentUrlTree;\n    /**\n     * Returns a `UrlTree` that is represents what the browser is actually showing.\n     *\n     * In the life of a navigation transition:\n     * 1. When a navigation begins, the raw `UrlTree` is updated to the full URL that's being\n     * navigated to.\n     * 2. During a navigation, redirects are applied, which might only apply to _part_ of the URL (due\n     * to `UrlHandlingStrategy`).\n     * 3. Just before activation, the raw `UrlTree` is updated to include the redirects on top of the\n     * original raw URL.\n     *\n     * Note that this is _only_ here to support `UrlHandlingStrategy.extract` and\n     * `UrlHandlingStrategy.shouldProcessUrl`. Without those APIs, the current `UrlTree` would not\n     * deviated from the raw `UrlTree`.\n     *\n     * For `extract`, a raw `UrlTree` is needed because `extract` may only return part\n     * of the navigation URL. Thus, the current `UrlTree` may only represent _part_ of the browser\n     * URL. When a navigation gets cancelled and the router needs to reset the URL or a new navigation\n     * occurs, it needs to know the _whole_ browser URL, not just the part handled by\n     * `UrlHandlingStrategy`.\n     * For `shouldProcessUrl`, when the return is `false`, the router ignores the navigation but\n     * still updates the raw `UrlTree` with the assumption that the navigation was caused by the\n     * location change listener due to a URL update by the AngularJS router. In this case, the router\n     * still need to know what the browser's URL is for future navigations.\n     */\n    getRawUrlTree() {\n      return this.rawUrlTree;\n    }\n    createBrowserPath({\n      finalUrl,\n      initialUrl,\n      targetBrowserUrl\n    }) {\n      const rawUrl = finalUrl !== undefined ? this.urlHandlingStrategy.merge(finalUrl, initialUrl) : initialUrl;\n      const url = targetBrowserUrl ?? rawUrl;\n      const path = url instanceof UrlTree ? this.urlSerializer.serialize(url) : url;\n      return path;\n    }\n    commitTransition({\n      targetRouterState,\n      finalUrl,\n      initialUrl\n    }) {\n      // If we are committing the transition after having a final URL and target state, we're updating\n      // all pieces of the state. Otherwise, we likely skipped the transition (due to URL handling strategy)\n      // and only want to update the rawUrlTree, which represents the browser URL (and doesn't necessarily match router state).\n      if (finalUrl && targetRouterState) {\n        this.currentUrlTree = finalUrl;\n        this.rawUrlTree = this.urlHandlingStrategy.merge(finalUrl, initialUrl);\n        this.routerState = targetRouterState;\n      } else {\n        this.rawUrlTree = initialUrl;\n      }\n    }\n    routerState = createEmptyState(null);\n    /** Returns the current RouterState. */\n    getRouterState() {\n      return this.routerState;\n    }\n    stateMemento = this.createStateMemento();\n    updateStateMemento() {\n      this.stateMemento = this.createStateMemento();\n    }\n    createStateMemento() {\n      return {\n        rawUrlTree: this.rawUrlTree,\n        currentUrlTree: this.currentUrlTree,\n        routerState: this.routerState\n      };\n    }\n    resetInternalState({\n      finalUrl\n    }) {\n      this.routerState = this.stateMemento.routerState;\n      this.currentUrlTree = this.stateMemento.currentUrlTree;\n      // Note here that we use the urlHandlingStrategy to get the reset `rawUrlTree` because it may be\n      // configured to handle only part of the navigation URL. This means we would only want to reset\n      // the part of the navigation handled by the Angular router rather than the whole URL. In\n      // addition, the URLHandlingStrategy may be configured to specifically preserve parts of the URL\n      // when merging, such as the query params so they are not lost on a refresh.\n      this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, finalUrl ?? this.rawUrlTree);\n    }\n    static ɵfac = function StateManager_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || StateManager)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: StateManager,\n      factory: () => (() => inject(HistoryStateManager))(),\n      providedIn: 'root'\n    });\n  }\n  return StateManager;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nlet HistoryStateManager = /*#__PURE__*/(() => {\n  class HistoryStateManager extends StateManager {\n    /**\n     * The id of the currently active page in the router.\n     * Updated to the transition's target id on a successful navigation.\n     *\n     * This is used to track what page the router last activated. When an attempted navigation fails,\n     * the router can then use this to compute how to restore the state back to the previously active\n     * page.\n     */\n    currentPageId = 0;\n    lastSuccessfulId = -1;\n    restoredState() {\n      return this.location.getState();\n    }\n    /**\n     * The ɵrouterPageId of whatever page is currently active in the browser history. This is\n     * important for computing the target page id for new navigations because we need to ensure each\n     * page id in the browser history is 1 more than the previous entry.\n     */\n    get browserPageId() {\n      if (this.canceledNavigationResolution !== 'computed') {\n        return this.currentPageId;\n      }\n      return this.restoredState()?.ɵrouterPageId ?? this.currentPageId;\n    }\n    registerNonRouterCurrentEntryChangeListener(listener) {\n      return this.location.subscribe(event => {\n        if (event['type'] === 'popstate') {\n          // The `setTimeout` was added in #12160 and is likely to support Angular/AngularJS\n          // hybrid apps.\n          setTimeout(() => {\n            listener(event['url'], event.state, 'popstate');\n          });\n        }\n      });\n    }\n    handleRouterEvent(e, currentTransition) {\n      if (e instanceof NavigationStart) {\n        this.updateStateMemento();\n      } else if (e instanceof NavigationSkipped) {\n        this.commitTransition(currentTransition);\n      } else if (e instanceof RoutesRecognized) {\n        if (this.urlUpdateStrategy === 'eager') {\n          if (!currentTransition.extras.skipLocationChange) {\n            this.setBrowserUrl(this.createBrowserPath(currentTransition), currentTransition);\n          }\n        }\n      } else if (e instanceof BeforeActivateRoutes) {\n        this.commitTransition(currentTransition);\n        if (this.urlUpdateStrategy === 'deferred' && !currentTransition.extras.skipLocationChange) {\n          this.setBrowserUrl(this.createBrowserPath(currentTransition), currentTransition);\n        }\n      } else if (e instanceof NavigationCancel && (e.code === NavigationCancellationCode.GuardRejected || e.code === NavigationCancellationCode.NoDataFromResolver)) {\n        this.restoreHistory(currentTransition);\n      } else if (e instanceof NavigationError) {\n        this.restoreHistory(currentTransition, true);\n      } else if (e instanceof NavigationEnd) {\n        this.lastSuccessfulId = e.id;\n        this.currentPageId = this.browserPageId;\n      }\n    }\n    setBrowserUrl(path, {\n      extras,\n      id\n    }) {\n      const {\n        replaceUrl,\n        state\n      } = extras;\n      if (this.location.isCurrentPathEqualTo(path) || !!replaceUrl) {\n        // replacements do not update the target page\n        const currentBrowserPageId = this.browserPageId;\n        const newState = {\n          ...state,\n          ...this.generateNgRouterState(id, currentBrowserPageId)\n        };\n        this.location.replaceState(path, '', newState);\n      } else {\n        const newState = {\n          ...state,\n          ...this.generateNgRouterState(id, this.browserPageId + 1)\n        };\n        this.location.go(path, '', newState);\n      }\n    }\n    /**\n     * Performs the necessary rollback action to restore the browser URL to the\n     * state before the transition.\n     */\n    restoreHistory(navigation, restoringFromCaughtError = false) {\n      if (this.canceledNavigationResolution === 'computed') {\n        const currentBrowserPageId = this.browserPageId;\n        const targetPagePosition = this.currentPageId - currentBrowserPageId;\n        if (targetPagePosition !== 0) {\n          this.location.historyGo(targetPagePosition);\n        } else if (this.getCurrentUrlTree() === navigation.finalUrl && targetPagePosition === 0) {\n          // We got to the activation stage (where currentUrlTree is set to the navigation's\n          // finalUrl), but we weren't moving anywhere in history (skipLocationChange or replaceUrl).\n          // We still need to reset the router state back to what it was when the navigation started.\n          this.resetInternalState(navigation);\n          this.resetUrlToCurrentUrlTree();\n        } else ;\n      } else if (this.canceledNavigationResolution === 'replace') {\n        // TODO(atscott): It seems like we should _always_ reset the state here. It would be a no-op\n        // for `deferred` navigations that haven't change the internal state yet because guards\n        // reject. For 'eager' navigations, it seems like we also really should reset the state\n        // because the navigation was cancelled. Investigate if this can be done by running TGP.\n        if (restoringFromCaughtError) {\n          this.resetInternalState(navigation);\n        }\n        this.resetUrlToCurrentUrlTree();\n      }\n    }\n    resetUrlToCurrentUrlTree() {\n      this.location.replaceState(this.urlSerializer.serialize(this.getRawUrlTree()), '', this.generateNgRouterState(this.lastSuccessfulId, this.currentPageId));\n    }\n    generateNgRouterState(navigationId, routerPageId) {\n      if (this.canceledNavigationResolution === 'computed') {\n        return {\n          navigationId,\n          ɵrouterPageId: routerPageId\n        };\n      }\n      return {\n        navigationId\n      };\n    }\n    static ɵfac = /* @__PURE__ */(() => {\n      let ɵHistoryStateManager_BaseFactory;\n      return function HistoryStateManager_Factory(__ngFactoryType__) {\n        return (ɵHistoryStateManager_BaseFactory || (ɵHistoryStateManager_BaseFactory = i0.ɵɵgetInheritedFactory(HistoryStateManager)))(__ngFactoryType__ || HistoryStateManager);\n      };\n    })();\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: HistoryStateManager,\n      factory: HistoryStateManager.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return HistoryStateManager;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\n\n/**\n * Performs the given action once the router finishes its next/current navigation.\n *\n * The navigation is considered complete under the following conditions:\n * - `NavigationCancel` event emits and the code is not `NavigationCancellationCode.Redirect` or\n * `NavigationCancellationCode.SupersededByNewNavigation`. In these cases, the\n * redirecting/superseding navigation must finish.\n * - `NavigationError`, `NavigationEnd`, or `NavigationSkipped` event emits\n */\nfunction afterNextNavigation(router, action) {\n  router.events.pipe(filter(e => e instanceof NavigationEnd || e instanceof NavigationCancel || e instanceof NavigationError || e instanceof NavigationSkipped), map(e => {\n    if (e instanceof NavigationEnd || e instanceof NavigationSkipped) {\n      return 0 /* NavigationResult.COMPLETE */;\n    }\n    const redirecting = e instanceof NavigationCancel ? e.code === NavigationCancellationCode.Redirect || e.code === NavigationCancellationCode.SupersededByNewNavigation : false;\n    return redirecting ? 2 /* NavigationResult.REDIRECTING */ : 1 /* NavigationResult.FAILED */;\n  }), filter(result => result !== 2 /* NavigationResult.REDIRECTING */), take(1)).subscribe(() => {\n    action();\n  });\n}\n\n/**\n * The equivalent `IsActiveMatchOptions` options for `Router.isActive` is called with `true`\n * (exact = true).\n */\nconst exactMatchOptions = {\n  paths: 'exact',\n  fragment: 'ignored',\n  matrixParams: 'ignored',\n  queryParams: 'exact'\n};\n/**\n * The equivalent `IsActiveMatchOptions` options for `Router.isActive` is called with `false`\n * (exact = false).\n */\nconst subsetMatchOptions = {\n  paths: 'subset',\n  fragment: 'ignored',\n  matrixParams: 'ignored',\n  queryParams: 'subset'\n};\n/**\n * @description\n *\n * A service that facilitates navigation among views and URL manipulation capabilities.\n * This service is provided in the root scope and configured with [provideRouter](api/router/provideRouter).\n *\n * @see {@link Route}\n * @see {@link provideRouter}\n * @see [Routing and Navigation Guide](guide/routing/common-router-tasks).\n *\n * @ngModule RouterModule\n *\n * @publicApi\n */\nlet Router = /*#__PURE__*/(() => {\n  class Router {\n    get currentUrlTree() {\n      return this.stateManager.getCurrentUrlTree();\n    }\n    get rawUrlTree() {\n      return this.stateManager.getRawUrlTree();\n    }\n    disposed = false;\n    nonRouterCurrentEntryChangeSubscription;\n    console = inject(_Console);\n    stateManager = inject(StateManager);\n    options = inject(ROUTER_CONFIGURATION, {\n      optional: true\n    }) || {};\n    pendingTasks = inject(_PendingTasksInternal);\n    urlUpdateStrategy = this.options.urlUpdateStrategy || 'deferred';\n    navigationTransitions = inject(NavigationTransitions);\n    urlSerializer = inject(UrlSerializer);\n    location = inject(Location);\n    urlHandlingStrategy = inject(UrlHandlingStrategy);\n    /**\n     * The private `Subject` type for the public events exposed in the getter. This is used internally\n     * to push events to. The separate field allows us to expose separate types in the public API\n     * (i.e., an Observable rather than the Subject).\n     */\n    _events = new Subject();\n    /**\n     * An event stream for routing events.\n     */\n    get events() {\n      // TODO(atscott): This _should_ be events.asObservable(). However, this change requires internal\n      // cleanup: tests are doing `(route.events as Subject<Event>).next(...)`. This isn't\n      // allowed/supported but we still have to fix these or file bugs against the teams before making\n      // the change.\n      return this._events;\n    }\n    /**\n     * The current state of routing in this NgModule.\n     */\n    get routerState() {\n      return this.stateManager.getRouterState();\n    }\n    /**\n     * True if at least one navigation event has occurred,\n     * false otherwise.\n     */\n    navigated = false;\n    /**\n     * A strategy for re-using routes.\n     *\n     * @deprecated Configure using `providers` instead:\n     *   `{provide: RouteReuseStrategy, useClass: MyStrategy}`.\n     */\n    routeReuseStrategy = inject(RouteReuseStrategy);\n    /**\n     * How to handle a navigation request to the current URL.\n     *\n     *\n     * @deprecated Configure this through `provideRouter` or `RouterModule.forRoot` instead.\n     * @see {@link withRouterConfig}\n     * @see {@link provideRouter}\n     * @see {@link RouterModule}\n     */\n    onSameUrlNavigation = this.options.onSameUrlNavigation || 'ignore';\n    config = inject(ROUTES, {\n      optional: true\n    })?.flat() ?? [];\n    /**\n     * Indicates whether the application has opted in to binding Router data to component inputs.\n     *\n     * This option is enabled by the `withComponentInputBinding` feature of `provideRouter` or\n     * `bindToComponentInputs` in the `ExtraOptions` of `RouterModule.forRoot`.\n     */\n    componentInputBindingEnabled = !!inject(INPUT_BINDER, {\n      optional: true\n    });\n    constructor() {\n      this.resetConfig(this.config);\n      this.navigationTransitions.setupNavigations(this).subscribe({\n        error: e => {\n          this.console.warn(ngDevMode ? `Unhandled Navigation Error: ${e}` : e);\n        }\n      });\n      this.subscribeToNavigationEvents();\n    }\n    eventsSubscription = new Subscription();\n    subscribeToNavigationEvents() {\n      const subscription = this.navigationTransitions.events.subscribe(e => {\n        try {\n          const currentTransition = this.navigationTransitions.currentTransition;\n          const currentNavigation = this.navigationTransitions.currentNavigation;\n          if (currentTransition !== null && currentNavigation !== null) {\n            this.stateManager.handleRouterEvent(e, currentNavigation);\n            if (e instanceof NavigationCancel && e.code !== NavigationCancellationCode.Redirect && e.code !== NavigationCancellationCode.SupersededByNewNavigation) {\n              // It seems weird that `navigated` is set to `true` when the navigation is rejected,\n              // however it's how things were written initially. Investigation would need to be done\n              // to determine if this can be removed.\n              this.navigated = true;\n            } else if (e instanceof NavigationEnd) {\n              this.navigated = true;\n            } else if (e instanceof RedirectRequest) {\n              const opts = e.navigationBehaviorOptions;\n              const mergedTree = this.urlHandlingStrategy.merge(e.url, currentTransition.currentRawUrl);\n              const extras = {\n                browserUrl: currentTransition.extras.browserUrl,\n                info: currentTransition.extras.info,\n                skipLocationChange: currentTransition.extras.skipLocationChange,\n                // The URL is already updated at this point if we have 'eager' URL\n                // updates or if the navigation was triggered by the browser (back\n                // button, URL bar, etc). We want to replace that item in history\n                // if the navigation is rejected.\n                replaceUrl: currentTransition.extras.replaceUrl || this.urlUpdateStrategy === 'eager' || isBrowserTriggeredNavigation(currentTransition.source),\n                // allow developer to override default options with RedirectCommand\n                ...opts\n              };\n              this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras, {\n                resolve: currentTransition.resolve,\n                reject: currentTransition.reject,\n                promise: currentTransition.promise\n              });\n            }\n          }\n          // Note that it's important to have the Router process the events _before_ the event is\n          // pushed through the public observable. This ensures the correct router state is in place\n          // before applications observe the events.\n          if (isPublicRouterEvent(e)) {\n            this._events.next(e);\n          }\n        } catch (e) {\n          this.navigationTransitions.transitionAbortSubject.next(e);\n        }\n      });\n      this.eventsSubscription.add(subscription);\n    }\n    /** @internal */\n    resetRootComponentType(rootComponentType) {\n      // TODO: vsavkin router 4.0 should make the root component set to null\n      // this will simplify the lifecycle of the router.\n      this.routerState.root.component = rootComponentType;\n      this.navigationTransitions.rootComponentType = rootComponentType;\n    }\n    /**\n     * Sets up the location change listener and performs the initial navigation.\n     */\n    initialNavigation() {\n      this.setUpLocationChangeListener();\n      if (!this.navigationTransitions.hasRequestedNavigation) {\n        this.navigateToSyncWithBrowser(this.location.path(true), IMPERATIVE_NAVIGATION, this.stateManager.restoredState());\n      }\n    }\n    /**\n     * Sets up the location change listener. This listener detects navigations triggered from outside\n     * the Router (the browser back/forward buttons, for example) and schedules a corresponding Router\n     * navigation so that the correct events, guards, etc. are triggered.\n     */\n    setUpLocationChangeListener() {\n      // Don't need to use Zone.wrap any more, because zone.js\n      // already patch onPopState, so location change callback will\n      // run into ngZone\n      this.nonRouterCurrentEntryChangeSubscription ??= this.stateManager.registerNonRouterCurrentEntryChangeListener((url, state, source) => {\n        this.navigateToSyncWithBrowser(url, source, state);\n      });\n    }\n    /**\n     * Schedules a router navigation to synchronize Router state with the browser state.\n     *\n     * This is done as a response to a popstate event and the initial navigation. These\n     * two scenarios represent times when the browser URL/state has been updated and\n     * the Router needs to respond to ensure its internal state matches.\n     */\n    navigateToSyncWithBrowser(url, source, state) {\n      const extras = {\n        replaceUrl: true\n      };\n      // TODO: restoredState should always include the entire state, regardless\n      // of navigationId. This requires a breaking change to update the type on\n      // NavigationStart’s restoredState, which currently requires navigationId\n      // to always be present. The Router used to only restore history state if\n      // a navigationId was present.\n      // The stored navigationId is used by the RouterScroller to retrieve the scroll\n      // position for the page.\n      const restoredState = state?.navigationId ? state : null;\n      // Separate to NavigationStart.restoredState, we must also restore the state to\n      // history.state and generate a new navigationId, since it will be overwritten\n      if (state) {\n        const stateCopy = {\n          ...state\n        };\n        delete stateCopy.navigationId;\n        delete stateCopy.ɵrouterPageId;\n        if (Object.keys(stateCopy).length !== 0) {\n          extras.state = stateCopy;\n        }\n      }\n      const urlTree = this.parseUrl(url);\n      this.scheduleNavigation(urlTree, source, restoredState, extras);\n    }\n    /** The current URL. */\n    get url() {\n      return this.serializeUrl(this.currentUrlTree);\n    }\n    /**\n     * Returns the current `Navigation` object when the router is navigating,\n     * and `null` when idle.\n     */\n    getCurrentNavigation() {\n      return this.navigationTransitions.currentNavigation;\n    }\n    /**\n     * The `Navigation` object of the most recent navigation to succeed and `null` if there\n     *     has not been a successful navigation yet.\n     */\n    get lastSuccessfulNavigation() {\n      return this.navigationTransitions.lastSuccessfulNavigation;\n    }\n    /**\n     * Resets the route configuration used for navigation and generating links.\n     *\n     * @param config The route array for the new configuration.\n     *\n     * @usageNotes\n     *\n     * ```ts\n     * router.resetConfig([\n     *  { path: 'team/:id', component: TeamCmp, children: [\n     *    { path: 'simple', component: SimpleCmp },\n     *    { path: 'user/:name', component: UserCmp }\n     *  ]}\n     * ]);\n     * ```\n     */\n    resetConfig(config) {\n      (typeof ngDevMode === 'undefined' || ngDevMode) && validateConfig(config);\n      this.config = config.map(standardizeConfig);\n      this.navigated = false;\n    }\n    /** @docs-private */\n    ngOnDestroy() {\n      this.dispose();\n    }\n    /** Disposes of the router. */\n    dispose() {\n      // We call `unsubscribe()` to release observers, as users may forget to\n      // unsubscribe manually when subscribing to `router.events`. We do not call\n      // `complete()` because it is unsafe; if someone subscribes using the `first`\n      // operator and the observable completes before emitting a value,\n      // RxJS will throw an error.\n      this._events.unsubscribe();\n      this.navigationTransitions.complete();\n      if (this.nonRouterCurrentEntryChangeSubscription) {\n        this.nonRouterCurrentEntryChangeSubscription.unsubscribe();\n        this.nonRouterCurrentEntryChangeSubscription = undefined;\n      }\n      this.disposed = true;\n      this.eventsSubscription.unsubscribe();\n    }\n    /**\n     * Appends URL segments to the current URL tree to create a new URL tree.\n     *\n     * @param commands An array of URL fragments with which to construct the new URL tree.\n     * If the path is static, can be the literal URL string. For a dynamic path, pass an array of path\n     * segments, followed by the parameters for each segment.\n     * The fragments are applied to the current URL tree or the one provided  in the `relativeTo`\n     * property of the options object, if supplied.\n     * @param navigationExtras Options that control the navigation strategy.\n     * @returns The new URL tree.\n     *\n     * @usageNotes\n     *\n     * ```\n     * // create /team/33/user/11\n     * router.createUrlTree(['/team', 33, 'user', 11]);\n     *\n     * // create /team/33;expand=true/user/11\n     * router.createUrlTree(['/team', 33, {expand: true}, 'user', 11]);\n     *\n     * // you can collapse static segments like this (this works only with the first passed-in value):\n     * router.createUrlTree(['/team/33/user', userId]);\n     *\n     * // If the first segment can contain slashes, and you do not want the router to split it,\n     * // you can do the following:\n     * router.createUrlTree([{segmentPath: '/one/two'}]);\n     *\n     * // create /team/33/(user/11//right:chat)\n     * router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: 'chat'}}]);\n     *\n     * // remove the right secondary node\n     * router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: null}}]);\n     *\n     * // assuming the current url is `/team/33/user/11` and the route points to `user/11`\n     *\n     * // navigate to /team/33/user/11/details\n     * router.createUrlTree(['details'], {relativeTo: route});\n     *\n     * // navigate to /team/33/user/22\n     * router.createUrlTree(['../22'], {relativeTo: route});\n     *\n     * // navigate to /team/44/user/22\n     * router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});\n     *\n     * Note that a value of `null` or `undefined` for `relativeTo` indicates that the\n     * tree should be created relative to the root.\n     * ```\n     */\n    createUrlTree(commands, navigationExtras = {}) {\n      const {\n        relativeTo,\n        queryParams,\n        fragment,\n        queryParamsHandling,\n        preserveFragment\n      } = navigationExtras;\n      const f = preserveFragment ? this.currentUrlTree.fragment : fragment;\n      let q = null;\n      switch (queryParamsHandling ?? this.options.defaultQueryParamsHandling) {\n        case 'merge':\n          q = {\n            ...this.currentUrlTree.queryParams,\n            ...queryParams\n          };\n          break;\n        case 'preserve':\n          q = this.currentUrlTree.queryParams;\n          break;\n        default:\n          q = queryParams || null;\n      }\n      if (q !== null) {\n        q = this.removeEmptyProps(q);\n      }\n      let relativeToUrlSegmentGroup;\n      try {\n        const relativeToSnapshot = relativeTo ? relativeTo.snapshot : this.routerState.snapshot.root;\n        relativeToUrlSegmentGroup = createSegmentGroupFromRoute(relativeToSnapshot);\n      } catch (e) {\n        // This is strictly for backwards compatibility with tests that create\n        // invalid `ActivatedRoute` mocks.\n        // Note: the difference between having this fallback for invalid `ActivatedRoute` setups and\n        // just throwing is ~500 test failures. Fixing all of those tests by hand is not feasible at\n        // the moment.\n        if (typeof commands[0] !== 'string' || commands[0][0] !== '/') {\n          // Navigations that were absolute in the old way of creating UrlTrees\n          // would still work because they wouldn't attempt to match the\n          // segments in the `ActivatedRoute` to the `currentUrlTree` but\n          // instead just replace the root segment with the navigation result.\n          // Non-absolute navigations would fail to apply the commands because\n          // the logic could not find the segment to replace (so they'd act like there were no\n          // commands).\n          commands = [];\n        }\n        relativeToUrlSegmentGroup = this.currentUrlTree.root;\n      }\n      return createUrlTreeFromSegmentGroup(relativeToUrlSegmentGroup, commands, q, f ?? null);\n    }\n    /**\n     * Navigates to a view using an absolute route path.\n     *\n     * @param url An absolute path for a defined route. The function does not apply any delta to the\n     *     current URL.\n     * @param extras An object containing properties that modify the navigation strategy.\n     *\n     * @returns A Promise that resolves to 'true' when navigation succeeds,\n     * to 'false' when navigation fails, or is rejected on error.\n     *\n     * @usageNotes\n     *\n     * The following calls request navigation to an absolute path.\n     *\n     * ```ts\n     * router.navigateByUrl(\"/team/33/user/11\");\n     *\n     * // Navigate without updating the URL\n     * router.navigateByUrl(\"/team/33/user/11\", { skipLocationChange: true });\n     * ```\n     *\n     * @see [Routing and Navigation guide](guide/routing/common-router-tasks)\n     *\n     */\n    navigateByUrl(url, extras = {\n      skipLocationChange: false\n    }) {\n      const urlTree = isUrlTree(url) ? url : this.parseUrl(url);\n      const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);\n      return this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras);\n    }\n    /**\n     * Navigate based on the provided array of commands and a starting point.\n     * If no starting route is provided, the navigation is absolute.\n     *\n     * @param commands An array of URL fragments with which to construct the target URL.\n     * If the path is static, can be the literal URL string. For a dynamic path, pass an array of path\n     * segments, followed by the parameters for each segment.\n     * The fragments are applied to the current URL or the one provided  in the `relativeTo` property\n     * of the options object, if supplied.\n     * @param extras An options object that determines how the URL should be constructed or\n     *     interpreted.\n     *\n     * @returns A Promise that resolves to `true` when navigation succeeds, or `false` when navigation\n     *     fails. The Promise is rejected when an error occurs if `resolveNavigationPromiseOnError` is\n     * not `true`.\n     *\n     * @usageNotes\n     *\n     * The following calls request navigation to a dynamic route path relative to the current URL.\n     *\n     * ```ts\n     * router.navigate(['team', 33, 'user', 11], {relativeTo: route});\n     *\n     * // Navigate without updating the URL, overriding the default behavior\n     * router.navigate(['team', 33, 'user', 11], {relativeTo: route, skipLocationChange: true});\n     * ```\n     *\n     * @see [Routing and Navigation guide](guide/routing/common-router-tasks)\n     *\n     */\n    navigate(commands, extras = {\n      skipLocationChange: false\n    }) {\n      validateCommands(commands);\n      return this.navigateByUrl(this.createUrlTree(commands, extras), extras);\n    }\n    /** Serializes a `UrlTree` into a string */\n    serializeUrl(url) {\n      return this.urlSerializer.serialize(url);\n    }\n    /** Parses a string into a `UrlTree` */\n    parseUrl(url) {\n      try {\n        return this.urlSerializer.parse(url);\n      } catch {\n        return this.urlSerializer.parse('/');\n      }\n    }\n    isActive(url, matchOptions) {\n      let options;\n      if (matchOptions === true) {\n        options = {\n          ...exactMatchOptions\n        };\n      } else if (matchOptions === false) {\n        options = {\n          ...subsetMatchOptions\n        };\n      } else {\n        options = matchOptions;\n      }\n      if (isUrlTree(url)) {\n        return containsTree(this.currentUrlTree, url, options);\n      }\n      const urlTree = this.parseUrl(url);\n      return containsTree(this.currentUrlTree, urlTree, options);\n    }\n    removeEmptyProps(params) {\n      return Object.entries(params).reduce((result, [key, value]) => {\n        if (value !== null && value !== undefined) {\n          result[key] = value;\n        }\n        return result;\n      }, {});\n    }\n    scheduleNavigation(rawUrl, source, restoredState, extras, priorPromise) {\n      if (this.disposed) {\n        return Promise.resolve(false);\n      }\n      let resolve;\n      let reject;\n      let promise;\n      if (priorPromise) {\n        resolve = priorPromise.resolve;\n        reject = priorPromise.reject;\n        promise = priorPromise.promise;\n      } else {\n        promise = new Promise((res, rej) => {\n          resolve = res;\n          reject = rej;\n        });\n      }\n      // Indicate that the navigation is happening.\n      const taskId = this.pendingTasks.add();\n      afterNextNavigation(this, () => {\n        // Remove pending task in a microtask to allow for cancelled\n        // initial navigations and redirects within the same task.\n        queueMicrotask(() => this.pendingTasks.remove(taskId));\n      });\n      this.navigationTransitions.handleNavigationRequest({\n        source,\n        restoredState,\n        currentUrlTree: this.currentUrlTree,\n        currentRawUrl: this.currentUrlTree,\n        rawUrl,\n        extras,\n        resolve: resolve,\n        reject: reject,\n        promise,\n        currentSnapshot: this.routerState.snapshot,\n        currentRouterState: this.routerState\n      });\n      // Make sure that the error is propagated even though `processNavigations` catch\n      // handler does not rethrow\n      return promise.catch(e => {\n        return Promise.reject(e);\n      });\n    }\n    static ɵfac = function Router_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || Router)();\n    };\n    static ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n      token: Router,\n      factory: Router.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return Router;\n})();\n/*#__PURE__*/(() => {\n  (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nfunction validateCommands(commands) {\n  for (let i = 0; i < commands.length; i++) {\n    const cmd = commands[i];\n    if (cmd == null) {\n      throw new _RuntimeError(4008 /* RuntimeErrorCode.NULLISH_COMMAND */, (typeof ngDevMode === 'undefined' || ngDevMode) && `The requested path contains ${cmd} segment at index ${i}`);\n    }\n  }\n}\nfunction isPublicRouterEvent(e) {\n  return !(e instanceof BeforeActivateRoutes) && !(e instanceof RedirectRequest);\n}\nexport { ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, BaseRouteReuseStrategy, CREATE_VIEW_TRANSITION, ChildActivationEnd, ChildActivationStart, ChildrenOutletContexts, DefaultTitleStrategy, DefaultUrlSerializer, EventType, GuardsCheckEnd, GuardsCheckStart, INPUT_BINDER, NAVIGATION_ERROR_HANDLER, NavigationCancel, NavigationCancellationCode, NavigationEnd, NavigationError, NavigationSkipped, NavigationSkippedCode, NavigationStart, NavigationTransitions, OutletContext, PRIMARY_OUTLET, ROUTER_CONFIGURATION, ROUTER_OUTLET_DATA, ROUTES, RedirectCommand, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, RoutedComponentInputBinder, Router, RouterConfigLoader, RouterEvent, RouterOutlet, RouterState, RouterStateSnapshot, RoutesRecognized, Scroll, TitleStrategy, UrlHandlingStrategy, UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree, VIEW_TRANSITION_OPTIONS, afterNextNavigation, convertToParamMap, createUrlTreeFromSnapshot, createViewTransition, defaultUrlMatcher, isUrlTree, loadChildren, stringifyEvent, ɵEmptyOutletComponent };\n//# sourceMappingURL=router-Dwfin5Au.mjs.map","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}