[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"env\", \"flow-vue\"],\n  \"plugins\": [\"syntax-dynamic-import\"]\n}\n"
  },
  {
    "path": ".circleci/config.yml",
    "content": "version: 2\n\ndefaults: &defaults\n  working_directory: ~/project/vue-router\n  docker:\n    - image: circleci/node:lts-browsers\n\njobs:\n  install:\n    <<: *defaults\n    steps:\n      - checkout\n      - restore_cache:\n          keys:\n            - v1-vue-router-{{ .Branch }}-{{ checksum \"yarn.lock\" }}\n            - v1-vue-router-{{ .Branch }}-\n            - v1-vue-router-\n      - run: yarn install\n      - save_cache:\n          key: v1-vue-router-{{ .Branch }}-{{ checksum \"yarn.lock\" }}\n          paths:\n            - node_modules/\n      - persist_to_workspace:\n          root: ~/project\n          paths:\n            - vue-router\n\n  lint-flow-types:\n    <<: *defaults\n    steps:\n      - attach_workspace:\n          at: ~/project\n      - run: yarn run lint\n      - run: yarn run flow\n      - run: yarn run test:types\n\n  test-unit:\n    <<: *defaults\n    steps:\n      - attach_workspace:\n          at: ~/project\n      - run: yarn run test:unit\n      # add codecov once it is actually ran\n      # - run:\n      #    name: report coverage stats for non-PRs\n      #    command: |\n      #      if [[ -z $CI_PULL_REQUEST ]]; then\n      #        ./node_modules/.bin/codecov\n      #      fi\n\n  test-e2e:\n    <<: *defaults\n    steps:\n      - attach_workspace:\n          at: ~/project\n      - run: yarn run test:e2e\n\n  test-e2e-bs-ie9:\n    <<: *defaults\n    steps:\n      - attach_workspace:\n          at: ~/project\n      - run: yarn run test:e2e:ie9\n\nworkflows:\n  version: 2\n  install-and-parallel-test:\n    jobs:\n      - install\n      - test-unit:\n          requires:\n            - install\n      - lint-flow-types:\n          requires:\n            - install\n      - test-e2e:\n          requires:\n            - install\n      - test-e2e-bs-ie9:\n          requires:\n            - install\n"
  },
  {
    "path": ".eslintignore",
    "content": "dist\n*.ts\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"root\": true,\n  \"plugins\": [\n    \"flowtype\"\n  ],\n  \"extends\": [\n    \"plugin:vue-libs/recommended\",\n    \"plugin:flowtype/recommended\"\n  ]\n}\n"
  },
  {
    "path": ".flowconfig",
    "content": "[ignore]\n.*/node_modules/.*\n.*/test/.*\n.*/dist/.*\n.*/examples/.*\n.*/vue/.*\n\n[include]\n\n[libs]\nflow\n\n[options]\n#unsafe.enable_getters_and_setters=true\nsuppress_comment= \\\\(.\\\\|\\n\\\\)*\\\\$flow-disable-line\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nIMPORTANT: Please use the following link to create a new issue:\n\n  https://new-issue.vuejs.org/?repo=vuejs/vue-router\n\nIf your issue was not created using the app above, it will be closed immediately.\n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nPlease make sure to read the Pull Request Guidelines:\nhttps://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines\n-->\n"
  },
  {
    "path": ".github/funding.yml",
    "content": "github: [posva, yyx990803]\nopen_collective: vuejs\n"
  },
  {
    "path": ".github/workflows/release-tag.yml",
    "content": "on:\n  push:\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\nname: Create Release\n\njobs:\n  build:\n    name: Create Release\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@master\n      - name: Create Release for Tag\n        id: release_tag\n        uses: yyx990803/release-tag@master\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: ${{ github.ref }}\n          body: |\n            Please refer to [CHANGELOG.md](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md) for details.\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\nTODOs.md\ntest/e2e/reports\ntest/e2e/screenshots\nselenium-debug.log\ndist/*.gz\ndist/*.map\nexplorations\ndocs/.vuepress/dist\nyarn-error.log\n.idea\n.vscode/settings.json\n.env\nselenium-server.log\nlocal.log\nbrowserstack.err\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"printWidth\": 80\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [3.6.5](https://github.com/vuejs/vue-router/compare/v3.6.4...v3.6.5) (2022-09-06)\n\n### Bug Fixes\n\n- **types:** Component with 4 generics for Vue 2.6 ([d6064df](https://github.com/vuejs/vue-router/commit/d6064df1112497dac98e4302d81607efdb1a58c6)), closes [#3786](https://github.com/vuejs/vue-router/issues/3786)\n\n## [3.6.4](https://github.com/vuejs/vue-router/compare/v3.6.3...v3.6.4) (2022-08-25)\n\nThis release fixes some compatibility issues of the new `vue-router/composables` with webpack 4.\n\n### Features\n\n- **types:** add composables.d.ts in root ([#3784](https://github.com/vuejs/vue-router/issues/3784)) ([0cf54de](https://github.com/vuejs/vue-router/commit/0cf54de782a0b05692bbe78a7181495b6a35b8d9))\n\n## [3.6.3](https://github.com/vuejs/vue-router/compare/v3.6.2...v3.6.3) (2022-08-23)\n\n### Bug Fixes\n\n- **build:** export all named exports esm build ([a6647c8](https://github.com/vuejs/vue-router/commit/a6647c8c3d7022f1b702935461c7d234b052ca06))\n- **types:** allow jsx components ([0cb86b3](https://github.com/vuejs/vue-router/commit/0cb86b3865b713201f9db49c7a8d23e9a2876f29)), closes [#3776](https://github.com/vuejs/vue-router/issues/3776)\n- **types:** missing NavigationFailureType and isNavigationFailure ([#3777](https://github.com/vuejs/vue-router/issues/3777)) ([9d001dd](https://github.com/vuejs/vue-router/commit/9d001dd0bebdea1e1a8ec2f0c77113b6a2e2b6a3))\n\n## [3.6.2](https://github.com/vuejs/vue-router/compare/v3.6.1...v3.6.2) (2022-08-23)\n\n### Bug Fixes\n\n- **build:** add mjs build ([b4c3940](https://github.com/vuejs/vue-router/commit/b4c39404eff7ae2f657c405d7b0f939ce20cfdec))\n- **types:** missing start location ([1356acb](https://github.com/vuejs/vue-router/commit/1356acb983c5eccb00c5c0ec3f406218ae49a8c1))\n\n## [3.6.1](https://github.com/vuejs/vue-router/compare/v3.6.0...v3.6.1) (2022-08-23)\n\n### Bug Fixes\n\n- **build:** ensure install fn before Vue.use ([0126bcb](https://github.com/vuejs/vue-router/commit/0126bcbfb0e3cb824bfce05090ca018faf02ce5e)), closes [#3772](https://github.com/vuejs/vue-router/issues/3772)\n\n# [3.6.0](https://github.com/vuejs/vue-router/compare/v3.5.4...v3.6.0) (2022-08-22)\n\nThis release of Vue Router introduces composables from Vue Router 4:\n\n```js\nimport { useRoute, useRouter, useLink, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router/composables'\n```\n\nSince these composables **require Vue 2.7**, they are only exposed under `vue-router/composables` submodule, so it shouldn't affect you if you stay on Vue 2.6 (Note there are no new features or fixes besides the composables in this release). Refer to [the Vue Router 4 API documentation](https://router.vuejs.org/api/#onbeforerouteleave) for details on the composables.\n\n### Features\n\n- **types:** useLink() ([77bd0e3](https://github.com/vuejs/vue-router/commit/77bd0e317dd5a9aebfca515f0f28f3284c7d8260))\n- useLink() ([50332e5](https://github.com/vuejs/vue-router/commit/50332e5e93e6aa1194a9e68a60937a6f9e8bcecd))\n- **types:** expose RouterLink and RouterView in d.ts ([cad978a](https://github.com/vuejs/vue-router/commit/cad978a832174aac59cad86fe780f8a64a9754d7))\n- add RouterLink and RouterView to esm ([4511f39](https://github.com/vuejs/vue-router/commit/4511f393334247c9702ed378220bf925cdc09add))\n- add vue 2.7 types ([cba9650](https://github.com/vuejs/vue-router/commit/cba9650e5cbf958c1db9cd259a2e7bfbc28bddbe))\n- onBeforeRouteUpdate onBeforeRouteLeave ([9861c55](https://github.com/vuejs/vue-router/commit/9861c553627f5f34a07ad3ac28e2ed02aab99d47))\n- useRoute and useRouter ([ea35594](https://github.com/vuejs/vue-router/commit/ea355943e097914ae55fa54ccb7df929c901e80d))\n\n## [3.5.4](https://github.com/vuejs/vue-router/compare/v3.5.3...v3.5.4) (2022-05-16)\n\n### Bug Fixes\n\n- remove whitespace between mulitple slashes ([86d7f1f](https://github.com/vuejs/vue-router/commit/86d7f1fdaa36432f6564309925690ec20bb2981e)), closes [#3743](https://github.com/vuejs/vue-router/issues/3743)\n\n## [3.5.3](https://github.com/vuejs/vue-router/compare/v3.5.2...v3.5.3) (2021-10-26)\n\n### Bug Fixes\n\n- clean more than two consecutive slashes ([#3652](https://github.com/vuejs/vue-router/issues/3652)) ([3e3a07e](https://github.com/vuejs/vue-router/commit/3e3a07ee6e7defd6cae75bddcede5a28b0092709))\n- **scrollBehavior:** trigger scroll behavior if same route with hash ([#3592](https://github.com/vuejs/vue-router/issues/3592)) ([57d8042](https://github.com/vuejs/vue-router/commit/57d8042c8b99f92bfe35493b8ae9bba827864bf0))\n\n### Features\n\n- add constructor hint ([#3626](https://github.com/vuejs/vue-router/issues/3626)) ([28b769b](https://github.com/vuejs/vue-router/commit/28b769b2a07e3bf984c0ec20d6d797291a480e81))\n\n## [3.5.2](https://github.com/vuejs/vue-router/compare/v3.5.1...v3.5.2) (2021-06-21)\n\n### Bug Fixes\n\n- **history:** stricter check of base in HTML5 ([#3556](https://github.com/vuejs/vue-router/issues/3556)) ([11dd184](https://github.com/vuejs/vue-router/commit/11dd184dc6a872c6399977fa4b7c259225ce4834))\n- **types:** added missing router.match ([#3554](https://github.com/vuejs/vue-router/issues/3554)) ([394a3b6](https://github.com/vuejs/vue-router/commit/394a3b6cce5e395ae4ccf3e2efb0c115d492978c))\n\n## [3.5.1](https://github.com/vuejs/vue-router/compare/v3.5.0...v3.5.1) (2021-01-26)\n\n### Bug Fixes\n\n- **warn:** only warn if \"tag\" or \"event\" is used ([#3458](https://github.com/vuejs/vue-router/issues/3458)) ([b7a31b9](https://github.com/vuejs/vue-router/commit/b7a31b9)), closes [#3457](https://github.com/vuejs/vue-router/issues/3457)\n\n# [3.5.0](https://github.com/vuejs/vue-router/compare/v3.4.9...v3.5.0) (2021-01-25)\n\n### Features\n\n- **link:** exact-path prop ([825328e](https://github.com/vuejs/vue-router/commit/825328e)), closes [#2040](https://github.com/vuejs/vue-router/issues/2040)\n- **warn:** warn deprecated addRoutes ([2e41445](https://github.com/vuejs/vue-router/commit/2e41445))\n- expose START_LOCATION ([53b68dd](https://github.com/vuejs/vue-router/commit/53b68dd)), closes [#2718](https://github.com/vuejs/vue-router/issues/2718)\n- **link:** deprecate v-slot without custom prop ([ceeda4c](https://github.com/vuejs/vue-router/commit/ceeda4c))\n- **link:** warn deprecated props ([d2cb951](https://github.com/vuejs/vue-router/commit/d2cb951))\n- **router:** add getRoutes ([6bc30aa](https://github.com/vuejs/vue-router/commit/6bc30aa))\n- **types:** add types for getRoutes addRoute ([fb9bb60](https://github.com/vuejs/vue-router/commit/fb9bb60))\n- addRoute as nested route ([ca80c44](https://github.com/vuejs/vue-router/commit/ca80c44)), closes [#1156](https://github.com/vuejs/vue-router/issues/1156)\n\n## [3.4.9](https://github.com/vuejs/vue-router/compare/v3.4.8...v3.4.9) (2020-11-05)\n\n### Bug Fixes\n\n- **encoding:** decode params ([#3350](https://github.com/vuejs/vue-router/issues/3350)) ([63c749c](https://github.com/vuejs/vue-router/commit/63c749c))\n\n## [3.4.8](https://github.com/vuejs/vue-router/compare/v3.4.7...v3.4.8) (2020-10-26)\n\n### Features\n\n- **scroll:** add behavior support on scrollBehavior ([#3351](https://github.com/vuejs/vue-router/issues/3351)) ([4e0b3e0](https://github.com/vuejs/vue-router/commit/4e0b3e0))\n\n## [3.4.7](https://github.com/vuejs/vue-router/compare/v3.4.6...v3.4.7) (2020-10-16)\n\n### Bug Fixes\n\n- **matcher:** should try catch decode only ([1f32f03](https://github.com/vuejs/vue-router/commit/1f32f03))\n- **query:** check existing keys ([4b926e3](https://github.com/vuejs/vue-router/commit/4b926e3)), closes [#3341](https://github.com/vuejs/vue-router/issues/3341)\n\n## [3.4.6](https://github.com/vuejs/vue-router/compare/v3.4.5...v3.4.6) (2020-10-07)\n\n### Bug Fixes\n\n- **encoding:** try catch decodes ([607ce2d](https://github.com/vuejs/vue-router/commit/607ce2d))\n- **ssr:** memory leak in poll method ([#2875](https://github.com/vuejs/vue-router/issues/2875)) ([7693eb5](https://github.com/vuejs/vue-router/commit/7693eb5))\n- remove duplicated decodeURIComponent ([#3323](https://github.com/vuejs/vue-router/issues/3323)) ([560d11d](https://github.com/vuejs/vue-router/commit/560d11d))\n\n## [3.4.5](https://github.com/vuejs/vue-router/compare/v3.4.4...v3.4.5) (2020-09-26)\n\n### Bug Fixes\n\n- **history:** do not call onReady on initial redirection ([a1a290e](https://github.com/vuejs/vue-router/commit/a1a290e)), closes [#3331](https://github.com/vuejs/vue-router/issues/3331)\n\n## [3.4.4](https://github.com/vuejs/vue-router/compare/v3.4.3...v3.4.4) (2020-09-24)\n\n### Bug Fixes\n\n- **abstract:** call afterHooks with go ([4da7021](https://github.com/vuejs/vue-router/commit/4da7021)), closes [#3250](https://github.com/vuejs/vue-router/issues/3250)\n- **history:** mark redundant navigation as pending ([893d86b](https://github.com/vuejs/vue-router/commit/893d86b)), closes [#3133](https://github.com/vuejs/vue-router/issues/3133)\n- **types:** add missing NavigationFailure types ([fda7067](https://github.com/vuejs/vue-router/commit/fda7067)), closes [#3293](https://github.com/vuejs/vue-router/issues/3293)\n- **types:** fix VueRouter.NavigationFailureType ([ecc8e27](https://github.com/vuejs/vue-router/commit/ecc8e27))\n\n### Features\n\n- **history:** Reset history.current when all apps are destroyed ([#3298](https://github.com/vuejs/vue-router/issues/3298)) ([c69ff7b](https://github.com/vuejs/vue-router/commit/c69ff7b))\n\n## [3.4.3](https://github.com/vuejs/vue-router/compare/v3.4.2...v3.4.3) (2020-08-11)\n\n- Revert 4fbaa9f7880276e661227442ef5923131a589210: \"fix: keep repeated params in query/hash relative locations\" Closes #3289\n\n## [3.4.2](https://github.com/vuejs/vue-router/compare/v3.4.1...v3.4.2) (2020-08-07)\n\n### Bug Fixes\n\n- **query:** leave object as is ([7b3328d](https://github.com/vuejs/vue-router/commit/7b3328d)), closes [#3282](https://github.com/vuejs/vue-router/issues/3282)\n- keep repeated params in query/hash relative locations ([4fbaa9f](https://github.com/vuejs/vue-router/commit/4fbaa9f))\n\n## [3.4.1](https://github.com/vuejs/vue-router/compare/v3.4.0...v3.4.1) (2020-08-06)\n\n### Bug Fixes\n\n- **query:** remove undefined values ([b952573](https://github.com/vuejs/vue-router/commit/b952573)), closes [#3276](https://github.com/vuejs/vue-router/issues/3276)\n- **router:** properly check null and undefined in isSameRoute ([d6546d9](https://github.com/vuejs/vue-router/commit/d6546d9))\n\n# [3.4.0](https://github.com/vuejs/vue-router/compare/v3.3.4...v3.4.0) (2020-08-05)\n\n### Bug Fixes\n\n- **query:** cast query values to strings (fix [#2131](https://github.com/vuejs/vue-router/issues/2131)) ([#3232](https://github.com/vuejs/vue-router/issues/3232)) ([f0d9c2d](https://github.com/vuejs/vue-router/commit/f0d9c2d))\n- **scroll:** run scrollBehavior on initial load (fix [#3196](https://github.com/vuejs/vue-router/issues/3196)) ([#3199](https://github.com/vuejs/vue-router/issues/3199)) ([84398ae](https://github.com/vuejs/vue-router/commit/84398ae))\n- **types:** add missing `options` property type ([#3248](https://github.com/vuejs/vue-router/issues/3248)) ([83920c9](https://github.com/vuejs/vue-router/commit/83920c9))\n\n### Features\n\n- add vetur tags and attributes ([bf1e1bd](https://github.com/vuejs/vue-router/commit/bf1e1bd))\n- **errors:** capture errors thrown in redirect callback in onError ([#3251](https://github.com/vuejs/vue-router/issues/3251)) ([40e4df7](https://github.com/vuejs/vue-router/commit/40e4df7)), closes [#3201](https://github.com/vuejs/vue-router/issues/3201) [#3201](https://github.com/vuejs/vue-router/issues/3201) [#3201](https://github.com/vuejs/vue-router/issues/3201)\n- **errors:** expose `isNavigationFailure` ([8d92dc0](https://github.com/vuejs/vue-router/commit/8d92dc0))\n- **errors:** NavigationDuplicated name for backwards compatibility ([b854a20](https://github.com/vuejs/vue-router/commit/b854a20))\n\n## [3.3.4](https://github.com/vuejs/vue-router/compare/v3.3.3...v3.3.4) (2020-06-13)\n\n### Bug Fixes\n\n- **matcher:** navigate to same as current location ([62598b9](https://github.com/vuejs/vue-router/commit/62598b9)), closes [#3216](https://github.com/vuejs/vue-router/issues/3216)\n- **types:** missing children ([c1df447](https://github.com/vuejs/vue-router/commit/c1df447)), closes [#3230](https://github.com/vuejs/vue-router/issues/3230)\n\n## [3.3.3](https://github.com/vuejs/vue-router/compare/v3.3.2...v3.3.3) (2020-06-12)\n\n### Bug Fixes\n\n- **history:** initial redirect call onReady's onSuccess ([4d484bf](https://github.com/vuejs/vue-router/commit/4d484bf)), closes [#3225](https://github.com/vuejs/vue-router/issues/3225)\n- update ja docs ([#3214](https://github.com/vuejs/vue-router/issues/3214)) ([c05f741](https://github.com/vuejs/vue-router/commit/c05f741))\n\n### Features\n\n- better wording for navigation redirected failure ([1f3aea6](https://github.com/vuejs/vue-router/commit/1f3aea6))\n- **types:** RouterConfig for multiple components ([#3217](https://github.com/vuejs/vue-router/issues/3217)) ([#3218](https://github.com/vuejs/vue-router/issues/3218)) ([dab86c5](https://github.com/vuejs/vue-router/commit/dab86c5))\n\n## [3.3.2](https://github.com/vuejs/vue-router/compare/v3.3.1...v3.3.2) (2020-05-29)\n\n### Bug Fixes\n\n- **errors:** NavigationCanceled with async components ([#3211](https://github.com/vuejs/vue-router/issues/3211)) ([be39ca3](https://github.com/vuejs/vue-router/commit/be39ca3))\n- remove error.stack modification ([#3212](https://github.com/vuejs/vue-router/issues/3212)) ([a0075ed](https://github.com/vuejs/vue-router/commit/a0075ed))\n\n## [3.3.1](https://github.com/vuejs/vue-router/compare/v3.3.0...v3.3.1) (2020-05-27)\n\n### Bug Fixes\n\n- **errors:** avoid unnecessary log of errors ([2c77247](https://github.com/vuejs/vue-router/commit/2c77247))\n\n# [3.3.0](https://github.com/vuejs/vue-router/compare/v3.2.0...v3.3.0) (2020-05-27)\n\n### Features\n\n- **errors:** create router errors ([#3047](https://github.com/vuejs/vue-router/issues/3047)) ([4c727f9](https://github.com/vuejs/vue-router/commit/4c727f9))\n- **history:** Remove event listeners when all apps are destroyed. ([#3172](https://github.com/vuejs/vue-router/issues/3172)) ([4c81be8](https://github.com/vuejs/vue-router/commit/4c81be8)), closes [#3152](https://github.com/vuejs/vue-router/issues/3152) [#2341](https://github.com/vuejs/vue-router/issues/2341)\n- **url:** call afterEach hooks after url is ensured ([#2292](https://github.com/vuejs/vue-router/issues/2292)) ([1575a18](https://github.com/vuejs/vue-router/commit/1575a18)), closes [#2079](https://github.com/vuejs/vue-router/issues/2079)\n\n# [3.2.0](https://github.com/vuejs/vue-router/compare/v3.1.6...v3.2.0) (2020-05-19)\n\n### Bug Fixes\n\n- **html5:** make base case insensitive ([04a2143](https://github.com/vuejs/vue-router/commit/04a2143)), closes [#2154](https://github.com/vuejs/vue-router/issues/2154)\n- check for pushState being a function ([bc41f67](https://github.com/vuejs/vue-router/commit/bc41f67)), closes [#3154](https://github.com/vuejs/vue-router/issues/3154)\n\n### Features\n\n- **link:** add aria-current to active links (close [#2116](https://github.com/vuejs/vue-router/issues/2116)) ([#3073](https://github.com/vuejs/vue-router/issues/3073)) ([6ec0ee5](https://github.com/vuejs/vue-router/commit/6ec0ee5))\n- **scroll:** use manual scrollRestoration with scrollBehavior ([#1814](https://github.com/vuejs/vue-router/issues/1814)) ([1261363](https://github.com/vuejs/vue-router/commit/1261363))\n- **types:** NavigationGuardNext ([#2497](https://github.com/vuejs/vue-router/issues/2497)) ([d18c497](https://github.com/vuejs/vue-router/commit/d18c497))\n\n## [3.1.6](https://github.com/vuejs/vue-router/compare/v3.1.5...v3.1.6) (2020-02-26)\n\n### Bug Fixes\n\n- preserve history state when reloading ([a4ec3e2](https://github.com/vuejs/vue-router/commit/a4ec3e2))\n- **ts:** add null to Route.name ([#3117](https://github.com/vuejs/vue-router/issues/3117)) ([8f831f2](https://github.com/vuejs/vue-router/commit/8f831f2))\n- correctly calculate `path` when `pathMatch` is empty string ([#3111](https://github.com/vuejs/vue-router/issues/3111)) ([38e6ccd](https://github.com/vuejs/vue-router/commit/38e6ccd)), closes [#3106](https://github.com/vuejs/vue-router/issues/3106)\n\n## [3.1.5](https://github.com/vuejs/vue-router/compare/v3.1.4...v3.1.5) (2020-01-15)\n\n### Bug Fixes\n\n- **view:** add passing props to inactive component ([#2773](https://github.com/vuejs/vue-router/issues/2773)) ([0fb1343](https://github.com/vuejs/vue-router/commit/0fb1343)), closes [#2301](https://github.com/vuejs/vue-router/issues/2301)\n- **view:** fix deeply nested keep-alive router-views displaying ([#2930](https://github.com/vuejs/vue-router/issues/2930)) ([0c2b1aa](https://github.com/vuejs/vue-router/commit/0c2b1aa)), closes [#2923](https://github.com/vuejs/vue-router/issues/2923)\n\n## [3.1.4](https://github.com/vuejs/vue-router/compare/v3.1.3...v3.1.4) (2020-01-14)\n\n### Bug Fixes\n\n- suppress warning if `pathMatch` is empty ([#3081](https://github.com/vuejs/vue-router/issues/3081)) ([ddc6bc7](https://github.com/vuejs/vue-router/commit/ddc6bc7)), closes [#3072](https://github.com/vuejs/vue-router/issues/3072)\n- **link:** correctly warn wrong v-slot usage ([a150291](https://github.com/vuejs/vue-router/commit/a150291)), closes [#3091](https://github.com/vuejs/vue-router/issues/3091)\n- **location:** add a copy for params with named locations ([#2802](https://github.com/vuejs/vue-router/issues/2802)) ([2b39f5a](https://github.com/vuejs/vue-router/commit/2b39f5a)), closes [#2800](https://github.com/vuejs/vue-router/issues/2800) [#2938](https://github.com/vuejs/vue-router/issues/2938) [#2938](https://github.com/vuejs/vue-router/issues/2938)\n\n### Features\n\n- **history:** preserve existing history.state ([c0d3376](https://github.com/vuejs/vue-router/commit/c0d3376)), closes [#3006](https://github.com/vuejs/vue-router/issues/3006)\n\n## [3.1.3](https://github.com/vuejs/vue-router/compare/v3.1.2...v3.1.3) (2019-08-30)\n\n### Bug Fixes\n\n- **link:** merge event listeners when provided in an anchor ([e0d4dc4](https://github.com/vuejs/vue-router/commit/e0d4dc4)), closes [#2890](https://github.com/vuejs/vue-router/issues/2890)\n\n### Features\n\n- **errors:** add stack trace to NavigationDuplicated ([5ef5d73](https://github.com/vuejs/vue-router/commit/5ef5d73)), closes [#2881](https://github.com/vuejs/vue-router/issues/2881)\n- warn about root paths without a leading slash ([#2591](https://github.com/vuejs/vue-router/issues/2591)) ([7d7e048](https://github.com/vuejs/vue-router/commit/7d7e048)), closes [#2550](https://github.com/vuejs/vue-router/issues/2550) [#2550](https://github.com/vuejs/vue-router/issues/2550)\n\n## [3.1.2](https://github.com/vuejs/vue-router/compare/v3.1.1...v3.1.2) (2019-08-08)\n\n### Bug Fixes\n\n- **types:** prioritize promise based push/replace ([1243e8b](https://github.com/vuejs/vue-router/commit/1243e8b))\n\n### Reverts\n\n- \"fix(hash): correctly place query if placed before hash ([#2851](https://github.com/vuejs/vue-router/issues/2851))\" ([9b30e4c](https://github.com/vuejs/vue-router/commit/9b30e4c)), closes [#2876](https://github.com/vuejs/vue-router/issues/2876). See more information at https://github.com/vuejs/vue-router/issues/2125#issuecomment-519521424\n\n## [3.1.1](https://github.com/vuejs/vue-router/compare/v3.1.0...v3.1.1) (2019-08-06)\n\n### Bug Fixes\n\n- **link:** silence back navigations errors ([59b6da3](https://github.com/vuejs/vue-router/commit/59b6da3))\n\n# [3.1.0](https://github.com/vuejs/vue-router/compare/v3.0.7...v3.1.0) (2019-08-06)\n\n### Bug Fixes\n\n- **abstract history:** allow router.back in abstract mode when 2 consecutive same routes appear in history stack ([#2771](https://github.com/vuejs/vue-router/issues/2771)) ([8910979](https://github.com/vuejs/vue-router/commit/8910979)), closes [#2607](https://github.com/vuejs/vue-router/issues/2607)\n- **hash:** correctly place query if placed before hash ([#2851](https://github.com/vuejs/vue-router/issues/2851)) ([b7715dc](https://github.com/vuejs/vue-router/commit/b7715dc)), closes [#2125](https://github.com/vuejs/vue-router/issues/2125) [#2262](https://github.com/vuejs/vue-router/issues/2262)\n- **link:** Fix active links when parent link redirects to child ([#2772](https://github.com/vuejs/vue-router/issues/2772)) ([64785a9](https://github.com/vuejs/vue-router/commit/64785a9)), closes [#2724](https://github.com/vuejs/vue-router/issues/2724)\n- adapt error to work on IE9 ([527d6d5](https://github.com/vuejs/vue-router/commit/527d6d5))\n\n### Features\n\n- **alias:** warn against redundant aliases ([04a02c0](https://github.com/vuejs/vue-router/commit/04a02c0)), closes [#2461](https://github.com/vuejs/vue-router/issues/2461) [#2462](https://github.com/vuejs/vue-router/issues/2462)\n- **scroll:** handle id selectors starting with a number ([799ceca](https://github.com/vuejs/vue-router/commit/799ceca)), closes [#2163](https://github.com/vuejs/vue-router/issues/2163)\n- return a promise with push and replace ([#2862](https://github.com/vuejs/vue-router/issues/2862)) ([d907a13](https://github.com/vuejs/vue-router/commit/d907a13)), closes [#1769](https://github.com/vuejs/vue-router/issues/1769) [#1769](https://github.com/vuejs/vue-router/issues/1769)\n- scoped slot for link ([e289dde](https://github.com/vuejs/vue-router/commit/e289dde))\n- warn the user for invalid uses of v-slot with Link ([44c63a9](https://github.com/vuejs/vue-router/commit/44c63a9))\n\n## [3.0.7](https://github.com/vuejs/vue-router/compare/v3.0.6...v3.0.7) (2019-07-03)\n\n### Bug Fixes\n\n- apps loaded from Windows file shares not mapped to network drives ([#2774](https://github.com/vuejs/vue-router/issues/2774)) ([c2c78a3](https://github.com/vuejs/vue-router/commit/c2c78a3))\n- make callback of next in beforeRouterEnter more consistent ([#2738](https://github.com/vuejs/vue-router/issues/2738)) ([8ac478f](https://github.com/vuejs/vue-router/commit/8ac478f)), closes [#2761](https://github.com/vuejs/vue-router/issues/2761) [#2728](https://github.com/vuejs/vue-router/issues/2728)\n\n## [3.0.6](https://github.com/vuejs/vue-router/compare/v3.0.5...v3.0.6) (2019-04-17)\n\n### Bug Fixes\n\n- revert [#2713](https://github.com/vuejs/vue-router/issues/2713) ([#2723](https://github.com/vuejs/vue-router/issues/2723)) ([ec6eab7](https://github.com/vuejs/vue-router/commit/ec6eab7)), closes [#2719](https://github.com/vuejs/vue-router/issues/2719)\n\n## [3.0.5](https://github.com/vuejs/vue-router/compare/v3.0.4...v3.0.5) (2019-04-15)\n\n### Bug Fixes\n\n- push before creating Vue instance ([#2713](https://github.com/vuejs/vue-router/issues/2713)) ([6974a6f](https://github.com/vuejs/vue-router/commit/6974a6f)), closes [#2712](https://github.com/vuejs/vue-router/issues/2712)\n- **router-view:** add condition to see whether the tree is inactive (fix [#2552](https://github.com/vuejs/vue-router/issues/2552)) ([#2592](https://github.com/vuejs/vue-router/issues/2592)) ([e6d8fd2](https://github.com/vuejs/vue-router/commit/e6d8fd2))\n- **router-view:** register instance in init hook ([c3abdf6](https://github.com/vuejs/vue-router/commit/c3abdf6)), closes [#2561](https://github.com/vuejs/vue-router/issues/2561) [#2689](https://github.com/vuejs/vue-router/issues/2689) [#2561](https://github.com/vuejs/vue-router/issues/2561) [#2561](https://github.com/vuejs/vue-router/issues/2561)\n\n## [3.0.4](https://github.com/vuejs/vue-router/compare/v3.0.3...v3.0.4) (2019-04-12)\n\n### Bug Fixes\n\n- prevent memory leaks by removing app references ([#2706](https://github.com/vuejs/vue-router/issues/2706)) ([8056105](https://github.com/vuejs/vue-router/commit/8056105)), closes [#2639](https://github.com/vuejs/vue-router/issues/2639)\n- **hash:** prevent double decoding ([#2711](https://github.com/vuejs/vue-router/issues/2711)) ([a775fb1](https://github.com/vuejs/vue-router/commit/a775fb1)), closes [#2708](https://github.com/vuejs/vue-router/issues/2708)\n\n### Features\n\n- **esm build:** build ES modules for browser ([#2705](https://github.com/vuejs/vue-router/issues/2705)) ([627027f](https://github.com/vuejs/vue-router/commit/627027f))\n\n## [3.0.3](https://github.com/vuejs/vue-router/compare/v3.0.2...v3.0.3) (2019-04-08)\n\n### Bug Fixes\n\n- removes warning resolving asterisk routes ([e224637](https://github.com/vuejs/vue-router/commit/e224637)), closes [#2505](https://github.com/vuejs/vue-router/issues/2505) [#2505](https://github.com/vuejs/vue-router/issues/2505)\n- **normalizeLocation:** create a copy with named locations ([#2286](https://github.com/vuejs/vue-router/issues/2286)) ([53cce99](https://github.com/vuejs/vue-router/commit/53cce99)), closes [#2121](https://github.com/vuejs/vue-router/issues/2121)\n- **resolve:** use current location if not provided ([#2390](https://github.com/vuejs/vue-router/issues/2390)) ([7ff4de4](https://github.com/vuejs/vue-router/commit/7ff4de4)), closes [#2385](https://github.com/vuejs/vue-router/issues/2385)\n- **types:** allow null/undefined in query params ([ca30a75](https://github.com/vuejs/vue-router/commit/ca30a75)), closes [#2605](https://github.com/vuejs/vue-router/issues/2605)\n\n## [3.0.2](https://github.com/vuejs/vue-router/compare/v3.0.1...v3.0.2) (2018-11-23)\n\n### Bug Fixes\n\n- **errors:** throws with invalid route objects ([#1893](https://github.com/vuejs/vue-router/issues/1893)) ([c837666](https://github.com/vuejs/vue-router/commit/c837666))\n- fix the test in async.spec.js ([#1953](https://github.com/vuejs/vue-router/issues/1953)) ([4e9e66b](https://github.com/vuejs/vue-router/commit/4e9e66b))\n- initial url path for non ascii urls ([#2375](https://github.com/vuejs/vue-router/issues/2375)) ([c3b0a33](https://github.com/vuejs/vue-router/commit/c3b0a33))\n- only setupScroll when support pushState due to possible fallback: false ([#1835](https://github.com/vuejs/vue-router/issues/1835)) ([fac60f6](https://github.com/vuejs/vue-router/commit/fac60f6)), closes [#1834](https://github.com/vuejs/vue-router/issues/1834)\n- workaround replaceState bug in Safari ([#2295](https://github.com/vuejs/vue-router/issues/2295)) ([3c7d8ab](https://github.com/vuejs/vue-router/commit/3c7d8ab)), closes [#2195](https://github.com/vuejs/vue-router/issues/2195)\n- **hash:** support unicode in initial route ([8369c6b](https://github.com/vuejs/vue-router/commit/8369c6b))\n- **history-mode:** correcting indentation in web.config example ([#1948](https://github.com/vuejs/vue-router/issues/1948)) ([4b071f9](https://github.com/vuejs/vue-router/commit/4b071f9))\n- **match:** use pathMatch for the param of \\* routes ([#1995](https://github.com/vuejs/vue-router/issues/1995)) ([ca1fccd](https://github.com/vuejs/vue-router/commit/ca1fccd)), closes [#1994](https://github.com/vuejs/vue-router/issues/1994)\n\n### Features\n\n- call scrollBehavior with app context ([#1804](https://github.com/vuejs/vue-router/issues/1804)) ([c93a734](https://github.com/vuejs/vue-router/commit/c93a734))\n\n## [3.0.1](https://github.com/vuejs/vue-router/compare/v3.0.0...v3.0.1) (2017-10-13)\n\n### Bug Fixes\n\n- fix props-passing regression ([02ff792](https://github.com/vuejs/vue-router/commit/02ff792)), closes [#1800](https://github.com/vuejs/vue-router/issues/1800)\n\n## [3.0.0](https://github.com/vuejs/vue-router/compare/v2.8.0...v3.0.0) (2017-10-11)\n\n### Features\n\n- **typings:** adapt to the new Vue typings ([#1685](https://github.com/vuejs/vue-router/issues/1685)) ([8855e36](https://github.com/vuejs/vue-router/commit/8855e36))\n\n### BREAKING CHANGES\n\n- **typings:** It is no longer compatible with the old Vue typings\n\n## [2.8.0](https://github.com/vuejs/vue-router/compare/v2.7.0...v2.8.0) (2017-10-11)\n\n### Bug Fixes\n\n- allow insllation on extended Vue copies ([f62c5d6](https://github.com/vuejs/vue-router/commit/f62c5d6))\n- avoid first popstate event with async guard together (fix [#1508](https://github.com/vuejs/vue-router/issues/1508)) ([#1661](https://github.com/vuejs/vue-router/issues/1661)) ([3cbc0f3](https://github.com/vuejs/vue-router/commit/3cbc0f3))\n- deep clone query when creating routes ([effb114](https://github.com/vuejs/vue-router/commit/effb114)), closes [#1690](https://github.com/vuejs/vue-router/issues/1690)\n- fix scroll when going back to initial route ([#1586](https://github.com/vuejs/vue-router/issues/1586)) ([c166822](https://github.com/vuejs/vue-router/commit/c166822))\n- handle null values when comparing objects ([#1568](https://github.com/vuejs/vue-router/issues/1568)) ([4e95bd8](https://github.com/vuejs/vue-router/commit/4e95bd8)), closes [#1566](https://github.com/vuejs/vue-router/issues/1566)\n- resolve native ES modules ([8a28426](https://github.com/vuejs/vue-router/commit/8a28426))\n- send props not defined on the route component in \\$attrs. Fixes [#1695](https://github.com/vuejs/vue-router/issues/1695). ([#1702](https://github.com/vuejs/vue-router/issues/1702)) ([a722b6a](https://github.com/vuejs/vue-router/commit/a722b6a))\n\n### Features\n\n- enhance hashHistory to support scrollBehavior ([#1662](https://github.com/vuejs/vue-router/issues/1662)) ([1422eb5](https://github.com/vuejs/vue-router/commit/1422eb5))\n- scrollBehavior accept returning a promise ([#1758](https://github.com/vuejs/vue-router/issues/1758)) ([ce13b55](https://github.com/vuejs/vue-router/commit/ce13b55))\n\n# [2.7.0](https://github.com/vuejs/vue-router/compare/v2.6.0...v2.7.0) (2017-06-29)\n\n### Features\n\n- auto resolve ES module default when resolving async components ([d539788](https://github.com/vuejs/vue-router/commit/d539788))\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2013-present Evan You\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# vue-router [![Build Status](https://img.shields.io/circleci/project/github/vuejs/vue-router/dev.svg)](https://circleci.com/gh/vuejs/vue-router)\n\n> This is vue-router 3.0 which works only with Vue 2.0. and both have reached end of life.\n>\n> - For the 1.x router see the [1.0 branch](https://github.com/vuejs/vue-router/tree/1.0).\n> - For Vue Router 4 (for Vue 3) see [vuejs/router](https://github.com/vuejs/router).\n\n<h2 align=\"center\">Supporting Vue Router</h2>\n\nVue Router is part of the Vue Ecosystem and is an MIT-licensed open source project with its ongoing development made possible entirely by the support of Sponsors. If you would like to become a sponsor, please consider:\n\n- [Become a Sponsor on GitHub](https://github.com/sponsors/posva)\n- [One-time donation via PayPal](https://paypal.me/posva)\n\n<!--sponsors start-->\n\n<h4 align=\"center\">Gold Sponsors</h4>\n<p align=\"center\">\n    <a href=\"https://vuejobs.com/?utm_source=vuerouter&utm_campaign=sponsor\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://posva-sponsors.pages.dev/logos/vuejobs.svg\" media=\"(prefers-color-scheme: dark)\" height=\"72px\" alt=\"VueJobs\" />\n      <img src=\"https://posva-sponsors.pages.dev/logos/vuejobs.svg\" height=\"72px\" alt=\"VueJobs\" />\n    </picture>\n  </a>\n</p>\n\n<h4 align=\"center\">Silver Sponsors</h4>\n<p align=\"center\">\n    <a href=\"https://www.vuemastery.com/\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://posva-sponsors.pages.dev/logos/vuemastery-dark.png\" media=\"(prefers-color-scheme: dark)\" height=\"42px\" alt=\"VueMastery\" />\n      <img src=\"https://posva-sponsors.pages.dev/logos/vuemastery-light.svg\" height=\"42px\" alt=\"VueMastery\" />\n    </picture>\n  </a>\n    <a href=\"https://www.prefect.io/\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://posva-sponsors.pages.dev/logos/prefectlogo-dark.svg\" media=\"(prefers-color-scheme: dark)\" height=\"42px\" alt=\"Prefect\" />\n      <img src=\"https://posva-sponsors.pages.dev/logos/prefectlogo-light.svg\" height=\"42px\" alt=\"Prefect\" />\n    </picture>\n  </a>\n</p>\n\n<h4 align=\"center\">Bronze Sponsors</h4>\n<p align=\"center\">\n    <a href=\"https://stormier.ninja\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4\" media=\"(prefers-color-scheme: dark)\" height=\"26px\" alt=\"Stanislas OrmiÃ¨res\" />\n      <img src=\"https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4\" height=\"26px\" alt=\"Stanislas OrmiÃ¨res\" />\n    </picture>\n  </a>\n    <a href=\"www.vuejs.de\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4\" media=\"(prefers-color-scheme: dark)\" height=\"26px\" alt=\"Antony Konstantinidis\" />\n      <img src=\"https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4\" height=\"26px\" alt=\"Antony Konstantinidis\" />\n    </picture>\n  </a>\n    <a href=\"https://storyblok.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://posva-sponsors.pages.dev/logos/storyblok.png\" media=\"(prefers-color-scheme: dark)\" height=\"26px\" alt=\"Storyblok\" />\n      <img src=\"https://posva-sponsors.pages.dev/logos/storyblok.png\" height=\"26px\" alt=\"Storyblok\" />\n    </picture>\n  </a>\n    <a href=\"https://nuxtjs.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <picture>\n      <source srcset=\"https://posva-sponsors.pages.dev/logos/nuxt-dark.svg\" media=\"(prefers-color-scheme: dark)\" height=\"26px\" alt=\"NuxtJS\" />\n      <img src=\"https://posva-sponsors.pages.dev/logos/nuxt-light.svg\" height=\"26px\" alt=\"NuxtJS\" />\n    </picture>\n  </a>\n</p>\n\n<!--sponsors end-->\n\n---\n\nGet started with the [documentation](http://v3.router.vuejs.org), or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see how to run them below).\n\n### Development Setup\n\n```bash\n# install deps\nyarn\n\n# build dist files\nyarn build\n\n# serve examples at localhost:8080\nyarn dev\n\n# lint & run all tests\nyarn test\n\n# serve docs at localhost:8080\nyarn docs\n```\n\n## Releasing\n\n- `yarn run release`\n  - Ensure tests are passing `yarn run test`\n  - Build dist files `VERSION=<the_version> yarn run build`\n  - Build changelog `yarn run changelog`\n  - Commit dist files `git add dist CHANGELOG.md && git commit -m \"[build $VERSION]\"`\n  - Publish a new version `npm version $VERSION --message \"[release] $VERSION\"\n  - Push tags `git push origin refs/tags/v$VERSION && git push`\n  - Publish to npm `npm publish`\n\n## Questions\n\nFor questions and support please use the [Discord chat server](https://chat.vuejs.org) or [the official forum](http://forum.vuejs.org). The issue list of this repo is **exclusively** for bug reports and feature requests.\n\n## Issues\n\nPlease make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.\n\n## Contribution\n\nPlease make sure to read the [Contributing Guide](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md) before making a pull request.\n\n## Changelog\n\nDetails changes for each release are documented in the [`CHANGELOG.md file`](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md).\n\n## Stay In Touch\n\n- For latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs)\n\n## License\n\n[MIT](http://opensource.org/licenses/MIT)\n\nCopyright (c) 2013-present Evan You\n\n## Special Thanks\n\n<a href=\"https://www.browserstack.com\">\n  <img src=\"/assets/browserstack-logo-600x315.png\" height=\"80\" title=\"BrowserStack Logo\" alt=\"BrowserStack Logo\" />\n</a>\n\nSpecial thanks to [BrowserStack](https://www.browserstack.com) for letting the maintainers use their service to debug browser specific issues.\n"
  },
  {
    "path": "build/build.js",
    "content": "const fs = require('fs')\nconst path = require('path')\nconst zlib = require('zlib')\nconst terser = require('terser')\nconst rollup = require('rollup')\nconst configs = require('./configs')\n\nif (!fs.existsSync('dist')) {\n  fs.mkdirSync('dist')\n}\n\nbuild(configs)\n\nfunction build (builds) {\n  let built = 0\n  const total = builds.length\n  const next = () => {\n    buildEntry(builds[built])\n      .then(() => {\n        built++\n        if (built < total) {\n          next()\n        }\n      })\n      .catch(logError)\n  }\n\n  next()\n}\n\nfunction buildEntry ({ input, output }) {\n  const { file, banner } = output\n  const isProd = /min\\.js$/.test(file)\n  return rollup\n    .rollup(input)\n    .then(bundle => bundle.generate(output))\n    .then(bundle => {\n      // console.log(bundle)\n      const code = bundle.output[0].code\n      if (isProd) {\n        const minified =\n          (banner ? banner + '\\n' : '') +\n          terser.minify(code, {\n            toplevel: true,\n            output: {\n              ascii_only: true\n            },\n            compress: {\n              pure_funcs: ['makeMap']\n            }\n          }).code\n        return write(file, minified, true)\n      } else {\n        return write(file, code)\n      }\n    })\n}\n\nfunction write (dest, code, zip) {\n  return new Promise((resolve, reject) => {\n    function report (extra) {\n      console.log(\n        blue(path.relative(process.cwd(), dest)) +\n          ' ' +\n          getSize(code) +\n          (extra || '')\n      )\n      resolve()\n    }\n\n    fs.writeFile(dest, code, err => {\n      if (err) return reject(err)\n      if (zip) {\n        zlib.gzip(code, (err, zipped) => {\n          if (err) return reject(err)\n          report(' (gzipped: ' + getSize(zipped) + ')')\n        })\n      } else {\n        report()\n      }\n    })\n  })\n}\n\nfunction getSize (code) {\n  return (code.length / 1024).toFixed(2) + 'kb'\n}\n\nfunction logError (e) {\n  console.log(e)\n}\n\nfunction blue (str) {\n  return '\\x1b[1m\\x1b[34m' + str + '\\x1b[39m\\x1b[22m'\n}\n"
  },
  {
    "path": "build/configs.js",
    "content": "const path = require('path')\nconst buble = require('rollup-plugin-buble')\nconst flow = require('rollup-plugin-flow-no-whitespace')\nconst cjs = require('@rollup/plugin-commonjs')\nconst node = require('@rollup/plugin-node-resolve').nodeResolve\nconst replace = require('rollup-plugin-replace')\nconst version = process.env.VERSION || require('../package.json').version\nconst banner = `/*!\n  * vue-router v${version}\n  * (c) ${new Date().getFullYear()} Evan You\n  * @license MIT\n  */`\n\nconst resolve = _path => path.resolve(__dirname, '../', _path)\n\nmodule.exports = [\n  // browser dev\n  {\n    file: resolve('dist/vue-router.js'),\n    format: 'umd',\n    env: 'development'\n  },\n  {\n    file: resolve('dist/vue-router.min.js'),\n    format: 'umd',\n    env: 'production'\n  },\n  {\n    file: resolve('dist/vue-router.common.js'),\n    format: 'cjs'\n  },\n  {\n    input: resolve('src/entries/esm.js'),\n    file: resolve('dist/vue-router.esm.js'),\n    format: 'es'\n  },\n  {\n    input: resolve('src/entries/esm.js'),\n    file: resolve('dist/vue-router.mjs'),\n    format: 'es'\n  },\n  {\n    input: resolve('src/entries/esm.js'),\n    file: resolve('dist/vue-router.esm.browser.js'),\n    format: 'es',\n    env: 'development',\n    transpile: false\n  },\n  {\n    input: resolve('src/entries/esm.js'),\n    file: resolve('dist/vue-router.esm.browser.min.js'),\n    format: 'es',\n    env: 'production',\n    transpile: false\n  },\n  {\n    input: resolve('src/composables/index.js'),\n    file: resolve('./composables.mjs'),\n    format: 'es'\n  },\n  {\n    input: resolve('src/composables/index.js'),\n    file: resolve('./composables.js'),\n    format: 'cjs'\n  }\n].map(genConfig)\n\nfunction genConfig (opts) {\n  const config = {\n    input: {\n      input: opts.input || resolve('src/index.js'),\n      plugins: [\n        flow(),\n        node(),\n        cjs(),\n        replace({\n          __VERSION__: version\n        })\n      ],\n      external: ['vue']\n    },\n    output: {\n      file: opts.file,\n      format: opts.format,\n      banner,\n      name: 'VueRouter'\n    }\n  }\n\n  if (opts.env) {\n    config.input.plugins.unshift(\n      replace({\n        'process.env.NODE_ENV': JSON.stringify(opts.env)\n      })\n    )\n  }\n\n  if (opts.transpile !== false) {\n    config.input.plugins.push(buble())\n  }\n\n  return config\n}\n"
  },
  {
    "path": "build/rollup.dev.config.js",
    "content": "const { input, output } = require('./configs')[0]\n\nmodule.exports = Object.assign({}, input, { output })\n"
  },
  {
    "path": "composables.d.ts",
    "content": "export * from './types/composables'\n"
  },
  {
    "path": "composables.js",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\n'use strict'\n\nObject.defineProperty(exports, '__esModule', { value: true })\n\nvar vue = require('vue')\n\n// dev only warn if no current instance\n\nfunction throwNoCurrentInstance (method) {\n  if (!vue.getCurrentInstance()) {\n    throw new Error(\n      ('[vue-router]: Missing current instance. ' + method + '() must be called inside <script setup> or setup().')\n    )\n  }\n}\n\nfunction useRouter () {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useRouter')\n  }\n\n  return vue.getCurrentInstance().proxy.$root.$router\n}\n\nfunction useRoute () {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useRoute')\n  }\n\n  var root = vue.getCurrentInstance().proxy.$root\n  if (!root._$route) {\n    var route = vue.effectScope(true).run(function () { return vue.shallowReactive(Object.assign({}, root.$router.currentRoute)) }\n    )\n    root._$route = route\n\n    root.$router.afterEach(function (to) {\n      Object.assign(route, to)\n    })\n  }\n\n  return root._$route\n}\n\nfunction onBeforeRouteUpdate (guard) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('onBeforeRouteUpdate')\n  }\n\n  return useFilteredGuard(guard, isUpdateNavigation)\n}\nfunction isUpdateNavigation (to, from, depth) {\n  var toMatched = to.matched\n  var fromMatched = from.matched\n  return (\n    toMatched.length >= depth &&\n    toMatched\n      .slice(0, depth + 1)\n      .every(function (record, i) { return record === fromMatched[i] })\n  )\n}\n\nfunction isLeaveNavigation (to, from, depth) {\n  var toMatched = to.matched\n  var fromMatched = from.matched\n  return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]\n}\n\nfunction onBeforeRouteLeave (guard) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('onBeforeRouteLeave')\n  }\n\n  return useFilteredGuard(guard, isLeaveNavigation)\n}\n\nvar noop = function () {}\nfunction useFilteredGuard (guard, fn) {\n  var instance = vue.getCurrentInstance()\n  var router = useRouter()\n\n  var target = instance.proxy\n  // find the nearest RouterView to know the depth\n  while (\n    target &&\n    target.$vnode &&\n    target.$vnode.data &&\n    target.$vnode.data.routerViewDepth == null\n  ) {\n    target = target.$parent\n  }\n\n  var depth =\n    target && target.$vnode && target.$vnode.data\n      ? target.$vnode.data.routerViewDepth\n      : null\n\n  if (depth != null) {\n    var removeGuard = router.beforeEach(function (to, from, next) {\n      return fn(to, from, depth) ? guard(to, from, next) : next()\n    })\n\n    vue.onUnmounted(removeGuard)\n    return removeGuard\n  }\n\n  return noop\n}\n\n/*  */\n\nfunction guardEvent (e) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) { return }\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) { return }\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    var target = e.currentTarget.getAttribute('target')\n    if (/\\b_blank\\b/i.test(target)) { return }\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault()\n  }\n  return true\n}\n\nfunction includesParams (outer, inner) {\n  var loop = function (key) {\n    var innerValue = inner[key]\n    var outerValue = outer[key]\n    if (typeof innerValue === 'string') {\n      if (innerValue !== outerValue) { return { v: false } }\n    } else {\n      if (\n        !Array.isArray(outerValue) ||\n        outerValue.length !== innerValue.length ||\n        innerValue.some(function (value, i) { return value !== outerValue[i] })\n      ) {\n        return { v: false }\n      }\n    }\n  }\n\n  for (var key in inner) {\n    var returned = loop(key)\n\n    if (returned) return returned.v\n  }\n\n  return true\n}\n\n// helpers from vue router 4\n\nfunction isSameRouteLocationParamsValue (a, b) {\n  return Array.isArray(a)\n    ? isEquivalentArray(a, b)\n    : Array.isArray(b)\n      ? isEquivalentArray(b, a)\n      : a === b\n}\n\nfunction isEquivalentArray (a, b) {\n  return Array.isArray(b)\n    ? a.length === b.length && a.every(function (value, i) { return value === b[i] })\n    : a.length === 1 && a[0] === b\n}\n\nfunction isSameRouteLocationParams (a, b) {\n  if (Object.keys(a).length !== Object.keys(b).length) { return false }\n\n  for (var key in a) {\n    if (!isSameRouteLocationParamsValue(a[key], b[key])) { return false }\n  }\n\n  return true\n}\n\nfunction useLink (props) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useLink')\n  }\n\n  var router = useRouter()\n  var currentRoute = useRoute()\n\n  var resolvedRoute = vue.computed(function () { return router.resolve(vue.unref(props.to), currentRoute) })\n\n  var activeRecordIndex = vue.computed(function () {\n    var route = resolvedRoute.value.route\n    var matched = route.matched\n    var length = matched.length\n    var routeMatched = matched[length - 1]\n    var currentMatched = currentRoute.matched\n    if (!routeMatched || !currentMatched.length) { return -1 }\n    var index = currentMatched.indexOf(routeMatched)\n    if (index > -1) { return index }\n    // possible parent record\n    var parentRecord = currentMatched[currentMatched.length - 2]\n\n    return (\n      // we are dealing with nested routes\n      length > 1 &&\n        // if the parent and matched route have the same path, this link is\n        // referring to the empty child. Or we currently are on a different\n        // child of the same parent\n        parentRecord && parentRecord === routeMatched.parent\n    )\n  })\n\n  var isActive = vue.computed(\n    function () {\n      return activeRecordIndex.value > -1 &&\n      includesParams(currentRoute.params, resolvedRoute.value.route.params)\n    }\n  )\n  var isExactActive = vue.computed(\n    function () {\n      return activeRecordIndex.value > -1 &&\n      activeRecordIndex.value === currentRoute.matched.length - 1 &&\n      isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params)\n    }\n  )\n\n  var navigate = function (e) {\n    var href = resolvedRoute.value.route\n    if (guardEvent(e)) {\n      return props.replace\n        ? router.replace(href)\n        : router.push(href)\n    }\n    return Promise.resolve()\n  }\n\n  return {\n    href: vue.computed(function () { return resolvedRoute.value.href }),\n    route: vue.computed(function () { return resolvedRoute.value.route }),\n    isExactActive: isExactActive,\n    isActive: isActive,\n    navigate: navigate\n  }\n}\n\nexports.isSameRouteLocationParams = isSameRouteLocationParams\nexports.onBeforeRouteLeave = onBeforeRouteLeave\nexports.onBeforeRouteUpdate = onBeforeRouteUpdate\nexports.useLink = useLink\nexports.useRoute = useRoute\nexports.useRouter = useRouter\n"
  },
  {
    "path": "composables.mjs",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\nimport { getCurrentInstance, effectScope, shallowReactive, onUnmounted, computed, unref } from 'vue';\n\n// dev only warn if no current instance\n\nfunction throwNoCurrentInstance (method) {\n  if (!getCurrentInstance()) {\n    throw new Error(\n      (\"[vue-router]: Missing current instance. \" + method + \"() must be called inside <script setup> or setup().\")\n    )\n  }\n}\n\nfunction useRouter () {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useRouter');\n  }\n\n  return getCurrentInstance().proxy.$root.$router\n}\n\nfunction useRoute () {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useRoute');\n  }\n\n  var root = getCurrentInstance().proxy.$root;\n  if (!root._$route) {\n    var route = effectScope(true).run(function () { return shallowReactive(Object.assign({}, root.$router.currentRoute)); }\n    );\n    root._$route = route;\n\n    root.$router.afterEach(function (to) {\n      Object.assign(route, to);\n    });\n  }\n\n  return root._$route\n}\n\nfunction onBeforeRouteUpdate (guard) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('onBeforeRouteUpdate');\n  }\n\n  return useFilteredGuard(guard, isUpdateNavigation)\n}\nfunction isUpdateNavigation (to, from, depth) {\n  var toMatched = to.matched;\n  var fromMatched = from.matched;\n  return (\n    toMatched.length >= depth &&\n    toMatched\n      .slice(0, depth + 1)\n      .every(function (record, i) { return record === fromMatched[i]; })\n  )\n}\n\nfunction isLeaveNavigation (to, from, depth) {\n  var toMatched = to.matched;\n  var fromMatched = from.matched;\n  return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]\n}\n\nfunction onBeforeRouteLeave (guard) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('onBeforeRouteLeave');\n  }\n\n  return useFilteredGuard(guard, isLeaveNavigation)\n}\n\nvar noop = function () {};\nfunction useFilteredGuard (guard, fn) {\n  var instance = getCurrentInstance();\n  var router = useRouter();\n\n  var target = instance.proxy;\n  // find the nearest RouterView to know the depth\n  while (\n    target &&\n    target.$vnode &&\n    target.$vnode.data &&\n    target.$vnode.data.routerViewDepth == null\n  ) {\n    target = target.$parent;\n  }\n\n  var depth =\n    target && target.$vnode && target.$vnode.data\n      ? target.$vnode.data.routerViewDepth\n      : null;\n\n  if (depth != null) {\n    var removeGuard = router.beforeEach(function (to, from, next) {\n      return fn(to, from, depth) ? guard(to, from, next) : next()\n    });\n\n    onUnmounted(removeGuard);\n    return removeGuard\n  }\n\n  return noop\n}\n\n/*  */\n\nfunction guardEvent (e) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) { return }\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) { return }\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    var target = e.currentTarget.getAttribute('target');\n    if (/\\b_blank\\b/i.test(target)) { return }\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault();\n  }\n  return true\n}\n\nfunction includesParams (outer, inner) {\n  var loop = function ( key ) {\n    var innerValue = inner[key];\n    var outerValue = outer[key];\n    if (typeof innerValue === 'string') {\n      if (innerValue !== outerValue) { return { v: false } }\n    } else {\n      if (\n        !Array.isArray(outerValue) ||\n        outerValue.length !== innerValue.length ||\n        innerValue.some(function (value, i) { return value !== outerValue[i]; })\n      ) {\n        return { v: false }\n      }\n    }\n  };\n\n  for (var key in inner) {\n    var returned = loop( key );\n\n    if ( returned ) return returned.v;\n  }\n\n  return true\n}\n\n// helpers from vue router 4\n\nfunction isSameRouteLocationParamsValue (a, b) {\n  return Array.isArray(a)\n    ? isEquivalentArray(a, b)\n    : Array.isArray(b)\n      ? isEquivalentArray(b, a)\n      : a === b\n}\n\nfunction isEquivalentArray (a, b) {\n  return Array.isArray(b)\n    ? a.length === b.length && a.every(function (value, i) { return value === b[i]; })\n    : a.length === 1 && a[0] === b\n}\n\nfunction isSameRouteLocationParams (a, b) {\n  if (Object.keys(a).length !== Object.keys(b).length) { return false }\n\n  for (var key in a) {\n    if (!isSameRouteLocationParamsValue(a[key], b[key])) { return false }\n  }\n\n  return true\n}\n\nfunction useLink (props) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useLink');\n  }\n\n  var router = useRouter();\n  var currentRoute = useRoute();\n\n  var resolvedRoute = computed(function () { return router.resolve(unref(props.to), currentRoute); });\n\n  var activeRecordIndex = computed(function () {\n    var route = resolvedRoute.value.route;\n    var matched = route.matched;\n    var length = matched.length;\n    var routeMatched = matched[length - 1];\n    var currentMatched = currentRoute.matched;\n    if (!routeMatched || !currentMatched.length) { return -1 }\n    var index = currentMatched.indexOf(routeMatched);\n    if (index > -1) { return index }\n    // possible parent record\n    var parentRecord = currentMatched[currentMatched.length - 2];\n\n    return (\n      // we are dealing with nested routes\n      length > 1 &&\n        // if the parent and matched route have the same path, this link is\n        // referring to the empty child. Or we currently are on a different\n        // child of the same parent\n        parentRecord && parentRecord === routeMatched.parent\n    )\n  });\n\n  var isActive = computed(\n    function () { return activeRecordIndex.value > -1 &&\n      includesParams(currentRoute.params, resolvedRoute.value.route.params); }\n  );\n  var isExactActive = computed(\n    function () { return activeRecordIndex.value > -1 &&\n      activeRecordIndex.value === currentRoute.matched.length - 1 &&\n      isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params); }\n  );\n\n  var navigate = function (e) {\n    var href = resolvedRoute.value.route;\n    if (guardEvent(e)) {\n      return props.replace\n        ? router.replace(href)\n        : router.push(href)\n    }\n    return Promise.resolve()\n  };\n\n  return {\n    href: computed(function () { return resolvedRoute.value.href; }),\n    route: computed(function () { return resolvedRoute.value.route; }),\n    isExactActive: isExactActive,\n    isActive: isActive,\n    navigate: navigate\n  }\n}\n\nexport { isSameRouteLocationParams, onBeforeRouteLeave, onBeforeRouteUpdate, useLink, useRoute, useRouter };\n"
  },
  {
    "path": "dist/vue-router.common.js",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\n'use strict';\n\n/*  */\n\nfunction assert (condition, message) {\n  if (!condition) {\n    throw new Error((\"[vue-router] \" + message))\n  }\n}\n\nfunction warn (condition, message) {\n  if (!condition) {\n    typeof console !== 'undefined' && console.warn((\"[vue-router] \" + message));\n  }\n}\n\nfunction extend (a, b) {\n  for (var key in b) {\n    a[key] = b[key];\n  }\n  return a\n}\n\n/*  */\n\nvar encodeReserveRE = /[!'()*]/g;\nvar encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };\nvar commaRE = /%2C/g;\n\n// fixed encodeURIComponent which is more conformant to RFC3986:\n// - escapes [!'()*]\n// - preserve commas\nvar encode = function (str) { return encodeURIComponent(str)\n    .replace(encodeReserveRE, encodeReserveReplacer)\n    .replace(commaRE, ','); };\n\nfunction decode (str) {\n  try {\n    return decodeURIComponent(str)\n  } catch (err) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(false, (\"Error decoding \\\"\" + str + \"\\\". Leaving it intact.\"));\n    }\n  }\n  return str\n}\n\nfunction resolveQuery (\n  query,\n  extraQuery,\n  _parseQuery\n) {\n  if ( extraQuery === void 0 ) extraQuery = {};\n\n  var parse = _parseQuery || parseQuery;\n  var parsedQuery;\n  try {\n    parsedQuery = parse(query || '');\n  } catch (e) {\n    process.env.NODE_ENV !== 'production' && warn(false, e.message);\n    parsedQuery = {};\n  }\n  for (var key in extraQuery) {\n    var value = extraQuery[key];\n    parsedQuery[key] = Array.isArray(value)\n      ? value.map(castQueryParamValue)\n      : castQueryParamValue(value);\n  }\n  return parsedQuery\n}\n\nvar castQueryParamValue = function (value) { return (value == null || typeof value === 'object' ? value : String(value)); };\n\nfunction parseQuery (query) {\n  var res = {};\n\n  query = query.trim().replace(/^(\\?|#|&)/, '');\n\n  if (!query) {\n    return res\n  }\n\n  query.split('&').forEach(function (param) {\n    var parts = param.replace(/\\+/g, ' ').split('=');\n    var key = decode(parts.shift());\n    var val = parts.length > 0 ? decode(parts.join('=')) : null;\n\n    if (res[key] === undefined) {\n      res[key] = val;\n    } else if (Array.isArray(res[key])) {\n      res[key].push(val);\n    } else {\n      res[key] = [res[key], val];\n    }\n  });\n\n  return res\n}\n\nfunction stringifyQuery (obj) {\n  var res = obj\n    ? Object.keys(obj)\n      .map(function (key) {\n        var val = obj[key];\n\n        if (val === undefined) {\n          return ''\n        }\n\n        if (val === null) {\n          return encode(key)\n        }\n\n        if (Array.isArray(val)) {\n          var result = [];\n          val.forEach(function (val2) {\n            if (val2 === undefined) {\n              return\n            }\n            if (val2 === null) {\n              result.push(encode(key));\n            } else {\n              result.push(encode(key) + '=' + encode(val2));\n            }\n          });\n          return result.join('&')\n        }\n\n        return encode(key) + '=' + encode(val)\n      })\n      .filter(function (x) { return x.length > 0; })\n      .join('&')\n    : null;\n  return res ? (\"?\" + res) : ''\n}\n\n/*  */\n\nvar trailingSlashRE = /\\/?$/;\n\nfunction createRoute (\n  record,\n  location,\n  redirectedFrom,\n  router\n) {\n  var stringifyQuery = router && router.options.stringifyQuery;\n\n  var query = location.query || {};\n  try {\n    query = clone(query);\n  } catch (e) {}\n\n  var route = {\n    name: location.name || (record && record.name),\n    meta: (record && record.meta) || {},\n    path: location.path || '/',\n    hash: location.hash || '',\n    query: query,\n    params: location.params || {},\n    fullPath: getFullPath(location, stringifyQuery),\n    matched: record ? formatMatch(record) : []\n  };\n  if (redirectedFrom) {\n    route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);\n  }\n  return Object.freeze(route)\n}\n\nfunction clone (value) {\n  if (Array.isArray(value)) {\n    return value.map(clone)\n  } else if (value && typeof value === 'object') {\n    var res = {};\n    for (var key in value) {\n      res[key] = clone(value[key]);\n    }\n    return res\n  } else {\n    return value\n  }\n}\n\n// the starting route that represents the initial state\nvar START = createRoute(null, {\n  path: '/'\n});\n\nfunction formatMatch (record) {\n  var res = [];\n  while (record) {\n    res.unshift(record);\n    record = record.parent;\n  }\n  return res\n}\n\nfunction getFullPath (\n  ref,\n  _stringifyQuery\n) {\n  var path = ref.path;\n  var query = ref.query; if ( query === void 0 ) query = {};\n  var hash = ref.hash; if ( hash === void 0 ) hash = '';\n\n  var stringify = _stringifyQuery || stringifyQuery;\n  return (path || '/') + stringify(query) + hash\n}\n\nfunction isSameRoute (a, b, onlyPath) {\n  if (b === START) {\n    return a === b\n  } else if (!b) {\n    return false\n  } else if (a.path && b.path) {\n    return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||\n      a.hash === b.hash &&\n      isObjectEqual(a.query, b.query))\n  } else if (a.name && b.name) {\n    return (\n      a.name === b.name &&\n      (onlyPath || (\n        a.hash === b.hash &&\n      isObjectEqual(a.query, b.query) &&\n      isObjectEqual(a.params, b.params))\n      )\n    )\n  } else {\n    return false\n  }\n}\n\nfunction isObjectEqual (a, b) {\n  if ( a === void 0 ) a = {};\n  if ( b === void 0 ) b = {};\n\n  // handle null value #1566\n  if (!a || !b) { return a === b }\n  var aKeys = Object.keys(a).sort();\n  var bKeys = Object.keys(b).sort();\n  if (aKeys.length !== bKeys.length) {\n    return false\n  }\n  return aKeys.every(function (key, i) {\n    var aVal = a[key];\n    var bKey = bKeys[i];\n    if (bKey !== key) { return false }\n    var bVal = b[key];\n    // query values can be null and undefined\n    if (aVal == null || bVal == null) { return aVal === bVal }\n    // check nested equality\n    if (typeof aVal === 'object' && typeof bVal === 'object') {\n      return isObjectEqual(aVal, bVal)\n    }\n    return String(aVal) === String(bVal)\n  })\n}\n\nfunction isIncludedRoute (current, target) {\n  return (\n    current.path.replace(trailingSlashRE, '/').indexOf(\n      target.path.replace(trailingSlashRE, '/')\n    ) === 0 &&\n    (!target.hash || current.hash === target.hash) &&\n    queryIncludes(current.query, target.query)\n  )\n}\n\nfunction queryIncludes (current, target) {\n  for (var key in target) {\n    if (!(key in current)) {\n      return false\n    }\n  }\n  return true\n}\n\nfunction handleRouteEntered (route) {\n  for (var i = 0; i < route.matched.length; i++) {\n    var record = route.matched[i];\n    for (var name in record.instances) {\n      var instance = record.instances[name];\n      var cbs = record.enteredCbs[name];\n      if (!instance || !cbs) { continue }\n      delete record.enteredCbs[name];\n      for (var i$1 = 0; i$1 < cbs.length; i$1++) {\n        if (!instance._isBeingDestroyed) { cbs[i$1](instance); }\n      }\n    }\n  }\n}\n\nvar View = {\n  name: 'RouterView',\n  functional: true,\n  props: {\n    name: {\n      type: String,\n      default: 'default'\n    }\n  },\n  render: function render (_, ref) {\n    var props = ref.props;\n    var children = ref.children;\n    var parent = ref.parent;\n    var data = ref.data;\n\n    // used by devtools to display a router-view badge\n    data.routerView = true;\n\n    // directly use parent context's createElement() function\n    // so that components rendered by router-view can resolve named slots\n    var h = parent.$createElement;\n    var name = props.name;\n    var route = parent.$route;\n    var cache = parent._routerViewCache || (parent._routerViewCache = {});\n\n    // determine current view depth, also check to see if the tree\n    // has been toggled inactive but kept-alive.\n    var depth = 0;\n    var inactive = false;\n    while (parent && parent._routerRoot !== parent) {\n      var vnodeData = parent.$vnode ? parent.$vnode.data : {};\n      if (vnodeData.routerView) {\n        depth++;\n      }\n      if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {\n        inactive = true;\n      }\n      parent = parent.$parent;\n    }\n    data.routerViewDepth = depth;\n\n    // render previous view if the tree is inactive and kept-alive\n    if (inactive) {\n      var cachedData = cache[name];\n      var cachedComponent = cachedData && cachedData.component;\n      if (cachedComponent) {\n        // #2301\n        // pass props\n        if (cachedData.configProps) {\n          fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps);\n        }\n        return h(cachedComponent, data, children)\n      } else {\n        // render previous empty view\n        return h()\n      }\n    }\n\n    var matched = route.matched[depth];\n    var component = matched && matched.components[name];\n\n    // render empty node if no matched route or no config component\n    if (!matched || !component) {\n      cache[name] = null;\n      return h()\n    }\n\n    // cache component\n    cache[name] = { component: component };\n\n    // attach instance registration hook\n    // this will be called in the instance's injected lifecycle hooks\n    data.registerRouteInstance = function (vm, val) {\n      // val could be undefined for unregistration\n      var current = matched.instances[name];\n      if (\n        (val && current !== vm) ||\n        (!val && current === vm)\n      ) {\n        matched.instances[name] = val;\n      }\n    }\n\n    // also register instance in prepatch hook\n    // in case the same component instance is reused across different routes\n    ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {\n      matched.instances[name] = vnode.componentInstance;\n    };\n\n    // register instance in init hook\n    // in case kept-alive component be actived when routes changed\n    data.hook.init = function (vnode) {\n      if (vnode.data.keepAlive &&\n        vnode.componentInstance &&\n        vnode.componentInstance !== matched.instances[name]\n      ) {\n        matched.instances[name] = vnode.componentInstance;\n      }\n\n      // if the route transition has already been confirmed then we weren't\n      // able to call the cbs during confirmation as the component was not\n      // registered yet, so we call it here.\n      handleRouteEntered(route);\n    };\n\n    var configProps = matched.props && matched.props[name];\n    // save route and configProps in cache\n    if (configProps) {\n      extend(cache[name], {\n        route: route,\n        configProps: configProps\n      });\n      fillPropsinData(component, data, route, configProps);\n    }\n\n    return h(component, data, children)\n  }\n};\n\nfunction fillPropsinData (component, data, route, configProps) {\n  // resolve props\n  var propsToPass = data.props = resolveProps(route, configProps);\n  if (propsToPass) {\n    // clone to prevent mutation\n    propsToPass = data.props = extend({}, propsToPass);\n    // pass non-declared props as attrs\n    var attrs = data.attrs = data.attrs || {};\n    for (var key in propsToPass) {\n      if (!component.props || !(key in component.props)) {\n        attrs[key] = propsToPass[key];\n        delete propsToPass[key];\n      }\n    }\n  }\n}\n\nfunction resolveProps (route, config) {\n  switch (typeof config) {\n    case 'undefined':\n      return\n    case 'object':\n      return config\n    case 'function':\n      return config(route)\n    case 'boolean':\n      return config ? route.params : undefined\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false,\n          \"props in \\\"\" + (route.path) + \"\\\" is a \" + (typeof config) + \", \" +\n          \"expecting an object, function or boolean.\"\n        );\n      }\n  }\n}\n\n/*  */\n\nfunction resolvePath (\n  relative,\n  base,\n  append\n) {\n  var firstChar = relative.charAt(0);\n  if (firstChar === '/') {\n    return relative\n  }\n\n  if (firstChar === '?' || firstChar === '#') {\n    return base + relative\n  }\n\n  var stack = base.split('/');\n\n  // remove trailing segment if:\n  // - not appending\n  // - appending to trailing slash (last segment is empty)\n  if (!append || !stack[stack.length - 1]) {\n    stack.pop();\n  }\n\n  // resolve relative path\n  var segments = relative.replace(/^\\//, '').split('/');\n  for (var i = 0; i < segments.length; i++) {\n    var segment = segments[i];\n    if (segment === '..') {\n      stack.pop();\n    } else if (segment !== '.') {\n      stack.push(segment);\n    }\n  }\n\n  // ensure leading slash\n  if (stack[0] !== '') {\n    stack.unshift('');\n  }\n\n  return stack.join('/')\n}\n\nfunction parsePath (path) {\n  var hash = '';\n  var query = '';\n\n  var hashIndex = path.indexOf('#');\n  if (hashIndex >= 0) {\n    hash = path.slice(hashIndex);\n    path = path.slice(0, hashIndex);\n  }\n\n  var queryIndex = path.indexOf('?');\n  if (queryIndex >= 0) {\n    query = path.slice(queryIndex + 1);\n    path = path.slice(0, queryIndex);\n  }\n\n  return {\n    path: path,\n    query: query,\n    hash: hash\n  }\n}\n\nfunction cleanPath (path) {\n  return path.replace(/\\/(?:\\s*\\/)+/g, '/')\n}\n\nvar isarray = Array.isArray || function (arr) {\n  return Object.prototype.toString.call(arr) == '[object Array]';\n};\n\n/**\n * Expose `pathToRegexp`.\n */\nvar pathToRegexp_1 = pathToRegexp;\nvar parse_1 = parse;\nvar compile_1 = compile;\nvar tokensToFunction_1 = tokensToFunction;\nvar tokensToRegExp_1 = tokensToRegExp;\n\n/**\n * The main path matching regexp utility.\n *\n * @type {RegExp}\n */\nvar PATH_REGEXP = new RegExp([\n  // Match escaped characters that would otherwise appear in future matches.\n  // This allows the user to escape special characters that won't transform.\n  '(\\\\\\\\.)',\n  // Match Express-style parameters and un-named parameters with a prefix\n  // and optional suffixes. Matches appear as:\n  //\n  // \"/:test(\\\\d+)?\" => [\"/\", \"test\", \"\\d+\", undefined, \"?\", undefined]\n  // \"/route(\\\\d+)\"  => [undefined, undefined, undefined, \"\\d+\", undefined, undefined]\n  // \"/*\"            => [\"/\", undefined, undefined, undefined, undefined, \"*\"]\n  '([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))'\n].join('|'), 'g');\n\n/**\n * Parse a string for the raw tokens.\n *\n * @param  {string}  str\n * @param  {Object=} options\n * @return {!Array}\n */\nfunction parse (str, options) {\n  var tokens = [];\n  var key = 0;\n  var index = 0;\n  var path = '';\n  var defaultDelimiter = options && options.delimiter || '/';\n  var res;\n\n  while ((res = PATH_REGEXP.exec(str)) != null) {\n    var m = res[0];\n    var escaped = res[1];\n    var offset = res.index;\n    path += str.slice(index, offset);\n    index = offset + m.length;\n\n    // Ignore already escaped sequences.\n    if (escaped) {\n      path += escaped[1];\n      continue\n    }\n\n    var next = str[index];\n    var prefix = res[2];\n    var name = res[3];\n    var capture = res[4];\n    var group = res[5];\n    var modifier = res[6];\n    var asterisk = res[7];\n\n    // Push the current path onto the tokens.\n    if (path) {\n      tokens.push(path);\n      path = '';\n    }\n\n    var partial = prefix != null && next != null && next !== prefix;\n    var repeat = modifier === '+' || modifier === '*';\n    var optional = modifier === '?' || modifier === '*';\n    var delimiter = res[2] || defaultDelimiter;\n    var pattern = capture || group;\n\n    tokens.push({\n      name: name || key++,\n      prefix: prefix || '',\n      delimiter: delimiter,\n      optional: optional,\n      repeat: repeat,\n      partial: partial,\n      asterisk: !!asterisk,\n      pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')\n    });\n  }\n\n  // Match any characters still remaining.\n  if (index < str.length) {\n    path += str.substr(index);\n  }\n\n  // If the path exists, push it onto the end.\n  if (path) {\n    tokens.push(path);\n  }\n\n  return tokens\n}\n\n/**\n * Compile a string to a template function for the path.\n *\n * @param  {string}             str\n * @param  {Object=}            options\n * @return {!function(Object=, Object=)}\n */\nfunction compile (str, options) {\n  return tokensToFunction(parse(str, options), options)\n}\n\n/**\n * Prettier encoding of URI path segments.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeURIComponentPretty (str) {\n  return encodeURI(str).replace(/[\\/?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeAsterisk (str) {\n  return encodeURI(str).replace(/[?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Expose a method for transforming tokens into the path function.\n */\nfunction tokensToFunction (tokens, options) {\n  // Compile all the tokens into regexps.\n  var matches = new Array(tokens.length);\n\n  // Compile all the patterns before compilation.\n  for (var i = 0; i < tokens.length; i++) {\n    if (typeof tokens[i] === 'object') {\n      matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));\n    }\n  }\n\n  return function (obj, opts) {\n    var path = '';\n    var data = obj || {};\n    var options = opts || {};\n    var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;\n\n    for (var i = 0; i < tokens.length; i++) {\n      var token = tokens[i];\n\n      if (typeof token === 'string') {\n        path += token;\n\n        continue\n      }\n\n      var value = data[token.name];\n      var segment;\n\n      if (value == null) {\n        if (token.optional) {\n          // Prepend partial segment prefixes.\n          if (token.partial) {\n            path += token.prefix;\n          }\n\n          continue\n        } else {\n          throw new TypeError('Expected \"' + token.name + '\" to be defined')\n        }\n      }\n\n      if (isarray(value)) {\n        if (!token.repeat) {\n          throw new TypeError('Expected \"' + token.name + '\" to not repeat, but received `' + JSON.stringify(value) + '`')\n        }\n\n        if (value.length === 0) {\n          if (token.optional) {\n            continue\n          } else {\n            throw new TypeError('Expected \"' + token.name + '\" to not be empty')\n          }\n        }\n\n        for (var j = 0; j < value.length; j++) {\n          segment = encode(value[j]);\n\n          if (!matches[i].test(segment)) {\n            throw new TypeError('Expected all \"' + token.name + '\" to match \"' + token.pattern + '\", but received `' + JSON.stringify(segment) + '`')\n          }\n\n          path += (j === 0 ? token.prefix : token.delimiter) + segment;\n        }\n\n        continue\n      }\n\n      segment = token.asterisk ? encodeAsterisk(value) : encode(value);\n\n      if (!matches[i].test(segment)) {\n        throw new TypeError('Expected \"' + token.name + '\" to match \"' + token.pattern + '\", but received \"' + segment + '\"')\n      }\n\n      path += token.prefix + segment;\n    }\n\n    return path\n  }\n}\n\n/**\n * Escape a regular expression string.\n *\n * @param  {string} str\n * @return {string}\n */\nfunction escapeString (str) {\n  return str.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g, '\\\\$1')\n}\n\n/**\n * Escape the capturing group by escaping special characters and meaning.\n *\n * @param  {string} group\n * @return {string}\n */\nfunction escapeGroup (group) {\n  return group.replace(/([=!:$\\/()])/g, '\\\\$1')\n}\n\n/**\n * Attach the keys as a property of the regexp.\n *\n * @param  {!RegExp} re\n * @param  {Array}   keys\n * @return {!RegExp}\n */\nfunction attachKeys (re, keys) {\n  re.keys = keys;\n  return re\n}\n\n/**\n * Get the flags for a regexp from the options.\n *\n * @param  {Object} options\n * @return {string}\n */\nfunction flags (options) {\n  return options && options.sensitive ? '' : 'i'\n}\n\n/**\n * Pull out keys from a regexp.\n *\n * @param  {!RegExp} path\n * @param  {!Array}  keys\n * @return {!RegExp}\n */\nfunction regexpToRegexp (path, keys) {\n  // Use a negative lookahead to match only capturing groups.\n  var groups = path.source.match(/\\((?!\\?)/g);\n\n  if (groups) {\n    for (var i = 0; i < groups.length; i++) {\n      keys.push({\n        name: i,\n        prefix: null,\n        delimiter: null,\n        optional: false,\n        repeat: false,\n        partial: false,\n        asterisk: false,\n        pattern: null\n      });\n    }\n  }\n\n  return attachKeys(path, keys)\n}\n\n/**\n * Transform an array into a regexp.\n *\n * @param  {!Array}  path\n * @param  {Array}   keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction arrayToRegexp (path, keys, options) {\n  var parts = [];\n\n  for (var i = 0; i < path.length; i++) {\n    parts.push(pathToRegexp(path[i], keys, options).source);\n  }\n\n  var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));\n\n  return attachKeys(regexp, keys)\n}\n\n/**\n * Create a path regexp from string input.\n *\n * @param  {string}  path\n * @param  {!Array}  keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction stringToRegexp (path, keys, options) {\n  return tokensToRegExp(parse(path, options), keys, options)\n}\n\n/**\n * Expose a function for taking tokens and returning a RegExp.\n *\n * @param  {!Array}          tokens\n * @param  {(Array|Object)=} keys\n * @param  {Object=}         options\n * @return {!RegExp}\n */\nfunction tokensToRegExp (tokens, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  var strict = options.strict;\n  var end = options.end !== false;\n  var route = '';\n\n  // Iterate over the tokens and create our regexp string.\n  for (var i = 0; i < tokens.length; i++) {\n    var token = tokens[i];\n\n    if (typeof token === 'string') {\n      route += escapeString(token);\n    } else {\n      var prefix = escapeString(token.prefix);\n      var capture = '(?:' + token.pattern + ')';\n\n      keys.push(token);\n\n      if (token.repeat) {\n        capture += '(?:' + prefix + capture + ')*';\n      }\n\n      if (token.optional) {\n        if (!token.partial) {\n          capture = '(?:' + prefix + '(' + capture + '))?';\n        } else {\n          capture = prefix + '(' + capture + ')?';\n        }\n      } else {\n        capture = prefix + '(' + capture + ')';\n      }\n\n      route += capture;\n    }\n  }\n\n  var delimiter = escapeString(options.delimiter || '/');\n  var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;\n\n  // In non-strict mode we allow a slash at the end of match. If the path to\n  // match already ends with a slash, we remove it for consistency. The slash\n  // is valid at the end of a path match, not in the middle. This is important\n  // in non-ending mode, where \"/test/\" shouldn't match \"/test//route\".\n  if (!strict) {\n    route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';\n  }\n\n  if (end) {\n    route += '$';\n  } else {\n    // In non-ending mode, we need the capturing groups to match as much as\n    // possible by using a positive lookahead to the end or next path segment.\n    route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';\n  }\n\n  return attachKeys(new RegExp('^' + route, flags(options)), keys)\n}\n\n/**\n * Normalize the given path string, returning a regular expression.\n *\n * An empty array can be passed in for the keys, which will hold the\n * placeholder key descriptions. For example, using `/user/:id`, `keys` will\n * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.\n *\n * @param  {(string|RegExp|Array)} path\n * @param  {(Array|Object)=}       keys\n * @param  {Object=}               options\n * @return {!RegExp}\n */\nfunction pathToRegexp (path, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  if (path instanceof RegExp) {\n    return regexpToRegexp(path, /** @type {!Array} */ (keys))\n  }\n\n  if (isarray(path)) {\n    return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)\n  }\n\n  return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)\n}\npathToRegexp_1.parse = parse_1;\npathToRegexp_1.compile = compile_1;\npathToRegexp_1.tokensToFunction = tokensToFunction_1;\npathToRegexp_1.tokensToRegExp = tokensToRegExp_1;\n\n/*  */\n\n// $flow-disable-line\nvar regexpCompileCache = Object.create(null);\n\nfunction fillParams (\n  path,\n  params,\n  routeMsg\n) {\n  params = params || {};\n  try {\n    var filler =\n      regexpCompileCache[path] ||\n      (regexpCompileCache[path] = pathToRegexp_1.compile(path));\n\n    // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}\n    // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string\n    if (typeof params.pathMatch === 'string') { params[0] = params.pathMatch; }\n\n    return filler(params, { pretty: true })\n  } catch (e) {\n    if (process.env.NODE_ENV !== 'production') {\n      // Fix #3072 no warn if `pathMatch` is string\n      warn(typeof params.pathMatch === 'string', (\"missing param for \" + routeMsg + \": \" + (e.message)));\n    }\n    return ''\n  } finally {\n    // delete the 0 if it was added\n    delete params[0];\n  }\n}\n\n/*  */\n\nfunction normalizeLocation (\n  raw,\n  current,\n  append,\n  router\n) {\n  var next = typeof raw === 'string' ? { path: raw } : raw;\n  // named target\n  if (next._normalized) {\n    return next\n  } else if (next.name) {\n    next = extend({}, raw);\n    var params = next.params;\n    if (params && typeof params === 'object') {\n      next.params = extend({}, params);\n    }\n    return next\n  }\n\n  // relative params\n  if (!next.path && next.params && current) {\n    next = extend({}, next);\n    next._normalized = true;\n    var params$1 = extend(extend({}, current.params), next.params);\n    if (current.name) {\n      next.name = current.name;\n      next.params = params$1;\n    } else if (current.matched.length) {\n      var rawPath = current.matched[current.matched.length - 1].path;\n      next.path = fillParams(rawPath, params$1, (\"path \" + (current.path)));\n    } else if (process.env.NODE_ENV !== 'production') {\n      warn(false, \"relative params navigation requires a current route.\");\n    }\n    return next\n  }\n\n  var parsedPath = parsePath(next.path || '');\n  var basePath = (current && current.path) || '/';\n  var path = parsedPath.path\n    ? resolvePath(parsedPath.path, basePath, append || next.append)\n    : basePath;\n\n  var query = resolveQuery(\n    parsedPath.query,\n    next.query,\n    router && router.options.parseQuery\n  );\n\n  var hash = next.hash || parsedPath.hash;\n  if (hash && hash.charAt(0) !== '#') {\n    hash = \"#\" + hash;\n  }\n\n  return {\n    _normalized: true,\n    path: path,\n    query: query,\n    hash: hash\n  }\n}\n\n/*  */\n\n// work around weird flow bug\nvar toTypes = [String, Object];\nvar eventTypes = [String, Array];\n\nvar noop = function () {};\n\nvar warnedCustomSlot;\nvar warnedTagProp;\nvar warnedEventProp;\n\nvar Link = {\n  name: 'RouterLink',\n  props: {\n    to: {\n      type: toTypes,\n      required: true\n    },\n    tag: {\n      type: String,\n      default: 'a'\n    },\n    custom: Boolean,\n    exact: Boolean,\n    exactPath: Boolean,\n    append: Boolean,\n    replace: Boolean,\n    activeClass: String,\n    exactActiveClass: String,\n    ariaCurrentValue: {\n      type: String,\n      default: 'page'\n    },\n    event: {\n      type: eventTypes,\n      default: 'click'\n    }\n  },\n  render: function render (h) {\n    var this$1$1 = this;\n\n    var router = this.$router;\n    var current = this.$route;\n    var ref = router.resolve(\n      this.to,\n      current,\n      this.append\n    );\n    var location = ref.location;\n    var route = ref.route;\n    var href = ref.href;\n\n    var classes = {};\n    var globalActiveClass = router.options.linkActiveClass;\n    var globalExactActiveClass = router.options.linkExactActiveClass;\n    // Support global empty active class\n    var activeClassFallback =\n      globalActiveClass == null ? 'router-link-active' : globalActiveClass;\n    var exactActiveClassFallback =\n      globalExactActiveClass == null\n        ? 'router-link-exact-active'\n        : globalExactActiveClass;\n    var activeClass =\n      this.activeClass == null ? activeClassFallback : this.activeClass;\n    var exactActiveClass =\n      this.exactActiveClass == null\n        ? exactActiveClassFallback\n        : this.exactActiveClass;\n\n    var compareTarget = route.redirectedFrom\n      ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)\n      : route;\n\n    classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath);\n    classes[activeClass] = this.exact || this.exactPath\n      ? classes[exactActiveClass]\n      : isIncludedRoute(current, compareTarget);\n\n    var ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null;\n\n    var handler = function (e) {\n      if (guardEvent(e)) {\n        if (this$1$1.replace) {\n          router.replace(location, noop);\n        } else {\n          router.push(location, noop);\n        }\n      }\n    };\n\n    var on = { click: guardEvent };\n    if (Array.isArray(this.event)) {\n      this.event.forEach(function (e) {\n        on[e] = handler;\n      });\n    } else {\n      on[this.event] = handler;\n    }\n\n    var data = { class: classes };\n\n    var scopedSlot =\n      !this.$scopedSlots.$hasNormal &&\n      this.$scopedSlots.default &&\n      this.$scopedSlots.default({\n        href: href,\n        route: route,\n        navigate: handler,\n        isActive: classes[activeClass],\n        isExactActive: classes[exactActiveClass]\n      });\n\n    if (scopedSlot) {\n      if (process.env.NODE_ENV !== 'production' && !this.custom) {\n        !warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\\n<router-link v-slot=\"{ navigate, href }\" custom></router-link>\\n');\n        warnedCustomSlot = true;\n      }\n      if (scopedSlot.length === 1) {\n        return scopedSlot[0]\n      } else if (scopedSlot.length > 1 || !scopedSlot.length) {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(\n            false,\n            (\"<router-link> with to=\\\"\" + (this.to) + \"\\\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.\")\n          );\n        }\n        return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)\n      }\n    }\n\n    if (process.env.NODE_ENV !== 'production') {\n      if ('tag' in this.$options.propsData && !warnedTagProp) {\n        warn(\n          false,\n          \"<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n        );\n        warnedTagProp = true;\n      }\n      if ('event' in this.$options.propsData && !warnedEventProp) {\n        warn(\n          false,\n          \"<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n        );\n        warnedEventProp = true;\n      }\n    }\n\n    if (this.tag === 'a') {\n      data.on = on;\n      data.attrs = { href: href, 'aria-current': ariaCurrentValue };\n    } else {\n      // find the first <a> child and apply listener and href\n      var a = findAnchor(this.$slots.default);\n      if (a) {\n        // in case the <a> is a static node\n        a.isStatic = false;\n        var aData = (a.data = extend({}, a.data));\n        aData.on = aData.on || {};\n        // transform existing events in both objects into arrays so we can push later\n        for (var event in aData.on) {\n          var handler$1 = aData.on[event];\n          if (event in on) {\n            aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];\n          }\n        }\n        // append new listeners for router-link\n        for (var event$1 in on) {\n          if (event$1 in aData.on) {\n            // on[event] is always a function\n            aData.on[event$1].push(on[event$1]);\n          } else {\n            aData.on[event$1] = handler;\n          }\n        }\n\n        var aAttrs = (a.data.attrs = extend({}, a.data.attrs));\n        aAttrs.href = href;\n        aAttrs['aria-current'] = ariaCurrentValue;\n      } else {\n        // doesn't have <a> child, apply listener to self\n        data.on = on;\n      }\n    }\n\n    return h(this.tag, data, this.$slots.default)\n  }\n};\n\nfunction guardEvent (e) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) { return }\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) { return }\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    var target = e.currentTarget.getAttribute('target');\n    if (/\\b_blank\\b/i.test(target)) { return }\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault();\n  }\n  return true\n}\n\nfunction findAnchor (children) {\n  if (children) {\n    var child;\n    for (var i = 0; i < children.length; i++) {\n      child = children[i];\n      if (child.tag === 'a') {\n        return child\n      }\n      if (child.children && (child = findAnchor(child.children))) {\n        return child\n      }\n    }\n  }\n}\n\nvar _Vue;\n\nfunction install (Vue) {\n  if (install.installed && _Vue === Vue) { return }\n  install.installed = true;\n\n  _Vue = Vue;\n\n  var isDef = function (v) { return v !== undefined; };\n\n  var registerInstance = function (vm, callVal) {\n    var i = vm.$options._parentVnode;\n    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {\n      i(vm, callVal);\n    }\n  };\n\n  Vue.mixin({\n    beforeCreate: function beforeCreate () {\n      if (isDef(this.$options.router)) {\n        this._routerRoot = this;\n        this._router = this.$options.router;\n        this._router.init(this);\n        Vue.util.defineReactive(this, '_route', this._router.history.current);\n      } else {\n        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;\n      }\n      registerInstance(this, this);\n    },\n    destroyed: function destroyed () {\n      registerInstance(this);\n    }\n  });\n\n  Object.defineProperty(Vue.prototype, '$router', {\n    get: function get () { return this._routerRoot._router }\n  });\n\n  Object.defineProperty(Vue.prototype, '$route', {\n    get: function get () { return this._routerRoot._route }\n  });\n\n  Vue.component('RouterView', View);\n  Vue.component('RouterLink', Link);\n\n  var strats = Vue.config.optionMergeStrategies;\n  // use the same hook merging strategy for route hooks\n  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;\n}\n\n/*  */\n\nvar inBrowser = typeof window !== 'undefined';\n\n/*  */\n\nfunction createRouteMap (\n  routes,\n  oldPathList,\n  oldPathMap,\n  oldNameMap,\n  parentRoute\n) {\n  // the path list is used to control path matching priority\n  var pathList = oldPathList || [];\n  // $flow-disable-line\n  var pathMap = oldPathMap || Object.create(null);\n  // $flow-disable-line\n  var nameMap = oldNameMap || Object.create(null);\n\n  routes.forEach(function (route) {\n    addRouteRecord(pathList, pathMap, nameMap, route, parentRoute);\n  });\n\n  // ensure wildcard routes are always at the end\n  for (var i = 0, l = pathList.length; i < l; i++) {\n    if (pathList[i] === '*') {\n      pathList.push(pathList.splice(i, 1)[0]);\n      l--;\n      i--;\n    }\n  }\n\n  if (process.env.NODE_ENV === 'development') {\n    // warn if routes do not include leading slashes\n    var found = pathList\n    // check for missing leading slash\n      .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });\n\n    if (found.length > 0) {\n      var pathNames = found.map(function (path) { return (\"- \" + path); }).join('\\n');\n      warn(false, (\"Non-nested routes must include a leading slash character. Fix the following routes: \\n\" + pathNames));\n    }\n  }\n\n  return {\n    pathList: pathList,\n    pathMap: pathMap,\n    nameMap: nameMap\n  }\n}\n\nfunction addRouteRecord (\n  pathList,\n  pathMap,\n  nameMap,\n  route,\n  parent,\n  matchAs\n) {\n  var path = route.path;\n  var name = route.name;\n  if (process.env.NODE_ENV !== 'production') {\n    assert(path != null, \"\\\"path\\\" is required in a route configuration.\");\n    assert(\n      typeof route.component !== 'string',\n      \"route config \\\"component\\\" for path: \" + (String(\n        path || name\n      )) + \" cannot be a \" + \"string id. Use an actual component instead.\"\n    );\n\n    warn(\n      // eslint-disable-next-line no-control-regex\n      !/[^\\u0000-\\u007F]+/.test(path),\n      \"Route with path \\\"\" + path + \"\\\" contains unencoded characters, make sure \" +\n        \"your path is correctly encoded before passing it to the router. Use \" +\n        \"encodeURI to encode static segments of your path.\"\n    );\n  }\n\n  var pathToRegexpOptions =\n    route.pathToRegexpOptions || {};\n  var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);\n\n  if (typeof route.caseSensitive === 'boolean') {\n    pathToRegexpOptions.sensitive = route.caseSensitive;\n  }\n\n  var record = {\n    path: normalizedPath,\n    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),\n    components: route.components || { default: route.component },\n    alias: route.alias\n      ? typeof route.alias === 'string'\n        ? [route.alias]\n        : route.alias\n      : [],\n    instances: {},\n    enteredCbs: {},\n    name: name,\n    parent: parent,\n    matchAs: matchAs,\n    redirect: route.redirect,\n    beforeEnter: route.beforeEnter,\n    meta: route.meta || {},\n    props:\n      route.props == null\n        ? {}\n        : route.components\n          ? route.props\n          : { default: route.props }\n  };\n\n  if (route.children) {\n    // Warn if route is named, does not redirect and has a default child route.\n    // If users navigate to this route by name, the default child will\n    // not be rendered (GH Issue #629)\n    if (process.env.NODE_ENV !== 'production') {\n      if (\n        route.name &&\n        !route.redirect &&\n        route.children.some(function (child) { return /^\\/?$/.test(child.path); })\n      ) {\n        warn(\n          false,\n          \"Named Route '\" + (route.name) + \"' has a default child route. \" +\n            \"When navigating to this named route (:to=\\\"{name: '\" + (route.name) + \"'}\\\"), \" +\n            \"the default child route will not be rendered. Remove the name from \" +\n            \"this route and use the name of the default child route for named \" +\n            \"links instead.\"\n        );\n      }\n    }\n    route.children.forEach(function (child) {\n      var childMatchAs = matchAs\n        ? cleanPath((matchAs + \"/\" + (child.path)))\n        : undefined;\n      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);\n    });\n  }\n\n  if (!pathMap[record.path]) {\n    pathList.push(record.path);\n    pathMap[record.path] = record;\n  }\n\n  if (route.alias !== undefined) {\n    var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];\n    for (var i = 0; i < aliases.length; ++i) {\n      var alias = aliases[i];\n      if (process.env.NODE_ENV !== 'production' && alias === path) {\n        warn(\n          false,\n          (\"Found an alias with the same value as the path: \\\"\" + path + \"\\\". You have to remove that alias. It will be ignored in development.\")\n        );\n        // skip in dev to make it work\n        continue\n      }\n\n      var aliasRoute = {\n        path: alias,\n        children: route.children\n      };\n      addRouteRecord(\n        pathList,\n        pathMap,\n        nameMap,\n        aliasRoute,\n        parent,\n        record.path || '/' // matchAs\n      );\n    }\n  }\n\n  if (name) {\n    if (!nameMap[name]) {\n      nameMap[name] = record;\n    } else if (process.env.NODE_ENV !== 'production' && !matchAs) {\n      warn(\n        false,\n        \"Duplicate named routes definition: \" +\n          \"{ name: \\\"\" + name + \"\\\", path: \\\"\" + (record.path) + \"\\\" }\"\n      );\n    }\n  }\n}\n\nfunction compileRouteRegex (\n  path,\n  pathToRegexpOptions\n) {\n  var regex = pathToRegexp_1(path, [], pathToRegexpOptions);\n  if (process.env.NODE_ENV !== 'production') {\n    var keys = Object.create(null);\n    regex.keys.forEach(function (key) {\n      warn(\n        !keys[key.name],\n        (\"Duplicate param keys in route with path: \\\"\" + path + \"\\\"\")\n      );\n      keys[key.name] = true;\n    });\n  }\n  return regex\n}\n\nfunction normalizePath (\n  path,\n  parent,\n  strict\n) {\n  if (!strict) { path = path.replace(/\\/$/, ''); }\n  if (path[0] === '/') { return path }\n  if (parent == null) { return path }\n  return cleanPath(((parent.path) + \"/\" + path))\n}\n\n/*  */\n\n\n\nfunction createMatcher (\n  routes,\n  router\n) {\n  var ref = createRouteMap(routes);\n  var pathList = ref.pathList;\n  var pathMap = ref.pathMap;\n  var nameMap = ref.nameMap;\n\n  function addRoutes (routes) {\n    createRouteMap(routes, pathList, pathMap, nameMap);\n  }\n\n  function addRoute (parentOrRoute, route) {\n    var parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined;\n    // $flow-disable-line\n    createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent);\n\n    // add aliases of parent\n    if (parent && parent.alias.length) {\n      createRouteMap(\n        // $flow-disable-line route is defined if parent is\n        parent.alias.map(function (alias) { return ({ path: alias, children: [route] }); }),\n        pathList,\n        pathMap,\n        nameMap,\n        parent\n      );\n    }\n  }\n\n  function getRoutes () {\n    return pathList.map(function (path) { return pathMap[path]; })\n  }\n\n  function match (\n    raw,\n    currentRoute,\n    redirectedFrom\n  ) {\n    var location = normalizeLocation(raw, currentRoute, false, router);\n    var name = location.name;\n\n    if (name) {\n      var record = nameMap[name];\n      if (process.env.NODE_ENV !== 'production') {\n        warn(record, (\"Route with name '\" + name + \"' does not exist\"));\n      }\n      if (!record) { return _createRoute(null, location) }\n      var paramNames = record.regex.keys\n        .filter(function (key) { return !key.optional; })\n        .map(function (key) { return key.name; });\n\n      if (typeof location.params !== 'object') {\n        location.params = {};\n      }\n\n      if (currentRoute && typeof currentRoute.params === 'object') {\n        for (var key in currentRoute.params) {\n          if (!(key in location.params) && paramNames.indexOf(key) > -1) {\n            location.params[key] = currentRoute.params[key];\n          }\n        }\n      }\n\n      location.path = fillParams(record.path, location.params, (\"named route \\\"\" + name + \"\\\"\"));\n      return _createRoute(record, location, redirectedFrom)\n    } else if (location.path) {\n      location.params = {};\n      for (var i = 0; i < pathList.length; i++) {\n        var path = pathList[i];\n        var record$1 = pathMap[path];\n        if (matchRoute(record$1.regex, location.path, location.params)) {\n          return _createRoute(record$1, location, redirectedFrom)\n        }\n      }\n    }\n    // no match\n    return _createRoute(null, location)\n  }\n\n  function redirect (\n    record,\n    location\n  ) {\n    var originalRedirect = record.redirect;\n    var redirect = typeof originalRedirect === 'function'\n      ? originalRedirect(createRoute(record, location, null, router))\n      : originalRedirect;\n\n    if (typeof redirect === 'string') {\n      redirect = { path: redirect };\n    }\n\n    if (!redirect || typeof redirect !== 'object') {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false, (\"invalid redirect option: \" + (JSON.stringify(redirect)))\n        );\n      }\n      return _createRoute(null, location)\n    }\n\n    var re = redirect;\n    var name = re.name;\n    var path = re.path;\n    var query = location.query;\n    var hash = location.hash;\n    var params = location.params;\n    query = re.hasOwnProperty('query') ? re.query : query;\n    hash = re.hasOwnProperty('hash') ? re.hash : hash;\n    params = re.hasOwnProperty('params') ? re.params : params;\n\n    if (name) {\n      // resolved named direct\n      var targetRecord = nameMap[name];\n      if (process.env.NODE_ENV !== 'production') {\n        assert(targetRecord, (\"redirect failed: named route \\\"\" + name + \"\\\" not found.\"));\n      }\n      return match({\n        _normalized: true,\n        name: name,\n        query: query,\n        hash: hash,\n        params: params\n      }, undefined, location)\n    } else if (path) {\n      // 1. resolve relative redirect\n      var rawPath = resolveRecordPath(path, record);\n      // 2. resolve params\n      var resolvedPath = fillParams(rawPath, params, (\"redirect route with path \\\"\" + rawPath + \"\\\"\"));\n      // 3. rematch with existing query and hash\n      return match({\n        _normalized: true,\n        path: resolvedPath,\n        query: query,\n        hash: hash\n      }, undefined, location)\n    } else {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(false, (\"invalid redirect option: \" + (JSON.stringify(redirect))));\n      }\n      return _createRoute(null, location)\n    }\n  }\n\n  function alias (\n    record,\n    location,\n    matchAs\n  ) {\n    var aliasedPath = fillParams(matchAs, location.params, (\"aliased route with path \\\"\" + matchAs + \"\\\"\"));\n    var aliasedMatch = match({\n      _normalized: true,\n      path: aliasedPath\n    });\n    if (aliasedMatch) {\n      var matched = aliasedMatch.matched;\n      var aliasedRecord = matched[matched.length - 1];\n      location.params = aliasedMatch.params;\n      return _createRoute(aliasedRecord, location)\n    }\n    return _createRoute(null, location)\n  }\n\n  function _createRoute (\n    record,\n    location,\n    redirectedFrom\n  ) {\n    if (record && record.redirect) {\n      return redirect(record, redirectedFrom || location)\n    }\n    if (record && record.matchAs) {\n      return alias(record, location, record.matchAs)\n    }\n    return createRoute(record, location, redirectedFrom, router)\n  }\n\n  return {\n    match: match,\n    addRoute: addRoute,\n    getRoutes: getRoutes,\n    addRoutes: addRoutes\n  }\n}\n\nfunction matchRoute (\n  regex,\n  path,\n  params\n) {\n  var m = path.match(regex);\n\n  if (!m) {\n    return false\n  } else if (!params) {\n    return true\n  }\n\n  for (var i = 1, len = m.length; i < len; ++i) {\n    var key = regex.keys[i - 1];\n    if (key) {\n      // Fix #1994: using * with props: true generates a param named 0\n      params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i];\n    }\n  }\n\n  return true\n}\n\nfunction resolveRecordPath (path, record) {\n  return resolvePath(path, record.parent ? record.parent.path : '/', true)\n}\n\n/*  */\n\n// use User Timing api (if present) for more accurate key precision\nvar Time =\n  inBrowser && window.performance && window.performance.now\n    ? window.performance\n    : Date;\n\nfunction genStateKey () {\n  return Time.now().toFixed(3)\n}\n\nvar _key = genStateKey();\n\nfunction getStateKey () {\n  return _key\n}\n\nfunction setStateKey (key) {\n  return (_key = key)\n}\n\n/*  */\n\nvar positionStore = Object.create(null);\n\nfunction setupScroll () {\n  // Prevent browser scroll behavior on History popstate\n  if ('scrollRestoration' in window.history) {\n    window.history.scrollRestoration = 'manual';\n  }\n  // Fix for #1585 for Firefox\n  // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678\n  // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with\n  // window.location.protocol + '//' + window.location.host\n  // location.host contains the port and location.hostname doesn't\n  var protocolAndPath = window.location.protocol + '//' + window.location.host;\n  var absolutePath = window.location.href.replace(protocolAndPath, '');\n  // preserve existing history state as it could be overriden by the user\n  var stateCopy = extend({}, window.history.state);\n  stateCopy.key = getStateKey();\n  window.history.replaceState(stateCopy, '', absolutePath);\n  window.addEventListener('popstate', handlePopState);\n  return function () {\n    window.removeEventListener('popstate', handlePopState);\n  }\n}\n\nfunction handleScroll (\n  router,\n  to,\n  from,\n  isPop\n) {\n  if (!router.app) {\n    return\n  }\n\n  var behavior = router.options.scrollBehavior;\n  if (!behavior) {\n    return\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    assert(typeof behavior === 'function', \"scrollBehavior must be a function\");\n  }\n\n  // wait until re-render finishes before scrolling\n  router.app.$nextTick(function () {\n    var position = getScrollPosition();\n    var shouldScroll = behavior.call(\n      router,\n      to,\n      from,\n      isPop ? position : null\n    );\n\n    if (!shouldScroll) {\n      return\n    }\n\n    if (typeof shouldScroll.then === 'function') {\n      shouldScroll\n        .then(function (shouldScroll) {\n          scrollToPosition((shouldScroll), position);\n        })\n        .catch(function (err) {\n          if (process.env.NODE_ENV !== 'production') {\n            assert(false, err.toString());\n          }\n        });\n    } else {\n      scrollToPosition(shouldScroll, position);\n    }\n  });\n}\n\nfunction saveScrollPosition () {\n  var key = getStateKey();\n  if (key) {\n    positionStore[key] = {\n      x: window.pageXOffset,\n      y: window.pageYOffset\n    };\n  }\n}\n\nfunction handlePopState (e) {\n  saveScrollPosition();\n  if (e.state && e.state.key) {\n    setStateKey(e.state.key);\n  }\n}\n\nfunction getScrollPosition () {\n  var key = getStateKey();\n  if (key) {\n    return positionStore[key]\n  }\n}\n\nfunction getElementPosition (el, offset) {\n  var docEl = document.documentElement;\n  var docRect = docEl.getBoundingClientRect();\n  var elRect = el.getBoundingClientRect();\n  return {\n    x: elRect.left - docRect.left - offset.x,\n    y: elRect.top - docRect.top - offset.y\n  }\n}\n\nfunction isValidPosition (obj) {\n  return isNumber(obj.x) || isNumber(obj.y)\n}\n\nfunction normalizePosition (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : window.pageXOffset,\n    y: isNumber(obj.y) ? obj.y : window.pageYOffset\n  }\n}\n\nfunction normalizeOffset (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : 0,\n    y: isNumber(obj.y) ? obj.y : 0\n  }\n}\n\nfunction isNumber (v) {\n  return typeof v === 'number'\n}\n\nvar hashStartsWithNumberRE = /^#\\d/;\n\nfunction scrollToPosition (shouldScroll, position) {\n  var isObject = typeof shouldScroll === 'object';\n  if (isObject && typeof shouldScroll.selector === 'string') {\n    // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]\n    // but at the same time, it doesn't make much sense to select an element with an id and an extra selector\n    var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line\n      ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line\n      : document.querySelector(shouldScroll.selector);\n\n    if (el) {\n      var offset =\n        shouldScroll.offset && typeof shouldScroll.offset === 'object'\n          ? shouldScroll.offset\n          : {};\n      offset = normalizeOffset(offset);\n      position = getElementPosition(el, offset);\n    } else if (isValidPosition(shouldScroll)) {\n      position = normalizePosition(shouldScroll);\n    }\n  } else if (isObject && isValidPosition(shouldScroll)) {\n    position = normalizePosition(shouldScroll);\n  }\n\n  if (position) {\n    // $flow-disable-line\n    if ('scrollBehavior' in document.documentElement.style) {\n      window.scrollTo({\n        left: position.x,\n        top: position.y,\n        // $flow-disable-line\n        behavior: shouldScroll.behavior\n      });\n    } else {\n      window.scrollTo(position.x, position.y);\n    }\n  }\n}\n\n/*  */\n\nvar supportsPushState =\n  inBrowser &&\n  (function () {\n    var ua = window.navigator.userAgent;\n\n    if (\n      (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&\n      ua.indexOf('Mobile Safari') !== -1 &&\n      ua.indexOf('Chrome') === -1 &&\n      ua.indexOf('Windows Phone') === -1\n    ) {\n      return false\n    }\n\n    return window.history && typeof window.history.pushState === 'function'\n  })();\n\nfunction pushState (url, replace) {\n  saveScrollPosition();\n  // try...catch the pushState call to get around Safari\n  // DOM Exception 18 where it limits to 100 pushState calls\n  var history = window.history;\n  try {\n    if (replace) {\n      // preserve existing history state as it could be overriden by the user\n      var stateCopy = extend({}, history.state);\n      stateCopy.key = getStateKey();\n      history.replaceState(stateCopy, '', url);\n    } else {\n      history.pushState({ key: setStateKey(genStateKey()) }, '', url);\n    }\n  } catch (e) {\n    window.location[replace ? 'replace' : 'assign'](url);\n  }\n}\n\nfunction replaceState (url) {\n  pushState(url, true);\n}\n\n// When changing thing, also edit router.d.ts\nvar NavigationFailureType = {\n  redirected: 2,\n  aborted: 4,\n  cancelled: 8,\n  duplicated: 16\n};\n\nfunction createNavigationRedirectedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.redirected,\n    (\"Redirected when going from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (stringifyRoute(\n      to\n    )) + \"\\\" via a navigation guard.\")\n  )\n}\n\nfunction createNavigationDuplicatedError (from, to) {\n  var error = createRouterError(\n    from,\n    to,\n    NavigationFailureType.duplicated,\n    (\"Avoided redundant navigation to current location: \\\"\" + (from.fullPath) + \"\\\".\")\n  );\n  // backwards compatible with the first introduction of Errors\n  error.name = 'NavigationDuplicated';\n  return error\n}\n\nfunction createNavigationCancelledError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.cancelled,\n    (\"Navigation cancelled from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" with a new navigation.\")\n  )\n}\n\nfunction createNavigationAbortedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.aborted,\n    (\"Navigation aborted from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" via a navigation guard.\")\n  )\n}\n\nfunction createRouterError (from, to, type, message) {\n  var error = new Error(message);\n  error._isRouter = true;\n  error.from = from;\n  error.to = to;\n  error.type = type;\n\n  return error\n}\n\nvar propertiesToLog = ['params', 'query', 'hash'];\n\nfunction stringifyRoute (to) {\n  if (typeof to === 'string') { return to }\n  if ('path' in to) { return to.path }\n  var location = {};\n  propertiesToLog.forEach(function (key) {\n    if (key in to) { location[key] = to[key]; }\n  });\n  return JSON.stringify(location, null, 2)\n}\n\nfunction isError (err) {\n  return Object.prototype.toString.call(err).indexOf('Error') > -1\n}\n\nfunction isNavigationFailure (err, errorType) {\n  return (\n    isError(err) &&\n    err._isRouter &&\n    (errorType == null || err.type === errorType)\n  )\n}\n\n/*  */\n\nfunction runQueue (queue, fn, cb) {\n  var step = function (index) {\n    if (index >= queue.length) {\n      cb();\n    } else {\n      if (queue[index]) {\n        fn(queue[index], function () {\n          step(index + 1);\n        });\n      } else {\n        step(index + 1);\n      }\n    }\n  };\n  step(0);\n}\n\n/*  */\n\nfunction resolveAsyncComponents (matched) {\n  return function (to, from, next) {\n    var hasAsync = false;\n    var pending = 0;\n    var error = null;\n\n    flatMapComponents(matched, function (def, _, match, key) {\n      // if it's a function and doesn't have cid attached,\n      // assume it's an async component resolve function.\n      // we are not using Vue's default async resolving mechanism because\n      // we want to halt the navigation until the incoming component has been\n      // resolved.\n      if (typeof def === 'function' && def.cid === undefined) {\n        hasAsync = true;\n        pending++;\n\n        var resolve = once(function (resolvedDef) {\n          if (isESModule(resolvedDef)) {\n            resolvedDef = resolvedDef.default;\n          }\n          // save resolved on async factory in case it's used elsewhere\n          def.resolved = typeof resolvedDef === 'function'\n            ? resolvedDef\n            : _Vue.extend(resolvedDef);\n          match.components[key] = resolvedDef;\n          pending--;\n          if (pending <= 0) {\n            next();\n          }\n        });\n\n        var reject = once(function (reason) {\n          var msg = \"Failed to resolve async component \" + key + \": \" + reason;\n          process.env.NODE_ENV !== 'production' && warn(false, msg);\n          if (!error) {\n            error = isError(reason)\n              ? reason\n              : new Error(msg);\n            next(error);\n          }\n        });\n\n        var res;\n        try {\n          res = def(resolve, reject);\n        } catch (e) {\n          reject(e);\n        }\n        if (res) {\n          if (typeof res.then === 'function') {\n            res.then(resolve, reject);\n          } else {\n            // new syntax in Vue 2.3\n            var comp = res.component;\n            if (comp && typeof comp.then === 'function') {\n              comp.then(resolve, reject);\n            }\n          }\n        }\n      }\n    });\n\n    if (!hasAsync) { next(); }\n  }\n}\n\nfunction flatMapComponents (\n  matched,\n  fn\n) {\n  return flatten(matched.map(function (m) {\n    return Object.keys(m.components).map(function (key) { return fn(\n      m.components[key],\n      m.instances[key],\n      m, key\n    ); })\n  }))\n}\n\nfunction flatten (arr) {\n  return Array.prototype.concat.apply([], arr)\n}\n\nvar hasSymbol =\n  typeof Symbol === 'function' &&\n  typeof Symbol.toStringTag === 'symbol';\n\nfunction isESModule (obj) {\n  return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')\n}\n\n// in Webpack 2, require.ensure now also returns a Promise\n// so the resolve/reject functions may get called an extra time\n// if the user uses an arrow function shorthand that happens to\n// return that Promise.\nfunction once (fn) {\n  var called = false;\n  return function () {\n    var args = [], len = arguments.length;\n    while ( len-- ) args[ len ] = arguments[ len ];\n\n    if (called) { return }\n    called = true;\n    return fn.apply(this, args)\n  }\n}\n\n/*  */\n\nvar History = function History (router, base) {\n  this.router = router;\n  this.base = normalizeBase(base);\n  // start with a route object that stands for \"nowhere\"\n  this.current = START;\n  this.pending = null;\n  this.ready = false;\n  this.readyCbs = [];\n  this.readyErrorCbs = [];\n  this.errorCbs = [];\n  this.listeners = [];\n};\n\nHistory.prototype.listen = function listen (cb) {\n  this.cb = cb;\n};\n\nHistory.prototype.onReady = function onReady (cb, errorCb) {\n  if (this.ready) {\n    cb();\n  } else {\n    this.readyCbs.push(cb);\n    if (errorCb) {\n      this.readyErrorCbs.push(errorCb);\n    }\n  }\n};\n\nHistory.prototype.onError = function onError (errorCb) {\n  this.errorCbs.push(errorCb);\n};\n\nHistory.prototype.transitionTo = function transitionTo (\n  location,\n  onComplete,\n  onAbort\n) {\n    var this$1$1 = this;\n\n  var route;\n  // catch redirect option https://github.com/vuejs/vue-router/issues/3201\n  try {\n    route = this.router.match(location, this.current);\n  } catch (e) {\n    this.errorCbs.forEach(function (cb) {\n      cb(e);\n    });\n    // Exception should still be thrown\n    throw e\n  }\n  var prev = this.current;\n  this.confirmTransition(\n    route,\n    function () {\n      this$1$1.updateRoute(route);\n      onComplete && onComplete(route);\n      this$1$1.ensureURL();\n      this$1$1.router.afterHooks.forEach(function (hook) {\n        hook && hook(route, prev);\n      });\n\n      // fire ready cbs once\n      if (!this$1$1.ready) {\n        this$1$1.ready = true;\n        this$1$1.readyCbs.forEach(function (cb) {\n          cb(route);\n        });\n      }\n    },\n    function (err) {\n      if (onAbort) {\n        onAbort(err);\n      }\n      if (err && !this$1$1.ready) {\n        // Initial redirection should not mark the history as ready yet\n        // because it's triggered by the redirection instead\n        // https://github.com/vuejs/vue-router/issues/3225\n        // https://github.com/vuejs/vue-router/issues/3331\n        if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {\n          this$1$1.ready = true;\n          this$1$1.readyErrorCbs.forEach(function (cb) {\n            cb(err);\n          });\n        }\n      }\n    }\n  );\n};\n\nHistory.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  var current = this.current;\n  this.pending = route;\n  var abort = function (err) {\n    // changed after adding errors with\n    // https://github.com/vuejs/vue-router/pull/3047 before that change,\n    // redirect and aborted navigation would produce an err == null\n    if (!isNavigationFailure(err) && isError(err)) {\n      if (this$1$1.errorCbs.length) {\n        this$1$1.errorCbs.forEach(function (cb) {\n          cb(err);\n        });\n      } else {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(false, 'uncaught error during route navigation:');\n        }\n        console.error(err);\n      }\n    }\n    onAbort && onAbort(err);\n  };\n  var lastRouteIndex = route.matched.length - 1;\n  var lastCurrentIndex = current.matched.length - 1;\n  if (\n    isSameRoute(route, current) &&\n    // in the case the route map has been dynamically appended to\n    lastRouteIndex === lastCurrentIndex &&\n    route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]\n  ) {\n    this.ensureURL();\n    if (route.hash) {\n      handleScroll(this.router, current, route, false);\n    }\n    return abort(createNavigationDuplicatedError(current, route))\n  }\n\n  var ref = resolveQueue(\n    this.current.matched,\n    route.matched\n  );\n    var updated = ref.updated;\n    var deactivated = ref.deactivated;\n    var activated = ref.activated;\n\n  var queue = [].concat(\n    // in-component leave guards\n    extractLeaveGuards(deactivated),\n    // global before hooks\n    this.router.beforeHooks,\n    // in-component update hooks\n    extractUpdateHooks(updated),\n    // in-config enter guards\n    activated.map(function (m) { return m.beforeEnter; }),\n    // async components\n    resolveAsyncComponents(activated)\n  );\n\n  var iterator = function (hook, next) {\n    if (this$1$1.pending !== route) {\n      return abort(createNavigationCancelledError(current, route))\n    }\n    try {\n      hook(route, current, function (to) {\n        if (to === false) {\n          // next(false) -> abort navigation, ensure current URL\n          this$1$1.ensureURL(true);\n          abort(createNavigationAbortedError(current, route));\n        } else if (isError(to)) {\n          this$1$1.ensureURL(true);\n          abort(to);\n        } else if (\n          typeof to === 'string' ||\n          (typeof to === 'object' &&\n            (typeof to.path === 'string' || typeof to.name === 'string'))\n        ) {\n          // next('/') or next({ path: '/' }) -> redirect\n          abort(createNavigationRedirectedError(current, route));\n          if (typeof to === 'object' && to.replace) {\n            this$1$1.replace(to);\n          } else {\n            this$1$1.push(to);\n          }\n        } else {\n          // confirm transition and pass on the value\n          next(to);\n        }\n      });\n    } catch (e) {\n      abort(e);\n    }\n  };\n\n  runQueue(queue, iterator, function () {\n    // wait until async components are resolved before\n    // extracting in-component enter guards\n    var enterGuards = extractEnterGuards(activated);\n    var queue = enterGuards.concat(this$1$1.router.resolveHooks);\n    runQueue(queue, iterator, function () {\n      if (this$1$1.pending !== route) {\n        return abort(createNavigationCancelledError(current, route))\n      }\n      this$1$1.pending = null;\n      onComplete(route);\n      if (this$1$1.router.app) {\n        this$1$1.router.app.$nextTick(function () {\n          handleRouteEntered(route);\n        });\n      }\n    });\n  });\n};\n\nHistory.prototype.updateRoute = function updateRoute (route) {\n  this.current = route;\n  this.cb && this.cb(route);\n};\n\nHistory.prototype.setupListeners = function setupListeners () {\n  // Default implementation is empty\n};\n\nHistory.prototype.teardown = function teardown () {\n  // clean up event listeners\n  // https://github.com/vuejs/vue-router/issues/2341\n  this.listeners.forEach(function (cleanupListener) {\n    cleanupListener();\n  });\n  this.listeners = [];\n\n  // reset current history route\n  // https://github.com/vuejs/vue-router/issues/3294\n  this.current = START;\n  this.pending = null;\n};\n\nfunction normalizeBase (base) {\n  if (!base) {\n    if (inBrowser) {\n      // respect <base> tag\n      var baseEl = document.querySelector('base');\n      base = (baseEl && baseEl.getAttribute('href')) || '/';\n      // strip full URL origin\n      base = base.replace(/^https?:\\/\\/[^\\/]+/, '');\n    } else {\n      base = '/';\n    }\n  }\n  // make sure there's the starting slash\n  if (base.charAt(0) !== '/') {\n    base = '/' + base;\n  }\n  // remove trailing slash\n  return base.replace(/\\/$/, '')\n}\n\nfunction resolveQueue (\n  current,\n  next\n) {\n  var i;\n  var max = Math.max(current.length, next.length);\n  for (i = 0; i < max; i++) {\n    if (current[i] !== next[i]) {\n      break\n    }\n  }\n  return {\n    updated: next.slice(0, i),\n    activated: next.slice(i),\n    deactivated: current.slice(i)\n  }\n}\n\nfunction extractGuards (\n  records,\n  name,\n  bind,\n  reverse\n) {\n  var guards = flatMapComponents(records, function (def, instance, match, key) {\n    var guard = extractGuard(def, name);\n    if (guard) {\n      return Array.isArray(guard)\n        ? guard.map(function (guard) { return bind(guard, instance, match, key); })\n        : bind(guard, instance, match, key)\n    }\n  });\n  return flatten(reverse ? guards.reverse() : guards)\n}\n\nfunction extractGuard (\n  def,\n  key\n) {\n  if (typeof def !== 'function') {\n    // extend now so that global mixins are applied.\n    def = _Vue.extend(def);\n  }\n  return def.options[key]\n}\n\nfunction extractLeaveGuards (deactivated) {\n  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)\n}\n\nfunction extractUpdateHooks (updated) {\n  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)\n}\n\nfunction bindGuard (guard, instance) {\n  if (instance) {\n    return function boundRouteGuard () {\n      return guard.apply(instance, arguments)\n    }\n  }\n}\n\nfunction extractEnterGuards (\n  activated\n) {\n  return extractGuards(\n    activated,\n    'beforeRouteEnter',\n    function (guard, _, match, key) {\n      return bindEnterGuard(guard, match, key)\n    }\n  )\n}\n\nfunction bindEnterGuard (\n  guard,\n  match,\n  key\n) {\n  return function routeEnterGuard (to, from, next) {\n    return guard(to, from, function (cb) {\n      if (typeof cb === 'function') {\n        if (!match.enteredCbs[key]) {\n          match.enteredCbs[key] = [];\n        }\n        match.enteredCbs[key].push(cb);\n      }\n      next(cb);\n    })\n  }\n}\n\n/*  */\n\nvar HTML5History = /*@__PURE__*/(function (History) {\n  function HTML5History (router, base) {\n    History.call(this, router, base);\n\n    this._startLocation = getLocation(this.base);\n  }\n\n  if ( History ) HTML5History.__proto__ = History;\n  HTML5History.prototype = Object.create( History && History.prototype );\n  HTML5History.prototype.constructor = HTML5History;\n\n  HTML5History.prototype.setupListeners = function setupListeners () {\n    var this$1$1 = this;\n\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    var router = this.router;\n    var expectScroll = router.options.scrollBehavior;\n    var supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    var handleRoutingEvent = function () {\n      var current = this$1$1.current;\n\n      // Avoiding first `popstate` event dispatched in some browsers but first\n      // history route not updated since async guard at the same time.\n      var location = getLocation(this$1$1.base);\n      if (this$1$1.current === START && location === this$1$1._startLocation) {\n        return\n      }\n\n      this$1$1.transitionTo(location, function (route) {\n        if (supportsScroll) {\n          handleScroll(router, route, current, true);\n        }\n      });\n    };\n    window.addEventListener('popstate', handleRoutingEvent);\n    this.listeners.push(function () {\n      window.removeEventListener('popstate', handleRoutingEvent);\n    });\n  };\n\n  HTML5History.prototype.go = function go (n) {\n    window.history.go(n);\n  };\n\n  HTML5History.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(location, function (route) {\n      pushState(cleanPath(this$1$1.base + route.fullPath));\n      handleScroll(this$1$1.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  };\n\n  HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(location, function (route) {\n      replaceState(cleanPath(this$1$1.base + route.fullPath));\n      handleScroll(this$1$1.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  };\n\n  HTML5History.prototype.ensureURL = function ensureURL (push) {\n    if (getLocation(this.base) !== this.current.fullPath) {\n      var current = cleanPath(this.base + this.current.fullPath);\n      push ? pushState(current) : replaceState(current);\n    }\n  };\n\n  HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {\n    return getLocation(this.base)\n  };\n\n  return HTML5History;\n}(History));\n\nfunction getLocation (base) {\n  var path = window.location.pathname;\n  var pathLowerCase = path.toLowerCase();\n  var baseLowerCase = base.toLowerCase();\n  // base=\"/a\" shouldn't turn path=\"/app\" into \"/a/pp\"\n  // https://github.com/vuejs/vue-router/issues/3555\n  // so we ensure the trailing slash in the base\n  if (base && ((pathLowerCase === baseLowerCase) ||\n    (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {\n    path = path.slice(base.length);\n  }\n  return (path || '/') + window.location.search + window.location.hash\n}\n\n/*  */\n\nvar HashHistory = /*@__PURE__*/(function (History) {\n  function HashHistory (router, base, fallback) {\n    History.call(this, router, base);\n    // check history fallback deeplinking\n    if (fallback && checkFallback(this.base)) {\n      return\n    }\n    ensureSlash();\n  }\n\n  if ( History ) HashHistory.__proto__ = History;\n  HashHistory.prototype = Object.create( History && History.prototype );\n  HashHistory.prototype.constructor = HashHistory;\n\n  // this is delayed until the app mounts\n  // to avoid the hashchange listener being fired too early\n  HashHistory.prototype.setupListeners = function setupListeners () {\n    var this$1$1 = this;\n\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    var router = this.router;\n    var expectScroll = router.options.scrollBehavior;\n    var supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    var handleRoutingEvent = function () {\n      var current = this$1$1.current;\n      if (!ensureSlash()) {\n        return\n      }\n      this$1$1.transitionTo(getHash(), function (route) {\n        if (supportsScroll) {\n          handleScroll(this$1$1.router, route, current, true);\n        }\n        if (!supportsPushState) {\n          replaceHash(route.fullPath);\n        }\n      });\n    };\n    var eventType = supportsPushState ? 'popstate' : 'hashchange';\n    window.addEventListener(\n      eventType,\n      handleRoutingEvent\n    );\n    this.listeners.push(function () {\n      window.removeEventListener(eventType, handleRoutingEvent);\n    });\n  };\n\n  HashHistory.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(\n      location,\n      function (route) {\n        pushHash(route.fullPath);\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(\n      location,\n      function (route) {\n        replaceHash(route.fullPath);\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  HashHistory.prototype.go = function go (n) {\n    window.history.go(n);\n  };\n\n  HashHistory.prototype.ensureURL = function ensureURL (push) {\n    var current = this.current.fullPath;\n    if (getHash() !== current) {\n      push ? pushHash(current) : replaceHash(current);\n    }\n  };\n\n  HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n    return getHash()\n  };\n\n  return HashHistory;\n}(History));\n\nfunction checkFallback (base) {\n  var location = getLocation(base);\n  if (!/^\\/#/.test(location)) {\n    window.location.replace(cleanPath(base + '/#' + location));\n    return true\n  }\n}\n\nfunction ensureSlash () {\n  var path = getHash();\n  if (path.charAt(0) === '/') {\n    return true\n  }\n  replaceHash('/' + path);\n  return false\n}\n\nfunction getHash () {\n  // We can't use window.location.hash here because it's not\n  // consistent across browsers - Firefox will pre-decode it!\n  var href = window.location.href;\n  var index = href.indexOf('#');\n  // empty path\n  if (index < 0) { return '' }\n\n  href = href.slice(index + 1);\n\n  return href\n}\n\nfunction getUrl (path) {\n  var href = window.location.href;\n  var i = href.indexOf('#');\n  var base = i >= 0 ? href.slice(0, i) : href;\n  return (base + \"#\" + path)\n}\n\nfunction pushHash (path) {\n  if (supportsPushState) {\n    pushState(getUrl(path));\n  } else {\n    window.location.hash = path;\n  }\n}\n\nfunction replaceHash (path) {\n  if (supportsPushState) {\n    replaceState(getUrl(path));\n  } else {\n    window.location.replace(getUrl(path));\n  }\n}\n\n/*  */\n\nvar AbstractHistory = /*@__PURE__*/(function (History) {\n  function AbstractHistory (router, base) {\n    History.call(this, router, base);\n    this.stack = [];\n    this.index = -1;\n  }\n\n  if ( History ) AbstractHistory.__proto__ = History;\n  AbstractHistory.prototype = Object.create( History && History.prototype );\n  AbstractHistory.prototype.constructor = AbstractHistory;\n\n  AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    this.transitionTo(\n      location,\n      function (route) {\n        this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index + 1).concat(route);\n        this$1$1.index++;\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    this.transitionTo(\n      location,\n      function (route) {\n        this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index).concat(route);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  AbstractHistory.prototype.go = function go (n) {\n    var this$1$1 = this;\n\n    var targetIndex = this.index + n;\n    if (targetIndex < 0 || targetIndex >= this.stack.length) {\n      return\n    }\n    var route = this.stack[targetIndex];\n    this.confirmTransition(\n      route,\n      function () {\n        var prev = this$1$1.current;\n        this$1$1.index = targetIndex;\n        this$1$1.updateRoute(route);\n        this$1$1.router.afterHooks.forEach(function (hook) {\n          hook && hook(route, prev);\n        });\n      },\n      function (err) {\n        if (isNavigationFailure(err, NavigationFailureType.duplicated)) {\n          this$1$1.index = targetIndex;\n        }\n      }\n    );\n  };\n\n  AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n    var current = this.stack[this.stack.length - 1];\n    return current ? current.fullPath : '/'\n  };\n\n  AbstractHistory.prototype.ensureURL = function ensureURL () {\n    // noop\n  };\n\n  return AbstractHistory;\n}(History));\n\n/*  */\n\n\n\nvar VueRouter = function VueRouter (options) {\n  if ( options === void 0 ) options = {};\n\n  if (process.env.NODE_ENV !== 'production') {\n    warn(this instanceof VueRouter, \"Router must be called with the new operator.\");\n  }\n  this.app = null;\n  this.apps = [];\n  this.options = options;\n  this.beforeHooks = [];\n  this.resolveHooks = [];\n  this.afterHooks = [];\n  this.matcher = createMatcher(options.routes || [], this);\n\n  var mode = options.mode || 'hash';\n  this.fallback =\n    mode === 'history' && !supportsPushState && options.fallback !== false;\n  if (this.fallback) {\n    mode = 'hash';\n  }\n  if (!inBrowser) {\n    mode = 'abstract';\n  }\n  this.mode = mode;\n\n  switch (mode) {\n    case 'history':\n      this.history = new HTML5History(this, options.base);\n      break\n    case 'hash':\n      this.history = new HashHistory(this, options.base, this.fallback);\n      break\n    case 'abstract':\n      this.history = new AbstractHistory(this, options.base);\n      break\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        assert(false, (\"invalid mode: \" + mode));\n      }\n  }\n};\n\nvar prototypeAccessors = { currentRoute: { configurable: true } };\n\nVueRouter.prototype.match = function match (raw, current, redirectedFrom) {\n  return this.matcher.match(raw, current, redirectedFrom)\n};\n\nprototypeAccessors.currentRoute.get = function () {\n  return this.history && this.history.current\n};\n\nVueRouter.prototype.init = function init (app /* Vue component instance */) {\n    var this$1$1 = this;\n\n  process.env.NODE_ENV !== 'production' &&\n    assert(\n      install.installed,\n      \"not installed. Make sure to call `Vue.use(VueRouter)` \" +\n        \"before creating root instance.\"\n    );\n\n  this.apps.push(app);\n\n  // set up app destroyed handler\n  // https://github.com/vuejs/vue-router/issues/2639\n  app.$once('hook:destroyed', function () {\n    // clean out app from this.apps array once destroyed\n    var index = this$1$1.apps.indexOf(app);\n    if (index > -1) { this$1$1.apps.splice(index, 1); }\n    // ensure we still have a main app or null if no apps\n    // we do not release the router so it can be reused\n    if (this$1$1.app === app) { this$1$1.app = this$1$1.apps[0] || null; }\n\n    if (!this$1$1.app) { this$1$1.history.teardown(); }\n  });\n\n  // main app previously initialized\n  // return as we don't need to set up new history listener\n  if (this.app) {\n    return\n  }\n\n  this.app = app;\n\n  var history = this.history;\n\n  if (history instanceof HTML5History || history instanceof HashHistory) {\n    var handleInitialScroll = function (routeOrError) {\n      var from = history.current;\n      var expectScroll = this$1$1.options.scrollBehavior;\n      var supportsScroll = supportsPushState && expectScroll;\n\n      if (supportsScroll && 'fullPath' in routeOrError) {\n        handleScroll(this$1$1, routeOrError, from, false);\n      }\n    };\n    var setupListeners = function (routeOrError) {\n      history.setupListeners();\n      handleInitialScroll(routeOrError);\n    };\n    history.transitionTo(\n      history.getCurrentLocation(),\n      setupListeners,\n      setupListeners\n    );\n  }\n\n  history.listen(function (route) {\n    this$1$1.apps.forEach(function (app) {\n      app._route = route;\n    });\n  });\n};\n\nVueRouter.prototype.beforeEach = function beforeEach (fn) {\n  return registerHook(this.beforeHooks, fn)\n};\n\nVueRouter.prototype.beforeResolve = function beforeResolve (fn) {\n  return registerHook(this.resolveHooks, fn)\n};\n\nVueRouter.prototype.afterEach = function afterEach (fn) {\n  return registerHook(this.afterHooks, fn)\n};\n\nVueRouter.prototype.onReady = function onReady (cb, errorCb) {\n  this.history.onReady(cb, errorCb);\n};\n\nVueRouter.prototype.onError = function onError (errorCb) {\n  this.history.onError(errorCb);\n};\n\nVueRouter.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  // $flow-disable-line\n  if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n    return new Promise(function (resolve, reject) {\n      this$1$1.history.push(location, resolve, reject);\n    })\n  } else {\n    this.history.push(location, onComplete, onAbort);\n  }\n};\n\nVueRouter.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  // $flow-disable-line\n  if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n    return new Promise(function (resolve, reject) {\n      this$1$1.history.replace(location, resolve, reject);\n    })\n  } else {\n    this.history.replace(location, onComplete, onAbort);\n  }\n};\n\nVueRouter.prototype.go = function go (n) {\n  this.history.go(n);\n};\n\nVueRouter.prototype.back = function back () {\n  this.go(-1);\n};\n\nVueRouter.prototype.forward = function forward () {\n  this.go(1);\n};\n\nVueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {\n  var route = to\n    ? to.matched\n      ? to\n      : this.resolve(to).route\n    : this.currentRoute;\n  if (!route) {\n    return []\n  }\n  return [].concat.apply(\n    [],\n    route.matched.map(function (m) {\n      return Object.keys(m.components).map(function (key) {\n        return m.components[key]\n      })\n    })\n  )\n};\n\nVueRouter.prototype.resolve = function resolve (\n  to,\n  current,\n  append\n) {\n  current = current || this.history.current;\n  var location = normalizeLocation(to, current, append, this);\n  var route = this.match(location, current);\n  var fullPath = route.redirectedFrom || route.fullPath;\n  var base = this.history.base;\n  var href = createHref(base, fullPath, this.mode);\n  return {\n    location: location,\n    route: route,\n    href: href,\n    // for backwards compat\n    normalizedTo: location,\n    resolved: route\n  }\n};\n\nVueRouter.prototype.getRoutes = function getRoutes () {\n  return this.matcher.getRoutes()\n};\n\nVueRouter.prototype.addRoute = function addRoute (parentOrRoute, route) {\n  this.matcher.addRoute(parentOrRoute, route);\n  if (this.history.current !== START) {\n    this.history.transitionTo(this.history.getCurrentLocation());\n  }\n};\n\nVueRouter.prototype.addRoutes = function addRoutes (routes) {\n  if (process.env.NODE_ENV !== 'production') {\n    warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.');\n  }\n  this.matcher.addRoutes(routes);\n  if (this.history.current !== START) {\n    this.history.transitionTo(this.history.getCurrentLocation());\n  }\n};\n\nObject.defineProperties( VueRouter.prototype, prototypeAccessors );\n\nvar VueRouter$1 = VueRouter;\n\nfunction registerHook (list, fn) {\n  list.push(fn);\n  return function () {\n    var i = list.indexOf(fn);\n    if (i > -1) { list.splice(i, 1); }\n  }\n}\n\nfunction createHref (base, fullPath, mode) {\n  var path = mode === 'hash' ? '#' + fullPath : fullPath;\n  return base ? cleanPath(base + '/' + path) : path\n}\n\n// We cannot remove this as it would be a breaking change\nVueRouter.install = install;\nVueRouter.version = '3.6.5';\nVueRouter.isNavigationFailure = isNavigationFailure;\nVueRouter.NavigationFailureType = NavigationFailureType;\nVueRouter.START_LOCATION = START;\n\nif (inBrowser && window.Vue) {\n  window.Vue.use(VueRouter);\n}\n\nmodule.exports = VueRouter$1;\n"
  },
  {
    "path": "dist/vue-router.esm.browser.js",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\n/*  */\n\nfunction assert (condition, message) {\n  if (!condition) {\n    throw new Error(`[vue-router] ${message}`)\n  }\n}\n\nfunction warn (condition, message) {\n  if (!condition) {\n    typeof console !== 'undefined' && console.warn(`[vue-router] ${message}`);\n  }\n}\n\nfunction extend (a, b) {\n  for (const key in b) {\n    a[key] = b[key];\n  }\n  return a\n}\n\n/*  */\n\nconst encodeReserveRE = /[!'()*]/g;\nconst encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16);\nconst commaRE = /%2C/g;\n\n// fixed encodeURIComponent which is more conformant to RFC3986:\n// - escapes [!'()*]\n// - preserve commas\nconst encode = str =>\n  encodeURIComponent(str)\n    .replace(encodeReserveRE, encodeReserveReplacer)\n    .replace(commaRE, ',');\n\nfunction decode (str) {\n  try {\n    return decodeURIComponent(str)\n  } catch (err) {\n    {\n      warn(false, `Error decoding \"${str}\". Leaving it intact.`);\n    }\n  }\n  return str\n}\n\nfunction resolveQuery (\n  query,\n  extraQuery = {},\n  _parseQuery\n) {\n  const parse = _parseQuery || parseQuery;\n  let parsedQuery;\n  try {\n    parsedQuery = parse(query || '');\n  } catch (e) {\n    warn(false, e.message);\n    parsedQuery = {};\n  }\n  for (const key in extraQuery) {\n    const value = extraQuery[key];\n    parsedQuery[key] = Array.isArray(value)\n      ? value.map(castQueryParamValue)\n      : castQueryParamValue(value);\n  }\n  return parsedQuery\n}\n\nconst castQueryParamValue = value => (value == null || typeof value === 'object' ? value : String(value));\n\nfunction parseQuery (query) {\n  const res = {};\n\n  query = query.trim().replace(/^(\\?|#|&)/, '');\n\n  if (!query) {\n    return res\n  }\n\n  query.split('&').forEach(param => {\n    const parts = param.replace(/\\+/g, ' ').split('=');\n    const key = decode(parts.shift());\n    const val = parts.length > 0 ? decode(parts.join('=')) : null;\n\n    if (res[key] === undefined) {\n      res[key] = val;\n    } else if (Array.isArray(res[key])) {\n      res[key].push(val);\n    } else {\n      res[key] = [res[key], val];\n    }\n  });\n\n  return res\n}\n\nfunction stringifyQuery (obj) {\n  const res = obj\n    ? Object.keys(obj)\n      .map(key => {\n        const val = obj[key];\n\n        if (val === undefined) {\n          return ''\n        }\n\n        if (val === null) {\n          return encode(key)\n        }\n\n        if (Array.isArray(val)) {\n          const result = [];\n          val.forEach(val2 => {\n            if (val2 === undefined) {\n              return\n            }\n            if (val2 === null) {\n              result.push(encode(key));\n            } else {\n              result.push(encode(key) + '=' + encode(val2));\n            }\n          });\n          return result.join('&')\n        }\n\n        return encode(key) + '=' + encode(val)\n      })\n      .filter(x => x.length > 0)\n      .join('&')\n    : null;\n  return res ? `?${res}` : ''\n}\n\n/*  */\n\nconst trailingSlashRE = /\\/?$/;\n\nfunction createRoute (\n  record,\n  location,\n  redirectedFrom,\n  router\n) {\n  const stringifyQuery = router && router.options.stringifyQuery;\n\n  let query = location.query || {};\n  try {\n    query = clone(query);\n  } catch (e) {}\n\n  const route = {\n    name: location.name || (record && record.name),\n    meta: (record && record.meta) || {},\n    path: location.path || '/',\n    hash: location.hash || '',\n    query,\n    params: location.params || {},\n    fullPath: getFullPath(location, stringifyQuery),\n    matched: record ? formatMatch(record) : []\n  };\n  if (redirectedFrom) {\n    route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);\n  }\n  return Object.freeze(route)\n}\n\nfunction clone (value) {\n  if (Array.isArray(value)) {\n    return value.map(clone)\n  } else if (value && typeof value === 'object') {\n    const res = {};\n    for (const key in value) {\n      res[key] = clone(value[key]);\n    }\n    return res\n  } else {\n    return value\n  }\n}\n\n// the starting route that represents the initial state\nconst START = createRoute(null, {\n  path: '/'\n});\n\nfunction formatMatch (record) {\n  const res = [];\n  while (record) {\n    res.unshift(record);\n    record = record.parent;\n  }\n  return res\n}\n\nfunction getFullPath (\n  { path, query = {}, hash = '' },\n  _stringifyQuery\n) {\n  const stringify = _stringifyQuery || stringifyQuery;\n  return (path || '/') + stringify(query) + hash\n}\n\nfunction isSameRoute (a, b, onlyPath) {\n  if (b === START) {\n    return a === b\n  } else if (!b) {\n    return false\n  } else if (a.path && b.path) {\n    return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||\n      a.hash === b.hash &&\n      isObjectEqual(a.query, b.query))\n  } else if (a.name && b.name) {\n    return (\n      a.name === b.name &&\n      (onlyPath || (\n        a.hash === b.hash &&\n      isObjectEqual(a.query, b.query) &&\n      isObjectEqual(a.params, b.params))\n      )\n    )\n  } else {\n    return false\n  }\n}\n\nfunction isObjectEqual (a = {}, b = {}) {\n  // handle null value #1566\n  if (!a || !b) return a === b\n  const aKeys = Object.keys(a).sort();\n  const bKeys = Object.keys(b).sort();\n  if (aKeys.length !== bKeys.length) {\n    return false\n  }\n  return aKeys.every((key, i) => {\n    const aVal = a[key];\n    const bKey = bKeys[i];\n    if (bKey !== key) return false\n    const bVal = b[key];\n    // query values can be null and undefined\n    if (aVal == null || bVal == null) return aVal === bVal\n    // check nested equality\n    if (typeof aVal === 'object' && typeof bVal === 'object') {\n      return isObjectEqual(aVal, bVal)\n    }\n    return String(aVal) === String(bVal)\n  })\n}\n\nfunction isIncludedRoute (current, target) {\n  return (\n    current.path.replace(trailingSlashRE, '/').indexOf(\n      target.path.replace(trailingSlashRE, '/')\n    ) === 0 &&\n    (!target.hash || current.hash === target.hash) &&\n    queryIncludes(current.query, target.query)\n  )\n}\n\nfunction queryIncludes (current, target) {\n  for (const key in target) {\n    if (!(key in current)) {\n      return false\n    }\n  }\n  return true\n}\n\nfunction handleRouteEntered (route) {\n  for (let i = 0; i < route.matched.length; i++) {\n    const record = route.matched[i];\n    for (const name in record.instances) {\n      const instance = record.instances[name];\n      const cbs = record.enteredCbs[name];\n      if (!instance || !cbs) continue\n      delete record.enteredCbs[name];\n      for (let i = 0; i < cbs.length; i++) {\n        if (!instance._isBeingDestroyed) cbs[i](instance);\n      }\n    }\n  }\n}\n\nvar View = {\n  name: 'RouterView',\n  functional: true,\n  props: {\n    name: {\n      type: String,\n      default: 'default'\n    }\n  },\n  render (_, { props, children, parent, data }) {\n    // used by devtools to display a router-view badge\n    data.routerView = true;\n\n    // directly use parent context's createElement() function\n    // so that components rendered by router-view can resolve named slots\n    const h = parent.$createElement;\n    const name = props.name;\n    const route = parent.$route;\n    const cache = parent._routerViewCache || (parent._routerViewCache = {});\n\n    // determine current view depth, also check to see if the tree\n    // has been toggled inactive but kept-alive.\n    let depth = 0;\n    let inactive = false;\n    while (parent && parent._routerRoot !== parent) {\n      const vnodeData = parent.$vnode ? parent.$vnode.data : {};\n      if (vnodeData.routerView) {\n        depth++;\n      }\n      if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {\n        inactive = true;\n      }\n      parent = parent.$parent;\n    }\n    data.routerViewDepth = depth;\n\n    // render previous view if the tree is inactive and kept-alive\n    if (inactive) {\n      const cachedData = cache[name];\n      const cachedComponent = cachedData && cachedData.component;\n      if (cachedComponent) {\n        // #2301\n        // pass props\n        if (cachedData.configProps) {\n          fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps);\n        }\n        return h(cachedComponent, data, children)\n      } else {\n        // render previous empty view\n        return h()\n      }\n    }\n\n    const matched = route.matched[depth];\n    const component = matched && matched.components[name];\n\n    // render empty node if no matched route or no config component\n    if (!matched || !component) {\n      cache[name] = null;\n      return h()\n    }\n\n    // cache component\n    cache[name] = { component };\n\n    // attach instance registration hook\n    // this will be called in the instance's injected lifecycle hooks\n    data.registerRouteInstance = (vm, val) => {\n      // val could be undefined for unregistration\n      const current = matched.instances[name];\n      if (\n        (val && current !== vm) ||\n        (!val && current === vm)\n      ) {\n        matched.instances[name] = val;\n      }\n    }\n\n    // also register instance in prepatch hook\n    // in case the same component instance is reused across different routes\n    ;(data.hook || (data.hook = {})).prepatch = (_, vnode) => {\n      matched.instances[name] = vnode.componentInstance;\n    };\n\n    // register instance in init hook\n    // in case kept-alive component be actived when routes changed\n    data.hook.init = (vnode) => {\n      if (vnode.data.keepAlive &&\n        vnode.componentInstance &&\n        vnode.componentInstance !== matched.instances[name]\n      ) {\n        matched.instances[name] = vnode.componentInstance;\n      }\n\n      // if the route transition has already been confirmed then we weren't\n      // able to call the cbs during confirmation as the component was not\n      // registered yet, so we call it here.\n      handleRouteEntered(route);\n    };\n\n    const configProps = matched.props && matched.props[name];\n    // save route and configProps in cache\n    if (configProps) {\n      extend(cache[name], {\n        route,\n        configProps\n      });\n      fillPropsinData(component, data, route, configProps);\n    }\n\n    return h(component, data, children)\n  }\n};\n\nfunction fillPropsinData (component, data, route, configProps) {\n  // resolve props\n  let propsToPass = data.props = resolveProps(route, configProps);\n  if (propsToPass) {\n    // clone to prevent mutation\n    propsToPass = data.props = extend({}, propsToPass);\n    // pass non-declared props as attrs\n    const attrs = data.attrs = data.attrs || {};\n    for (const key in propsToPass) {\n      if (!component.props || !(key in component.props)) {\n        attrs[key] = propsToPass[key];\n        delete propsToPass[key];\n      }\n    }\n  }\n}\n\nfunction resolveProps (route, config) {\n  switch (typeof config) {\n    case 'undefined':\n      return\n    case 'object':\n      return config\n    case 'function':\n      return config(route)\n    case 'boolean':\n      return config ? route.params : undefined\n    default:\n      {\n        warn(\n          false,\n          `props in \"${route.path}\" is a ${typeof config}, ` +\n          `expecting an object, function or boolean.`\n        );\n      }\n  }\n}\n\n/*  */\n\nfunction resolvePath (\n  relative,\n  base,\n  append\n) {\n  const firstChar = relative.charAt(0);\n  if (firstChar === '/') {\n    return relative\n  }\n\n  if (firstChar === '?' || firstChar === '#') {\n    return base + relative\n  }\n\n  const stack = base.split('/');\n\n  // remove trailing segment if:\n  // - not appending\n  // - appending to trailing slash (last segment is empty)\n  if (!append || !stack[stack.length - 1]) {\n    stack.pop();\n  }\n\n  // resolve relative path\n  const segments = relative.replace(/^\\//, '').split('/');\n  for (let i = 0; i < segments.length; i++) {\n    const segment = segments[i];\n    if (segment === '..') {\n      stack.pop();\n    } else if (segment !== '.') {\n      stack.push(segment);\n    }\n  }\n\n  // ensure leading slash\n  if (stack[0] !== '') {\n    stack.unshift('');\n  }\n\n  return stack.join('/')\n}\n\nfunction parsePath (path) {\n  let hash = '';\n  let query = '';\n\n  const hashIndex = path.indexOf('#');\n  if (hashIndex >= 0) {\n    hash = path.slice(hashIndex);\n    path = path.slice(0, hashIndex);\n  }\n\n  const queryIndex = path.indexOf('?');\n  if (queryIndex >= 0) {\n    query = path.slice(queryIndex + 1);\n    path = path.slice(0, queryIndex);\n  }\n\n  return {\n    path,\n    query,\n    hash\n  }\n}\n\nfunction cleanPath (path) {\n  return path.replace(/\\/(?:\\s*\\/)+/g, '/')\n}\n\nvar isarray = Array.isArray || function (arr) {\n  return Object.prototype.toString.call(arr) == '[object Array]';\n};\n\n/**\n * Expose `pathToRegexp`.\n */\nvar pathToRegexp_1 = pathToRegexp;\nvar parse_1 = parse;\nvar compile_1 = compile;\nvar tokensToFunction_1 = tokensToFunction;\nvar tokensToRegExp_1 = tokensToRegExp;\n\n/**\n * The main path matching regexp utility.\n *\n * @type {RegExp}\n */\nvar PATH_REGEXP = new RegExp([\n  // Match escaped characters that would otherwise appear in future matches.\n  // This allows the user to escape special characters that won't transform.\n  '(\\\\\\\\.)',\n  // Match Express-style parameters and un-named parameters with a prefix\n  // and optional suffixes. Matches appear as:\n  //\n  // \"/:test(\\\\d+)?\" => [\"/\", \"test\", \"\\d+\", undefined, \"?\", undefined]\n  // \"/route(\\\\d+)\"  => [undefined, undefined, undefined, \"\\d+\", undefined, undefined]\n  // \"/*\"            => [\"/\", undefined, undefined, undefined, undefined, \"*\"]\n  '([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))'\n].join('|'), 'g');\n\n/**\n * Parse a string for the raw tokens.\n *\n * @param  {string}  str\n * @param  {Object=} options\n * @return {!Array}\n */\nfunction parse (str, options) {\n  var tokens = [];\n  var key = 0;\n  var index = 0;\n  var path = '';\n  var defaultDelimiter = options && options.delimiter || '/';\n  var res;\n\n  while ((res = PATH_REGEXP.exec(str)) != null) {\n    var m = res[0];\n    var escaped = res[1];\n    var offset = res.index;\n    path += str.slice(index, offset);\n    index = offset + m.length;\n\n    // Ignore already escaped sequences.\n    if (escaped) {\n      path += escaped[1];\n      continue\n    }\n\n    var next = str[index];\n    var prefix = res[2];\n    var name = res[3];\n    var capture = res[4];\n    var group = res[5];\n    var modifier = res[6];\n    var asterisk = res[7];\n\n    // Push the current path onto the tokens.\n    if (path) {\n      tokens.push(path);\n      path = '';\n    }\n\n    var partial = prefix != null && next != null && next !== prefix;\n    var repeat = modifier === '+' || modifier === '*';\n    var optional = modifier === '?' || modifier === '*';\n    var delimiter = res[2] || defaultDelimiter;\n    var pattern = capture || group;\n\n    tokens.push({\n      name: name || key++,\n      prefix: prefix || '',\n      delimiter: delimiter,\n      optional: optional,\n      repeat: repeat,\n      partial: partial,\n      asterisk: !!asterisk,\n      pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')\n    });\n  }\n\n  // Match any characters still remaining.\n  if (index < str.length) {\n    path += str.substr(index);\n  }\n\n  // If the path exists, push it onto the end.\n  if (path) {\n    tokens.push(path);\n  }\n\n  return tokens\n}\n\n/**\n * Compile a string to a template function for the path.\n *\n * @param  {string}             str\n * @param  {Object=}            options\n * @return {!function(Object=, Object=)}\n */\nfunction compile (str, options) {\n  return tokensToFunction(parse(str, options), options)\n}\n\n/**\n * Prettier encoding of URI path segments.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeURIComponentPretty (str) {\n  return encodeURI(str).replace(/[\\/?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeAsterisk (str) {\n  return encodeURI(str).replace(/[?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Expose a method for transforming tokens into the path function.\n */\nfunction tokensToFunction (tokens, options) {\n  // Compile all the tokens into regexps.\n  var matches = new Array(tokens.length);\n\n  // Compile all the patterns before compilation.\n  for (var i = 0; i < tokens.length; i++) {\n    if (typeof tokens[i] === 'object') {\n      matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));\n    }\n  }\n\n  return function (obj, opts) {\n    var path = '';\n    var data = obj || {};\n    var options = opts || {};\n    var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;\n\n    for (var i = 0; i < tokens.length; i++) {\n      var token = tokens[i];\n\n      if (typeof token === 'string') {\n        path += token;\n\n        continue\n      }\n\n      var value = data[token.name];\n      var segment;\n\n      if (value == null) {\n        if (token.optional) {\n          // Prepend partial segment prefixes.\n          if (token.partial) {\n            path += token.prefix;\n          }\n\n          continue\n        } else {\n          throw new TypeError('Expected \"' + token.name + '\" to be defined')\n        }\n      }\n\n      if (isarray(value)) {\n        if (!token.repeat) {\n          throw new TypeError('Expected \"' + token.name + '\" to not repeat, but received `' + JSON.stringify(value) + '`')\n        }\n\n        if (value.length === 0) {\n          if (token.optional) {\n            continue\n          } else {\n            throw new TypeError('Expected \"' + token.name + '\" to not be empty')\n          }\n        }\n\n        for (var j = 0; j < value.length; j++) {\n          segment = encode(value[j]);\n\n          if (!matches[i].test(segment)) {\n            throw new TypeError('Expected all \"' + token.name + '\" to match \"' + token.pattern + '\", but received `' + JSON.stringify(segment) + '`')\n          }\n\n          path += (j === 0 ? token.prefix : token.delimiter) + segment;\n        }\n\n        continue\n      }\n\n      segment = token.asterisk ? encodeAsterisk(value) : encode(value);\n\n      if (!matches[i].test(segment)) {\n        throw new TypeError('Expected \"' + token.name + '\" to match \"' + token.pattern + '\", but received \"' + segment + '\"')\n      }\n\n      path += token.prefix + segment;\n    }\n\n    return path\n  }\n}\n\n/**\n * Escape a regular expression string.\n *\n * @param  {string} str\n * @return {string}\n */\nfunction escapeString (str) {\n  return str.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g, '\\\\$1')\n}\n\n/**\n * Escape the capturing group by escaping special characters and meaning.\n *\n * @param  {string} group\n * @return {string}\n */\nfunction escapeGroup (group) {\n  return group.replace(/([=!:$\\/()])/g, '\\\\$1')\n}\n\n/**\n * Attach the keys as a property of the regexp.\n *\n * @param  {!RegExp} re\n * @param  {Array}   keys\n * @return {!RegExp}\n */\nfunction attachKeys (re, keys) {\n  re.keys = keys;\n  return re\n}\n\n/**\n * Get the flags for a regexp from the options.\n *\n * @param  {Object} options\n * @return {string}\n */\nfunction flags (options) {\n  return options && options.sensitive ? '' : 'i'\n}\n\n/**\n * Pull out keys from a regexp.\n *\n * @param  {!RegExp} path\n * @param  {!Array}  keys\n * @return {!RegExp}\n */\nfunction regexpToRegexp (path, keys) {\n  // Use a negative lookahead to match only capturing groups.\n  var groups = path.source.match(/\\((?!\\?)/g);\n\n  if (groups) {\n    for (var i = 0; i < groups.length; i++) {\n      keys.push({\n        name: i,\n        prefix: null,\n        delimiter: null,\n        optional: false,\n        repeat: false,\n        partial: false,\n        asterisk: false,\n        pattern: null\n      });\n    }\n  }\n\n  return attachKeys(path, keys)\n}\n\n/**\n * Transform an array into a regexp.\n *\n * @param  {!Array}  path\n * @param  {Array}   keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction arrayToRegexp (path, keys, options) {\n  var parts = [];\n\n  for (var i = 0; i < path.length; i++) {\n    parts.push(pathToRegexp(path[i], keys, options).source);\n  }\n\n  var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));\n\n  return attachKeys(regexp, keys)\n}\n\n/**\n * Create a path regexp from string input.\n *\n * @param  {string}  path\n * @param  {!Array}  keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction stringToRegexp (path, keys, options) {\n  return tokensToRegExp(parse(path, options), keys, options)\n}\n\n/**\n * Expose a function for taking tokens and returning a RegExp.\n *\n * @param  {!Array}          tokens\n * @param  {(Array|Object)=} keys\n * @param  {Object=}         options\n * @return {!RegExp}\n */\nfunction tokensToRegExp (tokens, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  var strict = options.strict;\n  var end = options.end !== false;\n  var route = '';\n\n  // Iterate over the tokens and create our regexp string.\n  for (var i = 0; i < tokens.length; i++) {\n    var token = tokens[i];\n\n    if (typeof token === 'string') {\n      route += escapeString(token);\n    } else {\n      var prefix = escapeString(token.prefix);\n      var capture = '(?:' + token.pattern + ')';\n\n      keys.push(token);\n\n      if (token.repeat) {\n        capture += '(?:' + prefix + capture + ')*';\n      }\n\n      if (token.optional) {\n        if (!token.partial) {\n          capture = '(?:' + prefix + '(' + capture + '))?';\n        } else {\n          capture = prefix + '(' + capture + ')?';\n        }\n      } else {\n        capture = prefix + '(' + capture + ')';\n      }\n\n      route += capture;\n    }\n  }\n\n  var delimiter = escapeString(options.delimiter || '/');\n  var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;\n\n  // In non-strict mode we allow a slash at the end of match. If the path to\n  // match already ends with a slash, we remove it for consistency. The slash\n  // is valid at the end of a path match, not in the middle. This is important\n  // in non-ending mode, where \"/test/\" shouldn't match \"/test//route\".\n  if (!strict) {\n    route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';\n  }\n\n  if (end) {\n    route += '$';\n  } else {\n    // In non-ending mode, we need the capturing groups to match as much as\n    // possible by using a positive lookahead to the end or next path segment.\n    route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';\n  }\n\n  return attachKeys(new RegExp('^' + route, flags(options)), keys)\n}\n\n/**\n * Normalize the given path string, returning a regular expression.\n *\n * An empty array can be passed in for the keys, which will hold the\n * placeholder key descriptions. For example, using `/user/:id`, `keys` will\n * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.\n *\n * @param  {(string|RegExp|Array)} path\n * @param  {(Array|Object)=}       keys\n * @param  {Object=}               options\n * @return {!RegExp}\n */\nfunction pathToRegexp (path, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  if (path instanceof RegExp) {\n    return regexpToRegexp(path, /** @type {!Array} */ (keys))\n  }\n\n  if (isarray(path)) {\n    return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)\n  }\n\n  return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)\n}\npathToRegexp_1.parse = parse_1;\npathToRegexp_1.compile = compile_1;\npathToRegexp_1.tokensToFunction = tokensToFunction_1;\npathToRegexp_1.tokensToRegExp = tokensToRegExp_1;\n\n/*  */\n\n// $flow-disable-line\nconst regexpCompileCache = Object.create(null);\n\nfunction fillParams (\n  path,\n  params,\n  routeMsg\n) {\n  params = params || {};\n  try {\n    const filler =\n      regexpCompileCache[path] ||\n      (regexpCompileCache[path] = pathToRegexp_1.compile(path));\n\n    // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}\n    // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string\n    if (typeof params.pathMatch === 'string') params[0] = params.pathMatch;\n\n    return filler(params, { pretty: true })\n  } catch (e) {\n    {\n      // Fix #3072 no warn if `pathMatch` is string\n      warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`);\n    }\n    return ''\n  } finally {\n    // delete the 0 if it was added\n    delete params[0];\n  }\n}\n\n/*  */\n\nfunction normalizeLocation (\n  raw,\n  current,\n  append,\n  router\n) {\n  let next = typeof raw === 'string' ? { path: raw } : raw;\n  // named target\n  if (next._normalized) {\n    return next\n  } else if (next.name) {\n    next = extend({}, raw);\n    const params = next.params;\n    if (params && typeof params === 'object') {\n      next.params = extend({}, params);\n    }\n    return next\n  }\n\n  // relative params\n  if (!next.path && next.params && current) {\n    next = extend({}, next);\n    next._normalized = true;\n    const params = extend(extend({}, current.params), next.params);\n    if (current.name) {\n      next.name = current.name;\n      next.params = params;\n    } else if (current.matched.length) {\n      const rawPath = current.matched[current.matched.length - 1].path;\n      next.path = fillParams(rawPath, params, `path ${current.path}`);\n    } else {\n      warn(false, `relative params navigation requires a current route.`);\n    }\n    return next\n  }\n\n  const parsedPath = parsePath(next.path || '');\n  const basePath = (current && current.path) || '/';\n  const path = parsedPath.path\n    ? resolvePath(parsedPath.path, basePath, append || next.append)\n    : basePath;\n\n  const query = resolveQuery(\n    parsedPath.query,\n    next.query,\n    router && router.options.parseQuery\n  );\n\n  let hash = next.hash || parsedPath.hash;\n  if (hash && hash.charAt(0) !== '#') {\n    hash = `#${hash}`;\n  }\n\n  return {\n    _normalized: true,\n    path,\n    query,\n    hash\n  }\n}\n\n/*  */\n\n// work around weird flow bug\nconst toTypes = [String, Object];\nconst eventTypes = [String, Array];\n\nconst noop = () => {};\n\nlet warnedCustomSlot;\nlet warnedTagProp;\nlet warnedEventProp;\n\nvar Link = {\n  name: 'RouterLink',\n  props: {\n    to: {\n      type: toTypes,\n      required: true\n    },\n    tag: {\n      type: String,\n      default: 'a'\n    },\n    custom: Boolean,\n    exact: Boolean,\n    exactPath: Boolean,\n    append: Boolean,\n    replace: Boolean,\n    activeClass: String,\n    exactActiveClass: String,\n    ariaCurrentValue: {\n      type: String,\n      default: 'page'\n    },\n    event: {\n      type: eventTypes,\n      default: 'click'\n    }\n  },\n  render (h) {\n    const router = this.$router;\n    const current = this.$route;\n    const { location, route, href } = router.resolve(\n      this.to,\n      current,\n      this.append\n    );\n\n    const classes = {};\n    const globalActiveClass = router.options.linkActiveClass;\n    const globalExactActiveClass = router.options.linkExactActiveClass;\n    // Support global empty active class\n    const activeClassFallback =\n      globalActiveClass == null ? 'router-link-active' : globalActiveClass;\n    const exactActiveClassFallback =\n      globalExactActiveClass == null\n        ? 'router-link-exact-active'\n        : globalExactActiveClass;\n    const activeClass =\n      this.activeClass == null ? activeClassFallback : this.activeClass;\n    const exactActiveClass =\n      this.exactActiveClass == null\n        ? exactActiveClassFallback\n        : this.exactActiveClass;\n\n    const compareTarget = route.redirectedFrom\n      ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)\n      : route;\n\n    classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath);\n    classes[activeClass] = this.exact || this.exactPath\n      ? classes[exactActiveClass]\n      : isIncludedRoute(current, compareTarget);\n\n    const ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null;\n\n    const handler = e => {\n      if (guardEvent(e)) {\n        if (this.replace) {\n          router.replace(location, noop);\n        } else {\n          router.push(location, noop);\n        }\n      }\n    };\n\n    const on = { click: guardEvent };\n    if (Array.isArray(this.event)) {\n      this.event.forEach(e => {\n        on[e] = handler;\n      });\n    } else {\n      on[this.event] = handler;\n    }\n\n    const data = { class: classes };\n\n    const scopedSlot =\n      !this.$scopedSlots.$hasNormal &&\n      this.$scopedSlots.default &&\n      this.$scopedSlots.default({\n        href,\n        route,\n        navigate: handler,\n        isActive: classes[activeClass],\n        isExactActive: classes[exactActiveClass]\n      });\n\n    if (scopedSlot) {\n      if (!this.custom) {\n        !warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\\n<router-link v-slot=\"{ navigate, href }\" custom></router-link>\\n');\n        warnedCustomSlot = true;\n      }\n      if (scopedSlot.length === 1) {\n        return scopedSlot[0]\n      } else if (scopedSlot.length > 1 || !scopedSlot.length) {\n        {\n          warn(\n            false,\n            `<router-link> with to=\"${\n              this.to\n            }\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.`\n          );\n        }\n        return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)\n      }\n    }\n\n    {\n      if ('tag' in this.$options.propsData && !warnedTagProp) {\n        warn(\n          false,\n          `<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.`\n        );\n        warnedTagProp = true;\n      }\n      if ('event' in this.$options.propsData && !warnedEventProp) {\n        warn(\n          false,\n          `<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.`\n        );\n        warnedEventProp = true;\n      }\n    }\n\n    if (this.tag === 'a') {\n      data.on = on;\n      data.attrs = { href, 'aria-current': ariaCurrentValue };\n    } else {\n      // find the first <a> child and apply listener and href\n      const a = findAnchor(this.$slots.default);\n      if (a) {\n        // in case the <a> is a static node\n        a.isStatic = false;\n        const aData = (a.data = extend({}, a.data));\n        aData.on = aData.on || {};\n        // transform existing events in both objects into arrays so we can push later\n        for (const event in aData.on) {\n          const handler = aData.on[event];\n          if (event in on) {\n            aData.on[event] = Array.isArray(handler) ? handler : [handler];\n          }\n        }\n        // append new listeners for router-link\n        for (const event in on) {\n          if (event in aData.on) {\n            // on[event] is always a function\n            aData.on[event].push(on[event]);\n          } else {\n            aData.on[event] = handler;\n          }\n        }\n\n        const aAttrs = (a.data.attrs = extend({}, a.data.attrs));\n        aAttrs.href = href;\n        aAttrs['aria-current'] = ariaCurrentValue;\n      } else {\n        // doesn't have <a> child, apply listener to self\n        data.on = on;\n      }\n    }\n\n    return h(this.tag, data, this.$slots.default)\n  }\n};\n\nfunction guardEvent (e) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) return\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) return\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    const target = e.currentTarget.getAttribute('target');\n    if (/\\b_blank\\b/i.test(target)) return\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault();\n  }\n  return true\n}\n\nfunction findAnchor (children) {\n  if (children) {\n    let child;\n    for (let i = 0; i < children.length; i++) {\n      child = children[i];\n      if (child.tag === 'a') {\n        return child\n      }\n      if (child.children && (child = findAnchor(child.children))) {\n        return child\n      }\n    }\n  }\n}\n\nlet _Vue;\n\nfunction install (Vue) {\n  if (install.installed && _Vue === Vue) return\n  install.installed = true;\n\n  _Vue = Vue;\n\n  const isDef = v => v !== undefined;\n\n  const registerInstance = (vm, callVal) => {\n    let i = vm.$options._parentVnode;\n    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {\n      i(vm, callVal);\n    }\n  };\n\n  Vue.mixin({\n    beforeCreate () {\n      if (isDef(this.$options.router)) {\n        this._routerRoot = this;\n        this._router = this.$options.router;\n        this._router.init(this);\n        Vue.util.defineReactive(this, '_route', this._router.history.current);\n      } else {\n        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;\n      }\n      registerInstance(this, this);\n    },\n    destroyed () {\n      registerInstance(this);\n    }\n  });\n\n  Object.defineProperty(Vue.prototype, '$router', {\n    get () { return this._routerRoot._router }\n  });\n\n  Object.defineProperty(Vue.prototype, '$route', {\n    get () { return this._routerRoot._route }\n  });\n\n  Vue.component('RouterView', View);\n  Vue.component('RouterLink', Link);\n\n  const strats = Vue.config.optionMergeStrategies;\n  // use the same hook merging strategy for route hooks\n  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;\n}\n\n/*  */\n\nconst inBrowser = typeof window !== 'undefined';\n\n/*  */\n\nfunction createRouteMap (\n  routes,\n  oldPathList,\n  oldPathMap,\n  oldNameMap,\n  parentRoute\n) {\n  // the path list is used to control path matching priority\n  const pathList = oldPathList || [];\n  // $flow-disable-line\n  const pathMap = oldPathMap || Object.create(null);\n  // $flow-disable-line\n  const nameMap = oldNameMap || Object.create(null);\n\n  routes.forEach(route => {\n    addRouteRecord(pathList, pathMap, nameMap, route, parentRoute);\n  });\n\n  // ensure wildcard routes are always at the end\n  for (let i = 0, l = pathList.length; i < l; i++) {\n    if (pathList[i] === '*') {\n      pathList.push(pathList.splice(i, 1)[0]);\n      l--;\n      i--;\n    }\n  }\n\n  {\n    // warn if routes do not include leading slashes\n    const found = pathList\n    // check for missing leading slash\n      .filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/');\n\n    if (found.length > 0) {\n      const pathNames = found.map(path => `- ${path}`).join('\\n');\n      warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \\n${pathNames}`);\n    }\n  }\n\n  return {\n    pathList,\n    pathMap,\n    nameMap\n  }\n}\n\nfunction addRouteRecord (\n  pathList,\n  pathMap,\n  nameMap,\n  route,\n  parent,\n  matchAs\n) {\n  const { path, name } = route;\n  {\n    assert(path != null, `\"path\" is required in a route configuration.`);\n    assert(\n      typeof route.component !== 'string',\n      `route config \"component\" for path: ${String(\n        path || name\n      )} cannot be a ` + `string id. Use an actual component instead.`\n    );\n\n    warn(\n      // eslint-disable-next-line no-control-regex\n      !/[^\\u0000-\\u007F]+/.test(path),\n      `Route with path \"${path}\" contains unencoded characters, make sure ` +\n        `your path is correctly encoded before passing it to the router. Use ` +\n        `encodeURI to encode static segments of your path.`\n    );\n  }\n\n  const pathToRegexpOptions =\n    route.pathToRegexpOptions || {};\n  const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);\n\n  if (typeof route.caseSensitive === 'boolean') {\n    pathToRegexpOptions.sensitive = route.caseSensitive;\n  }\n\n  const record = {\n    path: normalizedPath,\n    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),\n    components: route.components || { default: route.component },\n    alias: route.alias\n      ? typeof route.alias === 'string'\n        ? [route.alias]\n        : route.alias\n      : [],\n    instances: {},\n    enteredCbs: {},\n    name,\n    parent,\n    matchAs,\n    redirect: route.redirect,\n    beforeEnter: route.beforeEnter,\n    meta: route.meta || {},\n    props:\n      route.props == null\n        ? {}\n        : route.components\n          ? route.props\n          : { default: route.props }\n  };\n\n  if (route.children) {\n    // Warn if route is named, does not redirect and has a default child route.\n    // If users navigate to this route by name, the default child will\n    // not be rendered (GH Issue #629)\n    {\n      if (\n        route.name &&\n        !route.redirect &&\n        route.children.some(child => /^\\/?$/.test(child.path))\n      ) {\n        warn(\n          false,\n          `Named Route '${route.name}' has a default child route. ` +\n            `When navigating to this named route (:to=\"{name: '${\n              route.name\n            }'}\"), ` +\n            `the default child route will not be rendered. Remove the name from ` +\n            `this route and use the name of the default child route for named ` +\n            `links instead.`\n        );\n      }\n    }\n    route.children.forEach(child => {\n      const childMatchAs = matchAs\n        ? cleanPath(`${matchAs}/${child.path}`)\n        : undefined;\n      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);\n    });\n  }\n\n  if (!pathMap[record.path]) {\n    pathList.push(record.path);\n    pathMap[record.path] = record;\n  }\n\n  if (route.alias !== undefined) {\n    const aliases = Array.isArray(route.alias) ? route.alias : [route.alias];\n    for (let i = 0; i < aliases.length; ++i) {\n      const alias = aliases[i];\n      if (alias === path) {\n        warn(\n          false,\n          `Found an alias with the same value as the path: \"${path}\". You have to remove that alias. It will be ignored in development.`\n        );\n        // skip in dev to make it work\n        continue\n      }\n\n      const aliasRoute = {\n        path: alias,\n        children: route.children\n      };\n      addRouteRecord(\n        pathList,\n        pathMap,\n        nameMap,\n        aliasRoute,\n        parent,\n        record.path || '/' // matchAs\n      );\n    }\n  }\n\n  if (name) {\n    if (!nameMap[name]) {\n      nameMap[name] = record;\n    } else if (!matchAs) {\n      warn(\n        false,\n        `Duplicate named routes definition: ` +\n          `{ name: \"${name}\", path: \"${record.path}\" }`\n      );\n    }\n  }\n}\n\nfunction compileRouteRegex (\n  path,\n  pathToRegexpOptions\n) {\n  const regex = pathToRegexp_1(path, [], pathToRegexpOptions);\n  {\n    const keys = Object.create(null);\n    regex.keys.forEach(key => {\n      warn(\n        !keys[key.name],\n        `Duplicate param keys in route with path: \"${path}\"`\n      );\n      keys[key.name] = true;\n    });\n  }\n  return regex\n}\n\nfunction normalizePath (\n  path,\n  parent,\n  strict\n) {\n  if (!strict) path = path.replace(/\\/$/, '');\n  if (path[0] === '/') return path\n  if (parent == null) return path\n  return cleanPath(`${parent.path}/${path}`)\n}\n\n/*  */\n\n\n\nfunction createMatcher (\n  routes,\n  router\n) {\n  const { pathList, pathMap, nameMap } = createRouteMap(routes);\n\n  function addRoutes (routes) {\n    createRouteMap(routes, pathList, pathMap, nameMap);\n  }\n\n  function addRoute (parentOrRoute, route) {\n    const parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined;\n    // $flow-disable-line\n    createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent);\n\n    // add aliases of parent\n    if (parent && parent.alias.length) {\n      createRouteMap(\n        // $flow-disable-line route is defined if parent is\n        parent.alias.map(alias => ({ path: alias, children: [route] })),\n        pathList,\n        pathMap,\n        nameMap,\n        parent\n      );\n    }\n  }\n\n  function getRoutes () {\n    return pathList.map(path => pathMap[path])\n  }\n\n  function match (\n    raw,\n    currentRoute,\n    redirectedFrom\n  ) {\n    const location = normalizeLocation(raw, currentRoute, false, router);\n    const { name } = location;\n\n    if (name) {\n      const record = nameMap[name];\n      {\n        warn(record, `Route with name '${name}' does not exist`);\n      }\n      if (!record) return _createRoute(null, location)\n      const paramNames = record.regex.keys\n        .filter(key => !key.optional)\n        .map(key => key.name);\n\n      if (typeof location.params !== 'object') {\n        location.params = {};\n      }\n\n      if (currentRoute && typeof currentRoute.params === 'object') {\n        for (const key in currentRoute.params) {\n          if (!(key in location.params) && paramNames.indexOf(key) > -1) {\n            location.params[key] = currentRoute.params[key];\n          }\n        }\n      }\n\n      location.path = fillParams(record.path, location.params, `named route \"${name}\"`);\n      return _createRoute(record, location, redirectedFrom)\n    } else if (location.path) {\n      location.params = {};\n      for (let i = 0; i < pathList.length; i++) {\n        const path = pathList[i];\n        const record = pathMap[path];\n        if (matchRoute(record.regex, location.path, location.params)) {\n          return _createRoute(record, location, redirectedFrom)\n        }\n      }\n    }\n    // no match\n    return _createRoute(null, location)\n  }\n\n  function redirect (\n    record,\n    location\n  ) {\n    const originalRedirect = record.redirect;\n    let redirect = typeof originalRedirect === 'function'\n      ? originalRedirect(createRoute(record, location, null, router))\n      : originalRedirect;\n\n    if (typeof redirect === 'string') {\n      redirect = { path: redirect };\n    }\n\n    if (!redirect || typeof redirect !== 'object') {\n      {\n        warn(\n          false, `invalid redirect option: ${JSON.stringify(redirect)}`\n        );\n      }\n      return _createRoute(null, location)\n    }\n\n    const re = redirect;\n    const { name, path } = re;\n    let { query, hash, params } = location;\n    query = re.hasOwnProperty('query') ? re.query : query;\n    hash = re.hasOwnProperty('hash') ? re.hash : hash;\n    params = re.hasOwnProperty('params') ? re.params : params;\n\n    if (name) {\n      // resolved named direct\n      const targetRecord = nameMap[name];\n      {\n        assert(targetRecord, `redirect failed: named route \"${name}\" not found.`);\n      }\n      return match({\n        _normalized: true,\n        name,\n        query,\n        hash,\n        params\n      }, undefined, location)\n    } else if (path) {\n      // 1. resolve relative redirect\n      const rawPath = resolveRecordPath(path, record);\n      // 2. resolve params\n      const resolvedPath = fillParams(rawPath, params, `redirect route with path \"${rawPath}\"`);\n      // 3. rematch with existing query and hash\n      return match({\n        _normalized: true,\n        path: resolvedPath,\n        query,\n        hash\n      }, undefined, location)\n    } else {\n      {\n        warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`);\n      }\n      return _createRoute(null, location)\n    }\n  }\n\n  function alias (\n    record,\n    location,\n    matchAs\n  ) {\n    const aliasedPath = fillParams(matchAs, location.params, `aliased route with path \"${matchAs}\"`);\n    const aliasedMatch = match({\n      _normalized: true,\n      path: aliasedPath\n    });\n    if (aliasedMatch) {\n      const matched = aliasedMatch.matched;\n      const aliasedRecord = matched[matched.length - 1];\n      location.params = aliasedMatch.params;\n      return _createRoute(aliasedRecord, location)\n    }\n    return _createRoute(null, location)\n  }\n\n  function _createRoute (\n    record,\n    location,\n    redirectedFrom\n  ) {\n    if (record && record.redirect) {\n      return redirect(record, redirectedFrom || location)\n    }\n    if (record && record.matchAs) {\n      return alias(record, location, record.matchAs)\n    }\n    return createRoute(record, location, redirectedFrom, router)\n  }\n\n  return {\n    match,\n    addRoute,\n    getRoutes,\n    addRoutes\n  }\n}\n\nfunction matchRoute (\n  regex,\n  path,\n  params\n) {\n  const m = path.match(regex);\n\n  if (!m) {\n    return false\n  } else if (!params) {\n    return true\n  }\n\n  for (let i = 1, len = m.length; i < len; ++i) {\n    const key = regex.keys[i - 1];\n    if (key) {\n      // Fix #1994: using * with props: true generates a param named 0\n      params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i];\n    }\n  }\n\n  return true\n}\n\nfunction resolveRecordPath (path, record) {\n  return resolvePath(path, record.parent ? record.parent.path : '/', true)\n}\n\n/*  */\n\n// use User Timing api (if present) for more accurate key precision\nconst Time =\n  inBrowser && window.performance && window.performance.now\n    ? window.performance\n    : Date;\n\nfunction genStateKey () {\n  return Time.now().toFixed(3)\n}\n\nlet _key = genStateKey();\n\nfunction getStateKey () {\n  return _key\n}\n\nfunction setStateKey (key) {\n  return (_key = key)\n}\n\n/*  */\n\nconst positionStore = Object.create(null);\n\nfunction setupScroll () {\n  // Prevent browser scroll behavior on History popstate\n  if ('scrollRestoration' in window.history) {\n    window.history.scrollRestoration = 'manual';\n  }\n  // Fix for #1585 for Firefox\n  // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678\n  // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with\n  // window.location.protocol + '//' + window.location.host\n  // location.host contains the port and location.hostname doesn't\n  const protocolAndPath = window.location.protocol + '//' + window.location.host;\n  const absolutePath = window.location.href.replace(protocolAndPath, '');\n  // preserve existing history state as it could be overriden by the user\n  const stateCopy = extend({}, window.history.state);\n  stateCopy.key = getStateKey();\n  window.history.replaceState(stateCopy, '', absolutePath);\n  window.addEventListener('popstate', handlePopState);\n  return () => {\n    window.removeEventListener('popstate', handlePopState);\n  }\n}\n\nfunction handleScroll (\n  router,\n  to,\n  from,\n  isPop\n) {\n  if (!router.app) {\n    return\n  }\n\n  const behavior = router.options.scrollBehavior;\n  if (!behavior) {\n    return\n  }\n\n  {\n    assert(typeof behavior === 'function', `scrollBehavior must be a function`);\n  }\n\n  // wait until re-render finishes before scrolling\n  router.app.$nextTick(() => {\n    const position = getScrollPosition();\n    const shouldScroll = behavior.call(\n      router,\n      to,\n      from,\n      isPop ? position : null\n    );\n\n    if (!shouldScroll) {\n      return\n    }\n\n    if (typeof shouldScroll.then === 'function') {\n      shouldScroll\n        .then(shouldScroll => {\n          scrollToPosition((shouldScroll), position);\n        })\n        .catch(err => {\n          {\n            assert(false, err.toString());\n          }\n        });\n    } else {\n      scrollToPosition(shouldScroll, position);\n    }\n  });\n}\n\nfunction saveScrollPosition () {\n  const key = getStateKey();\n  if (key) {\n    positionStore[key] = {\n      x: window.pageXOffset,\n      y: window.pageYOffset\n    };\n  }\n}\n\nfunction handlePopState (e) {\n  saveScrollPosition();\n  if (e.state && e.state.key) {\n    setStateKey(e.state.key);\n  }\n}\n\nfunction getScrollPosition () {\n  const key = getStateKey();\n  if (key) {\n    return positionStore[key]\n  }\n}\n\nfunction getElementPosition (el, offset) {\n  const docEl = document.documentElement;\n  const docRect = docEl.getBoundingClientRect();\n  const elRect = el.getBoundingClientRect();\n  return {\n    x: elRect.left - docRect.left - offset.x,\n    y: elRect.top - docRect.top - offset.y\n  }\n}\n\nfunction isValidPosition (obj) {\n  return isNumber(obj.x) || isNumber(obj.y)\n}\n\nfunction normalizePosition (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : window.pageXOffset,\n    y: isNumber(obj.y) ? obj.y : window.pageYOffset\n  }\n}\n\nfunction normalizeOffset (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : 0,\n    y: isNumber(obj.y) ? obj.y : 0\n  }\n}\n\nfunction isNumber (v) {\n  return typeof v === 'number'\n}\n\nconst hashStartsWithNumberRE = /^#\\d/;\n\nfunction scrollToPosition (shouldScroll, position) {\n  const isObject = typeof shouldScroll === 'object';\n  if (isObject && typeof shouldScroll.selector === 'string') {\n    // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]\n    // but at the same time, it doesn't make much sense to select an element with an id and an extra selector\n    const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line\n      ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line\n      : document.querySelector(shouldScroll.selector);\n\n    if (el) {\n      let offset =\n        shouldScroll.offset && typeof shouldScroll.offset === 'object'\n          ? shouldScroll.offset\n          : {};\n      offset = normalizeOffset(offset);\n      position = getElementPosition(el, offset);\n    } else if (isValidPosition(shouldScroll)) {\n      position = normalizePosition(shouldScroll);\n    }\n  } else if (isObject && isValidPosition(shouldScroll)) {\n    position = normalizePosition(shouldScroll);\n  }\n\n  if (position) {\n    // $flow-disable-line\n    if ('scrollBehavior' in document.documentElement.style) {\n      window.scrollTo({\n        left: position.x,\n        top: position.y,\n        // $flow-disable-line\n        behavior: shouldScroll.behavior\n      });\n    } else {\n      window.scrollTo(position.x, position.y);\n    }\n  }\n}\n\n/*  */\n\nconst supportsPushState =\n  inBrowser &&\n  (function () {\n    const ua = window.navigator.userAgent;\n\n    if (\n      (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&\n      ua.indexOf('Mobile Safari') !== -1 &&\n      ua.indexOf('Chrome') === -1 &&\n      ua.indexOf('Windows Phone') === -1\n    ) {\n      return false\n    }\n\n    return window.history && typeof window.history.pushState === 'function'\n  })();\n\nfunction pushState (url, replace) {\n  saveScrollPosition();\n  // try...catch the pushState call to get around Safari\n  // DOM Exception 18 where it limits to 100 pushState calls\n  const history = window.history;\n  try {\n    if (replace) {\n      // preserve existing history state as it could be overriden by the user\n      const stateCopy = extend({}, history.state);\n      stateCopy.key = getStateKey();\n      history.replaceState(stateCopy, '', url);\n    } else {\n      history.pushState({ key: setStateKey(genStateKey()) }, '', url);\n    }\n  } catch (e) {\n    window.location[replace ? 'replace' : 'assign'](url);\n  }\n}\n\nfunction replaceState (url) {\n  pushState(url, true);\n}\n\n// When changing thing, also edit router.d.ts\nconst NavigationFailureType = {\n  redirected: 2,\n  aborted: 4,\n  cancelled: 8,\n  duplicated: 16\n};\n\nfunction createNavigationRedirectedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.redirected,\n    `Redirected when going from \"${from.fullPath}\" to \"${stringifyRoute(\n      to\n    )}\" via a navigation guard.`\n  )\n}\n\nfunction createNavigationDuplicatedError (from, to) {\n  const error = createRouterError(\n    from,\n    to,\n    NavigationFailureType.duplicated,\n    `Avoided redundant navigation to current location: \"${from.fullPath}\".`\n  );\n  // backwards compatible with the first introduction of Errors\n  error.name = 'NavigationDuplicated';\n  return error\n}\n\nfunction createNavigationCancelledError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.cancelled,\n    `Navigation cancelled from \"${from.fullPath}\" to \"${\n      to.fullPath\n    }\" with a new navigation.`\n  )\n}\n\nfunction createNavigationAbortedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.aborted,\n    `Navigation aborted from \"${from.fullPath}\" to \"${\n      to.fullPath\n    }\" via a navigation guard.`\n  )\n}\n\nfunction createRouterError (from, to, type, message) {\n  const error = new Error(message);\n  error._isRouter = true;\n  error.from = from;\n  error.to = to;\n  error.type = type;\n\n  return error\n}\n\nconst propertiesToLog = ['params', 'query', 'hash'];\n\nfunction stringifyRoute (to) {\n  if (typeof to === 'string') return to\n  if ('path' in to) return to.path\n  const location = {};\n  propertiesToLog.forEach(key => {\n    if (key in to) location[key] = to[key];\n  });\n  return JSON.stringify(location, null, 2)\n}\n\nfunction isError (err) {\n  return Object.prototype.toString.call(err).indexOf('Error') > -1\n}\n\nfunction isNavigationFailure (err, errorType) {\n  return (\n    isError(err) &&\n    err._isRouter &&\n    (errorType == null || err.type === errorType)\n  )\n}\n\n/*  */\n\nfunction runQueue (queue, fn, cb) {\n  const step = index => {\n    if (index >= queue.length) {\n      cb();\n    } else {\n      if (queue[index]) {\n        fn(queue[index], () => {\n          step(index + 1);\n        });\n      } else {\n        step(index + 1);\n      }\n    }\n  };\n  step(0);\n}\n\n/*  */\n\nfunction resolveAsyncComponents (matched) {\n  return (to, from, next) => {\n    let hasAsync = false;\n    let pending = 0;\n    let error = null;\n\n    flatMapComponents(matched, (def, _, match, key) => {\n      // if it's a function and doesn't have cid attached,\n      // assume it's an async component resolve function.\n      // we are not using Vue's default async resolving mechanism because\n      // we want to halt the navigation until the incoming component has been\n      // resolved.\n      if (typeof def === 'function' && def.cid === undefined) {\n        hasAsync = true;\n        pending++;\n\n        const resolve = once(resolvedDef => {\n          if (isESModule(resolvedDef)) {\n            resolvedDef = resolvedDef.default;\n          }\n          // save resolved on async factory in case it's used elsewhere\n          def.resolved = typeof resolvedDef === 'function'\n            ? resolvedDef\n            : _Vue.extend(resolvedDef);\n          match.components[key] = resolvedDef;\n          pending--;\n          if (pending <= 0) {\n            next();\n          }\n        });\n\n        const reject = once(reason => {\n          const msg = `Failed to resolve async component ${key}: ${reason}`;\n          warn(false, msg);\n          if (!error) {\n            error = isError(reason)\n              ? reason\n              : new Error(msg);\n            next(error);\n          }\n        });\n\n        let res;\n        try {\n          res = def(resolve, reject);\n        } catch (e) {\n          reject(e);\n        }\n        if (res) {\n          if (typeof res.then === 'function') {\n            res.then(resolve, reject);\n          } else {\n            // new syntax in Vue 2.3\n            const comp = res.component;\n            if (comp && typeof comp.then === 'function') {\n              comp.then(resolve, reject);\n            }\n          }\n        }\n      }\n    });\n\n    if (!hasAsync) next();\n  }\n}\n\nfunction flatMapComponents (\n  matched,\n  fn\n) {\n  return flatten(matched.map(m => {\n    return Object.keys(m.components).map(key => fn(\n      m.components[key],\n      m.instances[key],\n      m, key\n    ))\n  }))\n}\n\nfunction flatten (arr) {\n  return Array.prototype.concat.apply([], arr)\n}\n\nconst hasSymbol =\n  typeof Symbol === 'function' &&\n  typeof Symbol.toStringTag === 'symbol';\n\nfunction isESModule (obj) {\n  return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')\n}\n\n// in Webpack 2, require.ensure now also returns a Promise\n// so the resolve/reject functions may get called an extra time\n// if the user uses an arrow function shorthand that happens to\n// return that Promise.\nfunction once (fn) {\n  let called = false;\n  return function (...args) {\n    if (called) return\n    called = true;\n    return fn.apply(this, args)\n  }\n}\n\n/*  */\n\nclass History {\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n\n  // implemented by sub-classes\n  \n  \n  \n  \n  \n  \n\n  constructor (router, base) {\n    this.router = router;\n    this.base = normalizeBase(base);\n    // start with a route object that stands for \"nowhere\"\n    this.current = START;\n    this.pending = null;\n    this.ready = false;\n    this.readyCbs = [];\n    this.readyErrorCbs = [];\n    this.errorCbs = [];\n    this.listeners = [];\n  }\n\n  listen (cb) {\n    this.cb = cb;\n  }\n\n  onReady (cb, errorCb) {\n    if (this.ready) {\n      cb();\n    } else {\n      this.readyCbs.push(cb);\n      if (errorCb) {\n        this.readyErrorCbs.push(errorCb);\n      }\n    }\n  }\n\n  onError (errorCb) {\n    this.errorCbs.push(errorCb);\n  }\n\n  transitionTo (\n    location,\n    onComplete,\n    onAbort\n  ) {\n    let route;\n    // catch redirect option https://github.com/vuejs/vue-router/issues/3201\n    try {\n      route = this.router.match(location, this.current);\n    } catch (e) {\n      this.errorCbs.forEach(cb => {\n        cb(e);\n      });\n      // Exception should still be thrown\n      throw e\n    }\n    const prev = this.current;\n    this.confirmTransition(\n      route,\n      () => {\n        this.updateRoute(route);\n        onComplete && onComplete(route);\n        this.ensureURL();\n        this.router.afterHooks.forEach(hook => {\n          hook && hook(route, prev);\n        });\n\n        // fire ready cbs once\n        if (!this.ready) {\n          this.ready = true;\n          this.readyCbs.forEach(cb => {\n            cb(route);\n          });\n        }\n      },\n      err => {\n        if (onAbort) {\n          onAbort(err);\n        }\n        if (err && !this.ready) {\n          // Initial redirection should not mark the history as ready yet\n          // because it's triggered by the redirection instead\n          // https://github.com/vuejs/vue-router/issues/3225\n          // https://github.com/vuejs/vue-router/issues/3331\n          if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {\n            this.ready = true;\n            this.readyErrorCbs.forEach(cb => {\n              cb(err);\n            });\n          }\n        }\n      }\n    );\n  }\n\n  confirmTransition (route, onComplete, onAbort) {\n    const current = this.current;\n    this.pending = route;\n    const abort = err => {\n      // changed after adding errors with\n      // https://github.com/vuejs/vue-router/pull/3047 before that change,\n      // redirect and aborted navigation would produce an err == null\n      if (!isNavigationFailure(err) && isError(err)) {\n        if (this.errorCbs.length) {\n          this.errorCbs.forEach(cb => {\n            cb(err);\n          });\n        } else {\n          {\n            warn(false, 'uncaught error during route navigation:');\n          }\n          console.error(err);\n        }\n      }\n      onAbort && onAbort(err);\n    };\n    const lastRouteIndex = route.matched.length - 1;\n    const lastCurrentIndex = current.matched.length - 1;\n    if (\n      isSameRoute(route, current) &&\n      // in the case the route map has been dynamically appended to\n      lastRouteIndex === lastCurrentIndex &&\n      route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]\n    ) {\n      this.ensureURL();\n      if (route.hash) {\n        handleScroll(this.router, current, route, false);\n      }\n      return abort(createNavigationDuplicatedError(current, route))\n    }\n\n    const { updated, deactivated, activated } = resolveQueue(\n      this.current.matched,\n      route.matched\n    );\n\n    const queue = [].concat(\n      // in-component leave guards\n      extractLeaveGuards(deactivated),\n      // global before hooks\n      this.router.beforeHooks,\n      // in-component update hooks\n      extractUpdateHooks(updated),\n      // in-config enter guards\n      activated.map(m => m.beforeEnter),\n      // async components\n      resolveAsyncComponents(activated)\n    );\n\n    const iterator = (hook, next) => {\n      if (this.pending !== route) {\n        return abort(createNavigationCancelledError(current, route))\n      }\n      try {\n        hook(route, current, (to) => {\n          if (to === false) {\n            // next(false) -> abort navigation, ensure current URL\n            this.ensureURL(true);\n            abort(createNavigationAbortedError(current, route));\n          } else if (isError(to)) {\n            this.ensureURL(true);\n            abort(to);\n          } else if (\n            typeof to === 'string' ||\n            (typeof to === 'object' &&\n              (typeof to.path === 'string' || typeof to.name === 'string'))\n          ) {\n            // next('/') or next({ path: '/' }) -> redirect\n            abort(createNavigationRedirectedError(current, route));\n            if (typeof to === 'object' && to.replace) {\n              this.replace(to);\n            } else {\n              this.push(to);\n            }\n          } else {\n            // confirm transition and pass on the value\n            next(to);\n          }\n        });\n      } catch (e) {\n        abort(e);\n      }\n    };\n\n    runQueue(queue, iterator, () => {\n      // wait until async components are resolved before\n      // extracting in-component enter guards\n      const enterGuards = extractEnterGuards(activated);\n      const queue = enterGuards.concat(this.router.resolveHooks);\n      runQueue(queue, iterator, () => {\n        if (this.pending !== route) {\n          return abort(createNavigationCancelledError(current, route))\n        }\n        this.pending = null;\n        onComplete(route);\n        if (this.router.app) {\n          this.router.app.$nextTick(() => {\n            handleRouteEntered(route);\n          });\n        }\n      });\n    });\n  }\n\n  updateRoute (route) {\n    this.current = route;\n    this.cb && this.cb(route);\n  }\n\n  setupListeners () {\n    // Default implementation is empty\n  }\n\n  teardown () {\n    // clean up event listeners\n    // https://github.com/vuejs/vue-router/issues/2341\n    this.listeners.forEach(cleanupListener => {\n      cleanupListener();\n    });\n    this.listeners = [];\n\n    // reset current history route\n    // https://github.com/vuejs/vue-router/issues/3294\n    this.current = START;\n    this.pending = null;\n  }\n}\n\nfunction normalizeBase (base) {\n  if (!base) {\n    if (inBrowser) {\n      // respect <base> tag\n      const baseEl = document.querySelector('base');\n      base = (baseEl && baseEl.getAttribute('href')) || '/';\n      // strip full URL origin\n      base = base.replace(/^https?:\\/\\/[^\\/]+/, '');\n    } else {\n      base = '/';\n    }\n  }\n  // make sure there's the starting slash\n  if (base.charAt(0) !== '/') {\n    base = '/' + base;\n  }\n  // remove trailing slash\n  return base.replace(/\\/$/, '')\n}\n\nfunction resolveQueue (\n  current,\n  next\n) {\n  let i;\n  const max = Math.max(current.length, next.length);\n  for (i = 0; i < max; i++) {\n    if (current[i] !== next[i]) {\n      break\n    }\n  }\n  return {\n    updated: next.slice(0, i),\n    activated: next.slice(i),\n    deactivated: current.slice(i)\n  }\n}\n\nfunction extractGuards (\n  records,\n  name,\n  bind,\n  reverse\n) {\n  const guards = flatMapComponents(records, (def, instance, match, key) => {\n    const guard = extractGuard(def, name);\n    if (guard) {\n      return Array.isArray(guard)\n        ? guard.map(guard => bind(guard, instance, match, key))\n        : bind(guard, instance, match, key)\n    }\n  });\n  return flatten(reverse ? guards.reverse() : guards)\n}\n\nfunction extractGuard (\n  def,\n  key\n) {\n  if (typeof def !== 'function') {\n    // extend now so that global mixins are applied.\n    def = _Vue.extend(def);\n  }\n  return def.options[key]\n}\n\nfunction extractLeaveGuards (deactivated) {\n  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)\n}\n\nfunction extractUpdateHooks (updated) {\n  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)\n}\n\nfunction bindGuard (guard, instance) {\n  if (instance) {\n    return function boundRouteGuard () {\n      return guard.apply(instance, arguments)\n    }\n  }\n}\n\nfunction extractEnterGuards (\n  activated\n) {\n  return extractGuards(\n    activated,\n    'beforeRouteEnter',\n    (guard, _, match, key) => {\n      return bindEnterGuard(guard, match, key)\n    }\n  )\n}\n\nfunction bindEnterGuard (\n  guard,\n  match,\n  key\n) {\n  return function routeEnterGuard (to, from, next) {\n    return guard(to, from, cb => {\n      if (typeof cb === 'function') {\n        if (!match.enteredCbs[key]) {\n          match.enteredCbs[key] = [];\n        }\n        match.enteredCbs[key].push(cb);\n      }\n      next(cb);\n    })\n  }\n}\n\n/*  */\n\nclass HTML5History extends History {\n  \n\n  constructor (router, base) {\n    super(router, base);\n\n    this._startLocation = getLocation(this.base);\n  }\n\n  setupListeners () {\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    const router = this.router;\n    const expectScroll = router.options.scrollBehavior;\n    const supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    const handleRoutingEvent = () => {\n      const current = this.current;\n\n      // Avoiding first `popstate` event dispatched in some browsers but first\n      // history route not updated since async guard at the same time.\n      const location = getLocation(this.base);\n      if (this.current === START && location === this._startLocation) {\n        return\n      }\n\n      this.transitionTo(location, route => {\n        if (supportsScroll) {\n          handleScroll(router, route, current, true);\n        }\n      });\n    };\n    window.addEventListener('popstate', handleRoutingEvent);\n    this.listeners.push(() => {\n      window.removeEventListener('popstate', handleRoutingEvent);\n    });\n  }\n\n  go (n) {\n    window.history.go(n);\n  }\n\n  push (location, onComplete, onAbort) {\n    const { current: fromRoute } = this;\n    this.transitionTo(location, route => {\n      pushState(cleanPath(this.base + route.fullPath));\n      handleScroll(this.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  }\n\n  replace (location, onComplete, onAbort) {\n    const { current: fromRoute } = this;\n    this.transitionTo(location, route => {\n      replaceState(cleanPath(this.base + route.fullPath));\n      handleScroll(this.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  }\n\n  ensureURL (push) {\n    if (getLocation(this.base) !== this.current.fullPath) {\n      const current = cleanPath(this.base + this.current.fullPath);\n      push ? pushState(current) : replaceState(current);\n    }\n  }\n\n  getCurrentLocation () {\n    return getLocation(this.base)\n  }\n}\n\nfunction getLocation (base) {\n  let path = window.location.pathname;\n  const pathLowerCase = path.toLowerCase();\n  const baseLowerCase = base.toLowerCase();\n  // base=\"/a\" shouldn't turn path=\"/app\" into \"/a/pp\"\n  // https://github.com/vuejs/vue-router/issues/3555\n  // so we ensure the trailing slash in the base\n  if (base && ((pathLowerCase === baseLowerCase) ||\n    (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {\n    path = path.slice(base.length);\n  }\n  return (path || '/') + window.location.search + window.location.hash\n}\n\n/*  */\n\nclass HashHistory extends History {\n  constructor (router, base, fallback) {\n    super(router, base);\n    // check history fallback deeplinking\n    if (fallback && checkFallback(this.base)) {\n      return\n    }\n    ensureSlash();\n  }\n\n  // this is delayed until the app mounts\n  // to avoid the hashchange listener being fired too early\n  setupListeners () {\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    const router = this.router;\n    const expectScroll = router.options.scrollBehavior;\n    const supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    const handleRoutingEvent = () => {\n      const current = this.current;\n      if (!ensureSlash()) {\n        return\n      }\n      this.transitionTo(getHash(), route => {\n        if (supportsScroll) {\n          handleScroll(this.router, route, current, true);\n        }\n        if (!supportsPushState) {\n          replaceHash(route.fullPath);\n        }\n      });\n    };\n    const eventType = supportsPushState ? 'popstate' : 'hashchange';\n    window.addEventListener(\n      eventType,\n      handleRoutingEvent\n    );\n    this.listeners.push(() => {\n      window.removeEventListener(eventType, handleRoutingEvent);\n    });\n  }\n\n  push (location, onComplete, onAbort) {\n    const { current: fromRoute } = this;\n    this.transitionTo(\n      location,\n      route => {\n        pushHash(route.fullPath);\n        handleScroll(this.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  }\n\n  replace (location, onComplete, onAbort) {\n    const { current: fromRoute } = this;\n    this.transitionTo(\n      location,\n      route => {\n        replaceHash(route.fullPath);\n        handleScroll(this.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  }\n\n  go (n) {\n    window.history.go(n);\n  }\n\n  ensureURL (push) {\n    const current = this.current.fullPath;\n    if (getHash() !== current) {\n      push ? pushHash(current) : replaceHash(current);\n    }\n  }\n\n  getCurrentLocation () {\n    return getHash()\n  }\n}\n\nfunction checkFallback (base) {\n  const location = getLocation(base);\n  if (!/^\\/#/.test(location)) {\n    window.location.replace(cleanPath(base + '/#' + location));\n    return true\n  }\n}\n\nfunction ensureSlash () {\n  const path = getHash();\n  if (path.charAt(0) === '/') {\n    return true\n  }\n  replaceHash('/' + path);\n  return false\n}\n\nfunction getHash () {\n  // We can't use window.location.hash here because it's not\n  // consistent across browsers - Firefox will pre-decode it!\n  let href = window.location.href;\n  const index = href.indexOf('#');\n  // empty path\n  if (index < 0) return ''\n\n  href = href.slice(index + 1);\n\n  return href\n}\n\nfunction getUrl (path) {\n  const href = window.location.href;\n  const i = href.indexOf('#');\n  const base = i >= 0 ? href.slice(0, i) : href;\n  return `${base}#${path}`\n}\n\nfunction pushHash (path) {\n  if (supportsPushState) {\n    pushState(getUrl(path));\n  } else {\n    window.location.hash = path;\n  }\n}\n\nfunction replaceHash (path) {\n  if (supportsPushState) {\n    replaceState(getUrl(path));\n  } else {\n    window.location.replace(getUrl(path));\n  }\n}\n\n/*  */\n\nclass AbstractHistory extends History {\n  \n  \n\n  constructor (router, base) {\n    super(router, base);\n    this.stack = [];\n    this.index = -1;\n  }\n\n  push (location, onComplete, onAbort) {\n    this.transitionTo(\n      location,\n      route => {\n        this.stack = this.stack.slice(0, this.index + 1).concat(route);\n        this.index++;\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  }\n\n  replace (location, onComplete, onAbort) {\n    this.transitionTo(\n      location,\n      route => {\n        this.stack = this.stack.slice(0, this.index).concat(route);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  }\n\n  go (n) {\n    const targetIndex = this.index + n;\n    if (targetIndex < 0 || targetIndex >= this.stack.length) {\n      return\n    }\n    const route = this.stack[targetIndex];\n    this.confirmTransition(\n      route,\n      () => {\n        const prev = this.current;\n        this.index = targetIndex;\n        this.updateRoute(route);\n        this.router.afterHooks.forEach(hook => {\n          hook && hook(route, prev);\n        });\n      },\n      err => {\n        if (isNavigationFailure(err, NavigationFailureType.duplicated)) {\n          this.index = targetIndex;\n        }\n      }\n    );\n  }\n\n  getCurrentLocation () {\n    const current = this.stack[this.stack.length - 1];\n    return current ? current.fullPath : '/'\n  }\n\n  ensureURL () {\n    // noop\n  }\n}\n\n/*  */\n\n\n\nclass VueRouter {\n  \n  \n  \n  \n  \n\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n\n  constructor (options = {}) {\n    {\n      warn(this instanceof VueRouter, `Router must be called with the new operator.`);\n    }\n    this.app = null;\n    this.apps = [];\n    this.options = options;\n    this.beforeHooks = [];\n    this.resolveHooks = [];\n    this.afterHooks = [];\n    this.matcher = createMatcher(options.routes || [], this);\n\n    let mode = options.mode || 'hash';\n    this.fallback =\n      mode === 'history' && !supportsPushState && options.fallback !== false;\n    if (this.fallback) {\n      mode = 'hash';\n    }\n    if (!inBrowser) {\n      mode = 'abstract';\n    }\n    this.mode = mode;\n\n    switch (mode) {\n      case 'history':\n        this.history = new HTML5History(this, options.base);\n        break\n      case 'hash':\n        this.history = new HashHistory(this, options.base, this.fallback);\n        break\n      case 'abstract':\n        this.history = new AbstractHistory(this, options.base);\n        break\n      default:\n        {\n          assert(false, `invalid mode: ${mode}`);\n        }\n    }\n  }\n\n  match (raw, current, redirectedFrom) {\n    return this.matcher.match(raw, current, redirectedFrom)\n  }\n\n  get currentRoute () {\n    return this.history && this.history.current\n  }\n\n  init (app /* Vue component instance */) {\n    assert(\n        install.installed,\n        `not installed. Make sure to call \\`Vue.use(VueRouter)\\` ` +\n          `before creating root instance.`\n      );\n\n    this.apps.push(app);\n\n    // set up app destroyed handler\n    // https://github.com/vuejs/vue-router/issues/2639\n    app.$once('hook:destroyed', () => {\n      // clean out app from this.apps array once destroyed\n      const index = this.apps.indexOf(app);\n      if (index > -1) this.apps.splice(index, 1);\n      // ensure we still have a main app or null if no apps\n      // we do not release the router so it can be reused\n      if (this.app === app) this.app = this.apps[0] || null;\n\n      if (!this.app) this.history.teardown();\n    });\n\n    // main app previously initialized\n    // return as we don't need to set up new history listener\n    if (this.app) {\n      return\n    }\n\n    this.app = app;\n\n    const history = this.history;\n\n    if (history instanceof HTML5History || history instanceof HashHistory) {\n      const handleInitialScroll = routeOrError => {\n        const from = history.current;\n        const expectScroll = this.options.scrollBehavior;\n        const supportsScroll = supportsPushState && expectScroll;\n\n        if (supportsScroll && 'fullPath' in routeOrError) {\n          handleScroll(this, routeOrError, from, false);\n        }\n      };\n      const setupListeners = routeOrError => {\n        history.setupListeners();\n        handleInitialScroll(routeOrError);\n      };\n      history.transitionTo(\n        history.getCurrentLocation(),\n        setupListeners,\n        setupListeners\n      );\n    }\n\n    history.listen(route => {\n      this.apps.forEach(app => {\n        app._route = route;\n      });\n    });\n  }\n\n  beforeEach (fn) {\n    return registerHook(this.beforeHooks, fn)\n  }\n\n  beforeResolve (fn) {\n    return registerHook(this.resolveHooks, fn)\n  }\n\n  afterEach (fn) {\n    return registerHook(this.afterHooks, fn)\n  }\n\n  onReady (cb, errorCb) {\n    this.history.onReady(cb, errorCb);\n  }\n\n  onError (errorCb) {\n    this.history.onError(errorCb);\n  }\n\n  push (location, onComplete, onAbort) {\n    // $flow-disable-line\n    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n      return new Promise((resolve, reject) => {\n        this.history.push(location, resolve, reject);\n      })\n    } else {\n      this.history.push(location, onComplete, onAbort);\n    }\n  }\n\n  replace (location, onComplete, onAbort) {\n    // $flow-disable-line\n    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n      return new Promise((resolve, reject) => {\n        this.history.replace(location, resolve, reject);\n      })\n    } else {\n      this.history.replace(location, onComplete, onAbort);\n    }\n  }\n\n  go (n) {\n    this.history.go(n);\n  }\n\n  back () {\n    this.go(-1);\n  }\n\n  forward () {\n    this.go(1);\n  }\n\n  getMatchedComponents (to) {\n    const route = to\n      ? to.matched\n        ? to\n        : this.resolve(to).route\n      : this.currentRoute;\n    if (!route) {\n      return []\n    }\n    return [].concat.apply(\n      [],\n      route.matched.map(m => {\n        return Object.keys(m.components).map(key => {\n          return m.components[key]\n        })\n      })\n    )\n  }\n\n  resolve (\n    to,\n    current,\n    append\n  ) {\n    current = current || this.history.current;\n    const location = normalizeLocation(to, current, append, this);\n    const route = this.match(location, current);\n    const fullPath = route.redirectedFrom || route.fullPath;\n    const base = this.history.base;\n    const href = createHref(base, fullPath, this.mode);\n    return {\n      location,\n      route,\n      href,\n      // for backwards compat\n      normalizedTo: location,\n      resolved: route\n    }\n  }\n\n  getRoutes () {\n    return this.matcher.getRoutes()\n  }\n\n  addRoute (parentOrRoute, route) {\n    this.matcher.addRoute(parentOrRoute, route);\n    if (this.history.current !== START) {\n      this.history.transitionTo(this.history.getCurrentLocation());\n    }\n  }\n\n  addRoutes (routes) {\n    {\n      warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.');\n    }\n    this.matcher.addRoutes(routes);\n    if (this.history.current !== START) {\n      this.history.transitionTo(this.history.getCurrentLocation());\n    }\n  }\n}\n\nfunction registerHook (list, fn) {\n  list.push(fn);\n  return () => {\n    const i = list.indexOf(fn);\n    if (i > -1) list.splice(i, 1);\n  }\n}\n\nfunction createHref (base, fullPath, mode) {\n  var path = mode === 'hash' ? '#' + fullPath : fullPath;\n  return base ? cleanPath(base + '/' + path) : path\n}\n\n// We cannot remove this as it would be a breaking change\nVueRouter.install = install;\nVueRouter.version = '3.6.5';\nVueRouter.isNavigationFailure = isNavigationFailure;\nVueRouter.NavigationFailureType = NavigationFailureType;\nVueRouter.START_LOCATION = START;\n\nif (inBrowser && window.Vue) {\n  window.Vue.use(VueRouter);\n}\n\nconst version = '3.6.5';\n\nexport { NavigationFailureType, Link as RouterLink, View as RouterView, START as START_LOCATION, VueRouter as default, isNavigationFailure, version };\n"
  },
  {
    "path": "dist/vue-router.esm.js",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\n/*  */\n\nfunction assert (condition, message) {\n  if (!condition) {\n    throw new Error((\"[vue-router] \" + message))\n  }\n}\n\nfunction warn (condition, message) {\n  if (!condition) {\n    typeof console !== 'undefined' && console.warn((\"[vue-router] \" + message));\n  }\n}\n\nfunction extend (a, b) {\n  for (var key in b) {\n    a[key] = b[key];\n  }\n  return a\n}\n\n/*  */\n\nvar encodeReserveRE = /[!'()*]/g;\nvar encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };\nvar commaRE = /%2C/g;\n\n// fixed encodeURIComponent which is more conformant to RFC3986:\n// - escapes [!'()*]\n// - preserve commas\nvar encode = function (str) { return encodeURIComponent(str)\n    .replace(encodeReserveRE, encodeReserveReplacer)\n    .replace(commaRE, ','); };\n\nfunction decode (str) {\n  try {\n    return decodeURIComponent(str)\n  } catch (err) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(false, (\"Error decoding \\\"\" + str + \"\\\". Leaving it intact.\"));\n    }\n  }\n  return str\n}\n\nfunction resolveQuery (\n  query,\n  extraQuery,\n  _parseQuery\n) {\n  if ( extraQuery === void 0 ) extraQuery = {};\n\n  var parse = _parseQuery || parseQuery;\n  var parsedQuery;\n  try {\n    parsedQuery = parse(query || '');\n  } catch (e) {\n    process.env.NODE_ENV !== 'production' && warn(false, e.message);\n    parsedQuery = {};\n  }\n  for (var key in extraQuery) {\n    var value = extraQuery[key];\n    parsedQuery[key] = Array.isArray(value)\n      ? value.map(castQueryParamValue)\n      : castQueryParamValue(value);\n  }\n  return parsedQuery\n}\n\nvar castQueryParamValue = function (value) { return (value == null || typeof value === 'object' ? value : String(value)); };\n\nfunction parseQuery (query) {\n  var res = {};\n\n  query = query.trim().replace(/^(\\?|#|&)/, '');\n\n  if (!query) {\n    return res\n  }\n\n  query.split('&').forEach(function (param) {\n    var parts = param.replace(/\\+/g, ' ').split('=');\n    var key = decode(parts.shift());\n    var val = parts.length > 0 ? decode(parts.join('=')) : null;\n\n    if (res[key] === undefined) {\n      res[key] = val;\n    } else if (Array.isArray(res[key])) {\n      res[key].push(val);\n    } else {\n      res[key] = [res[key], val];\n    }\n  });\n\n  return res\n}\n\nfunction stringifyQuery (obj) {\n  var res = obj\n    ? Object.keys(obj)\n      .map(function (key) {\n        var val = obj[key];\n\n        if (val === undefined) {\n          return ''\n        }\n\n        if (val === null) {\n          return encode(key)\n        }\n\n        if (Array.isArray(val)) {\n          var result = [];\n          val.forEach(function (val2) {\n            if (val2 === undefined) {\n              return\n            }\n            if (val2 === null) {\n              result.push(encode(key));\n            } else {\n              result.push(encode(key) + '=' + encode(val2));\n            }\n          });\n          return result.join('&')\n        }\n\n        return encode(key) + '=' + encode(val)\n      })\n      .filter(function (x) { return x.length > 0; })\n      .join('&')\n    : null;\n  return res ? (\"?\" + res) : ''\n}\n\n/*  */\n\nvar trailingSlashRE = /\\/?$/;\n\nfunction createRoute (\n  record,\n  location,\n  redirectedFrom,\n  router\n) {\n  var stringifyQuery = router && router.options.stringifyQuery;\n\n  var query = location.query || {};\n  try {\n    query = clone(query);\n  } catch (e) {}\n\n  var route = {\n    name: location.name || (record && record.name),\n    meta: (record && record.meta) || {},\n    path: location.path || '/',\n    hash: location.hash || '',\n    query: query,\n    params: location.params || {},\n    fullPath: getFullPath(location, stringifyQuery),\n    matched: record ? formatMatch(record) : []\n  };\n  if (redirectedFrom) {\n    route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);\n  }\n  return Object.freeze(route)\n}\n\nfunction clone (value) {\n  if (Array.isArray(value)) {\n    return value.map(clone)\n  } else if (value && typeof value === 'object') {\n    var res = {};\n    for (var key in value) {\n      res[key] = clone(value[key]);\n    }\n    return res\n  } else {\n    return value\n  }\n}\n\n// the starting route that represents the initial state\nvar START = createRoute(null, {\n  path: '/'\n});\n\nfunction formatMatch (record) {\n  var res = [];\n  while (record) {\n    res.unshift(record);\n    record = record.parent;\n  }\n  return res\n}\n\nfunction getFullPath (\n  ref,\n  _stringifyQuery\n) {\n  var path = ref.path;\n  var query = ref.query; if ( query === void 0 ) query = {};\n  var hash = ref.hash; if ( hash === void 0 ) hash = '';\n\n  var stringify = _stringifyQuery || stringifyQuery;\n  return (path || '/') + stringify(query) + hash\n}\n\nfunction isSameRoute (a, b, onlyPath) {\n  if (b === START) {\n    return a === b\n  } else if (!b) {\n    return false\n  } else if (a.path && b.path) {\n    return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||\n      a.hash === b.hash &&\n      isObjectEqual(a.query, b.query))\n  } else if (a.name && b.name) {\n    return (\n      a.name === b.name &&\n      (onlyPath || (\n        a.hash === b.hash &&\n      isObjectEqual(a.query, b.query) &&\n      isObjectEqual(a.params, b.params))\n      )\n    )\n  } else {\n    return false\n  }\n}\n\nfunction isObjectEqual (a, b) {\n  if ( a === void 0 ) a = {};\n  if ( b === void 0 ) b = {};\n\n  // handle null value #1566\n  if (!a || !b) { return a === b }\n  var aKeys = Object.keys(a).sort();\n  var bKeys = Object.keys(b).sort();\n  if (aKeys.length !== bKeys.length) {\n    return false\n  }\n  return aKeys.every(function (key, i) {\n    var aVal = a[key];\n    var bKey = bKeys[i];\n    if (bKey !== key) { return false }\n    var bVal = b[key];\n    // query values can be null and undefined\n    if (aVal == null || bVal == null) { return aVal === bVal }\n    // check nested equality\n    if (typeof aVal === 'object' && typeof bVal === 'object') {\n      return isObjectEqual(aVal, bVal)\n    }\n    return String(aVal) === String(bVal)\n  })\n}\n\nfunction isIncludedRoute (current, target) {\n  return (\n    current.path.replace(trailingSlashRE, '/').indexOf(\n      target.path.replace(trailingSlashRE, '/')\n    ) === 0 &&\n    (!target.hash || current.hash === target.hash) &&\n    queryIncludes(current.query, target.query)\n  )\n}\n\nfunction queryIncludes (current, target) {\n  for (var key in target) {\n    if (!(key in current)) {\n      return false\n    }\n  }\n  return true\n}\n\nfunction handleRouteEntered (route) {\n  for (var i = 0; i < route.matched.length; i++) {\n    var record = route.matched[i];\n    for (var name in record.instances) {\n      var instance = record.instances[name];\n      var cbs = record.enteredCbs[name];\n      if (!instance || !cbs) { continue }\n      delete record.enteredCbs[name];\n      for (var i$1 = 0; i$1 < cbs.length; i$1++) {\n        if (!instance._isBeingDestroyed) { cbs[i$1](instance); }\n      }\n    }\n  }\n}\n\nvar View = {\n  name: 'RouterView',\n  functional: true,\n  props: {\n    name: {\n      type: String,\n      default: 'default'\n    }\n  },\n  render: function render (_, ref) {\n    var props = ref.props;\n    var children = ref.children;\n    var parent = ref.parent;\n    var data = ref.data;\n\n    // used by devtools to display a router-view badge\n    data.routerView = true;\n\n    // directly use parent context's createElement() function\n    // so that components rendered by router-view can resolve named slots\n    var h = parent.$createElement;\n    var name = props.name;\n    var route = parent.$route;\n    var cache = parent._routerViewCache || (parent._routerViewCache = {});\n\n    // determine current view depth, also check to see if the tree\n    // has been toggled inactive but kept-alive.\n    var depth = 0;\n    var inactive = false;\n    while (parent && parent._routerRoot !== parent) {\n      var vnodeData = parent.$vnode ? parent.$vnode.data : {};\n      if (vnodeData.routerView) {\n        depth++;\n      }\n      if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {\n        inactive = true;\n      }\n      parent = parent.$parent;\n    }\n    data.routerViewDepth = depth;\n\n    // render previous view if the tree is inactive and kept-alive\n    if (inactive) {\n      var cachedData = cache[name];\n      var cachedComponent = cachedData && cachedData.component;\n      if (cachedComponent) {\n        // #2301\n        // pass props\n        if (cachedData.configProps) {\n          fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps);\n        }\n        return h(cachedComponent, data, children)\n      } else {\n        // render previous empty view\n        return h()\n      }\n    }\n\n    var matched = route.matched[depth];\n    var component = matched && matched.components[name];\n\n    // render empty node if no matched route or no config component\n    if (!matched || !component) {\n      cache[name] = null;\n      return h()\n    }\n\n    // cache component\n    cache[name] = { component: component };\n\n    // attach instance registration hook\n    // this will be called in the instance's injected lifecycle hooks\n    data.registerRouteInstance = function (vm, val) {\n      // val could be undefined for unregistration\n      var current = matched.instances[name];\n      if (\n        (val && current !== vm) ||\n        (!val && current === vm)\n      ) {\n        matched.instances[name] = val;\n      }\n    }\n\n    // also register instance in prepatch hook\n    // in case the same component instance is reused across different routes\n    ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {\n      matched.instances[name] = vnode.componentInstance;\n    };\n\n    // register instance in init hook\n    // in case kept-alive component be actived when routes changed\n    data.hook.init = function (vnode) {\n      if (vnode.data.keepAlive &&\n        vnode.componentInstance &&\n        vnode.componentInstance !== matched.instances[name]\n      ) {\n        matched.instances[name] = vnode.componentInstance;\n      }\n\n      // if the route transition has already been confirmed then we weren't\n      // able to call the cbs during confirmation as the component was not\n      // registered yet, so we call it here.\n      handleRouteEntered(route);\n    };\n\n    var configProps = matched.props && matched.props[name];\n    // save route and configProps in cache\n    if (configProps) {\n      extend(cache[name], {\n        route: route,\n        configProps: configProps\n      });\n      fillPropsinData(component, data, route, configProps);\n    }\n\n    return h(component, data, children)\n  }\n};\n\nfunction fillPropsinData (component, data, route, configProps) {\n  // resolve props\n  var propsToPass = data.props = resolveProps(route, configProps);\n  if (propsToPass) {\n    // clone to prevent mutation\n    propsToPass = data.props = extend({}, propsToPass);\n    // pass non-declared props as attrs\n    var attrs = data.attrs = data.attrs || {};\n    for (var key in propsToPass) {\n      if (!component.props || !(key in component.props)) {\n        attrs[key] = propsToPass[key];\n        delete propsToPass[key];\n      }\n    }\n  }\n}\n\nfunction resolveProps (route, config) {\n  switch (typeof config) {\n    case 'undefined':\n      return\n    case 'object':\n      return config\n    case 'function':\n      return config(route)\n    case 'boolean':\n      return config ? route.params : undefined\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false,\n          \"props in \\\"\" + (route.path) + \"\\\" is a \" + (typeof config) + \", \" +\n          \"expecting an object, function or boolean.\"\n        );\n      }\n  }\n}\n\n/*  */\n\nfunction resolvePath (\n  relative,\n  base,\n  append\n) {\n  var firstChar = relative.charAt(0);\n  if (firstChar === '/') {\n    return relative\n  }\n\n  if (firstChar === '?' || firstChar === '#') {\n    return base + relative\n  }\n\n  var stack = base.split('/');\n\n  // remove trailing segment if:\n  // - not appending\n  // - appending to trailing slash (last segment is empty)\n  if (!append || !stack[stack.length - 1]) {\n    stack.pop();\n  }\n\n  // resolve relative path\n  var segments = relative.replace(/^\\//, '').split('/');\n  for (var i = 0; i < segments.length; i++) {\n    var segment = segments[i];\n    if (segment === '..') {\n      stack.pop();\n    } else if (segment !== '.') {\n      stack.push(segment);\n    }\n  }\n\n  // ensure leading slash\n  if (stack[0] !== '') {\n    stack.unshift('');\n  }\n\n  return stack.join('/')\n}\n\nfunction parsePath (path) {\n  var hash = '';\n  var query = '';\n\n  var hashIndex = path.indexOf('#');\n  if (hashIndex >= 0) {\n    hash = path.slice(hashIndex);\n    path = path.slice(0, hashIndex);\n  }\n\n  var queryIndex = path.indexOf('?');\n  if (queryIndex >= 0) {\n    query = path.slice(queryIndex + 1);\n    path = path.slice(0, queryIndex);\n  }\n\n  return {\n    path: path,\n    query: query,\n    hash: hash\n  }\n}\n\nfunction cleanPath (path) {\n  return path.replace(/\\/(?:\\s*\\/)+/g, '/')\n}\n\nvar isarray = Array.isArray || function (arr) {\n  return Object.prototype.toString.call(arr) == '[object Array]';\n};\n\n/**\n * Expose `pathToRegexp`.\n */\nvar pathToRegexp_1 = pathToRegexp;\nvar parse_1 = parse;\nvar compile_1 = compile;\nvar tokensToFunction_1 = tokensToFunction;\nvar tokensToRegExp_1 = tokensToRegExp;\n\n/**\n * The main path matching regexp utility.\n *\n * @type {RegExp}\n */\nvar PATH_REGEXP = new RegExp([\n  // Match escaped characters that would otherwise appear in future matches.\n  // This allows the user to escape special characters that won't transform.\n  '(\\\\\\\\.)',\n  // Match Express-style parameters and un-named parameters with a prefix\n  // and optional suffixes. Matches appear as:\n  //\n  // \"/:test(\\\\d+)?\" => [\"/\", \"test\", \"\\d+\", undefined, \"?\", undefined]\n  // \"/route(\\\\d+)\"  => [undefined, undefined, undefined, \"\\d+\", undefined, undefined]\n  // \"/*\"            => [\"/\", undefined, undefined, undefined, undefined, \"*\"]\n  '([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))'\n].join('|'), 'g');\n\n/**\n * Parse a string for the raw tokens.\n *\n * @param  {string}  str\n * @param  {Object=} options\n * @return {!Array}\n */\nfunction parse (str, options) {\n  var tokens = [];\n  var key = 0;\n  var index = 0;\n  var path = '';\n  var defaultDelimiter = options && options.delimiter || '/';\n  var res;\n\n  while ((res = PATH_REGEXP.exec(str)) != null) {\n    var m = res[0];\n    var escaped = res[1];\n    var offset = res.index;\n    path += str.slice(index, offset);\n    index = offset + m.length;\n\n    // Ignore already escaped sequences.\n    if (escaped) {\n      path += escaped[1];\n      continue\n    }\n\n    var next = str[index];\n    var prefix = res[2];\n    var name = res[3];\n    var capture = res[4];\n    var group = res[5];\n    var modifier = res[6];\n    var asterisk = res[7];\n\n    // Push the current path onto the tokens.\n    if (path) {\n      tokens.push(path);\n      path = '';\n    }\n\n    var partial = prefix != null && next != null && next !== prefix;\n    var repeat = modifier === '+' || modifier === '*';\n    var optional = modifier === '?' || modifier === '*';\n    var delimiter = res[2] || defaultDelimiter;\n    var pattern = capture || group;\n\n    tokens.push({\n      name: name || key++,\n      prefix: prefix || '',\n      delimiter: delimiter,\n      optional: optional,\n      repeat: repeat,\n      partial: partial,\n      asterisk: !!asterisk,\n      pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')\n    });\n  }\n\n  // Match any characters still remaining.\n  if (index < str.length) {\n    path += str.substr(index);\n  }\n\n  // If the path exists, push it onto the end.\n  if (path) {\n    tokens.push(path);\n  }\n\n  return tokens\n}\n\n/**\n * Compile a string to a template function for the path.\n *\n * @param  {string}             str\n * @param  {Object=}            options\n * @return {!function(Object=, Object=)}\n */\nfunction compile (str, options) {\n  return tokensToFunction(parse(str, options), options)\n}\n\n/**\n * Prettier encoding of URI path segments.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeURIComponentPretty (str) {\n  return encodeURI(str).replace(/[\\/?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeAsterisk (str) {\n  return encodeURI(str).replace(/[?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Expose a method for transforming tokens into the path function.\n */\nfunction tokensToFunction (tokens, options) {\n  // Compile all the tokens into regexps.\n  var matches = new Array(tokens.length);\n\n  // Compile all the patterns before compilation.\n  for (var i = 0; i < tokens.length; i++) {\n    if (typeof tokens[i] === 'object') {\n      matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));\n    }\n  }\n\n  return function (obj, opts) {\n    var path = '';\n    var data = obj || {};\n    var options = opts || {};\n    var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;\n\n    for (var i = 0; i < tokens.length; i++) {\n      var token = tokens[i];\n\n      if (typeof token === 'string') {\n        path += token;\n\n        continue\n      }\n\n      var value = data[token.name];\n      var segment;\n\n      if (value == null) {\n        if (token.optional) {\n          // Prepend partial segment prefixes.\n          if (token.partial) {\n            path += token.prefix;\n          }\n\n          continue\n        } else {\n          throw new TypeError('Expected \"' + token.name + '\" to be defined')\n        }\n      }\n\n      if (isarray(value)) {\n        if (!token.repeat) {\n          throw new TypeError('Expected \"' + token.name + '\" to not repeat, but received `' + JSON.stringify(value) + '`')\n        }\n\n        if (value.length === 0) {\n          if (token.optional) {\n            continue\n          } else {\n            throw new TypeError('Expected \"' + token.name + '\" to not be empty')\n          }\n        }\n\n        for (var j = 0; j < value.length; j++) {\n          segment = encode(value[j]);\n\n          if (!matches[i].test(segment)) {\n            throw new TypeError('Expected all \"' + token.name + '\" to match \"' + token.pattern + '\", but received `' + JSON.stringify(segment) + '`')\n          }\n\n          path += (j === 0 ? token.prefix : token.delimiter) + segment;\n        }\n\n        continue\n      }\n\n      segment = token.asterisk ? encodeAsterisk(value) : encode(value);\n\n      if (!matches[i].test(segment)) {\n        throw new TypeError('Expected \"' + token.name + '\" to match \"' + token.pattern + '\", but received \"' + segment + '\"')\n      }\n\n      path += token.prefix + segment;\n    }\n\n    return path\n  }\n}\n\n/**\n * Escape a regular expression string.\n *\n * @param  {string} str\n * @return {string}\n */\nfunction escapeString (str) {\n  return str.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g, '\\\\$1')\n}\n\n/**\n * Escape the capturing group by escaping special characters and meaning.\n *\n * @param  {string} group\n * @return {string}\n */\nfunction escapeGroup (group) {\n  return group.replace(/([=!:$\\/()])/g, '\\\\$1')\n}\n\n/**\n * Attach the keys as a property of the regexp.\n *\n * @param  {!RegExp} re\n * @param  {Array}   keys\n * @return {!RegExp}\n */\nfunction attachKeys (re, keys) {\n  re.keys = keys;\n  return re\n}\n\n/**\n * Get the flags for a regexp from the options.\n *\n * @param  {Object} options\n * @return {string}\n */\nfunction flags (options) {\n  return options && options.sensitive ? '' : 'i'\n}\n\n/**\n * Pull out keys from a regexp.\n *\n * @param  {!RegExp} path\n * @param  {!Array}  keys\n * @return {!RegExp}\n */\nfunction regexpToRegexp (path, keys) {\n  // Use a negative lookahead to match only capturing groups.\n  var groups = path.source.match(/\\((?!\\?)/g);\n\n  if (groups) {\n    for (var i = 0; i < groups.length; i++) {\n      keys.push({\n        name: i,\n        prefix: null,\n        delimiter: null,\n        optional: false,\n        repeat: false,\n        partial: false,\n        asterisk: false,\n        pattern: null\n      });\n    }\n  }\n\n  return attachKeys(path, keys)\n}\n\n/**\n * Transform an array into a regexp.\n *\n * @param  {!Array}  path\n * @param  {Array}   keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction arrayToRegexp (path, keys, options) {\n  var parts = [];\n\n  for (var i = 0; i < path.length; i++) {\n    parts.push(pathToRegexp(path[i], keys, options).source);\n  }\n\n  var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));\n\n  return attachKeys(regexp, keys)\n}\n\n/**\n * Create a path regexp from string input.\n *\n * @param  {string}  path\n * @param  {!Array}  keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction stringToRegexp (path, keys, options) {\n  return tokensToRegExp(parse(path, options), keys, options)\n}\n\n/**\n * Expose a function for taking tokens and returning a RegExp.\n *\n * @param  {!Array}          tokens\n * @param  {(Array|Object)=} keys\n * @param  {Object=}         options\n * @return {!RegExp}\n */\nfunction tokensToRegExp (tokens, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  var strict = options.strict;\n  var end = options.end !== false;\n  var route = '';\n\n  // Iterate over the tokens and create our regexp string.\n  for (var i = 0; i < tokens.length; i++) {\n    var token = tokens[i];\n\n    if (typeof token === 'string') {\n      route += escapeString(token);\n    } else {\n      var prefix = escapeString(token.prefix);\n      var capture = '(?:' + token.pattern + ')';\n\n      keys.push(token);\n\n      if (token.repeat) {\n        capture += '(?:' + prefix + capture + ')*';\n      }\n\n      if (token.optional) {\n        if (!token.partial) {\n          capture = '(?:' + prefix + '(' + capture + '))?';\n        } else {\n          capture = prefix + '(' + capture + ')?';\n        }\n      } else {\n        capture = prefix + '(' + capture + ')';\n      }\n\n      route += capture;\n    }\n  }\n\n  var delimiter = escapeString(options.delimiter || '/');\n  var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;\n\n  // In non-strict mode we allow a slash at the end of match. If the path to\n  // match already ends with a slash, we remove it for consistency. The slash\n  // is valid at the end of a path match, not in the middle. This is important\n  // in non-ending mode, where \"/test/\" shouldn't match \"/test//route\".\n  if (!strict) {\n    route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';\n  }\n\n  if (end) {\n    route += '$';\n  } else {\n    // In non-ending mode, we need the capturing groups to match as much as\n    // possible by using a positive lookahead to the end or next path segment.\n    route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';\n  }\n\n  return attachKeys(new RegExp('^' + route, flags(options)), keys)\n}\n\n/**\n * Normalize the given path string, returning a regular expression.\n *\n * An empty array can be passed in for the keys, which will hold the\n * placeholder key descriptions. For example, using `/user/:id`, `keys` will\n * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.\n *\n * @param  {(string|RegExp|Array)} path\n * @param  {(Array|Object)=}       keys\n * @param  {Object=}               options\n * @return {!RegExp}\n */\nfunction pathToRegexp (path, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  if (path instanceof RegExp) {\n    return regexpToRegexp(path, /** @type {!Array} */ (keys))\n  }\n\n  if (isarray(path)) {\n    return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)\n  }\n\n  return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)\n}\npathToRegexp_1.parse = parse_1;\npathToRegexp_1.compile = compile_1;\npathToRegexp_1.tokensToFunction = tokensToFunction_1;\npathToRegexp_1.tokensToRegExp = tokensToRegExp_1;\n\n/*  */\n\n// $flow-disable-line\nvar regexpCompileCache = Object.create(null);\n\nfunction fillParams (\n  path,\n  params,\n  routeMsg\n) {\n  params = params || {};\n  try {\n    var filler =\n      regexpCompileCache[path] ||\n      (regexpCompileCache[path] = pathToRegexp_1.compile(path));\n\n    // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}\n    // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string\n    if (typeof params.pathMatch === 'string') { params[0] = params.pathMatch; }\n\n    return filler(params, { pretty: true })\n  } catch (e) {\n    if (process.env.NODE_ENV !== 'production') {\n      // Fix #3072 no warn if `pathMatch` is string\n      warn(typeof params.pathMatch === 'string', (\"missing param for \" + routeMsg + \": \" + (e.message)));\n    }\n    return ''\n  } finally {\n    // delete the 0 if it was added\n    delete params[0];\n  }\n}\n\n/*  */\n\nfunction normalizeLocation (\n  raw,\n  current,\n  append,\n  router\n) {\n  var next = typeof raw === 'string' ? { path: raw } : raw;\n  // named target\n  if (next._normalized) {\n    return next\n  } else if (next.name) {\n    next = extend({}, raw);\n    var params = next.params;\n    if (params && typeof params === 'object') {\n      next.params = extend({}, params);\n    }\n    return next\n  }\n\n  // relative params\n  if (!next.path && next.params && current) {\n    next = extend({}, next);\n    next._normalized = true;\n    var params$1 = extend(extend({}, current.params), next.params);\n    if (current.name) {\n      next.name = current.name;\n      next.params = params$1;\n    } else if (current.matched.length) {\n      var rawPath = current.matched[current.matched.length - 1].path;\n      next.path = fillParams(rawPath, params$1, (\"path \" + (current.path)));\n    } else if (process.env.NODE_ENV !== 'production') {\n      warn(false, \"relative params navigation requires a current route.\");\n    }\n    return next\n  }\n\n  var parsedPath = parsePath(next.path || '');\n  var basePath = (current && current.path) || '/';\n  var path = parsedPath.path\n    ? resolvePath(parsedPath.path, basePath, append || next.append)\n    : basePath;\n\n  var query = resolveQuery(\n    parsedPath.query,\n    next.query,\n    router && router.options.parseQuery\n  );\n\n  var hash = next.hash || parsedPath.hash;\n  if (hash && hash.charAt(0) !== '#') {\n    hash = \"#\" + hash;\n  }\n\n  return {\n    _normalized: true,\n    path: path,\n    query: query,\n    hash: hash\n  }\n}\n\n/*  */\n\n// work around weird flow bug\nvar toTypes = [String, Object];\nvar eventTypes = [String, Array];\n\nvar noop = function () {};\n\nvar warnedCustomSlot;\nvar warnedTagProp;\nvar warnedEventProp;\n\nvar Link = {\n  name: 'RouterLink',\n  props: {\n    to: {\n      type: toTypes,\n      required: true\n    },\n    tag: {\n      type: String,\n      default: 'a'\n    },\n    custom: Boolean,\n    exact: Boolean,\n    exactPath: Boolean,\n    append: Boolean,\n    replace: Boolean,\n    activeClass: String,\n    exactActiveClass: String,\n    ariaCurrentValue: {\n      type: String,\n      default: 'page'\n    },\n    event: {\n      type: eventTypes,\n      default: 'click'\n    }\n  },\n  render: function render (h) {\n    var this$1$1 = this;\n\n    var router = this.$router;\n    var current = this.$route;\n    var ref = router.resolve(\n      this.to,\n      current,\n      this.append\n    );\n    var location = ref.location;\n    var route = ref.route;\n    var href = ref.href;\n\n    var classes = {};\n    var globalActiveClass = router.options.linkActiveClass;\n    var globalExactActiveClass = router.options.linkExactActiveClass;\n    // Support global empty active class\n    var activeClassFallback =\n      globalActiveClass == null ? 'router-link-active' : globalActiveClass;\n    var exactActiveClassFallback =\n      globalExactActiveClass == null\n        ? 'router-link-exact-active'\n        : globalExactActiveClass;\n    var activeClass =\n      this.activeClass == null ? activeClassFallback : this.activeClass;\n    var exactActiveClass =\n      this.exactActiveClass == null\n        ? exactActiveClassFallback\n        : this.exactActiveClass;\n\n    var compareTarget = route.redirectedFrom\n      ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)\n      : route;\n\n    classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath);\n    classes[activeClass] = this.exact || this.exactPath\n      ? classes[exactActiveClass]\n      : isIncludedRoute(current, compareTarget);\n\n    var ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null;\n\n    var handler = function (e) {\n      if (guardEvent(e)) {\n        if (this$1$1.replace) {\n          router.replace(location, noop);\n        } else {\n          router.push(location, noop);\n        }\n      }\n    };\n\n    var on = { click: guardEvent };\n    if (Array.isArray(this.event)) {\n      this.event.forEach(function (e) {\n        on[e] = handler;\n      });\n    } else {\n      on[this.event] = handler;\n    }\n\n    var data = { class: classes };\n\n    var scopedSlot =\n      !this.$scopedSlots.$hasNormal &&\n      this.$scopedSlots.default &&\n      this.$scopedSlots.default({\n        href: href,\n        route: route,\n        navigate: handler,\n        isActive: classes[activeClass],\n        isExactActive: classes[exactActiveClass]\n      });\n\n    if (scopedSlot) {\n      if (process.env.NODE_ENV !== 'production' && !this.custom) {\n        !warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\\n<router-link v-slot=\"{ navigate, href }\" custom></router-link>\\n');\n        warnedCustomSlot = true;\n      }\n      if (scopedSlot.length === 1) {\n        return scopedSlot[0]\n      } else if (scopedSlot.length > 1 || !scopedSlot.length) {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(\n            false,\n            (\"<router-link> with to=\\\"\" + (this.to) + \"\\\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.\")\n          );\n        }\n        return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)\n      }\n    }\n\n    if (process.env.NODE_ENV !== 'production') {\n      if ('tag' in this.$options.propsData && !warnedTagProp) {\n        warn(\n          false,\n          \"<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n        );\n        warnedTagProp = true;\n      }\n      if ('event' in this.$options.propsData && !warnedEventProp) {\n        warn(\n          false,\n          \"<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n        );\n        warnedEventProp = true;\n      }\n    }\n\n    if (this.tag === 'a') {\n      data.on = on;\n      data.attrs = { href: href, 'aria-current': ariaCurrentValue };\n    } else {\n      // find the first <a> child and apply listener and href\n      var a = findAnchor(this.$slots.default);\n      if (a) {\n        // in case the <a> is a static node\n        a.isStatic = false;\n        var aData = (a.data = extend({}, a.data));\n        aData.on = aData.on || {};\n        // transform existing events in both objects into arrays so we can push later\n        for (var event in aData.on) {\n          var handler$1 = aData.on[event];\n          if (event in on) {\n            aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];\n          }\n        }\n        // append new listeners for router-link\n        for (var event$1 in on) {\n          if (event$1 in aData.on) {\n            // on[event] is always a function\n            aData.on[event$1].push(on[event$1]);\n          } else {\n            aData.on[event$1] = handler;\n          }\n        }\n\n        var aAttrs = (a.data.attrs = extend({}, a.data.attrs));\n        aAttrs.href = href;\n        aAttrs['aria-current'] = ariaCurrentValue;\n      } else {\n        // doesn't have <a> child, apply listener to self\n        data.on = on;\n      }\n    }\n\n    return h(this.tag, data, this.$slots.default)\n  }\n};\n\nfunction guardEvent (e) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) { return }\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) { return }\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    var target = e.currentTarget.getAttribute('target');\n    if (/\\b_blank\\b/i.test(target)) { return }\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault();\n  }\n  return true\n}\n\nfunction findAnchor (children) {\n  if (children) {\n    var child;\n    for (var i = 0; i < children.length; i++) {\n      child = children[i];\n      if (child.tag === 'a') {\n        return child\n      }\n      if (child.children && (child = findAnchor(child.children))) {\n        return child\n      }\n    }\n  }\n}\n\nvar _Vue;\n\nfunction install (Vue) {\n  if (install.installed && _Vue === Vue) { return }\n  install.installed = true;\n\n  _Vue = Vue;\n\n  var isDef = function (v) { return v !== undefined; };\n\n  var registerInstance = function (vm, callVal) {\n    var i = vm.$options._parentVnode;\n    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {\n      i(vm, callVal);\n    }\n  };\n\n  Vue.mixin({\n    beforeCreate: function beforeCreate () {\n      if (isDef(this.$options.router)) {\n        this._routerRoot = this;\n        this._router = this.$options.router;\n        this._router.init(this);\n        Vue.util.defineReactive(this, '_route', this._router.history.current);\n      } else {\n        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;\n      }\n      registerInstance(this, this);\n    },\n    destroyed: function destroyed () {\n      registerInstance(this);\n    }\n  });\n\n  Object.defineProperty(Vue.prototype, '$router', {\n    get: function get () { return this._routerRoot._router }\n  });\n\n  Object.defineProperty(Vue.prototype, '$route', {\n    get: function get () { return this._routerRoot._route }\n  });\n\n  Vue.component('RouterView', View);\n  Vue.component('RouterLink', Link);\n\n  var strats = Vue.config.optionMergeStrategies;\n  // use the same hook merging strategy for route hooks\n  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;\n}\n\n/*  */\n\nvar inBrowser = typeof window !== 'undefined';\n\n/*  */\n\nfunction createRouteMap (\n  routes,\n  oldPathList,\n  oldPathMap,\n  oldNameMap,\n  parentRoute\n) {\n  // the path list is used to control path matching priority\n  var pathList = oldPathList || [];\n  // $flow-disable-line\n  var pathMap = oldPathMap || Object.create(null);\n  // $flow-disable-line\n  var nameMap = oldNameMap || Object.create(null);\n\n  routes.forEach(function (route) {\n    addRouteRecord(pathList, pathMap, nameMap, route, parentRoute);\n  });\n\n  // ensure wildcard routes are always at the end\n  for (var i = 0, l = pathList.length; i < l; i++) {\n    if (pathList[i] === '*') {\n      pathList.push(pathList.splice(i, 1)[0]);\n      l--;\n      i--;\n    }\n  }\n\n  if (process.env.NODE_ENV === 'development') {\n    // warn if routes do not include leading slashes\n    var found = pathList\n    // check for missing leading slash\n      .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });\n\n    if (found.length > 0) {\n      var pathNames = found.map(function (path) { return (\"- \" + path); }).join('\\n');\n      warn(false, (\"Non-nested routes must include a leading slash character. Fix the following routes: \\n\" + pathNames));\n    }\n  }\n\n  return {\n    pathList: pathList,\n    pathMap: pathMap,\n    nameMap: nameMap\n  }\n}\n\nfunction addRouteRecord (\n  pathList,\n  pathMap,\n  nameMap,\n  route,\n  parent,\n  matchAs\n) {\n  var path = route.path;\n  var name = route.name;\n  if (process.env.NODE_ENV !== 'production') {\n    assert(path != null, \"\\\"path\\\" is required in a route configuration.\");\n    assert(\n      typeof route.component !== 'string',\n      \"route config \\\"component\\\" for path: \" + (String(\n        path || name\n      )) + \" cannot be a \" + \"string id. Use an actual component instead.\"\n    );\n\n    warn(\n      // eslint-disable-next-line no-control-regex\n      !/[^\\u0000-\\u007F]+/.test(path),\n      \"Route with path \\\"\" + path + \"\\\" contains unencoded characters, make sure \" +\n        \"your path is correctly encoded before passing it to the router. Use \" +\n        \"encodeURI to encode static segments of your path.\"\n    );\n  }\n\n  var pathToRegexpOptions =\n    route.pathToRegexpOptions || {};\n  var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);\n\n  if (typeof route.caseSensitive === 'boolean') {\n    pathToRegexpOptions.sensitive = route.caseSensitive;\n  }\n\n  var record = {\n    path: normalizedPath,\n    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),\n    components: route.components || { default: route.component },\n    alias: route.alias\n      ? typeof route.alias === 'string'\n        ? [route.alias]\n        : route.alias\n      : [],\n    instances: {},\n    enteredCbs: {},\n    name: name,\n    parent: parent,\n    matchAs: matchAs,\n    redirect: route.redirect,\n    beforeEnter: route.beforeEnter,\n    meta: route.meta || {},\n    props:\n      route.props == null\n        ? {}\n        : route.components\n          ? route.props\n          : { default: route.props }\n  };\n\n  if (route.children) {\n    // Warn if route is named, does not redirect and has a default child route.\n    // If users navigate to this route by name, the default child will\n    // not be rendered (GH Issue #629)\n    if (process.env.NODE_ENV !== 'production') {\n      if (\n        route.name &&\n        !route.redirect &&\n        route.children.some(function (child) { return /^\\/?$/.test(child.path); })\n      ) {\n        warn(\n          false,\n          \"Named Route '\" + (route.name) + \"' has a default child route. \" +\n            \"When navigating to this named route (:to=\\\"{name: '\" + (route.name) + \"'}\\\"), \" +\n            \"the default child route will not be rendered. Remove the name from \" +\n            \"this route and use the name of the default child route for named \" +\n            \"links instead.\"\n        );\n      }\n    }\n    route.children.forEach(function (child) {\n      var childMatchAs = matchAs\n        ? cleanPath((matchAs + \"/\" + (child.path)))\n        : undefined;\n      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);\n    });\n  }\n\n  if (!pathMap[record.path]) {\n    pathList.push(record.path);\n    pathMap[record.path] = record;\n  }\n\n  if (route.alias !== undefined) {\n    var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];\n    for (var i = 0; i < aliases.length; ++i) {\n      var alias = aliases[i];\n      if (process.env.NODE_ENV !== 'production' && alias === path) {\n        warn(\n          false,\n          (\"Found an alias with the same value as the path: \\\"\" + path + \"\\\". You have to remove that alias. It will be ignored in development.\")\n        );\n        // skip in dev to make it work\n        continue\n      }\n\n      var aliasRoute = {\n        path: alias,\n        children: route.children\n      };\n      addRouteRecord(\n        pathList,\n        pathMap,\n        nameMap,\n        aliasRoute,\n        parent,\n        record.path || '/' // matchAs\n      );\n    }\n  }\n\n  if (name) {\n    if (!nameMap[name]) {\n      nameMap[name] = record;\n    } else if (process.env.NODE_ENV !== 'production' && !matchAs) {\n      warn(\n        false,\n        \"Duplicate named routes definition: \" +\n          \"{ name: \\\"\" + name + \"\\\", path: \\\"\" + (record.path) + \"\\\" }\"\n      );\n    }\n  }\n}\n\nfunction compileRouteRegex (\n  path,\n  pathToRegexpOptions\n) {\n  var regex = pathToRegexp_1(path, [], pathToRegexpOptions);\n  if (process.env.NODE_ENV !== 'production') {\n    var keys = Object.create(null);\n    regex.keys.forEach(function (key) {\n      warn(\n        !keys[key.name],\n        (\"Duplicate param keys in route with path: \\\"\" + path + \"\\\"\")\n      );\n      keys[key.name] = true;\n    });\n  }\n  return regex\n}\n\nfunction normalizePath (\n  path,\n  parent,\n  strict\n) {\n  if (!strict) { path = path.replace(/\\/$/, ''); }\n  if (path[0] === '/') { return path }\n  if (parent == null) { return path }\n  return cleanPath(((parent.path) + \"/\" + path))\n}\n\n/*  */\n\n\n\nfunction createMatcher (\n  routes,\n  router\n) {\n  var ref = createRouteMap(routes);\n  var pathList = ref.pathList;\n  var pathMap = ref.pathMap;\n  var nameMap = ref.nameMap;\n\n  function addRoutes (routes) {\n    createRouteMap(routes, pathList, pathMap, nameMap);\n  }\n\n  function addRoute (parentOrRoute, route) {\n    var parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined;\n    // $flow-disable-line\n    createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent);\n\n    // add aliases of parent\n    if (parent && parent.alias.length) {\n      createRouteMap(\n        // $flow-disable-line route is defined if parent is\n        parent.alias.map(function (alias) { return ({ path: alias, children: [route] }); }),\n        pathList,\n        pathMap,\n        nameMap,\n        parent\n      );\n    }\n  }\n\n  function getRoutes () {\n    return pathList.map(function (path) { return pathMap[path]; })\n  }\n\n  function match (\n    raw,\n    currentRoute,\n    redirectedFrom\n  ) {\n    var location = normalizeLocation(raw, currentRoute, false, router);\n    var name = location.name;\n\n    if (name) {\n      var record = nameMap[name];\n      if (process.env.NODE_ENV !== 'production') {\n        warn(record, (\"Route with name '\" + name + \"' does not exist\"));\n      }\n      if (!record) { return _createRoute(null, location) }\n      var paramNames = record.regex.keys\n        .filter(function (key) { return !key.optional; })\n        .map(function (key) { return key.name; });\n\n      if (typeof location.params !== 'object') {\n        location.params = {};\n      }\n\n      if (currentRoute && typeof currentRoute.params === 'object') {\n        for (var key in currentRoute.params) {\n          if (!(key in location.params) && paramNames.indexOf(key) > -1) {\n            location.params[key] = currentRoute.params[key];\n          }\n        }\n      }\n\n      location.path = fillParams(record.path, location.params, (\"named route \\\"\" + name + \"\\\"\"));\n      return _createRoute(record, location, redirectedFrom)\n    } else if (location.path) {\n      location.params = {};\n      for (var i = 0; i < pathList.length; i++) {\n        var path = pathList[i];\n        var record$1 = pathMap[path];\n        if (matchRoute(record$1.regex, location.path, location.params)) {\n          return _createRoute(record$1, location, redirectedFrom)\n        }\n      }\n    }\n    // no match\n    return _createRoute(null, location)\n  }\n\n  function redirect (\n    record,\n    location\n  ) {\n    var originalRedirect = record.redirect;\n    var redirect = typeof originalRedirect === 'function'\n      ? originalRedirect(createRoute(record, location, null, router))\n      : originalRedirect;\n\n    if (typeof redirect === 'string') {\n      redirect = { path: redirect };\n    }\n\n    if (!redirect || typeof redirect !== 'object') {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false, (\"invalid redirect option: \" + (JSON.stringify(redirect)))\n        );\n      }\n      return _createRoute(null, location)\n    }\n\n    var re = redirect;\n    var name = re.name;\n    var path = re.path;\n    var query = location.query;\n    var hash = location.hash;\n    var params = location.params;\n    query = re.hasOwnProperty('query') ? re.query : query;\n    hash = re.hasOwnProperty('hash') ? re.hash : hash;\n    params = re.hasOwnProperty('params') ? re.params : params;\n\n    if (name) {\n      // resolved named direct\n      var targetRecord = nameMap[name];\n      if (process.env.NODE_ENV !== 'production') {\n        assert(targetRecord, (\"redirect failed: named route \\\"\" + name + \"\\\" not found.\"));\n      }\n      return match({\n        _normalized: true,\n        name: name,\n        query: query,\n        hash: hash,\n        params: params\n      }, undefined, location)\n    } else if (path) {\n      // 1. resolve relative redirect\n      var rawPath = resolveRecordPath(path, record);\n      // 2. resolve params\n      var resolvedPath = fillParams(rawPath, params, (\"redirect route with path \\\"\" + rawPath + \"\\\"\"));\n      // 3. rematch with existing query and hash\n      return match({\n        _normalized: true,\n        path: resolvedPath,\n        query: query,\n        hash: hash\n      }, undefined, location)\n    } else {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(false, (\"invalid redirect option: \" + (JSON.stringify(redirect))));\n      }\n      return _createRoute(null, location)\n    }\n  }\n\n  function alias (\n    record,\n    location,\n    matchAs\n  ) {\n    var aliasedPath = fillParams(matchAs, location.params, (\"aliased route with path \\\"\" + matchAs + \"\\\"\"));\n    var aliasedMatch = match({\n      _normalized: true,\n      path: aliasedPath\n    });\n    if (aliasedMatch) {\n      var matched = aliasedMatch.matched;\n      var aliasedRecord = matched[matched.length - 1];\n      location.params = aliasedMatch.params;\n      return _createRoute(aliasedRecord, location)\n    }\n    return _createRoute(null, location)\n  }\n\n  function _createRoute (\n    record,\n    location,\n    redirectedFrom\n  ) {\n    if (record && record.redirect) {\n      return redirect(record, redirectedFrom || location)\n    }\n    if (record && record.matchAs) {\n      return alias(record, location, record.matchAs)\n    }\n    return createRoute(record, location, redirectedFrom, router)\n  }\n\n  return {\n    match: match,\n    addRoute: addRoute,\n    getRoutes: getRoutes,\n    addRoutes: addRoutes\n  }\n}\n\nfunction matchRoute (\n  regex,\n  path,\n  params\n) {\n  var m = path.match(regex);\n\n  if (!m) {\n    return false\n  } else if (!params) {\n    return true\n  }\n\n  for (var i = 1, len = m.length; i < len; ++i) {\n    var key = regex.keys[i - 1];\n    if (key) {\n      // Fix #1994: using * with props: true generates a param named 0\n      params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i];\n    }\n  }\n\n  return true\n}\n\nfunction resolveRecordPath (path, record) {\n  return resolvePath(path, record.parent ? record.parent.path : '/', true)\n}\n\n/*  */\n\n// use User Timing api (if present) for more accurate key precision\nvar Time =\n  inBrowser && window.performance && window.performance.now\n    ? window.performance\n    : Date;\n\nfunction genStateKey () {\n  return Time.now().toFixed(3)\n}\n\nvar _key = genStateKey();\n\nfunction getStateKey () {\n  return _key\n}\n\nfunction setStateKey (key) {\n  return (_key = key)\n}\n\n/*  */\n\nvar positionStore = Object.create(null);\n\nfunction setupScroll () {\n  // Prevent browser scroll behavior on History popstate\n  if ('scrollRestoration' in window.history) {\n    window.history.scrollRestoration = 'manual';\n  }\n  // Fix for #1585 for Firefox\n  // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678\n  // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with\n  // window.location.protocol + '//' + window.location.host\n  // location.host contains the port and location.hostname doesn't\n  var protocolAndPath = window.location.protocol + '//' + window.location.host;\n  var absolutePath = window.location.href.replace(protocolAndPath, '');\n  // preserve existing history state as it could be overriden by the user\n  var stateCopy = extend({}, window.history.state);\n  stateCopy.key = getStateKey();\n  window.history.replaceState(stateCopy, '', absolutePath);\n  window.addEventListener('popstate', handlePopState);\n  return function () {\n    window.removeEventListener('popstate', handlePopState);\n  }\n}\n\nfunction handleScroll (\n  router,\n  to,\n  from,\n  isPop\n) {\n  if (!router.app) {\n    return\n  }\n\n  var behavior = router.options.scrollBehavior;\n  if (!behavior) {\n    return\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    assert(typeof behavior === 'function', \"scrollBehavior must be a function\");\n  }\n\n  // wait until re-render finishes before scrolling\n  router.app.$nextTick(function () {\n    var position = getScrollPosition();\n    var shouldScroll = behavior.call(\n      router,\n      to,\n      from,\n      isPop ? position : null\n    );\n\n    if (!shouldScroll) {\n      return\n    }\n\n    if (typeof shouldScroll.then === 'function') {\n      shouldScroll\n        .then(function (shouldScroll) {\n          scrollToPosition((shouldScroll), position);\n        })\n        .catch(function (err) {\n          if (process.env.NODE_ENV !== 'production') {\n            assert(false, err.toString());\n          }\n        });\n    } else {\n      scrollToPosition(shouldScroll, position);\n    }\n  });\n}\n\nfunction saveScrollPosition () {\n  var key = getStateKey();\n  if (key) {\n    positionStore[key] = {\n      x: window.pageXOffset,\n      y: window.pageYOffset\n    };\n  }\n}\n\nfunction handlePopState (e) {\n  saveScrollPosition();\n  if (e.state && e.state.key) {\n    setStateKey(e.state.key);\n  }\n}\n\nfunction getScrollPosition () {\n  var key = getStateKey();\n  if (key) {\n    return positionStore[key]\n  }\n}\n\nfunction getElementPosition (el, offset) {\n  var docEl = document.documentElement;\n  var docRect = docEl.getBoundingClientRect();\n  var elRect = el.getBoundingClientRect();\n  return {\n    x: elRect.left - docRect.left - offset.x,\n    y: elRect.top - docRect.top - offset.y\n  }\n}\n\nfunction isValidPosition (obj) {\n  return isNumber(obj.x) || isNumber(obj.y)\n}\n\nfunction normalizePosition (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : window.pageXOffset,\n    y: isNumber(obj.y) ? obj.y : window.pageYOffset\n  }\n}\n\nfunction normalizeOffset (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : 0,\n    y: isNumber(obj.y) ? obj.y : 0\n  }\n}\n\nfunction isNumber (v) {\n  return typeof v === 'number'\n}\n\nvar hashStartsWithNumberRE = /^#\\d/;\n\nfunction scrollToPosition (shouldScroll, position) {\n  var isObject = typeof shouldScroll === 'object';\n  if (isObject && typeof shouldScroll.selector === 'string') {\n    // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]\n    // but at the same time, it doesn't make much sense to select an element with an id and an extra selector\n    var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line\n      ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line\n      : document.querySelector(shouldScroll.selector);\n\n    if (el) {\n      var offset =\n        shouldScroll.offset && typeof shouldScroll.offset === 'object'\n          ? shouldScroll.offset\n          : {};\n      offset = normalizeOffset(offset);\n      position = getElementPosition(el, offset);\n    } else if (isValidPosition(shouldScroll)) {\n      position = normalizePosition(shouldScroll);\n    }\n  } else if (isObject && isValidPosition(shouldScroll)) {\n    position = normalizePosition(shouldScroll);\n  }\n\n  if (position) {\n    // $flow-disable-line\n    if ('scrollBehavior' in document.documentElement.style) {\n      window.scrollTo({\n        left: position.x,\n        top: position.y,\n        // $flow-disable-line\n        behavior: shouldScroll.behavior\n      });\n    } else {\n      window.scrollTo(position.x, position.y);\n    }\n  }\n}\n\n/*  */\n\nvar supportsPushState =\n  inBrowser &&\n  (function () {\n    var ua = window.navigator.userAgent;\n\n    if (\n      (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&\n      ua.indexOf('Mobile Safari') !== -1 &&\n      ua.indexOf('Chrome') === -1 &&\n      ua.indexOf('Windows Phone') === -1\n    ) {\n      return false\n    }\n\n    return window.history && typeof window.history.pushState === 'function'\n  })();\n\nfunction pushState (url, replace) {\n  saveScrollPosition();\n  // try...catch the pushState call to get around Safari\n  // DOM Exception 18 where it limits to 100 pushState calls\n  var history = window.history;\n  try {\n    if (replace) {\n      // preserve existing history state as it could be overriden by the user\n      var stateCopy = extend({}, history.state);\n      stateCopy.key = getStateKey();\n      history.replaceState(stateCopy, '', url);\n    } else {\n      history.pushState({ key: setStateKey(genStateKey()) }, '', url);\n    }\n  } catch (e) {\n    window.location[replace ? 'replace' : 'assign'](url);\n  }\n}\n\nfunction replaceState (url) {\n  pushState(url, true);\n}\n\n// When changing thing, also edit router.d.ts\nvar NavigationFailureType = {\n  redirected: 2,\n  aborted: 4,\n  cancelled: 8,\n  duplicated: 16\n};\n\nfunction createNavigationRedirectedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.redirected,\n    (\"Redirected when going from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (stringifyRoute(\n      to\n    )) + \"\\\" via a navigation guard.\")\n  )\n}\n\nfunction createNavigationDuplicatedError (from, to) {\n  var error = createRouterError(\n    from,\n    to,\n    NavigationFailureType.duplicated,\n    (\"Avoided redundant navigation to current location: \\\"\" + (from.fullPath) + \"\\\".\")\n  );\n  // backwards compatible with the first introduction of Errors\n  error.name = 'NavigationDuplicated';\n  return error\n}\n\nfunction createNavigationCancelledError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.cancelled,\n    (\"Navigation cancelled from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" with a new navigation.\")\n  )\n}\n\nfunction createNavigationAbortedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.aborted,\n    (\"Navigation aborted from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" via a navigation guard.\")\n  )\n}\n\nfunction createRouterError (from, to, type, message) {\n  var error = new Error(message);\n  error._isRouter = true;\n  error.from = from;\n  error.to = to;\n  error.type = type;\n\n  return error\n}\n\nvar propertiesToLog = ['params', 'query', 'hash'];\n\nfunction stringifyRoute (to) {\n  if (typeof to === 'string') { return to }\n  if ('path' in to) { return to.path }\n  var location = {};\n  propertiesToLog.forEach(function (key) {\n    if (key in to) { location[key] = to[key]; }\n  });\n  return JSON.stringify(location, null, 2)\n}\n\nfunction isError (err) {\n  return Object.prototype.toString.call(err).indexOf('Error') > -1\n}\n\nfunction isNavigationFailure (err, errorType) {\n  return (\n    isError(err) &&\n    err._isRouter &&\n    (errorType == null || err.type === errorType)\n  )\n}\n\n/*  */\n\nfunction runQueue (queue, fn, cb) {\n  var step = function (index) {\n    if (index >= queue.length) {\n      cb();\n    } else {\n      if (queue[index]) {\n        fn(queue[index], function () {\n          step(index + 1);\n        });\n      } else {\n        step(index + 1);\n      }\n    }\n  };\n  step(0);\n}\n\n/*  */\n\nfunction resolveAsyncComponents (matched) {\n  return function (to, from, next) {\n    var hasAsync = false;\n    var pending = 0;\n    var error = null;\n\n    flatMapComponents(matched, function (def, _, match, key) {\n      // if it's a function and doesn't have cid attached,\n      // assume it's an async component resolve function.\n      // we are not using Vue's default async resolving mechanism because\n      // we want to halt the navigation until the incoming component has been\n      // resolved.\n      if (typeof def === 'function' && def.cid === undefined) {\n        hasAsync = true;\n        pending++;\n\n        var resolve = once(function (resolvedDef) {\n          if (isESModule(resolvedDef)) {\n            resolvedDef = resolvedDef.default;\n          }\n          // save resolved on async factory in case it's used elsewhere\n          def.resolved = typeof resolvedDef === 'function'\n            ? resolvedDef\n            : _Vue.extend(resolvedDef);\n          match.components[key] = resolvedDef;\n          pending--;\n          if (pending <= 0) {\n            next();\n          }\n        });\n\n        var reject = once(function (reason) {\n          var msg = \"Failed to resolve async component \" + key + \": \" + reason;\n          process.env.NODE_ENV !== 'production' && warn(false, msg);\n          if (!error) {\n            error = isError(reason)\n              ? reason\n              : new Error(msg);\n            next(error);\n          }\n        });\n\n        var res;\n        try {\n          res = def(resolve, reject);\n        } catch (e) {\n          reject(e);\n        }\n        if (res) {\n          if (typeof res.then === 'function') {\n            res.then(resolve, reject);\n          } else {\n            // new syntax in Vue 2.3\n            var comp = res.component;\n            if (comp && typeof comp.then === 'function') {\n              comp.then(resolve, reject);\n            }\n          }\n        }\n      }\n    });\n\n    if (!hasAsync) { next(); }\n  }\n}\n\nfunction flatMapComponents (\n  matched,\n  fn\n) {\n  return flatten(matched.map(function (m) {\n    return Object.keys(m.components).map(function (key) { return fn(\n      m.components[key],\n      m.instances[key],\n      m, key\n    ); })\n  }))\n}\n\nfunction flatten (arr) {\n  return Array.prototype.concat.apply([], arr)\n}\n\nvar hasSymbol =\n  typeof Symbol === 'function' &&\n  typeof Symbol.toStringTag === 'symbol';\n\nfunction isESModule (obj) {\n  return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')\n}\n\n// in Webpack 2, require.ensure now also returns a Promise\n// so the resolve/reject functions may get called an extra time\n// if the user uses an arrow function shorthand that happens to\n// return that Promise.\nfunction once (fn) {\n  var called = false;\n  return function () {\n    var args = [], len = arguments.length;\n    while ( len-- ) args[ len ] = arguments[ len ];\n\n    if (called) { return }\n    called = true;\n    return fn.apply(this, args)\n  }\n}\n\n/*  */\n\nvar History = function History (router, base) {\n  this.router = router;\n  this.base = normalizeBase(base);\n  // start with a route object that stands for \"nowhere\"\n  this.current = START;\n  this.pending = null;\n  this.ready = false;\n  this.readyCbs = [];\n  this.readyErrorCbs = [];\n  this.errorCbs = [];\n  this.listeners = [];\n};\n\nHistory.prototype.listen = function listen (cb) {\n  this.cb = cb;\n};\n\nHistory.prototype.onReady = function onReady (cb, errorCb) {\n  if (this.ready) {\n    cb();\n  } else {\n    this.readyCbs.push(cb);\n    if (errorCb) {\n      this.readyErrorCbs.push(errorCb);\n    }\n  }\n};\n\nHistory.prototype.onError = function onError (errorCb) {\n  this.errorCbs.push(errorCb);\n};\n\nHistory.prototype.transitionTo = function transitionTo (\n  location,\n  onComplete,\n  onAbort\n) {\n    var this$1$1 = this;\n\n  var route;\n  // catch redirect option https://github.com/vuejs/vue-router/issues/3201\n  try {\n    route = this.router.match(location, this.current);\n  } catch (e) {\n    this.errorCbs.forEach(function (cb) {\n      cb(e);\n    });\n    // Exception should still be thrown\n    throw e\n  }\n  var prev = this.current;\n  this.confirmTransition(\n    route,\n    function () {\n      this$1$1.updateRoute(route);\n      onComplete && onComplete(route);\n      this$1$1.ensureURL();\n      this$1$1.router.afterHooks.forEach(function (hook) {\n        hook && hook(route, prev);\n      });\n\n      // fire ready cbs once\n      if (!this$1$1.ready) {\n        this$1$1.ready = true;\n        this$1$1.readyCbs.forEach(function (cb) {\n          cb(route);\n        });\n      }\n    },\n    function (err) {\n      if (onAbort) {\n        onAbort(err);\n      }\n      if (err && !this$1$1.ready) {\n        // Initial redirection should not mark the history as ready yet\n        // because it's triggered by the redirection instead\n        // https://github.com/vuejs/vue-router/issues/3225\n        // https://github.com/vuejs/vue-router/issues/3331\n        if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {\n          this$1$1.ready = true;\n          this$1$1.readyErrorCbs.forEach(function (cb) {\n            cb(err);\n          });\n        }\n      }\n    }\n  );\n};\n\nHistory.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  var current = this.current;\n  this.pending = route;\n  var abort = function (err) {\n    // changed after adding errors with\n    // https://github.com/vuejs/vue-router/pull/3047 before that change,\n    // redirect and aborted navigation would produce an err == null\n    if (!isNavigationFailure(err) && isError(err)) {\n      if (this$1$1.errorCbs.length) {\n        this$1$1.errorCbs.forEach(function (cb) {\n          cb(err);\n        });\n      } else {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(false, 'uncaught error during route navigation:');\n        }\n        console.error(err);\n      }\n    }\n    onAbort && onAbort(err);\n  };\n  var lastRouteIndex = route.matched.length - 1;\n  var lastCurrentIndex = current.matched.length - 1;\n  if (\n    isSameRoute(route, current) &&\n    // in the case the route map has been dynamically appended to\n    lastRouteIndex === lastCurrentIndex &&\n    route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]\n  ) {\n    this.ensureURL();\n    if (route.hash) {\n      handleScroll(this.router, current, route, false);\n    }\n    return abort(createNavigationDuplicatedError(current, route))\n  }\n\n  var ref = resolveQueue(\n    this.current.matched,\n    route.matched\n  );\n    var updated = ref.updated;\n    var deactivated = ref.deactivated;\n    var activated = ref.activated;\n\n  var queue = [].concat(\n    // in-component leave guards\n    extractLeaveGuards(deactivated),\n    // global before hooks\n    this.router.beforeHooks,\n    // in-component update hooks\n    extractUpdateHooks(updated),\n    // in-config enter guards\n    activated.map(function (m) { return m.beforeEnter; }),\n    // async components\n    resolveAsyncComponents(activated)\n  );\n\n  var iterator = function (hook, next) {\n    if (this$1$1.pending !== route) {\n      return abort(createNavigationCancelledError(current, route))\n    }\n    try {\n      hook(route, current, function (to) {\n        if (to === false) {\n          // next(false) -> abort navigation, ensure current URL\n          this$1$1.ensureURL(true);\n          abort(createNavigationAbortedError(current, route));\n        } else if (isError(to)) {\n          this$1$1.ensureURL(true);\n          abort(to);\n        } else if (\n          typeof to === 'string' ||\n          (typeof to === 'object' &&\n            (typeof to.path === 'string' || typeof to.name === 'string'))\n        ) {\n          // next('/') or next({ path: '/' }) -> redirect\n          abort(createNavigationRedirectedError(current, route));\n          if (typeof to === 'object' && to.replace) {\n            this$1$1.replace(to);\n          } else {\n            this$1$1.push(to);\n          }\n        } else {\n          // confirm transition and pass on the value\n          next(to);\n        }\n      });\n    } catch (e) {\n      abort(e);\n    }\n  };\n\n  runQueue(queue, iterator, function () {\n    // wait until async components are resolved before\n    // extracting in-component enter guards\n    var enterGuards = extractEnterGuards(activated);\n    var queue = enterGuards.concat(this$1$1.router.resolveHooks);\n    runQueue(queue, iterator, function () {\n      if (this$1$1.pending !== route) {\n        return abort(createNavigationCancelledError(current, route))\n      }\n      this$1$1.pending = null;\n      onComplete(route);\n      if (this$1$1.router.app) {\n        this$1$1.router.app.$nextTick(function () {\n          handleRouteEntered(route);\n        });\n      }\n    });\n  });\n};\n\nHistory.prototype.updateRoute = function updateRoute (route) {\n  this.current = route;\n  this.cb && this.cb(route);\n};\n\nHistory.prototype.setupListeners = function setupListeners () {\n  // Default implementation is empty\n};\n\nHistory.prototype.teardown = function teardown () {\n  // clean up event listeners\n  // https://github.com/vuejs/vue-router/issues/2341\n  this.listeners.forEach(function (cleanupListener) {\n    cleanupListener();\n  });\n  this.listeners = [];\n\n  // reset current history route\n  // https://github.com/vuejs/vue-router/issues/3294\n  this.current = START;\n  this.pending = null;\n};\n\nfunction normalizeBase (base) {\n  if (!base) {\n    if (inBrowser) {\n      // respect <base> tag\n      var baseEl = document.querySelector('base');\n      base = (baseEl && baseEl.getAttribute('href')) || '/';\n      // strip full URL origin\n      base = base.replace(/^https?:\\/\\/[^\\/]+/, '');\n    } else {\n      base = '/';\n    }\n  }\n  // make sure there's the starting slash\n  if (base.charAt(0) !== '/') {\n    base = '/' + base;\n  }\n  // remove trailing slash\n  return base.replace(/\\/$/, '')\n}\n\nfunction resolveQueue (\n  current,\n  next\n) {\n  var i;\n  var max = Math.max(current.length, next.length);\n  for (i = 0; i < max; i++) {\n    if (current[i] !== next[i]) {\n      break\n    }\n  }\n  return {\n    updated: next.slice(0, i),\n    activated: next.slice(i),\n    deactivated: current.slice(i)\n  }\n}\n\nfunction extractGuards (\n  records,\n  name,\n  bind,\n  reverse\n) {\n  var guards = flatMapComponents(records, function (def, instance, match, key) {\n    var guard = extractGuard(def, name);\n    if (guard) {\n      return Array.isArray(guard)\n        ? guard.map(function (guard) { return bind(guard, instance, match, key); })\n        : bind(guard, instance, match, key)\n    }\n  });\n  return flatten(reverse ? guards.reverse() : guards)\n}\n\nfunction extractGuard (\n  def,\n  key\n) {\n  if (typeof def !== 'function') {\n    // extend now so that global mixins are applied.\n    def = _Vue.extend(def);\n  }\n  return def.options[key]\n}\n\nfunction extractLeaveGuards (deactivated) {\n  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)\n}\n\nfunction extractUpdateHooks (updated) {\n  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)\n}\n\nfunction bindGuard (guard, instance) {\n  if (instance) {\n    return function boundRouteGuard () {\n      return guard.apply(instance, arguments)\n    }\n  }\n}\n\nfunction extractEnterGuards (\n  activated\n) {\n  return extractGuards(\n    activated,\n    'beforeRouteEnter',\n    function (guard, _, match, key) {\n      return bindEnterGuard(guard, match, key)\n    }\n  )\n}\n\nfunction bindEnterGuard (\n  guard,\n  match,\n  key\n) {\n  return function routeEnterGuard (to, from, next) {\n    return guard(to, from, function (cb) {\n      if (typeof cb === 'function') {\n        if (!match.enteredCbs[key]) {\n          match.enteredCbs[key] = [];\n        }\n        match.enteredCbs[key].push(cb);\n      }\n      next(cb);\n    })\n  }\n}\n\n/*  */\n\nvar HTML5History = /*@__PURE__*/(function (History) {\n  function HTML5History (router, base) {\n    History.call(this, router, base);\n\n    this._startLocation = getLocation(this.base);\n  }\n\n  if ( History ) HTML5History.__proto__ = History;\n  HTML5History.prototype = Object.create( History && History.prototype );\n  HTML5History.prototype.constructor = HTML5History;\n\n  HTML5History.prototype.setupListeners = function setupListeners () {\n    var this$1$1 = this;\n\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    var router = this.router;\n    var expectScroll = router.options.scrollBehavior;\n    var supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    var handleRoutingEvent = function () {\n      var current = this$1$1.current;\n\n      // Avoiding first `popstate` event dispatched in some browsers but first\n      // history route not updated since async guard at the same time.\n      var location = getLocation(this$1$1.base);\n      if (this$1$1.current === START && location === this$1$1._startLocation) {\n        return\n      }\n\n      this$1$1.transitionTo(location, function (route) {\n        if (supportsScroll) {\n          handleScroll(router, route, current, true);\n        }\n      });\n    };\n    window.addEventListener('popstate', handleRoutingEvent);\n    this.listeners.push(function () {\n      window.removeEventListener('popstate', handleRoutingEvent);\n    });\n  };\n\n  HTML5History.prototype.go = function go (n) {\n    window.history.go(n);\n  };\n\n  HTML5History.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(location, function (route) {\n      pushState(cleanPath(this$1$1.base + route.fullPath));\n      handleScroll(this$1$1.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  };\n\n  HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(location, function (route) {\n      replaceState(cleanPath(this$1$1.base + route.fullPath));\n      handleScroll(this$1$1.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  };\n\n  HTML5History.prototype.ensureURL = function ensureURL (push) {\n    if (getLocation(this.base) !== this.current.fullPath) {\n      var current = cleanPath(this.base + this.current.fullPath);\n      push ? pushState(current) : replaceState(current);\n    }\n  };\n\n  HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {\n    return getLocation(this.base)\n  };\n\n  return HTML5History;\n}(History));\n\nfunction getLocation (base) {\n  var path = window.location.pathname;\n  var pathLowerCase = path.toLowerCase();\n  var baseLowerCase = base.toLowerCase();\n  // base=\"/a\" shouldn't turn path=\"/app\" into \"/a/pp\"\n  // https://github.com/vuejs/vue-router/issues/3555\n  // so we ensure the trailing slash in the base\n  if (base && ((pathLowerCase === baseLowerCase) ||\n    (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {\n    path = path.slice(base.length);\n  }\n  return (path || '/') + window.location.search + window.location.hash\n}\n\n/*  */\n\nvar HashHistory = /*@__PURE__*/(function (History) {\n  function HashHistory (router, base, fallback) {\n    History.call(this, router, base);\n    // check history fallback deeplinking\n    if (fallback && checkFallback(this.base)) {\n      return\n    }\n    ensureSlash();\n  }\n\n  if ( History ) HashHistory.__proto__ = History;\n  HashHistory.prototype = Object.create( History && History.prototype );\n  HashHistory.prototype.constructor = HashHistory;\n\n  // this is delayed until the app mounts\n  // to avoid the hashchange listener being fired too early\n  HashHistory.prototype.setupListeners = function setupListeners () {\n    var this$1$1 = this;\n\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    var router = this.router;\n    var expectScroll = router.options.scrollBehavior;\n    var supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    var handleRoutingEvent = function () {\n      var current = this$1$1.current;\n      if (!ensureSlash()) {\n        return\n      }\n      this$1$1.transitionTo(getHash(), function (route) {\n        if (supportsScroll) {\n          handleScroll(this$1$1.router, route, current, true);\n        }\n        if (!supportsPushState) {\n          replaceHash(route.fullPath);\n        }\n      });\n    };\n    var eventType = supportsPushState ? 'popstate' : 'hashchange';\n    window.addEventListener(\n      eventType,\n      handleRoutingEvent\n    );\n    this.listeners.push(function () {\n      window.removeEventListener(eventType, handleRoutingEvent);\n    });\n  };\n\n  HashHistory.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(\n      location,\n      function (route) {\n        pushHash(route.fullPath);\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(\n      location,\n      function (route) {\n        replaceHash(route.fullPath);\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  HashHistory.prototype.go = function go (n) {\n    window.history.go(n);\n  };\n\n  HashHistory.prototype.ensureURL = function ensureURL (push) {\n    var current = this.current.fullPath;\n    if (getHash() !== current) {\n      push ? pushHash(current) : replaceHash(current);\n    }\n  };\n\n  HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n    return getHash()\n  };\n\n  return HashHistory;\n}(History));\n\nfunction checkFallback (base) {\n  var location = getLocation(base);\n  if (!/^\\/#/.test(location)) {\n    window.location.replace(cleanPath(base + '/#' + location));\n    return true\n  }\n}\n\nfunction ensureSlash () {\n  var path = getHash();\n  if (path.charAt(0) === '/') {\n    return true\n  }\n  replaceHash('/' + path);\n  return false\n}\n\nfunction getHash () {\n  // We can't use window.location.hash here because it's not\n  // consistent across browsers - Firefox will pre-decode it!\n  var href = window.location.href;\n  var index = href.indexOf('#');\n  // empty path\n  if (index < 0) { return '' }\n\n  href = href.slice(index + 1);\n\n  return href\n}\n\nfunction getUrl (path) {\n  var href = window.location.href;\n  var i = href.indexOf('#');\n  var base = i >= 0 ? href.slice(0, i) : href;\n  return (base + \"#\" + path)\n}\n\nfunction pushHash (path) {\n  if (supportsPushState) {\n    pushState(getUrl(path));\n  } else {\n    window.location.hash = path;\n  }\n}\n\nfunction replaceHash (path) {\n  if (supportsPushState) {\n    replaceState(getUrl(path));\n  } else {\n    window.location.replace(getUrl(path));\n  }\n}\n\n/*  */\n\nvar AbstractHistory = /*@__PURE__*/(function (History) {\n  function AbstractHistory (router, base) {\n    History.call(this, router, base);\n    this.stack = [];\n    this.index = -1;\n  }\n\n  if ( History ) AbstractHistory.__proto__ = History;\n  AbstractHistory.prototype = Object.create( History && History.prototype );\n  AbstractHistory.prototype.constructor = AbstractHistory;\n\n  AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    this.transitionTo(\n      location,\n      function (route) {\n        this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index + 1).concat(route);\n        this$1$1.index++;\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    this.transitionTo(\n      location,\n      function (route) {\n        this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index).concat(route);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  AbstractHistory.prototype.go = function go (n) {\n    var this$1$1 = this;\n\n    var targetIndex = this.index + n;\n    if (targetIndex < 0 || targetIndex >= this.stack.length) {\n      return\n    }\n    var route = this.stack[targetIndex];\n    this.confirmTransition(\n      route,\n      function () {\n        var prev = this$1$1.current;\n        this$1$1.index = targetIndex;\n        this$1$1.updateRoute(route);\n        this$1$1.router.afterHooks.forEach(function (hook) {\n          hook && hook(route, prev);\n        });\n      },\n      function (err) {\n        if (isNavigationFailure(err, NavigationFailureType.duplicated)) {\n          this$1$1.index = targetIndex;\n        }\n      }\n    );\n  };\n\n  AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n    var current = this.stack[this.stack.length - 1];\n    return current ? current.fullPath : '/'\n  };\n\n  AbstractHistory.prototype.ensureURL = function ensureURL () {\n    // noop\n  };\n\n  return AbstractHistory;\n}(History));\n\n/*  */\n\n\n\nvar VueRouter = function VueRouter (options) {\n  if ( options === void 0 ) options = {};\n\n  if (process.env.NODE_ENV !== 'production') {\n    warn(this instanceof VueRouter, \"Router must be called with the new operator.\");\n  }\n  this.app = null;\n  this.apps = [];\n  this.options = options;\n  this.beforeHooks = [];\n  this.resolveHooks = [];\n  this.afterHooks = [];\n  this.matcher = createMatcher(options.routes || [], this);\n\n  var mode = options.mode || 'hash';\n  this.fallback =\n    mode === 'history' && !supportsPushState && options.fallback !== false;\n  if (this.fallback) {\n    mode = 'hash';\n  }\n  if (!inBrowser) {\n    mode = 'abstract';\n  }\n  this.mode = mode;\n\n  switch (mode) {\n    case 'history':\n      this.history = new HTML5History(this, options.base);\n      break\n    case 'hash':\n      this.history = new HashHistory(this, options.base, this.fallback);\n      break\n    case 'abstract':\n      this.history = new AbstractHistory(this, options.base);\n      break\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        assert(false, (\"invalid mode: \" + mode));\n      }\n  }\n};\n\nvar prototypeAccessors = { currentRoute: { configurable: true } };\n\nVueRouter.prototype.match = function match (raw, current, redirectedFrom) {\n  return this.matcher.match(raw, current, redirectedFrom)\n};\n\nprototypeAccessors.currentRoute.get = function () {\n  return this.history && this.history.current\n};\n\nVueRouter.prototype.init = function init (app /* Vue component instance */) {\n    var this$1$1 = this;\n\n  process.env.NODE_ENV !== 'production' &&\n    assert(\n      install.installed,\n      \"not installed. Make sure to call `Vue.use(VueRouter)` \" +\n        \"before creating root instance.\"\n    );\n\n  this.apps.push(app);\n\n  // set up app destroyed handler\n  // https://github.com/vuejs/vue-router/issues/2639\n  app.$once('hook:destroyed', function () {\n    // clean out app from this.apps array once destroyed\n    var index = this$1$1.apps.indexOf(app);\n    if (index > -1) { this$1$1.apps.splice(index, 1); }\n    // ensure we still have a main app or null if no apps\n    // we do not release the router so it can be reused\n    if (this$1$1.app === app) { this$1$1.app = this$1$1.apps[0] || null; }\n\n    if (!this$1$1.app) { this$1$1.history.teardown(); }\n  });\n\n  // main app previously initialized\n  // return as we don't need to set up new history listener\n  if (this.app) {\n    return\n  }\n\n  this.app = app;\n\n  var history = this.history;\n\n  if (history instanceof HTML5History || history instanceof HashHistory) {\n    var handleInitialScroll = function (routeOrError) {\n      var from = history.current;\n      var expectScroll = this$1$1.options.scrollBehavior;\n      var supportsScroll = supportsPushState && expectScroll;\n\n      if (supportsScroll && 'fullPath' in routeOrError) {\n        handleScroll(this$1$1, routeOrError, from, false);\n      }\n    };\n    var setupListeners = function (routeOrError) {\n      history.setupListeners();\n      handleInitialScroll(routeOrError);\n    };\n    history.transitionTo(\n      history.getCurrentLocation(),\n      setupListeners,\n      setupListeners\n    );\n  }\n\n  history.listen(function (route) {\n    this$1$1.apps.forEach(function (app) {\n      app._route = route;\n    });\n  });\n};\n\nVueRouter.prototype.beforeEach = function beforeEach (fn) {\n  return registerHook(this.beforeHooks, fn)\n};\n\nVueRouter.prototype.beforeResolve = function beforeResolve (fn) {\n  return registerHook(this.resolveHooks, fn)\n};\n\nVueRouter.prototype.afterEach = function afterEach (fn) {\n  return registerHook(this.afterHooks, fn)\n};\n\nVueRouter.prototype.onReady = function onReady (cb, errorCb) {\n  this.history.onReady(cb, errorCb);\n};\n\nVueRouter.prototype.onError = function onError (errorCb) {\n  this.history.onError(errorCb);\n};\n\nVueRouter.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  // $flow-disable-line\n  if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n    return new Promise(function (resolve, reject) {\n      this$1$1.history.push(location, resolve, reject);\n    })\n  } else {\n    this.history.push(location, onComplete, onAbort);\n  }\n};\n\nVueRouter.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  // $flow-disable-line\n  if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n    return new Promise(function (resolve, reject) {\n      this$1$1.history.replace(location, resolve, reject);\n    })\n  } else {\n    this.history.replace(location, onComplete, onAbort);\n  }\n};\n\nVueRouter.prototype.go = function go (n) {\n  this.history.go(n);\n};\n\nVueRouter.prototype.back = function back () {\n  this.go(-1);\n};\n\nVueRouter.prototype.forward = function forward () {\n  this.go(1);\n};\n\nVueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {\n  var route = to\n    ? to.matched\n      ? to\n      : this.resolve(to).route\n    : this.currentRoute;\n  if (!route) {\n    return []\n  }\n  return [].concat.apply(\n    [],\n    route.matched.map(function (m) {\n      return Object.keys(m.components).map(function (key) {\n        return m.components[key]\n      })\n    })\n  )\n};\n\nVueRouter.prototype.resolve = function resolve (\n  to,\n  current,\n  append\n) {\n  current = current || this.history.current;\n  var location = normalizeLocation(to, current, append, this);\n  var route = this.match(location, current);\n  var fullPath = route.redirectedFrom || route.fullPath;\n  var base = this.history.base;\n  var href = createHref(base, fullPath, this.mode);\n  return {\n    location: location,\n    route: route,\n    href: href,\n    // for backwards compat\n    normalizedTo: location,\n    resolved: route\n  }\n};\n\nVueRouter.prototype.getRoutes = function getRoutes () {\n  return this.matcher.getRoutes()\n};\n\nVueRouter.prototype.addRoute = function addRoute (parentOrRoute, route) {\n  this.matcher.addRoute(parentOrRoute, route);\n  if (this.history.current !== START) {\n    this.history.transitionTo(this.history.getCurrentLocation());\n  }\n};\n\nVueRouter.prototype.addRoutes = function addRoutes (routes) {\n  if (process.env.NODE_ENV !== 'production') {\n    warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.');\n  }\n  this.matcher.addRoutes(routes);\n  if (this.history.current !== START) {\n    this.history.transitionTo(this.history.getCurrentLocation());\n  }\n};\n\nObject.defineProperties( VueRouter.prototype, prototypeAccessors );\n\nvar VueRouter$1 = VueRouter;\n\nfunction registerHook (list, fn) {\n  list.push(fn);\n  return function () {\n    var i = list.indexOf(fn);\n    if (i > -1) { list.splice(i, 1); }\n  }\n}\n\nfunction createHref (base, fullPath, mode) {\n  var path = mode === 'hash' ? '#' + fullPath : fullPath;\n  return base ? cleanPath(base + '/' + path) : path\n}\n\n// We cannot remove this as it would be a breaking change\nVueRouter.install = install;\nVueRouter.version = '3.6.5';\nVueRouter.isNavigationFailure = isNavigationFailure;\nVueRouter.NavigationFailureType = NavigationFailureType;\nVueRouter.START_LOCATION = START;\n\nif (inBrowser && window.Vue) {\n  window.Vue.use(VueRouter);\n}\n\nvar version = '3.6.5';\n\nexport { NavigationFailureType, Link as RouterLink, View as RouterView, START as START_LOCATION, VueRouter$1 as default, isNavigationFailure, version };\n"
  },
  {
    "path": "dist/vue-router.js",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n  typeof define === 'function' && define.amd ? define(factory) :\n  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.VueRouter = factory());\n})(this, (function () { 'use strict';\n\n  /*  */\n\n  function assert (condition, message) {\n    if (!condition) {\n      throw new Error((\"[vue-router] \" + message))\n    }\n  }\n\n  function warn (condition, message) {\n    if (!condition) {\n      typeof console !== 'undefined' && console.warn((\"[vue-router] \" + message));\n    }\n  }\n\n  function extend (a, b) {\n    for (var key in b) {\n      a[key] = b[key];\n    }\n    return a\n  }\n\n  /*  */\n\n  var encodeReserveRE = /[!'()*]/g;\n  var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };\n  var commaRE = /%2C/g;\n\n  // fixed encodeURIComponent which is more conformant to RFC3986:\n  // - escapes [!'()*]\n  // - preserve commas\n  var encode = function (str) { return encodeURIComponent(str)\n      .replace(encodeReserveRE, encodeReserveReplacer)\n      .replace(commaRE, ','); };\n\n  function decode (str) {\n    try {\n      return decodeURIComponent(str)\n    } catch (err) {\n      {\n        warn(false, (\"Error decoding \\\"\" + str + \"\\\". Leaving it intact.\"));\n      }\n    }\n    return str\n  }\n\n  function resolveQuery (\n    query,\n    extraQuery,\n    _parseQuery\n  ) {\n    if ( extraQuery === void 0 ) extraQuery = {};\n\n    var parse = _parseQuery || parseQuery;\n    var parsedQuery;\n    try {\n      parsedQuery = parse(query || '');\n    } catch (e) {\n      warn(false, e.message);\n      parsedQuery = {};\n    }\n    for (var key in extraQuery) {\n      var value = extraQuery[key];\n      parsedQuery[key] = Array.isArray(value)\n        ? value.map(castQueryParamValue)\n        : castQueryParamValue(value);\n    }\n    return parsedQuery\n  }\n\n  var castQueryParamValue = function (value) { return (value == null || typeof value === 'object' ? value : String(value)); };\n\n  function parseQuery (query) {\n    var res = {};\n\n    query = query.trim().replace(/^(\\?|#|&)/, '');\n\n    if (!query) {\n      return res\n    }\n\n    query.split('&').forEach(function (param) {\n      var parts = param.replace(/\\+/g, ' ').split('=');\n      var key = decode(parts.shift());\n      var val = parts.length > 0 ? decode(parts.join('=')) : null;\n\n      if (res[key] === undefined) {\n        res[key] = val;\n      } else if (Array.isArray(res[key])) {\n        res[key].push(val);\n      } else {\n        res[key] = [res[key], val];\n      }\n    });\n\n    return res\n  }\n\n  function stringifyQuery (obj) {\n    var res = obj\n      ? Object.keys(obj)\n        .map(function (key) {\n          var val = obj[key];\n\n          if (val === undefined) {\n            return ''\n          }\n\n          if (val === null) {\n            return encode(key)\n          }\n\n          if (Array.isArray(val)) {\n            var result = [];\n            val.forEach(function (val2) {\n              if (val2 === undefined) {\n                return\n              }\n              if (val2 === null) {\n                result.push(encode(key));\n              } else {\n                result.push(encode(key) + '=' + encode(val2));\n              }\n            });\n            return result.join('&')\n          }\n\n          return encode(key) + '=' + encode(val)\n        })\n        .filter(function (x) { return x.length > 0; })\n        .join('&')\n      : null;\n    return res ? (\"?\" + res) : ''\n  }\n\n  /*  */\n\n  var trailingSlashRE = /\\/?$/;\n\n  function createRoute (\n    record,\n    location,\n    redirectedFrom,\n    router\n  ) {\n    var stringifyQuery = router && router.options.stringifyQuery;\n\n    var query = location.query || {};\n    try {\n      query = clone(query);\n    } catch (e) {}\n\n    var route = {\n      name: location.name || (record && record.name),\n      meta: (record && record.meta) || {},\n      path: location.path || '/',\n      hash: location.hash || '',\n      query: query,\n      params: location.params || {},\n      fullPath: getFullPath(location, stringifyQuery),\n      matched: record ? formatMatch(record) : []\n    };\n    if (redirectedFrom) {\n      route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);\n    }\n    return Object.freeze(route)\n  }\n\n  function clone (value) {\n    if (Array.isArray(value)) {\n      return value.map(clone)\n    } else if (value && typeof value === 'object') {\n      var res = {};\n      for (var key in value) {\n        res[key] = clone(value[key]);\n      }\n      return res\n    } else {\n      return value\n    }\n  }\n\n  // the starting route that represents the initial state\n  var START = createRoute(null, {\n    path: '/'\n  });\n\n  function formatMatch (record) {\n    var res = [];\n    while (record) {\n      res.unshift(record);\n      record = record.parent;\n    }\n    return res\n  }\n\n  function getFullPath (\n    ref,\n    _stringifyQuery\n  ) {\n    var path = ref.path;\n    var query = ref.query; if ( query === void 0 ) query = {};\n    var hash = ref.hash; if ( hash === void 0 ) hash = '';\n\n    var stringify = _stringifyQuery || stringifyQuery;\n    return (path || '/') + stringify(query) + hash\n  }\n\n  function isSameRoute (a, b, onlyPath) {\n    if (b === START) {\n      return a === b\n    } else if (!b) {\n      return false\n    } else if (a.path && b.path) {\n      return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||\n        a.hash === b.hash &&\n        isObjectEqual(a.query, b.query))\n    } else if (a.name && b.name) {\n      return (\n        a.name === b.name &&\n        (onlyPath || (\n          a.hash === b.hash &&\n        isObjectEqual(a.query, b.query) &&\n        isObjectEqual(a.params, b.params))\n        )\n      )\n    } else {\n      return false\n    }\n  }\n\n  function isObjectEqual (a, b) {\n    if ( a === void 0 ) a = {};\n    if ( b === void 0 ) b = {};\n\n    // handle null value #1566\n    if (!a || !b) { return a === b }\n    var aKeys = Object.keys(a).sort();\n    var bKeys = Object.keys(b).sort();\n    if (aKeys.length !== bKeys.length) {\n      return false\n    }\n    return aKeys.every(function (key, i) {\n      var aVal = a[key];\n      var bKey = bKeys[i];\n      if (bKey !== key) { return false }\n      var bVal = b[key];\n      // query values can be null and undefined\n      if (aVal == null || bVal == null) { return aVal === bVal }\n      // check nested equality\n      if (typeof aVal === 'object' && typeof bVal === 'object') {\n        return isObjectEqual(aVal, bVal)\n      }\n      return String(aVal) === String(bVal)\n    })\n  }\n\n  function isIncludedRoute (current, target) {\n    return (\n      current.path.replace(trailingSlashRE, '/').indexOf(\n        target.path.replace(trailingSlashRE, '/')\n      ) === 0 &&\n      (!target.hash || current.hash === target.hash) &&\n      queryIncludes(current.query, target.query)\n    )\n  }\n\n  function queryIncludes (current, target) {\n    for (var key in target) {\n      if (!(key in current)) {\n        return false\n      }\n    }\n    return true\n  }\n\n  function handleRouteEntered (route) {\n    for (var i = 0; i < route.matched.length; i++) {\n      var record = route.matched[i];\n      for (var name in record.instances) {\n        var instance = record.instances[name];\n        var cbs = record.enteredCbs[name];\n        if (!instance || !cbs) { continue }\n        delete record.enteredCbs[name];\n        for (var i$1 = 0; i$1 < cbs.length; i$1++) {\n          if (!instance._isBeingDestroyed) { cbs[i$1](instance); }\n        }\n      }\n    }\n  }\n\n  var View = {\n    name: 'RouterView',\n    functional: true,\n    props: {\n      name: {\n        type: String,\n        default: 'default'\n      }\n    },\n    render: function render (_, ref) {\n      var props = ref.props;\n      var children = ref.children;\n      var parent = ref.parent;\n      var data = ref.data;\n\n      // used by devtools to display a router-view badge\n      data.routerView = true;\n\n      // directly use parent context's createElement() function\n      // so that components rendered by router-view can resolve named slots\n      var h = parent.$createElement;\n      var name = props.name;\n      var route = parent.$route;\n      var cache = parent._routerViewCache || (parent._routerViewCache = {});\n\n      // determine current view depth, also check to see if the tree\n      // has been toggled inactive but kept-alive.\n      var depth = 0;\n      var inactive = false;\n      while (parent && parent._routerRoot !== parent) {\n        var vnodeData = parent.$vnode ? parent.$vnode.data : {};\n        if (vnodeData.routerView) {\n          depth++;\n        }\n        if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {\n          inactive = true;\n        }\n        parent = parent.$parent;\n      }\n      data.routerViewDepth = depth;\n\n      // render previous view if the tree is inactive and kept-alive\n      if (inactive) {\n        var cachedData = cache[name];\n        var cachedComponent = cachedData && cachedData.component;\n        if (cachedComponent) {\n          // #2301\n          // pass props\n          if (cachedData.configProps) {\n            fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps);\n          }\n          return h(cachedComponent, data, children)\n        } else {\n          // render previous empty view\n          return h()\n        }\n      }\n\n      var matched = route.matched[depth];\n      var component = matched && matched.components[name];\n\n      // render empty node if no matched route or no config component\n      if (!matched || !component) {\n        cache[name] = null;\n        return h()\n      }\n\n      // cache component\n      cache[name] = { component: component };\n\n      // attach instance registration hook\n      // this will be called in the instance's injected lifecycle hooks\n      data.registerRouteInstance = function (vm, val) {\n        // val could be undefined for unregistration\n        var current = matched.instances[name];\n        if (\n          (val && current !== vm) ||\n          (!val && current === vm)\n        ) {\n          matched.instances[name] = val;\n        }\n      }\n\n      // also register instance in prepatch hook\n      // in case the same component instance is reused across different routes\n      ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {\n        matched.instances[name] = vnode.componentInstance;\n      };\n\n      // register instance in init hook\n      // in case kept-alive component be actived when routes changed\n      data.hook.init = function (vnode) {\n        if (vnode.data.keepAlive &&\n          vnode.componentInstance &&\n          vnode.componentInstance !== matched.instances[name]\n        ) {\n          matched.instances[name] = vnode.componentInstance;\n        }\n\n        // if the route transition has already been confirmed then we weren't\n        // able to call the cbs during confirmation as the component was not\n        // registered yet, so we call it here.\n        handleRouteEntered(route);\n      };\n\n      var configProps = matched.props && matched.props[name];\n      // save route and configProps in cache\n      if (configProps) {\n        extend(cache[name], {\n          route: route,\n          configProps: configProps\n        });\n        fillPropsinData(component, data, route, configProps);\n      }\n\n      return h(component, data, children)\n    }\n  };\n\n  function fillPropsinData (component, data, route, configProps) {\n    // resolve props\n    var propsToPass = data.props = resolveProps(route, configProps);\n    if (propsToPass) {\n      // clone to prevent mutation\n      propsToPass = data.props = extend({}, propsToPass);\n      // pass non-declared props as attrs\n      var attrs = data.attrs = data.attrs || {};\n      for (var key in propsToPass) {\n        if (!component.props || !(key in component.props)) {\n          attrs[key] = propsToPass[key];\n          delete propsToPass[key];\n        }\n      }\n    }\n  }\n\n  function resolveProps (route, config) {\n    switch (typeof config) {\n      case 'undefined':\n        return\n      case 'object':\n        return config\n      case 'function':\n        return config(route)\n      case 'boolean':\n        return config ? route.params : undefined\n      default:\n        {\n          warn(\n            false,\n            \"props in \\\"\" + (route.path) + \"\\\" is a \" + (typeof config) + \", \" +\n            \"expecting an object, function or boolean.\"\n          );\n        }\n    }\n  }\n\n  /*  */\n\n  function resolvePath (\n    relative,\n    base,\n    append\n  ) {\n    var firstChar = relative.charAt(0);\n    if (firstChar === '/') {\n      return relative\n    }\n\n    if (firstChar === '?' || firstChar === '#') {\n      return base + relative\n    }\n\n    var stack = base.split('/');\n\n    // remove trailing segment if:\n    // - not appending\n    // - appending to trailing slash (last segment is empty)\n    if (!append || !stack[stack.length - 1]) {\n      stack.pop();\n    }\n\n    // resolve relative path\n    var segments = relative.replace(/^\\//, '').split('/');\n    for (var i = 0; i < segments.length; i++) {\n      var segment = segments[i];\n      if (segment === '..') {\n        stack.pop();\n      } else if (segment !== '.') {\n        stack.push(segment);\n      }\n    }\n\n    // ensure leading slash\n    if (stack[0] !== '') {\n      stack.unshift('');\n    }\n\n    return stack.join('/')\n  }\n\n  function parsePath (path) {\n    var hash = '';\n    var query = '';\n\n    var hashIndex = path.indexOf('#');\n    if (hashIndex >= 0) {\n      hash = path.slice(hashIndex);\n      path = path.slice(0, hashIndex);\n    }\n\n    var queryIndex = path.indexOf('?');\n    if (queryIndex >= 0) {\n      query = path.slice(queryIndex + 1);\n      path = path.slice(0, queryIndex);\n    }\n\n    return {\n      path: path,\n      query: query,\n      hash: hash\n    }\n  }\n\n  function cleanPath (path) {\n    return path.replace(/\\/(?:\\s*\\/)+/g, '/')\n  }\n\n  var isarray = Array.isArray || function (arr) {\n    return Object.prototype.toString.call(arr) == '[object Array]';\n  };\n\n  /**\n   * Expose `pathToRegexp`.\n   */\n  var pathToRegexp_1 = pathToRegexp;\n  var parse_1 = parse;\n  var compile_1 = compile;\n  var tokensToFunction_1 = tokensToFunction;\n  var tokensToRegExp_1 = tokensToRegExp;\n\n  /**\n   * The main path matching regexp utility.\n   *\n   * @type {RegExp}\n   */\n  var PATH_REGEXP = new RegExp([\n    // Match escaped characters that would otherwise appear in future matches.\n    // This allows the user to escape special characters that won't transform.\n    '(\\\\\\\\.)',\n    // Match Express-style parameters and un-named parameters with a prefix\n    // and optional suffixes. Matches appear as:\n    //\n    // \"/:test(\\\\d+)?\" => [\"/\", \"test\", \"\\d+\", undefined, \"?\", undefined]\n    // \"/route(\\\\d+)\"  => [undefined, undefined, undefined, \"\\d+\", undefined, undefined]\n    // \"/*\"            => [\"/\", undefined, undefined, undefined, undefined, \"*\"]\n    '([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))'\n  ].join('|'), 'g');\n\n  /**\n   * Parse a string for the raw tokens.\n   *\n   * @param  {string}  str\n   * @param  {Object=} options\n   * @return {!Array}\n   */\n  function parse (str, options) {\n    var tokens = [];\n    var key = 0;\n    var index = 0;\n    var path = '';\n    var defaultDelimiter = options && options.delimiter || '/';\n    var res;\n\n    while ((res = PATH_REGEXP.exec(str)) != null) {\n      var m = res[0];\n      var escaped = res[1];\n      var offset = res.index;\n      path += str.slice(index, offset);\n      index = offset + m.length;\n\n      // Ignore already escaped sequences.\n      if (escaped) {\n        path += escaped[1];\n        continue\n      }\n\n      var next = str[index];\n      var prefix = res[2];\n      var name = res[3];\n      var capture = res[4];\n      var group = res[5];\n      var modifier = res[6];\n      var asterisk = res[7];\n\n      // Push the current path onto the tokens.\n      if (path) {\n        tokens.push(path);\n        path = '';\n      }\n\n      var partial = prefix != null && next != null && next !== prefix;\n      var repeat = modifier === '+' || modifier === '*';\n      var optional = modifier === '?' || modifier === '*';\n      var delimiter = res[2] || defaultDelimiter;\n      var pattern = capture || group;\n\n      tokens.push({\n        name: name || key++,\n        prefix: prefix || '',\n        delimiter: delimiter,\n        optional: optional,\n        repeat: repeat,\n        partial: partial,\n        asterisk: !!asterisk,\n        pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')\n      });\n    }\n\n    // Match any characters still remaining.\n    if (index < str.length) {\n      path += str.substr(index);\n    }\n\n    // If the path exists, push it onto the end.\n    if (path) {\n      tokens.push(path);\n    }\n\n    return tokens\n  }\n\n  /**\n   * Compile a string to a template function for the path.\n   *\n   * @param  {string}             str\n   * @param  {Object=}            options\n   * @return {!function(Object=, Object=)}\n   */\n  function compile (str, options) {\n    return tokensToFunction(parse(str, options), options)\n  }\n\n  /**\n   * Prettier encoding of URI path segments.\n   *\n   * @param  {string}\n   * @return {string}\n   */\n  function encodeURIComponentPretty (str) {\n    return encodeURI(str).replace(/[\\/?#]/g, function (c) {\n      return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n    })\n  }\n\n  /**\n   * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.\n   *\n   * @param  {string}\n   * @return {string}\n   */\n  function encodeAsterisk (str) {\n    return encodeURI(str).replace(/[?#]/g, function (c) {\n      return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n    })\n  }\n\n  /**\n   * Expose a method for transforming tokens into the path function.\n   */\n  function tokensToFunction (tokens, options) {\n    // Compile all the tokens into regexps.\n    var matches = new Array(tokens.length);\n\n    // Compile all the patterns before compilation.\n    for (var i = 0; i < tokens.length; i++) {\n      if (typeof tokens[i] === 'object') {\n        matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));\n      }\n    }\n\n    return function (obj, opts) {\n      var path = '';\n      var data = obj || {};\n      var options = opts || {};\n      var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;\n\n      for (var i = 0; i < tokens.length; i++) {\n        var token = tokens[i];\n\n        if (typeof token === 'string') {\n          path += token;\n\n          continue\n        }\n\n        var value = data[token.name];\n        var segment;\n\n        if (value == null) {\n          if (token.optional) {\n            // Prepend partial segment prefixes.\n            if (token.partial) {\n              path += token.prefix;\n            }\n\n            continue\n          } else {\n            throw new TypeError('Expected \"' + token.name + '\" to be defined')\n          }\n        }\n\n        if (isarray(value)) {\n          if (!token.repeat) {\n            throw new TypeError('Expected \"' + token.name + '\" to not repeat, but received `' + JSON.stringify(value) + '`')\n          }\n\n          if (value.length === 0) {\n            if (token.optional) {\n              continue\n            } else {\n              throw new TypeError('Expected \"' + token.name + '\" to not be empty')\n            }\n          }\n\n          for (var j = 0; j < value.length; j++) {\n            segment = encode(value[j]);\n\n            if (!matches[i].test(segment)) {\n              throw new TypeError('Expected all \"' + token.name + '\" to match \"' + token.pattern + '\", but received `' + JSON.stringify(segment) + '`')\n            }\n\n            path += (j === 0 ? token.prefix : token.delimiter) + segment;\n          }\n\n          continue\n        }\n\n        segment = token.asterisk ? encodeAsterisk(value) : encode(value);\n\n        if (!matches[i].test(segment)) {\n          throw new TypeError('Expected \"' + token.name + '\" to match \"' + token.pattern + '\", but received \"' + segment + '\"')\n        }\n\n        path += token.prefix + segment;\n      }\n\n      return path\n    }\n  }\n\n  /**\n   * Escape a regular expression string.\n   *\n   * @param  {string} str\n   * @return {string}\n   */\n  function escapeString (str) {\n    return str.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g, '\\\\$1')\n  }\n\n  /**\n   * Escape the capturing group by escaping special characters and meaning.\n   *\n   * @param  {string} group\n   * @return {string}\n   */\n  function escapeGroup (group) {\n    return group.replace(/([=!:$\\/()])/g, '\\\\$1')\n  }\n\n  /**\n   * Attach the keys as a property of the regexp.\n   *\n   * @param  {!RegExp} re\n   * @param  {Array}   keys\n   * @return {!RegExp}\n   */\n  function attachKeys (re, keys) {\n    re.keys = keys;\n    return re\n  }\n\n  /**\n   * Get the flags for a regexp from the options.\n   *\n   * @param  {Object} options\n   * @return {string}\n   */\n  function flags (options) {\n    return options && options.sensitive ? '' : 'i'\n  }\n\n  /**\n   * Pull out keys from a regexp.\n   *\n   * @param  {!RegExp} path\n   * @param  {!Array}  keys\n   * @return {!RegExp}\n   */\n  function regexpToRegexp (path, keys) {\n    // Use a negative lookahead to match only capturing groups.\n    var groups = path.source.match(/\\((?!\\?)/g);\n\n    if (groups) {\n      for (var i = 0; i < groups.length; i++) {\n        keys.push({\n          name: i,\n          prefix: null,\n          delimiter: null,\n          optional: false,\n          repeat: false,\n          partial: false,\n          asterisk: false,\n          pattern: null\n        });\n      }\n    }\n\n    return attachKeys(path, keys)\n  }\n\n  /**\n   * Transform an array into a regexp.\n   *\n   * @param  {!Array}  path\n   * @param  {Array}   keys\n   * @param  {!Object} options\n   * @return {!RegExp}\n   */\n  function arrayToRegexp (path, keys, options) {\n    var parts = [];\n\n    for (var i = 0; i < path.length; i++) {\n      parts.push(pathToRegexp(path[i], keys, options).source);\n    }\n\n    var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));\n\n    return attachKeys(regexp, keys)\n  }\n\n  /**\n   * Create a path regexp from string input.\n   *\n   * @param  {string}  path\n   * @param  {!Array}  keys\n   * @param  {!Object} options\n   * @return {!RegExp}\n   */\n  function stringToRegexp (path, keys, options) {\n    return tokensToRegExp(parse(path, options), keys, options)\n  }\n\n  /**\n   * Expose a function for taking tokens and returning a RegExp.\n   *\n   * @param  {!Array}          tokens\n   * @param  {(Array|Object)=} keys\n   * @param  {Object=}         options\n   * @return {!RegExp}\n   */\n  function tokensToRegExp (tokens, keys, options) {\n    if (!isarray(keys)) {\n      options = /** @type {!Object} */ (keys || options);\n      keys = [];\n    }\n\n    options = options || {};\n\n    var strict = options.strict;\n    var end = options.end !== false;\n    var route = '';\n\n    // Iterate over the tokens and create our regexp string.\n    for (var i = 0; i < tokens.length; i++) {\n      var token = tokens[i];\n\n      if (typeof token === 'string') {\n        route += escapeString(token);\n      } else {\n        var prefix = escapeString(token.prefix);\n        var capture = '(?:' + token.pattern + ')';\n\n        keys.push(token);\n\n        if (token.repeat) {\n          capture += '(?:' + prefix + capture + ')*';\n        }\n\n        if (token.optional) {\n          if (!token.partial) {\n            capture = '(?:' + prefix + '(' + capture + '))?';\n          } else {\n            capture = prefix + '(' + capture + ')?';\n          }\n        } else {\n          capture = prefix + '(' + capture + ')';\n        }\n\n        route += capture;\n      }\n    }\n\n    var delimiter = escapeString(options.delimiter || '/');\n    var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;\n\n    // In non-strict mode we allow a slash at the end of match. If the path to\n    // match already ends with a slash, we remove it for consistency. The slash\n    // is valid at the end of a path match, not in the middle. This is important\n    // in non-ending mode, where \"/test/\" shouldn't match \"/test//route\".\n    if (!strict) {\n      route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';\n    }\n\n    if (end) {\n      route += '$';\n    } else {\n      // In non-ending mode, we need the capturing groups to match as much as\n      // possible by using a positive lookahead to the end or next path segment.\n      route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';\n    }\n\n    return attachKeys(new RegExp('^' + route, flags(options)), keys)\n  }\n\n  /**\n   * Normalize the given path string, returning a regular expression.\n   *\n   * An empty array can be passed in for the keys, which will hold the\n   * placeholder key descriptions. For example, using `/user/:id`, `keys` will\n   * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.\n   *\n   * @param  {(string|RegExp|Array)} path\n   * @param  {(Array|Object)=}       keys\n   * @param  {Object=}               options\n   * @return {!RegExp}\n   */\n  function pathToRegexp (path, keys, options) {\n    if (!isarray(keys)) {\n      options = /** @type {!Object} */ (keys || options);\n      keys = [];\n    }\n\n    options = options || {};\n\n    if (path instanceof RegExp) {\n      return regexpToRegexp(path, /** @type {!Array} */ (keys))\n    }\n\n    if (isarray(path)) {\n      return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)\n    }\n\n    return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)\n  }\n  pathToRegexp_1.parse = parse_1;\n  pathToRegexp_1.compile = compile_1;\n  pathToRegexp_1.tokensToFunction = tokensToFunction_1;\n  pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;\n\n  /*  */\n\n  // $flow-disable-line\n  var regexpCompileCache = Object.create(null);\n\n  function fillParams (\n    path,\n    params,\n    routeMsg\n  ) {\n    params = params || {};\n    try {\n      var filler =\n        regexpCompileCache[path] ||\n        (regexpCompileCache[path] = pathToRegexp_1.compile(path));\n\n      // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}\n      // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string\n      if (typeof params.pathMatch === 'string') { params[0] = params.pathMatch; }\n\n      return filler(params, { pretty: true })\n    } catch (e) {\n      {\n        // Fix #3072 no warn if `pathMatch` is string\n        warn(typeof params.pathMatch === 'string', (\"missing param for \" + routeMsg + \": \" + (e.message)));\n      }\n      return ''\n    } finally {\n      // delete the 0 if it was added\n      delete params[0];\n    }\n  }\n\n  /*  */\n\n  function normalizeLocation (\n    raw,\n    current,\n    append,\n    router\n  ) {\n    var next = typeof raw === 'string' ? { path: raw } : raw;\n    // named target\n    if (next._normalized) {\n      return next\n    } else if (next.name) {\n      next = extend({}, raw);\n      var params = next.params;\n      if (params && typeof params === 'object') {\n        next.params = extend({}, params);\n      }\n      return next\n    }\n\n    // relative params\n    if (!next.path && next.params && current) {\n      next = extend({}, next);\n      next._normalized = true;\n      var params$1 = extend(extend({}, current.params), next.params);\n      if (current.name) {\n        next.name = current.name;\n        next.params = params$1;\n      } else if (current.matched.length) {\n        var rawPath = current.matched[current.matched.length - 1].path;\n        next.path = fillParams(rawPath, params$1, (\"path \" + (current.path)));\n      } else {\n        warn(false, \"relative params navigation requires a current route.\");\n      }\n      return next\n    }\n\n    var parsedPath = parsePath(next.path || '');\n    var basePath = (current && current.path) || '/';\n    var path = parsedPath.path\n      ? resolvePath(parsedPath.path, basePath, append || next.append)\n      : basePath;\n\n    var query = resolveQuery(\n      parsedPath.query,\n      next.query,\n      router && router.options.parseQuery\n    );\n\n    var hash = next.hash || parsedPath.hash;\n    if (hash && hash.charAt(0) !== '#') {\n      hash = \"#\" + hash;\n    }\n\n    return {\n      _normalized: true,\n      path: path,\n      query: query,\n      hash: hash\n    }\n  }\n\n  /*  */\n\n  // work around weird flow bug\n  var toTypes = [String, Object];\n  var eventTypes = [String, Array];\n\n  var noop = function () {};\n\n  var warnedCustomSlot;\n  var warnedTagProp;\n  var warnedEventProp;\n\n  var Link = {\n    name: 'RouterLink',\n    props: {\n      to: {\n        type: toTypes,\n        required: true\n      },\n      tag: {\n        type: String,\n        default: 'a'\n      },\n      custom: Boolean,\n      exact: Boolean,\n      exactPath: Boolean,\n      append: Boolean,\n      replace: Boolean,\n      activeClass: String,\n      exactActiveClass: String,\n      ariaCurrentValue: {\n        type: String,\n        default: 'page'\n      },\n      event: {\n        type: eventTypes,\n        default: 'click'\n      }\n    },\n    render: function render (h) {\n      var this$1$1 = this;\n\n      var router = this.$router;\n      var current = this.$route;\n      var ref = router.resolve(\n        this.to,\n        current,\n        this.append\n      );\n      var location = ref.location;\n      var route = ref.route;\n      var href = ref.href;\n\n      var classes = {};\n      var globalActiveClass = router.options.linkActiveClass;\n      var globalExactActiveClass = router.options.linkExactActiveClass;\n      // Support global empty active class\n      var activeClassFallback =\n        globalActiveClass == null ? 'router-link-active' : globalActiveClass;\n      var exactActiveClassFallback =\n        globalExactActiveClass == null\n          ? 'router-link-exact-active'\n          : globalExactActiveClass;\n      var activeClass =\n        this.activeClass == null ? activeClassFallback : this.activeClass;\n      var exactActiveClass =\n        this.exactActiveClass == null\n          ? exactActiveClassFallback\n          : this.exactActiveClass;\n\n      var compareTarget = route.redirectedFrom\n        ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)\n        : route;\n\n      classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath);\n      classes[activeClass] = this.exact || this.exactPath\n        ? classes[exactActiveClass]\n        : isIncludedRoute(current, compareTarget);\n\n      var ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null;\n\n      var handler = function (e) {\n        if (guardEvent(e)) {\n          if (this$1$1.replace) {\n            router.replace(location, noop);\n          } else {\n            router.push(location, noop);\n          }\n        }\n      };\n\n      var on = { click: guardEvent };\n      if (Array.isArray(this.event)) {\n        this.event.forEach(function (e) {\n          on[e] = handler;\n        });\n      } else {\n        on[this.event] = handler;\n      }\n\n      var data = { class: classes };\n\n      var scopedSlot =\n        !this.$scopedSlots.$hasNormal &&\n        this.$scopedSlots.default &&\n        this.$scopedSlots.default({\n          href: href,\n          route: route,\n          navigate: handler,\n          isActive: classes[activeClass],\n          isExactActive: classes[exactActiveClass]\n        });\n\n      if (scopedSlot) {\n        if (!this.custom) {\n          !warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\\n<router-link v-slot=\"{ navigate, href }\" custom></router-link>\\n');\n          warnedCustomSlot = true;\n        }\n        if (scopedSlot.length === 1) {\n          return scopedSlot[0]\n        } else if (scopedSlot.length > 1 || !scopedSlot.length) {\n          {\n            warn(\n              false,\n              (\"<router-link> with to=\\\"\" + (this.to) + \"\\\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.\")\n            );\n          }\n          return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)\n        }\n      }\n\n      {\n        if ('tag' in this.$options.propsData && !warnedTagProp) {\n          warn(\n            false,\n            \"<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n          );\n          warnedTagProp = true;\n        }\n        if ('event' in this.$options.propsData && !warnedEventProp) {\n          warn(\n            false,\n            \"<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n          );\n          warnedEventProp = true;\n        }\n      }\n\n      if (this.tag === 'a') {\n        data.on = on;\n        data.attrs = { href: href, 'aria-current': ariaCurrentValue };\n      } else {\n        // find the first <a> child and apply listener and href\n        var a = findAnchor(this.$slots.default);\n        if (a) {\n          // in case the <a> is a static node\n          a.isStatic = false;\n          var aData = (a.data = extend({}, a.data));\n          aData.on = aData.on || {};\n          // transform existing events in both objects into arrays so we can push later\n          for (var event in aData.on) {\n            var handler$1 = aData.on[event];\n            if (event in on) {\n              aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];\n            }\n          }\n          // append new listeners for router-link\n          for (var event$1 in on) {\n            if (event$1 in aData.on) {\n              // on[event] is always a function\n              aData.on[event$1].push(on[event$1]);\n            } else {\n              aData.on[event$1] = handler;\n            }\n          }\n\n          var aAttrs = (a.data.attrs = extend({}, a.data.attrs));\n          aAttrs.href = href;\n          aAttrs['aria-current'] = ariaCurrentValue;\n        } else {\n          // doesn't have <a> child, apply listener to self\n          data.on = on;\n        }\n      }\n\n      return h(this.tag, data, this.$slots.default)\n    }\n  };\n\n  function guardEvent (e) {\n    // don't redirect with control keys\n    if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }\n    // don't redirect when preventDefault called\n    if (e.defaultPrevented) { return }\n    // don't redirect on right click\n    if (e.button !== undefined && e.button !== 0) { return }\n    // don't redirect if `target=\"_blank\"`\n    if (e.currentTarget && e.currentTarget.getAttribute) {\n      var target = e.currentTarget.getAttribute('target');\n      if (/\\b_blank\\b/i.test(target)) { return }\n    }\n    // this may be a Weex event which doesn't have this method\n    if (e.preventDefault) {\n      e.preventDefault();\n    }\n    return true\n  }\n\n  function findAnchor (children) {\n    if (children) {\n      var child;\n      for (var i = 0; i < children.length; i++) {\n        child = children[i];\n        if (child.tag === 'a') {\n          return child\n        }\n        if (child.children && (child = findAnchor(child.children))) {\n          return child\n        }\n      }\n    }\n  }\n\n  var _Vue;\n\n  function install (Vue) {\n    if (install.installed && _Vue === Vue) { return }\n    install.installed = true;\n\n    _Vue = Vue;\n\n    var isDef = function (v) { return v !== undefined; };\n\n    var registerInstance = function (vm, callVal) {\n      var i = vm.$options._parentVnode;\n      if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {\n        i(vm, callVal);\n      }\n    };\n\n    Vue.mixin({\n      beforeCreate: function beforeCreate () {\n        if (isDef(this.$options.router)) {\n          this._routerRoot = this;\n          this._router = this.$options.router;\n          this._router.init(this);\n          Vue.util.defineReactive(this, '_route', this._router.history.current);\n        } else {\n          this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;\n        }\n        registerInstance(this, this);\n      },\n      destroyed: function destroyed () {\n        registerInstance(this);\n      }\n    });\n\n    Object.defineProperty(Vue.prototype, '$router', {\n      get: function get () { return this._routerRoot._router }\n    });\n\n    Object.defineProperty(Vue.prototype, '$route', {\n      get: function get () { return this._routerRoot._route }\n    });\n\n    Vue.component('RouterView', View);\n    Vue.component('RouterLink', Link);\n\n    var strats = Vue.config.optionMergeStrategies;\n    // use the same hook merging strategy for route hooks\n    strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;\n  }\n\n  /*  */\n\n  var inBrowser = typeof window !== 'undefined';\n\n  /*  */\n\n  function createRouteMap (\n    routes,\n    oldPathList,\n    oldPathMap,\n    oldNameMap,\n    parentRoute\n  ) {\n    // the path list is used to control path matching priority\n    var pathList = oldPathList || [];\n    // $flow-disable-line\n    var pathMap = oldPathMap || Object.create(null);\n    // $flow-disable-line\n    var nameMap = oldNameMap || Object.create(null);\n\n    routes.forEach(function (route) {\n      addRouteRecord(pathList, pathMap, nameMap, route, parentRoute);\n    });\n\n    // ensure wildcard routes are always at the end\n    for (var i = 0, l = pathList.length; i < l; i++) {\n      if (pathList[i] === '*') {\n        pathList.push(pathList.splice(i, 1)[0]);\n        l--;\n        i--;\n      }\n    }\n\n    {\n      // warn if routes do not include leading slashes\n      var found = pathList\n      // check for missing leading slash\n        .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });\n\n      if (found.length > 0) {\n        var pathNames = found.map(function (path) { return (\"- \" + path); }).join('\\n');\n        warn(false, (\"Non-nested routes must include a leading slash character. Fix the following routes: \\n\" + pathNames));\n      }\n    }\n\n    return {\n      pathList: pathList,\n      pathMap: pathMap,\n      nameMap: nameMap\n    }\n  }\n\n  function addRouteRecord (\n    pathList,\n    pathMap,\n    nameMap,\n    route,\n    parent,\n    matchAs\n  ) {\n    var path = route.path;\n    var name = route.name;\n    {\n      assert(path != null, \"\\\"path\\\" is required in a route configuration.\");\n      assert(\n        typeof route.component !== 'string',\n        \"route config \\\"component\\\" for path: \" + (String(\n          path || name\n        )) + \" cannot be a \" + \"string id. Use an actual component instead.\"\n      );\n\n      warn(\n        // eslint-disable-next-line no-control-regex\n        !/[^\\u0000-\\u007F]+/.test(path),\n        \"Route with path \\\"\" + path + \"\\\" contains unencoded characters, make sure \" +\n          \"your path is correctly encoded before passing it to the router. Use \" +\n          \"encodeURI to encode static segments of your path.\"\n      );\n    }\n\n    var pathToRegexpOptions =\n      route.pathToRegexpOptions || {};\n    var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);\n\n    if (typeof route.caseSensitive === 'boolean') {\n      pathToRegexpOptions.sensitive = route.caseSensitive;\n    }\n\n    var record = {\n      path: normalizedPath,\n      regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),\n      components: route.components || { default: route.component },\n      alias: route.alias\n        ? typeof route.alias === 'string'\n          ? [route.alias]\n          : route.alias\n        : [],\n      instances: {},\n      enteredCbs: {},\n      name: name,\n      parent: parent,\n      matchAs: matchAs,\n      redirect: route.redirect,\n      beforeEnter: route.beforeEnter,\n      meta: route.meta || {},\n      props:\n        route.props == null\n          ? {}\n          : route.components\n            ? route.props\n            : { default: route.props }\n    };\n\n    if (route.children) {\n      // Warn if route is named, does not redirect and has a default child route.\n      // If users navigate to this route by name, the default child will\n      // not be rendered (GH Issue #629)\n      {\n        if (\n          route.name &&\n          !route.redirect &&\n          route.children.some(function (child) { return /^\\/?$/.test(child.path); })\n        ) {\n          warn(\n            false,\n            \"Named Route '\" + (route.name) + \"' has a default child route. \" +\n              \"When navigating to this named route (:to=\\\"{name: '\" + (route.name) + \"'}\\\"), \" +\n              \"the default child route will not be rendered. Remove the name from \" +\n              \"this route and use the name of the default child route for named \" +\n              \"links instead.\"\n          );\n        }\n      }\n      route.children.forEach(function (child) {\n        var childMatchAs = matchAs\n          ? cleanPath((matchAs + \"/\" + (child.path)))\n          : undefined;\n        addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);\n      });\n    }\n\n    if (!pathMap[record.path]) {\n      pathList.push(record.path);\n      pathMap[record.path] = record;\n    }\n\n    if (route.alias !== undefined) {\n      var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];\n      for (var i = 0; i < aliases.length; ++i) {\n        var alias = aliases[i];\n        if (alias === path) {\n          warn(\n            false,\n            (\"Found an alias with the same value as the path: \\\"\" + path + \"\\\". You have to remove that alias. It will be ignored in development.\")\n          );\n          // skip in dev to make it work\n          continue\n        }\n\n        var aliasRoute = {\n          path: alias,\n          children: route.children\n        };\n        addRouteRecord(\n          pathList,\n          pathMap,\n          nameMap,\n          aliasRoute,\n          parent,\n          record.path || '/' // matchAs\n        );\n      }\n    }\n\n    if (name) {\n      if (!nameMap[name]) {\n        nameMap[name] = record;\n      } else if (!matchAs) {\n        warn(\n          false,\n          \"Duplicate named routes definition: \" +\n            \"{ name: \\\"\" + name + \"\\\", path: \\\"\" + (record.path) + \"\\\" }\"\n        );\n      }\n    }\n  }\n\n  function compileRouteRegex (\n    path,\n    pathToRegexpOptions\n  ) {\n    var regex = pathToRegexp_1(path, [], pathToRegexpOptions);\n    {\n      var keys = Object.create(null);\n      regex.keys.forEach(function (key) {\n        warn(\n          !keys[key.name],\n          (\"Duplicate param keys in route with path: \\\"\" + path + \"\\\"\")\n        );\n        keys[key.name] = true;\n      });\n    }\n    return regex\n  }\n\n  function normalizePath (\n    path,\n    parent,\n    strict\n  ) {\n    if (!strict) { path = path.replace(/\\/$/, ''); }\n    if (path[0] === '/') { return path }\n    if (parent == null) { return path }\n    return cleanPath(((parent.path) + \"/\" + path))\n  }\n\n  /*  */\n\n\n\n  function createMatcher (\n    routes,\n    router\n  ) {\n    var ref = createRouteMap(routes);\n    var pathList = ref.pathList;\n    var pathMap = ref.pathMap;\n    var nameMap = ref.nameMap;\n\n    function addRoutes (routes) {\n      createRouteMap(routes, pathList, pathMap, nameMap);\n    }\n\n    function addRoute (parentOrRoute, route) {\n      var parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined;\n      // $flow-disable-line\n      createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent);\n\n      // add aliases of parent\n      if (parent && parent.alias.length) {\n        createRouteMap(\n          // $flow-disable-line route is defined if parent is\n          parent.alias.map(function (alias) { return ({ path: alias, children: [route] }); }),\n          pathList,\n          pathMap,\n          nameMap,\n          parent\n        );\n      }\n    }\n\n    function getRoutes () {\n      return pathList.map(function (path) { return pathMap[path]; })\n    }\n\n    function match (\n      raw,\n      currentRoute,\n      redirectedFrom\n    ) {\n      var location = normalizeLocation(raw, currentRoute, false, router);\n      var name = location.name;\n\n      if (name) {\n        var record = nameMap[name];\n        {\n          warn(record, (\"Route with name '\" + name + \"' does not exist\"));\n        }\n        if (!record) { return _createRoute(null, location) }\n        var paramNames = record.regex.keys\n          .filter(function (key) { return !key.optional; })\n          .map(function (key) { return key.name; });\n\n        if (typeof location.params !== 'object') {\n          location.params = {};\n        }\n\n        if (currentRoute && typeof currentRoute.params === 'object') {\n          for (var key in currentRoute.params) {\n            if (!(key in location.params) && paramNames.indexOf(key) > -1) {\n              location.params[key] = currentRoute.params[key];\n            }\n          }\n        }\n\n        location.path = fillParams(record.path, location.params, (\"named route \\\"\" + name + \"\\\"\"));\n        return _createRoute(record, location, redirectedFrom)\n      } else if (location.path) {\n        location.params = {};\n        for (var i = 0; i < pathList.length; i++) {\n          var path = pathList[i];\n          var record$1 = pathMap[path];\n          if (matchRoute(record$1.regex, location.path, location.params)) {\n            return _createRoute(record$1, location, redirectedFrom)\n          }\n        }\n      }\n      // no match\n      return _createRoute(null, location)\n    }\n\n    function redirect (\n      record,\n      location\n    ) {\n      var originalRedirect = record.redirect;\n      var redirect = typeof originalRedirect === 'function'\n        ? originalRedirect(createRoute(record, location, null, router))\n        : originalRedirect;\n\n      if (typeof redirect === 'string') {\n        redirect = { path: redirect };\n      }\n\n      if (!redirect || typeof redirect !== 'object') {\n        {\n          warn(\n            false, (\"invalid redirect option: \" + (JSON.stringify(redirect)))\n          );\n        }\n        return _createRoute(null, location)\n      }\n\n      var re = redirect;\n      var name = re.name;\n      var path = re.path;\n      var query = location.query;\n      var hash = location.hash;\n      var params = location.params;\n      query = re.hasOwnProperty('query') ? re.query : query;\n      hash = re.hasOwnProperty('hash') ? re.hash : hash;\n      params = re.hasOwnProperty('params') ? re.params : params;\n\n      if (name) {\n        // resolved named direct\n        var targetRecord = nameMap[name];\n        {\n          assert(targetRecord, (\"redirect failed: named route \\\"\" + name + \"\\\" not found.\"));\n        }\n        return match({\n          _normalized: true,\n          name: name,\n          query: query,\n          hash: hash,\n          params: params\n        }, undefined, location)\n      } else if (path) {\n        // 1. resolve relative redirect\n        var rawPath = resolveRecordPath(path, record);\n        // 2. resolve params\n        var resolvedPath = fillParams(rawPath, params, (\"redirect route with path \\\"\" + rawPath + \"\\\"\"));\n        // 3. rematch with existing query and hash\n        return match({\n          _normalized: true,\n          path: resolvedPath,\n          query: query,\n          hash: hash\n        }, undefined, location)\n      } else {\n        {\n          warn(false, (\"invalid redirect option: \" + (JSON.stringify(redirect))));\n        }\n        return _createRoute(null, location)\n      }\n    }\n\n    function alias (\n      record,\n      location,\n      matchAs\n    ) {\n      var aliasedPath = fillParams(matchAs, location.params, (\"aliased route with path \\\"\" + matchAs + \"\\\"\"));\n      var aliasedMatch = match({\n        _normalized: true,\n        path: aliasedPath\n      });\n      if (aliasedMatch) {\n        var matched = aliasedMatch.matched;\n        var aliasedRecord = matched[matched.length - 1];\n        location.params = aliasedMatch.params;\n        return _createRoute(aliasedRecord, location)\n      }\n      return _createRoute(null, location)\n    }\n\n    function _createRoute (\n      record,\n      location,\n      redirectedFrom\n    ) {\n      if (record && record.redirect) {\n        return redirect(record, redirectedFrom || location)\n      }\n      if (record && record.matchAs) {\n        return alias(record, location, record.matchAs)\n      }\n      return createRoute(record, location, redirectedFrom, router)\n    }\n\n    return {\n      match: match,\n      addRoute: addRoute,\n      getRoutes: getRoutes,\n      addRoutes: addRoutes\n    }\n  }\n\n  function matchRoute (\n    regex,\n    path,\n    params\n  ) {\n    var m = path.match(regex);\n\n    if (!m) {\n      return false\n    } else if (!params) {\n      return true\n    }\n\n    for (var i = 1, len = m.length; i < len; ++i) {\n      var key = regex.keys[i - 1];\n      if (key) {\n        // Fix #1994: using * with props: true generates a param named 0\n        params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i];\n      }\n    }\n\n    return true\n  }\n\n  function resolveRecordPath (path, record) {\n    return resolvePath(path, record.parent ? record.parent.path : '/', true)\n  }\n\n  /*  */\n\n  // use User Timing api (if present) for more accurate key precision\n  var Time =\n    inBrowser && window.performance && window.performance.now\n      ? window.performance\n      : Date;\n\n  function genStateKey () {\n    return Time.now().toFixed(3)\n  }\n\n  var _key = genStateKey();\n\n  function getStateKey () {\n    return _key\n  }\n\n  function setStateKey (key) {\n    return (_key = key)\n  }\n\n  /*  */\n\n  var positionStore = Object.create(null);\n\n  function setupScroll () {\n    // Prevent browser scroll behavior on History popstate\n    if ('scrollRestoration' in window.history) {\n      window.history.scrollRestoration = 'manual';\n    }\n    // Fix for #1585 for Firefox\n    // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678\n    // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with\n    // window.location.protocol + '//' + window.location.host\n    // location.host contains the port and location.hostname doesn't\n    var protocolAndPath = window.location.protocol + '//' + window.location.host;\n    var absolutePath = window.location.href.replace(protocolAndPath, '');\n    // preserve existing history state as it could be overriden by the user\n    var stateCopy = extend({}, window.history.state);\n    stateCopy.key = getStateKey();\n    window.history.replaceState(stateCopy, '', absolutePath);\n    window.addEventListener('popstate', handlePopState);\n    return function () {\n      window.removeEventListener('popstate', handlePopState);\n    }\n  }\n\n  function handleScroll (\n    router,\n    to,\n    from,\n    isPop\n  ) {\n    if (!router.app) {\n      return\n    }\n\n    var behavior = router.options.scrollBehavior;\n    if (!behavior) {\n      return\n    }\n\n    {\n      assert(typeof behavior === 'function', \"scrollBehavior must be a function\");\n    }\n\n    // wait until re-render finishes before scrolling\n    router.app.$nextTick(function () {\n      var position = getScrollPosition();\n      var shouldScroll = behavior.call(\n        router,\n        to,\n        from,\n        isPop ? position : null\n      );\n\n      if (!shouldScroll) {\n        return\n      }\n\n      if (typeof shouldScroll.then === 'function') {\n        shouldScroll\n          .then(function (shouldScroll) {\n            scrollToPosition((shouldScroll), position);\n          })\n          .catch(function (err) {\n            {\n              assert(false, err.toString());\n            }\n          });\n      } else {\n        scrollToPosition(shouldScroll, position);\n      }\n    });\n  }\n\n  function saveScrollPosition () {\n    var key = getStateKey();\n    if (key) {\n      positionStore[key] = {\n        x: window.pageXOffset,\n        y: window.pageYOffset\n      };\n    }\n  }\n\n  function handlePopState (e) {\n    saveScrollPosition();\n    if (e.state && e.state.key) {\n      setStateKey(e.state.key);\n    }\n  }\n\n  function getScrollPosition () {\n    var key = getStateKey();\n    if (key) {\n      return positionStore[key]\n    }\n  }\n\n  function getElementPosition (el, offset) {\n    var docEl = document.documentElement;\n    var docRect = docEl.getBoundingClientRect();\n    var elRect = el.getBoundingClientRect();\n    return {\n      x: elRect.left - docRect.left - offset.x,\n      y: elRect.top - docRect.top - offset.y\n    }\n  }\n\n  function isValidPosition (obj) {\n    return isNumber(obj.x) || isNumber(obj.y)\n  }\n\n  function normalizePosition (obj) {\n    return {\n      x: isNumber(obj.x) ? obj.x : window.pageXOffset,\n      y: isNumber(obj.y) ? obj.y : window.pageYOffset\n    }\n  }\n\n  function normalizeOffset (obj) {\n    return {\n      x: isNumber(obj.x) ? obj.x : 0,\n      y: isNumber(obj.y) ? obj.y : 0\n    }\n  }\n\n  function isNumber (v) {\n    return typeof v === 'number'\n  }\n\n  var hashStartsWithNumberRE = /^#\\d/;\n\n  function scrollToPosition (shouldScroll, position) {\n    var isObject = typeof shouldScroll === 'object';\n    if (isObject && typeof shouldScroll.selector === 'string') {\n      // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]\n      // but at the same time, it doesn't make much sense to select an element with an id and an extra selector\n      var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line\n        ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line\n        : document.querySelector(shouldScroll.selector);\n\n      if (el) {\n        var offset =\n          shouldScroll.offset && typeof shouldScroll.offset === 'object'\n            ? shouldScroll.offset\n            : {};\n        offset = normalizeOffset(offset);\n        position = getElementPosition(el, offset);\n      } else if (isValidPosition(shouldScroll)) {\n        position = normalizePosition(shouldScroll);\n      }\n    } else if (isObject && isValidPosition(shouldScroll)) {\n      position = normalizePosition(shouldScroll);\n    }\n\n    if (position) {\n      // $flow-disable-line\n      if ('scrollBehavior' in document.documentElement.style) {\n        window.scrollTo({\n          left: position.x,\n          top: position.y,\n          // $flow-disable-line\n          behavior: shouldScroll.behavior\n        });\n      } else {\n        window.scrollTo(position.x, position.y);\n      }\n    }\n  }\n\n  /*  */\n\n  var supportsPushState =\n    inBrowser &&\n    (function () {\n      var ua = window.navigator.userAgent;\n\n      if (\n        (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&\n        ua.indexOf('Mobile Safari') !== -1 &&\n        ua.indexOf('Chrome') === -1 &&\n        ua.indexOf('Windows Phone') === -1\n      ) {\n        return false\n      }\n\n      return window.history && typeof window.history.pushState === 'function'\n    })();\n\n  function pushState (url, replace) {\n    saveScrollPosition();\n    // try...catch the pushState call to get around Safari\n    // DOM Exception 18 where it limits to 100 pushState calls\n    var history = window.history;\n    try {\n      if (replace) {\n        // preserve existing history state as it could be overriden by the user\n        var stateCopy = extend({}, history.state);\n        stateCopy.key = getStateKey();\n        history.replaceState(stateCopy, '', url);\n      } else {\n        history.pushState({ key: setStateKey(genStateKey()) }, '', url);\n      }\n    } catch (e) {\n      window.location[replace ? 'replace' : 'assign'](url);\n    }\n  }\n\n  function replaceState (url) {\n    pushState(url, true);\n  }\n\n  // When changing thing, also edit router.d.ts\n  var NavigationFailureType = {\n    redirected: 2,\n    aborted: 4,\n    cancelled: 8,\n    duplicated: 16\n  };\n\n  function createNavigationRedirectedError (from, to) {\n    return createRouterError(\n      from,\n      to,\n      NavigationFailureType.redirected,\n      (\"Redirected when going from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (stringifyRoute(\n        to\n      )) + \"\\\" via a navigation guard.\")\n    )\n  }\n\n  function createNavigationDuplicatedError (from, to) {\n    var error = createRouterError(\n      from,\n      to,\n      NavigationFailureType.duplicated,\n      (\"Avoided redundant navigation to current location: \\\"\" + (from.fullPath) + \"\\\".\")\n    );\n    // backwards compatible with the first introduction of Errors\n    error.name = 'NavigationDuplicated';\n    return error\n  }\n\n  function createNavigationCancelledError (from, to) {\n    return createRouterError(\n      from,\n      to,\n      NavigationFailureType.cancelled,\n      (\"Navigation cancelled from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" with a new navigation.\")\n    )\n  }\n\n  function createNavigationAbortedError (from, to) {\n    return createRouterError(\n      from,\n      to,\n      NavigationFailureType.aborted,\n      (\"Navigation aborted from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" via a navigation guard.\")\n    )\n  }\n\n  function createRouterError (from, to, type, message) {\n    var error = new Error(message);\n    error._isRouter = true;\n    error.from = from;\n    error.to = to;\n    error.type = type;\n\n    return error\n  }\n\n  var propertiesToLog = ['params', 'query', 'hash'];\n\n  function stringifyRoute (to) {\n    if (typeof to === 'string') { return to }\n    if ('path' in to) { return to.path }\n    var location = {};\n    propertiesToLog.forEach(function (key) {\n      if (key in to) { location[key] = to[key]; }\n    });\n    return JSON.stringify(location, null, 2)\n  }\n\n  function isError (err) {\n    return Object.prototype.toString.call(err).indexOf('Error') > -1\n  }\n\n  function isNavigationFailure (err, errorType) {\n    return (\n      isError(err) &&\n      err._isRouter &&\n      (errorType == null || err.type === errorType)\n    )\n  }\n\n  /*  */\n\n  function runQueue (queue, fn, cb) {\n    var step = function (index) {\n      if (index >= queue.length) {\n        cb();\n      } else {\n        if (queue[index]) {\n          fn(queue[index], function () {\n            step(index + 1);\n          });\n        } else {\n          step(index + 1);\n        }\n      }\n    };\n    step(0);\n  }\n\n  /*  */\n\n  function resolveAsyncComponents (matched) {\n    return function (to, from, next) {\n      var hasAsync = false;\n      var pending = 0;\n      var error = null;\n\n      flatMapComponents(matched, function (def, _, match, key) {\n        // if it's a function and doesn't have cid attached,\n        // assume it's an async component resolve function.\n        // we are not using Vue's default async resolving mechanism because\n        // we want to halt the navigation until the incoming component has been\n        // resolved.\n        if (typeof def === 'function' && def.cid === undefined) {\n          hasAsync = true;\n          pending++;\n\n          var resolve = once(function (resolvedDef) {\n            if (isESModule(resolvedDef)) {\n              resolvedDef = resolvedDef.default;\n            }\n            // save resolved on async factory in case it's used elsewhere\n            def.resolved = typeof resolvedDef === 'function'\n              ? resolvedDef\n              : _Vue.extend(resolvedDef);\n            match.components[key] = resolvedDef;\n            pending--;\n            if (pending <= 0) {\n              next();\n            }\n          });\n\n          var reject = once(function (reason) {\n            var msg = \"Failed to resolve async component \" + key + \": \" + reason;\n            warn(false, msg);\n            if (!error) {\n              error = isError(reason)\n                ? reason\n                : new Error(msg);\n              next(error);\n            }\n          });\n\n          var res;\n          try {\n            res = def(resolve, reject);\n          } catch (e) {\n            reject(e);\n          }\n          if (res) {\n            if (typeof res.then === 'function') {\n              res.then(resolve, reject);\n            } else {\n              // new syntax in Vue 2.3\n              var comp = res.component;\n              if (comp && typeof comp.then === 'function') {\n                comp.then(resolve, reject);\n              }\n            }\n          }\n        }\n      });\n\n      if (!hasAsync) { next(); }\n    }\n  }\n\n  function flatMapComponents (\n    matched,\n    fn\n  ) {\n    return flatten(matched.map(function (m) {\n      return Object.keys(m.components).map(function (key) { return fn(\n        m.components[key],\n        m.instances[key],\n        m, key\n      ); })\n    }))\n  }\n\n  function flatten (arr) {\n    return Array.prototype.concat.apply([], arr)\n  }\n\n  var hasSymbol =\n    typeof Symbol === 'function' &&\n    typeof Symbol.toStringTag === 'symbol';\n\n  function isESModule (obj) {\n    return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')\n  }\n\n  // in Webpack 2, require.ensure now also returns a Promise\n  // so the resolve/reject functions may get called an extra time\n  // if the user uses an arrow function shorthand that happens to\n  // return that Promise.\n  function once (fn) {\n    var called = false;\n    return function () {\n      var args = [], len = arguments.length;\n      while ( len-- ) args[ len ] = arguments[ len ];\n\n      if (called) { return }\n      called = true;\n      return fn.apply(this, args)\n    }\n  }\n\n  /*  */\n\n  var History = function History (router, base) {\n    this.router = router;\n    this.base = normalizeBase(base);\n    // start with a route object that stands for \"nowhere\"\n    this.current = START;\n    this.pending = null;\n    this.ready = false;\n    this.readyCbs = [];\n    this.readyErrorCbs = [];\n    this.errorCbs = [];\n    this.listeners = [];\n  };\n\n  History.prototype.listen = function listen (cb) {\n    this.cb = cb;\n  };\n\n  History.prototype.onReady = function onReady (cb, errorCb) {\n    if (this.ready) {\n      cb();\n    } else {\n      this.readyCbs.push(cb);\n      if (errorCb) {\n        this.readyErrorCbs.push(errorCb);\n      }\n    }\n  };\n\n  History.prototype.onError = function onError (errorCb) {\n    this.errorCbs.push(errorCb);\n  };\n\n  History.prototype.transitionTo = function transitionTo (\n    location,\n    onComplete,\n    onAbort\n  ) {\n      var this$1$1 = this;\n\n    var route;\n    // catch redirect option https://github.com/vuejs/vue-router/issues/3201\n    try {\n      route = this.router.match(location, this.current);\n    } catch (e) {\n      this.errorCbs.forEach(function (cb) {\n        cb(e);\n      });\n      // Exception should still be thrown\n      throw e\n    }\n    var prev = this.current;\n    this.confirmTransition(\n      route,\n      function () {\n        this$1$1.updateRoute(route);\n        onComplete && onComplete(route);\n        this$1$1.ensureURL();\n        this$1$1.router.afterHooks.forEach(function (hook) {\n          hook && hook(route, prev);\n        });\n\n        // fire ready cbs once\n        if (!this$1$1.ready) {\n          this$1$1.ready = true;\n          this$1$1.readyCbs.forEach(function (cb) {\n            cb(route);\n          });\n        }\n      },\n      function (err) {\n        if (onAbort) {\n          onAbort(err);\n        }\n        if (err && !this$1$1.ready) {\n          // Initial redirection should not mark the history as ready yet\n          // because it's triggered by the redirection instead\n          // https://github.com/vuejs/vue-router/issues/3225\n          // https://github.com/vuejs/vue-router/issues/3331\n          if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {\n            this$1$1.ready = true;\n            this$1$1.readyErrorCbs.forEach(function (cb) {\n              cb(err);\n            });\n          }\n        }\n      }\n    );\n  };\n\n  History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {\n      var this$1$1 = this;\n\n    var current = this.current;\n    this.pending = route;\n    var abort = function (err) {\n      // changed after adding errors with\n      // https://github.com/vuejs/vue-router/pull/3047 before that change,\n      // redirect and aborted navigation would produce an err == null\n      if (!isNavigationFailure(err) && isError(err)) {\n        if (this$1$1.errorCbs.length) {\n          this$1$1.errorCbs.forEach(function (cb) {\n            cb(err);\n          });\n        } else {\n          {\n            warn(false, 'uncaught error during route navigation:');\n          }\n          console.error(err);\n        }\n      }\n      onAbort && onAbort(err);\n    };\n    var lastRouteIndex = route.matched.length - 1;\n    var lastCurrentIndex = current.matched.length - 1;\n    if (\n      isSameRoute(route, current) &&\n      // in the case the route map has been dynamically appended to\n      lastRouteIndex === lastCurrentIndex &&\n      route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]\n    ) {\n      this.ensureURL();\n      if (route.hash) {\n        handleScroll(this.router, current, route, false);\n      }\n      return abort(createNavigationDuplicatedError(current, route))\n    }\n\n    var ref = resolveQueue(\n      this.current.matched,\n      route.matched\n    );\n      var updated = ref.updated;\n      var deactivated = ref.deactivated;\n      var activated = ref.activated;\n\n    var queue = [].concat(\n      // in-component leave guards\n      extractLeaveGuards(deactivated),\n      // global before hooks\n      this.router.beforeHooks,\n      // in-component update hooks\n      extractUpdateHooks(updated),\n      // in-config enter guards\n      activated.map(function (m) { return m.beforeEnter; }),\n      // async components\n      resolveAsyncComponents(activated)\n    );\n\n    var iterator = function (hook, next) {\n      if (this$1$1.pending !== route) {\n        return abort(createNavigationCancelledError(current, route))\n      }\n      try {\n        hook(route, current, function (to) {\n          if (to === false) {\n            // next(false) -> abort navigation, ensure current URL\n            this$1$1.ensureURL(true);\n            abort(createNavigationAbortedError(current, route));\n          } else if (isError(to)) {\n            this$1$1.ensureURL(true);\n            abort(to);\n          } else if (\n            typeof to === 'string' ||\n            (typeof to === 'object' &&\n              (typeof to.path === 'string' || typeof to.name === 'string'))\n          ) {\n            // next('/') or next({ path: '/' }) -> redirect\n            abort(createNavigationRedirectedError(current, route));\n            if (typeof to === 'object' && to.replace) {\n              this$1$1.replace(to);\n            } else {\n              this$1$1.push(to);\n            }\n          } else {\n            // confirm transition and pass on the value\n            next(to);\n          }\n        });\n      } catch (e) {\n        abort(e);\n      }\n    };\n\n    runQueue(queue, iterator, function () {\n      // wait until async components are resolved before\n      // extracting in-component enter guards\n      var enterGuards = extractEnterGuards(activated);\n      var queue = enterGuards.concat(this$1$1.router.resolveHooks);\n      runQueue(queue, iterator, function () {\n        if (this$1$1.pending !== route) {\n          return abort(createNavigationCancelledError(current, route))\n        }\n        this$1$1.pending = null;\n        onComplete(route);\n        if (this$1$1.router.app) {\n          this$1$1.router.app.$nextTick(function () {\n            handleRouteEntered(route);\n          });\n        }\n      });\n    });\n  };\n\n  History.prototype.updateRoute = function updateRoute (route) {\n    this.current = route;\n    this.cb && this.cb(route);\n  };\n\n  History.prototype.setupListeners = function setupListeners () {\n    // Default implementation is empty\n  };\n\n  History.prototype.teardown = function teardown () {\n    // clean up event listeners\n    // https://github.com/vuejs/vue-router/issues/2341\n    this.listeners.forEach(function (cleanupListener) {\n      cleanupListener();\n    });\n    this.listeners = [];\n\n    // reset current history route\n    // https://github.com/vuejs/vue-router/issues/3294\n    this.current = START;\n    this.pending = null;\n  };\n\n  function normalizeBase (base) {\n    if (!base) {\n      if (inBrowser) {\n        // respect <base> tag\n        var baseEl = document.querySelector('base');\n        base = (baseEl && baseEl.getAttribute('href')) || '/';\n        // strip full URL origin\n        base = base.replace(/^https?:\\/\\/[^\\/]+/, '');\n      } else {\n        base = '/';\n      }\n    }\n    // make sure there's the starting slash\n    if (base.charAt(0) !== '/') {\n      base = '/' + base;\n    }\n    // remove trailing slash\n    return base.replace(/\\/$/, '')\n  }\n\n  function resolveQueue (\n    current,\n    next\n  ) {\n    var i;\n    var max = Math.max(current.length, next.length);\n    for (i = 0; i < max; i++) {\n      if (current[i] !== next[i]) {\n        break\n      }\n    }\n    return {\n      updated: next.slice(0, i),\n      activated: next.slice(i),\n      deactivated: current.slice(i)\n    }\n  }\n\n  function extractGuards (\n    records,\n    name,\n    bind,\n    reverse\n  ) {\n    var guards = flatMapComponents(records, function (def, instance, match, key) {\n      var guard = extractGuard(def, name);\n      if (guard) {\n        return Array.isArray(guard)\n          ? guard.map(function (guard) { return bind(guard, instance, match, key); })\n          : bind(guard, instance, match, key)\n      }\n    });\n    return flatten(reverse ? guards.reverse() : guards)\n  }\n\n  function extractGuard (\n    def,\n    key\n  ) {\n    if (typeof def !== 'function') {\n      // extend now so that global mixins are applied.\n      def = _Vue.extend(def);\n    }\n    return def.options[key]\n  }\n\n  function extractLeaveGuards (deactivated) {\n    return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)\n  }\n\n  function extractUpdateHooks (updated) {\n    return extractGuards(updated, 'beforeRouteUpdate', bindGuard)\n  }\n\n  function bindGuard (guard, instance) {\n    if (instance) {\n      return function boundRouteGuard () {\n        return guard.apply(instance, arguments)\n      }\n    }\n  }\n\n  function extractEnterGuards (\n    activated\n  ) {\n    return extractGuards(\n      activated,\n      'beforeRouteEnter',\n      function (guard, _, match, key) {\n        return bindEnterGuard(guard, match, key)\n      }\n    )\n  }\n\n  function bindEnterGuard (\n    guard,\n    match,\n    key\n  ) {\n    return function routeEnterGuard (to, from, next) {\n      return guard(to, from, function (cb) {\n        if (typeof cb === 'function') {\n          if (!match.enteredCbs[key]) {\n            match.enteredCbs[key] = [];\n          }\n          match.enteredCbs[key].push(cb);\n        }\n        next(cb);\n      })\n    }\n  }\n\n  /*  */\n\n  var HTML5History = /*@__PURE__*/(function (History) {\n    function HTML5History (router, base) {\n      History.call(this, router, base);\n\n      this._startLocation = getLocation(this.base);\n    }\n\n    if ( History ) HTML5History.__proto__ = History;\n    HTML5History.prototype = Object.create( History && History.prototype );\n    HTML5History.prototype.constructor = HTML5History;\n\n    HTML5History.prototype.setupListeners = function setupListeners () {\n      var this$1$1 = this;\n\n      if (this.listeners.length > 0) {\n        return\n      }\n\n      var router = this.router;\n      var expectScroll = router.options.scrollBehavior;\n      var supportsScroll = supportsPushState && expectScroll;\n\n      if (supportsScroll) {\n        this.listeners.push(setupScroll());\n      }\n\n      var handleRoutingEvent = function () {\n        var current = this$1$1.current;\n\n        // Avoiding first `popstate` event dispatched in some browsers but first\n        // history route not updated since async guard at the same time.\n        var location = getLocation(this$1$1.base);\n        if (this$1$1.current === START && location === this$1$1._startLocation) {\n          return\n        }\n\n        this$1$1.transitionTo(location, function (route) {\n          if (supportsScroll) {\n            handleScroll(router, route, current, true);\n          }\n        });\n      };\n      window.addEventListener('popstate', handleRoutingEvent);\n      this.listeners.push(function () {\n        window.removeEventListener('popstate', handleRoutingEvent);\n      });\n    };\n\n    HTML5History.prototype.go = function go (n) {\n      window.history.go(n);\n    };\n\n    HTML5History.prototype.push = function push (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n      var ref = this;\n      var fromRoute = ref.current;\n      this.transitionTo(location, function (route) {\n        pushState(cleanPath(this$1$1.base + route.fullPath));\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      }, onAbort);\n    };\n\n    HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n      var ref = this;\n      var fromRoute = ref.current;\n      this.transitionTo(location, function (route) {\n        replaceState(cleanPath(this$1$1.base + route.fullPath));\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      }, onAbort);\n    };\n\n    HTML5History.prototype.ensureURL = function ensureURL (push) {\n      if (getLocation(this.base) !== this.current.fullPath) {\n        var current = cleanPath(this.base + this.current.fullPath);\n        push ? pushState(current) : replaceState(current);\n      }\n    };\n\n    HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {\n      return getLocation(this.base)\n    };\n\n    return HTML5History;\n  }(History));\n\n  function getLocation (base) {\n    var path = window.location.pathname;\n    var pathLowerCase = path.toLowerCase();\n    var baseLowerCase = base.toLowerCase();\n    // base=\"/a\" shouldn't turn path=\"/app\" into \"/a/pp\"\n    // https://github.com/vuejs/vue-router/issues/3555\n    // so we ensure the trailing slash in the base\n    if (base && ((pathLowerCase === baseLowerCase) ||\n      (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {\n      path = path.slice(base.length);\n    }\n    return (path || '/') + window.location.search + window.location.hash\n  }\n\n  /*  */\n\n  var HashHistory = /*@__PURE__*/(function (History) {\n    function HashHistory (router, base, fallback) {\n      History.call(this, router, base);\n      // check history fallback deeplinking\n      if (fallback && checkFallback(this.base)) {\n        return\n      }\n      ensureSlash();\n    }\n\n    if ( History ) HashHistory.__proto__ = History;\n    HashHistory.prototype = Object.create( History && History.prototype );\n    HashHistory.prototype.constructor = HashHistory;\n\n    // this is delayed until the app mounts\n    // to avoid the hashchange listener being fired too early\n    HashHistory.prototype.setupListeners = function setupListeners () {\n      var this$1$1 = this;\n\n      if (this.listeners.length > 0) {\n        return\n      }\n\n      var router = this.router;\n      var expectScroll = router.options.scrollBehavior;\n      var supportsScroll = supportsPushState && expectScroll;\n\n      if (supportsScroll) {\n        this.listeners.push(setupScroll());\n      }\n\n      var handleRoutingEvent = function () {\n        var current = this$1$1.current;\n        if (!ensureSlash()) {\n          return\n        }\n        this$1$1.transitionTo(getHash(), function (route) {\n          if (supportsScroll) {\n            handleScroll(this$1$1.router, route, current, true);\n          }\n          if (!supportsPushState) {\n            replaceHash(route.fullPath);\n          }\n        });\n      };\n      var eventType = supportsPushState ? 'popstate' : 'hashchange';\n      window.addEventListener(\n        eventType,\n        handleRoutingEvent\n      );\n      this.listeners.push(function () {\n        window.removeEventListener(eventType, handleRoutingEvent);\n      });\n    };\n\n    HashHistory.prototype.push = function push (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n      var ref = this;\n      var fromRoute = ref.current;\n      this.transitionTo(\n        location,\n        function (route) {\n          pushHash(route.fullPath);\n          handleScroll(this$1$1.router, route, fromRoute, false);\n          onComplete && onComplete(route);\n        },\n        onAbort\n      );\n    };\n\n    HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n      var ref = this;\n      var fromRoute = ref.current;\n      this.transitionTo(\n        location,\n        function (route) {\n          replaceHash(route.fullPath);\n          handleScroll(this$1$1.router, route, fromRoute, false);\n          onComplete && onComplete(route);\n        },\n        onAbort\n      );\n    };\n\n    HashHistory.prototype.go = function go (n) {\n      window.history.go(n);\n    };\n\n    HashHistory.prototype.ensureURL = function ensureURL (push) {\n      var current = this.current.fullPath;\n      if (getHash() !== current) {\n        push ? pushHash(current) : replaceHash(current);\n      }\n    };\n\n    HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n      return getHash()\n    };\n\n    return HashHistory;\n  }(History));\n\n  function checkFallback (base) {\n    var location = getLocation(base);\n    if (!/^\\/#/.test(location)) {\n      window.location.replace(cleanPath(base + '/#' + location));\n      return true\n    }\n  }\n\n  function ensureSlash () {\n    var path = getHash();\n    if (path.charAt(0) === '/') {\n      return true\n    }\n    replaceHash('/' + path);\n    return false\n  }\n\n  function getHash () {\n    // We can't use window.location.hash here because it's not\n    // consistent across browsers - Firefox will pre-decode it!\n    var href = window.location.href;\n    var index = href.indexOf('#');\n    // empty path\n    if (index < 0) { return '' }\n\n    href = href.slice(index + 1);\n\n    return href\n  }\n\n  function getUrl (path) {\n    var href = window.location.href;\n    var i = href.indexOf('#');\n    var base = i >= 0 ? href.slice(0, i) : href;\n    return (base + \"#\" + path)\n  }\n\n  function pushHash (path) {\n    if (supportsPushState) {\n      pushState(getUrl(path));\n    } else {\n      window.location.hash = path;\n    }\n  }\n\n  function replaceHash (path) {\n    if (supportsPushState) {\n      replaceState(getUrl(path));\n    } else {\n      window.location.replace(getUrl(path));\n    }\n  }\n\n  /*  */\n\n  var AbstractHistory = /*@__PURE__*/(function (History) {\n    function AbstractHistory (router, base) {\n      History.call(this, router, base);\n      this.stack = [];\n      this.index = -1;\n    }\n\n    if ( History ) AbstractHistory.__proto__ = History;\n    AbstractHistory.prototype = Object.create( History && History.prototype );\n    AbstractHistory.prototype.constructor = AbstractHistory;\n\n    AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n      this.transitionTo(\n        location,\n        function (route) {\n          this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index + 1).concat(route);\n          this$1$1.index++;\n          onComplete && onComplete(route);\n        },\n        onAbort\n      );\n    };\n\n    AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n      this.transitionTo(\n        location,\n        function (route) {\n          this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index).concat(route);\n          onComplete && onComplete(route);\n        },\n        onAbort\n      );\n    };\n\n    AbstractHistory.prototype.go = function go (n) {\n      var this$1$1 = this;\n\n      var targetIndex = this.index + n;\n      if (targetIndex < 0 || targetIndex >= this.stack.length) {\n        return\n      }\n      var route = this.stack[targetIndex];\n      this.confirmTransition(\n        route,\n        function () {\n          var prev = this$1$1.current;\n          this$1$1.index = targetIndex;\n          this$1$1.updateRoute(route);\n          this$1$1.router.afterHooks.forEach(function (hook) {\n            hook && hook(route, prev);\n          });\n        },\n        function (err) {\n          if (isNavigationFailure(err, NavigationFailureType.duplicated)) {\n            this$1$1.index = targetIndex;\n          }\n        }\n      );\n    };\n\n    AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n      var current = this.stack[this.stack.length - 1];\n      return current ? current.fullPath : '/'\n    };\n\n    AbstractHistory.prototype.ensureURL = function ensureURL () {\n      // noop\n    };\n\n    return AbstractHistory;\n  }(History));\n\n  /*  */\n\n\n\n  var VueRouter = function VueRouter (options) {\n    if ( options === void 0 ) options = {};\n\n    {\n      warn(this instanceof VueRouter, \"Router must be called with the new operator.\");\n    }\n    this.app = null;\n    this.apps = [];\n    this.options = options;\n    this.beforeHooks = [];\n    this.resolveHooks = [];\n    this.afterHooks = [];\n    this.matcher = createMatcher(options.routes || [], this);\n\n    var mode = options.mode || 'hash';\n    this.fallback =\n      mode === 'history' && !supportsPushState && options.fallback !== false;\n    if (this.fallback) {\n      mode = 'hash';\n    }\n    if (!inBrowser) {\n      mode = 'abstract';\n    }\n    this.mode = mode;\n\n    switch (mode) {\n      case 'history':\n        this.history = new HTML5History(this, options.base);\n        break\n      case 'hash':\n        this.history = new HashHistory(this, options.base, this.fallback);\n        break\n      case 'abstract':\n        this.history = new AbstractHistory(this, options.base);\n        break\n      default:\n        {\n          assert(false, (\"invalid mode: \" + mode));\n        }\n    }\n  };\n\n  var prototypeAccessors = { currentRoute: { configurable: true } };\n\n  VueRouter.prototype.match = function match (raw, current, redirectedFrom) {\n    return this.matcher.match(raw, current, redirectedFrom)\n  };\n\n  prototypeAccessors.currentRoute.get = function () {\n    return this.history && this.history.current\n  };\n\n  VueRouter.prototype.init = function init (app /* Vue component instance */) {\n      var this$1$1 = this;\n\n    assert(\n        install.installed,\n        \"not installed. Make sure to call `Vue.use(VueRouter)` \" +\n          \"before creating root instance.\"\n      );\n\n    this.apps.push(app);\n\n    // set up app destroyed handler\n    // https://github.com/vuejs/vue-router/issues/2639\n    app.$once('hook:destroyed', function () {\n      // clean out app from this.apps array once destroyed\n      var index = this$1$1.apps.indexOf(app);\n      if (index > -1) { this$1$1.apps.splice(index, 1); }\n      // ensure we still have a main app or null if no apps\n      // we do not release the router so it can be reused\n      if (this$1$1.app === app) { this$1$1.app = this$1$1.apps[0] || null; }\n\n      if (!this$1$1.app) { this$1$1.history.teardown(); }\n    });\n\n    // main app previously initialized\n    // return as we don't need to set up new history listener\n    if (this.app) {\n      return\n    }\n\n    this.app = app;\n\n    var history = this.history;\n\n    if (history instanceof HTML5History || history instanceof HashHistory) {\n      var handleInitialScroll = function (routeOrError) {\n        var from = history.current;\n        var expectScroll = this$1$1.options.scrollBehavior;\n        var supportsScroll = supportsPushState && expectScroll;\n\n        if (supportsScroll && 'fullPath' in routeOrError) {\n          handleScroll(this$1$1, routeOrError, from, false);\n        }\n      };\n      var setupListeners = function (routeOrError) {\n        history.setupListeners();\n        handleInitialScroll(routeOrError);\n      };\n      history.transitionTo(\n        history.getCurrentLocation(),\n        setupListeners,\n        setupListeners\n      );\n    }\n\n    history.listen(function (route) {\n      this$1$1.apps.forEach(function (app) {\n        app._route = route;\n      });\n    });\n  };\n\n  VueRouter.prototype.beforeEach = function beforeEach (fn) {\n    return registerHook(this.beforeHooks, fn)\n  };\n\n  VueRouter.prototype.beforeResolve = function beforeResolve (fn) {\n    return registerHook(this.resolveHooks, fn)\n  };\n\n  VueRouter.prototype.afterEach = function afterEach (fn) {\n    return registerHook(this.afterHooks, fn)\n  };\n\n  VueRouter.prototype.onReady = function onReady (cb, errorCb) {\n    this.history.onReady(cb, errorCb);\n  };\n\n  VueRouter.prototype.onError = function onError (errorCb) {\n    this.history.onError(errorCb);\n  };\n\n  VueRouter.prototype.push = function push (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n    // $flow-disable-line\n    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n      return new Promise(function (resolve, reject) {\n        this$1$1.history.push(location, resolve, reject);\n      })\n    } else {\n      this.history.push(location, onComplete, onAbort);\n    }\n  };\n\n  VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {\n      var this$1$1 = this;\n\n    // $flow-disable-line\n    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n      return new Promise(function (resolve, reject) {\n        this$1$1.history.replace(location, resolve, reject);\n      })\n    } else {\n      this.history.replace(location, onComplete, onAbort);\n    }\n  };\n\n  VueRouter.prototype.go = function go (n) {\n    this.history.go(n);\n  };\n\n  VueRouter.prototype.back = function back () {\n    this.go(-1);\n  };\n\n  VueRouter.prototype.forward = function forward () {\n    this.go(1);\n  };\n\n  VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {\n    var route = to\n      ? to.matched\n        ? to\n        : this.resolve(to).route\n      : this.currentRoute;\n    if (!route) {\n      return []\n    }\n    return [].concat.apply(\n      [],\n      route.matched.map(function (m) {\n        return Object.keys(m.components).map(function (key) {\n          return m.components[key]\n        })\n      })\n    )\n  };\n\n  VueRouter.prototype.resolve = function resolve (\n    to,\n    current,\n    append\n  ) {\n    current = current || this.history.current;\n    var location = normalizeLocation(to, current, append, this);\n    var route = this.match(location, current);\n    var fullPath = route.redirectedFrom || route.fullPath;\n    var base = this.history.base;\n    var href = createHref(base, fullPath, this.mode);\n    return {\n      location: location,\n      route: route,\n      href: href,\n      // for backwards compat\n      normalizedTo: location,\n      resolved: route\n    }\n  };\n\n  VueRouter.prototype.getRoutes = function getRoutes () {\n    return this.matcher.getRoutes()\n  };\n\n  VueRouter.prototype.addRoute = function addRoute (parentOrRoute, route) {\n    this.matcher.addRoute(parentOrRoute, route);\n    if (this.history.current !== START) {\n      this.history.transitionTo(this.history.getCurrentLocation());\n    }\n  };\n\n  VueRouter.prototype.addRoutes = function addRoutes (routes) {\n    {\n      warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.');\n    }\n    this.matcher.addRoutes(routes);\n    if (this.history.current !== START) {\n      this.history.transitionTo(this.history.getCurrentLocation());\n    }\n  };\n\n  Object.defineProperties( VueRouter.prototype, prototypeAccessors );\n\n  var VueRouter$1 = VueRouter;\n\n  function registerHook (list, fn) {\n    list.push(fn);\n    return function () {\n      var i = list.indexOf(fn);\n      if (i > -1) { list.splice(i, 1); }\n    }\n  }\n\n  function createHref (base, fullPath, mode) {\n    var path = mode === 'hash' ? '#' + fullPath : fullPath;\n    return base ? cleanPath(base + '/' + path) : path\n  }\n\n  // We cannot remove this as it would be a breaking change\n  VueRouter.install = install;\n  VueRouter.version = '3.6.5';\n  VueRouter.isNavigationFailure = isNavigationFailure;\n  VueRouter.NavigationFailureType = NavigationFailureType;\n  VueRouter.START_LOCATION = START;\n\n  if (inBrowser && window.Vue) {\n    window.Vue.use(VueRouter);\n  }\n\n  return VueRouter$1;\n\n}));\n"
  },
  {
    "path": "dist/vue-router.mjs",
    "content": "/*!\n  * vue-router v3.6.5\n  * (c) 2022 Evan You\n  * @license MIT\n  */\n/*  */\n\nfunction assert (condition, message) {\n  if (!condition) {\n    throw new Error((\"[vue-router] \" + message))\n  }\n}\n\nfunction warn (condition, message) {\n  if (!condition) {\n    typeof console !== 'undefined' && console.warn((\"[vue-router] \" + message));\n  }\n}\n\nfunction extend (a, b) {\n  for (var key in b) {\n    a[key] = b[key];\n  }\n  return a\n}\n\n/*  */\n\nvar encodeReserveRE = /[!'()*]/g;\nvar encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };\nvar commaRE = /%2C/g;\n\n// fixed encodeURIComponent which is more conformant to RFC3986:\n// - escapes [!'()*]\n// - preserve commas\nvar encode = function (str) { return encodeURIComponent(str)\n    .replace(encodeReserveRE, encodeReserveReplacer)\n    .replace(commaRE, ','); };\n\nfunction decode (str) {\n  try {\n    return decodeURIComponent(str)\n  } catch (err) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(false, (\"Error decoding \\\"\" + str + \"\\\". Leaving it intact.\"));\n    }\n  }\n  return str\n}\n\nfunction resolveQuery (\n  query,\n  extraQuery,\n  _parseQuery\n) {\n  if ( extraQuery === void 0 ) extraQuery = {};\n\n  var parse = _parseQuery || parseQuery;\n  var parsedQuery;\n  try {\n    parsedQuery = parse(query || '');\n  } catch (e) {\n    process.env.NODE_ENV !== 'production' && warn(false, e.message);\n    parsedQuery = {};\n  }\n  for (var key in extraQuery) {\n    var value = extraQuery[key];\n    parsedQuery[key] = Array.isArray(value)\n      ? value.map(castQueryParamValue)\n      : castQueryParamValue(value);\n  }\n  return parsedQuery\n}\n\nvar castQueryParamValue = function (value) { return (value == null || typeof value === 'object' ? value : String(value)); };\n\nfunction parseQuery (query) {\n  var res = {};\n\n  query = query.trim().replace(/^(\\?|#|&)/, '');\n\n  if (!query) {\n    return res\n  }\n\n  query.split('&').forEach(function (param) {\n    var parts = param.replace(/\\+/g, ' ').split('=');\n    var key = decode(parts.shift());\n    var val = parts.length > 0 ? decode(parts.join('=')) : null;\n\n    if (res[key] === undefined) {\n      res[key] = val;\n    } else if (Array.isArray(res[key])) {\n      res[key].push(val);\n    } else {\n      res[key] = [res[key], val];\n    }\n  });\n\n  return res\n}\n\nfunction stringifyQuery (obj) {\n  var res = obj\n    ? Object.keys(obj)\n      .map(function (key) {\n        var val = obj[key];\n\n        if (val === undefined) {\n          return ''\n        }\n\n        if (val === null) {\n          return encode(key)\n        }\n\n        if (Array.isArray(val)) {\n          var result = [];\n          val.forEach(function (val2) {\n            if (val2 === undefined) {\n              return\n            }\n            if (val2 === null) {\n              result.push(encode(key));\n            } else {\n              result.push(encode(key) + '=' + encode(val2));\n            }\n          });\n          return result.join('&')\n        }\n\n        return encode(key) + '=' + encode(val)\n      })\n      .filter(function (x) { return x.length > 0; })\n      .join('&')\n    : null;\n  return res ? (\"?\" + res) : ''\n}\n\n/*  */\n\nvar trailingSlashRE = /\\/?$/;\n\nfunction createRoute (\n  record,\n  location,\n  redirectedFrom,\n  router\n) {\n  var stringifyQuery = router && router.options.stringifyQuery;\n\n  var query = location.query || {};\n  try {\n    query = clone(query);\n  } catch (e) {}\n\n  var route = {\n    name: location.name || (record && record.name),\n    meta: (record && record.meta) || {},\n    path: location.path || '/',\n    hash: location.hash || '',\n    query: query,\n    params: location.params || {},\n    fullPath: getFullPath(location, stringifyQuery),\n    matched: record ? formatMatch(record) : []\n  };\n  if (redirectedFrom) {\n    route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);\n  }\n  return Object.freeze(route)\n}\n\nfunction clone (value) {\n  if (Array.isArray(value)) {\n    return value.map(clone)\n  } else if (value && typeof value === 'object') {\n    var res = {};\n    for (var key in value) {\n      res[key] = clone(value[key]);\n    }\n    return res\n  } else {\n    return value\n  }\n}\n\n// the starting route that represents the initial state\nvar START = createRoute(null, {\n  path: '/'\n});\n\nfunction formatMatch (record) {\n  var res = [];\n  while (record) {\n    res.unshift(record);\n    record = record.parent;\n  }\n  return res\n}\n\nfunction getFullPath (\n  ref,\n  _stringifyQuery\n) {\n  var path = ref.path;\n  var query = ref.query; if ( query === void 0 ) query = {};\n  var hash = ref.hash; if ( hash === void 0 ) hash = '';\n\n  var stringify = _stringifyQuery || stringifyQuery;\n  return (path || '/') + stringify(query) + hash\n}\n\nfunction isSameRoute (a, b, onlyPath) {\n  if (b === START) {\n    return a === b\n  } else if (!b) {\n    return false\n  } else if (a.path && b.path) {\n    return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||\n      a.hash === b.hash &&\n      isObjectEqual(a.query, b.query))\n  } else if (a.name && b.name) {\n    return (\n      a.name === b.name &&\n      (onlyPath || (\n        a.hash === b.hash &&\n      isObjectEqual(a.query, b.query) &&\n      isObjectEqual(a.params, b.params))\n      )\n    )\n  } else {\n    return false\n  }\n}\n\nfunction isObjectEqual (a, b) {\n  if ( a === void 0 ) a = {};\n  if ( b === void 0 ) b = {};\n\n  // handle null value #1566\n  if (!a || !b) { return a === b }\n  var aKeys = Object.keys(a).sort();\n  var bKeys = Object.keys(b).sort();\n  if (aKeys.length !== bKeys.length) {\n    return false\n  }\n  return aKeys.every(function (key, i) {\n    var aVal = a[key];\n    var bKey = bKeys[i];\n    if (bKey !== key) { return false }\n    var bVal = b[key];\n    // query values can be null and undefined\n    if (aVal == null || bVal == null) { return aVal === bVal }\n    // check nested equality\n    if (typeof aVal === 'object' && typeof bVal === 'object') {\n      return isObjectEqual(aVal, bVal)\n    }\n    return String(aVal) === String(bVal)\n  })\n}\n\nfunction isIncludedRoute (current, target) {\n  return (\n    current.path.replace(trailingSlashRE, '/').indexOf(\n      target.path.replace(trailingSlashRE, '/')\n    ) === 0 &&\n    (!target.hash || current.hash === target.hash) &&\n    queryIncludes(current.query, target.query)\n  )\n}\n\nfunction queryIncludes (current, target) {\n  for (var key in target) {\n    if (!(key in current)) {\n      return false\n    }\n  }\n  return true\n}\n\nfunction handleRouteEntered (route) {\n  for (var i = 0; i < route.matched.length; i++) {\n    var record = route.matched[i];\n    for (var name in record.instances) {\n      var instance = record.instances[name];\n      var cbs = record.enteredCbs[name];\n      if (!instance || !cbs) { continue }\n      delete record.enteredCbs[name];\n      for (var i$1 = 0; i$1 < cbs.length; i$1++) {\n        if (!instance._isBeingDestroyed) { cbs[i$1](instance); }\n      }\n    }\n  }\n}\n\nvar View = {\n  name: 'RouterView',\n  functional: true,\n  props: {\n    name: {\n      type: String,\n      default: 'default'\n    }\n  },\n  render: function render (_, ref) {\n    var props = ref.props;\n    var children = ref.children;\n    var parent = ref.parent;\n    var data = ref.data;\n\n    // used by devtools to display a router-view badge\n    data.routerView = true;\n\n    // directly use parent context's createElement() function\n    // so that components rendered by router-view can resolve named slots\n    var h = parent.$createElement;\n    var name = props.name;\n    var route = parent.$route;\n    var cache = parent._routerViewCache || (parent._routerViewCache = {});\n\n    // determine current view depth, also check to see if the tree\n    // has been toggled inactive but kept-alive.\n    var depth = 0;\n    var inactive = false;\n    while (parent && parent._routerRoot !== parent) {\n      var vnodeData = parent.$vnode ? parent.$vnode.data : {};\n      if (vnodeData.routerView) {\n        depth++;\n      }\n      if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {\n        inactive = true;\n      }\n      parent = parent.$parent;\n    }\n    data.routerViewDepth = depth;\n\n    // render previous view if the tree is inactive and kept-alive\n    if (inactive) {\n      var cachedData = cache[name];\n      var cachedComponent = cachedData && cachedData.component;\n      if (cachedComponent) {\n        // #2301\n        // pass props\n        if (cachedData.configProps) {\n          fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps);\n        }\n        return h(cachedComponent, data, children)\n      } else {\n        // render previous empty view\n        return h()\n      }\n    }\n\n    var matched = route.matched[depth];\n    var component = matched && matched.components[name];\n\n    // render empty node if no matched route or no config component\n    if (!matched || !component) {\n      cache[name] = null;\n      return h()\n    }\n\n    // cache component\n    cache[name] = { component: component };\n\n    // attach instance registration hook\n    // this will be called in the instance's injected lifecycle hooks\n    data.registerRouteInstance = function (vm, val) {\n      // val could be undefined for unregistration\n      var current = matched.instances[name];\n      if (\n        (val && current !== vm) ||\n        (!val && current === vm)\n      ) {\n        matched.instances[name] = val;\n      }\n    }\n\n    // also register instance in prepatch hook\n    // in case the same component instance is reused across different routes\n    ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {\n      matched.instances[name] = vnode.componentInstance;\n    };\n\n    // register instance in init hook\n    // in case kept-alive component be actived when routes changed\n    data.hook.init = function (vnode) {\n      if (vnode.data.keepAlive &&\n        vnode.componentInstance &&\n        vnode.componentInstance !== matched.instances[name]\n      ) {\n        matched.instances[name] = vnode.componentInstance;\n      }\n\n      // if the route transition has already been confirmed then we weren't\n      // able to call the cbs during confirmation as the component was not\n      // registered yet, so we call it here.\n      handleRouteEntered(route);\n    };\n\n    var configProps = matched.props && matched.props[name];\n    // save route and configProps in cache\n    if (configProps) {\n      extend(cache[name], {\n        route: route,\n        configProps: configProps\n      });\n      fillPropsinData(component, data, route, configProps);\n    }\n\n    return h(component, data, children)\n  }\n};\n\nfunction fillPropsinData (component, data, route, configProps) {\n  // resolve props\n  var propsToPass = data.props = resolveProps(route, configProps);\n  if (propsToPass) {\n    // clone to prevent mutation\n    propsToPass = data.props = extend({}, propsToPass);\n    // pass non-declared props as attrs\n    var attrs = data.attrs = data.attrs || {};\n    for (var key in propsToPass) {\n      if (!component.props || !(key in component.props)) {\n        attrs[key] = propsToPass[key];\n        delete propsToPass[key];\n      }\n    }\n  }\n}\n\nfunction resolveProps (route, config) {\n  switch (typeof config) {\n    case 'undefined':\n      return\n    case 'object':\n      return config\n    case 'function':\n      return config(route)\n    case 'boolean':\n      return config ? route.params : undefined\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false,\n          \"props in \\\"\" + (route.path) + \"\\\" is a \" + (typeof config) + \", \" +\n          \"expecting an object, function or boolean.\"\n        );\n      }\n  }\n}\n\n/*  */\n\nfunction resolvePath (\n  relative,\n  base,\n  append\n) {\n  var firstChar = relative.charAt(0);\n  if (firstChar === '/') {\n    return relative\n  }\n\n  if (firstChar === '?' || firstChar === '#') {\n    return base + relative\n  }\n\n  var stack = base.split('/');\n\n  // remove trailing segment if:\n  // - not appending\n  // - appending to trailing slash (last segment is empty)\n  if (!append || !stack[stack.length - 1]) {\n    stack.pop();\n  }\n\n  // resolve relative path\n  var segments = relative.replace(/^\\//, '').split('/');\n  for (var i = 0; i < segments.length; i++) {\n    var segment = segments[i];\n    if (segment === '..') {\n      stack.pop();\n    } else if (segment !== '.') {\n      stack.push(segment);\n    }\n  }\n\n  // ensure leading slash\n  if (stack[0] !== '') {\n    stack.unshift('');\n  }\n\n  return stack.join('/')\n}\n\nfunction parsePath (path) {\n  var hash = '';\n  var query = '';\n\n  var hashIndex = path.indexOf('#');\n  if (hashIndex >= 0) {\n    hash = path.slice(hashIndex);\n    path = path.slice(0, hashIndex);\n  }\n\n  var queryIndex = path.indexOf('?');\n  if (queryIndex >= 0) {\n    query = path.slice(queryIndex + 1);\n    path = path.slice(0, queryIndex);\n  }\n\n  return {\n    path: path,\n    query: query,\n    hash: hash\n  }\n}\n\nfunction cleanPath (path) {\n  return path.replace(/\\/(?:\\s*\\/)+/g, '/')\n}\n\nvar isarray = Array.isArray || function (arr) {\n  return Object.prototype.toString.call(arr) == '[object Array]';\n};\n\n/**\n * Expose `pathToRegexp`.\n */\nvar pathToRegexp_1 = pathToRegexp;\nvar parse_1 = parse;\nvar compile_1 = compile;\nvar tokensToFunction_1 = tokensToFunction;\nvar tokensToRegExp_1 = tokensToRegExp;\n\n/**\n * The main path matching regexp utility.\n *\n * @type {RegExp}\n */\nvar PATH_REGEXP = new RegExp([\n  // Match escaped characters that would otherwise appear in future matches.\n  // This allows the user to escape special characters that won't transform.\n  '(\\\\\\\\.)',\n  // Match Express-style parameters and un-named parameters with a prefix\n  // and optional suffixes. Matches appear as:\n  //\n  // \"/:test(\\\\d+)?\" => [\"/\", \"test\", \"\\d+\", undefined, \"?\", undefined]\n  // \"/route(\\\\d+)\"  => [undefined, undefined, undefined, \"\\d+\", undefined, undefined]\n  // \"/*\"            => [\"/\", undefined, undefined, undefined, undefined, \"*\"]\n  '([\\\\/.])?(?:(?:\\\\:(\\\\w+)(?:\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))?|\\\\(((?:\\\\\\\\.|[^\\\\\\\\()])+)\\\\))([+*?])?|(\\\\*))'\n].join('|'), 'g');\n\n/**\n * Parse a string for the raw tokens.\n *\n * @param  {string}  str\n * @param  {Object=} options\n * @return {!Array}\n */\nfunction parse (str, options) {\n  var tokens = [];\n  var key = 0;\n  var index = 0;\n  var path = '';\n  var defaultDelimiter = options && options.delimiter || '/';\n  var res;\n\n  while ((res = PATH_REGEXP.exec(str)) != null) {\n    var m = res[0];\n    var escaped = res[1];\n    var offset = res.index;\n    path += str.slice(index, offset);\n    index = offset + m.length;\n\n    // Ignore already escaped sequences.\n    if (escaped) {\n      path += escaped[1];\n      continue\n    }\n\n    var next = str[index];\n    var prefix = res[2];\n    var name = res[3];\n    var capture = res[4];\n    var group = res[5];\n    var modifier = res[6];\n    var asterisk = res[7];\n\n    // Push the current path onto the tokens.\n    if (path) {\n      tokens.push(path);\n      path = '';\n    }\n\n    var partial = prefix != null && next != null && next !== prefix;\n    var repeat = modifier === '+' || modifier === '*';\n    var optional = modifier === '?' || modifier === '*';\n    var delimiter = res[2] || defaultDelimiter;\n    var pattern = capture || group;\n\n    tokens.push({\n      name: name || key++,\n      prefix: prefix || '',\n      delimiter: delimiter,\n      optional: optional,\n      repeat: repeat,\n      partial: partial,\n      asterisk: !!asterisk,\n      pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')\n    });\n  }\n\n  // Match any characters still remaining.\n  if (index < str.length) {\n    path += str.substr(index);\n  }\n\n  // If the path exists, push it onto the end.\n  if (path) {\n    tokens.push(path);\n  }\n\n  return tokens\n}\n\n/**\n * Compile a string to a template function for the path.\n *\n * @param  {string}             str\n * @param  {Object=}            options\n * @return {!function(Object=, Object=)}\n */\nfunction compile (str, options) {\n  return tokensToFunction(parse(str, options), options)\n}\n\n/**\n * Prettier encoding of URI path segments.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeURIComponentPretty (str) {\n  return encodeURI(str).replace(/[\\/?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.\n *\n * @param  {string}\n * @return {string}\n */\nfunction encodeAsterisk (str) {\n  return encodeURI(str).replace(/[?#]/g, function (c) {\n    return '%' + c.charCodeAt(0).toString(16).toUpperCase()\n  })\n}\n\n/**\n * Expose a method for transforming tokens into the path function.\n */\nfunction tokensToFunction (tokens, options) {\n  // Compile all the tokens into regexps.\n  var matches = new Array(tokens.length);\n\n  // Compile all the patterns before compilation.\n  for (var i = 0; i < tokens.length; i++) {\n    if (typeof tokens[i] === 'object') {\n      matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options));\n    }\n  }\n\n  return function (obj, opts) {\n    var path = '';\n    var data = obj || {};\n    var options = opts || {};\n    var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;\n\n    for (var i = 0; i < tokens.length; i++) {\n      var token = tokens[i];\n\n      if (typeof token === 'string') {\n        path += token;\n\n        continue\n      }\n\n      var value = data[token.name];\n      var segment;\n\n      if (value == null) {\n        if (token.optional) {\n          // Prepend partial segment prefixes.\n          if (token.partial) {\n            path += token.prefix;\n          }\n\n          continue\n        } else {\n          throw new TypeError('Expected \"' + token.name + '\" to be defined')\n        }\n      }\n\n      if (isarray(value)) {\n        if (!token.repeat) {\n          throw new TypeError('Expected \"' + token.name + '\" to not repeat, but received `' + JSON.stringify(value) + '`')\n        }\n\n        if (value.length === 0) {\n          if (token.optional) {\n            continue\n          } else {\n            throw new TypeError('Expected \"' + token.name + '\" to not be empty')\n          }\n        }\n\n        for (var j = 0; j < value.length; j++) {\n          segment = encode(value[j]);\n\n          if (!matches[i].test(segment)) {\n            throw new TypeError('Expected all \"' + token.name + '\" to match \"' + token.pattern + '\", but received `' + JSON.stringify(segment) + '`')\n          }\n\n          path += (j === 0 ? token.prefix : token.delimiter) + segment;\n        }\n\n        continue\n      }\n\n      segment = token.asterisk ? encodeAsterisk(value) : encode(value);\n\n      if (!matches[i].test(segment)) {\n        throw new TypeError('Expected \"' + token.name + '\" to match \"' + token.pattern + '\", but received \"' + segment + '\"')\n      }\n\n      path += token.prefix + segment;\n    }\n\n    return path\n  }\n}\n\n/**\n * Escape a regular expression string.\n *\n * @param  {string} str\n * @return {string}\n */\nfunction escapeString (str) {\n  return str.replace(/([.+*?=^!:${}()[\\]|\\/\\\\])/g, '\\\\$1')\n}\n\n/**\n * Escape the capturing group by escaping special characters and meaning.\n *\n * @param  {string} group\n * @return {string}\n */\nfunction escapeGroup (group) {\n  return group.replace(/([=!:$\\/()])/g, '\\\\$1')\n}\n\n/**\n * Attach the keys as a property of the regexp.\n *\n * @param  {!RegExp} re\n * @param  {Array}   keys\n * @return {!RegExp}\n */\nfunction attachKeys (re, keys) {\n  re.keys = keys;\n  return re\n}\n\n/**\n * Get the flags for a regexp from the options.\n *\n * @param  {Object} options\n * @return {string}\n */\nfunction flags (options) {\n  return options && options.sensitive ? '' : 'i'\n}\n\n/**\n * Pull out keys from a regexp.\n *\n * @param  {!RegExp} path\n * @param  {!Array}  keys\n * @return {!RegExp}\n */\nfunction regexpToRegexp (path, keys) {\n  // Use a negative lookahead to match only capturing groups.\n  var groups = path.source.match(/\\((?!\\?)/g);\n\n  if (groups) {\n    for (var i = 0; i < groups.length; i++) {\n      keys.push({\n        name: i,\n        prefix: null,\n        delimiter: null,\n        optional: false,\n        repeat: false,\n        partial: false,\n        asterisk: false,\n        pattern: null\n      });\n    }\n  }\n\n  return attachKeys(path, keys)\n}\n\n/**\n * Transform an array into a regexp.\n *\n * @param  {!Array}  path\n * @param  {Array}   keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction arrayToRegexp (path, keys, options) {\n  var parts = [];\n\n  for (var i = 0; i < path.length; i++) {\n    parts.push(pathToRegexp(path[i], keys, options).source);\n  }\n\n  var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));\n\n  return attachKeys(regexp, keys)\n}\n\n/**\n * Create a path regexp from string input.\n *\n * @param  {string}  path\n * @param  {!Array}  keys\n * @param  {!Object} options\n * @return {!RegExp}\n */\nfunction stringToRegexp (path, keys, options) {\n  return tokensToRegExp(parse(path, options), keys, options)\n}\n\n/**\n * Expose a function for taking tokens and returning a RegExp.\n *\n * @param  {!Array}          tokens\n * @param  {(Array|Object)=} keys\n * @param  {Object=}         options\n * @return {!RegExp}\n */\nfunction tokensToRegExp (tokens, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  var strict = options.strict;\n  var end = options.end !== false;\n  var route = '';\n\n  // Iterate over the tokens and create our regexp string.\n  for (var i = 0; i < tokens.length; i++) {\n    var token = tokens[i];\n\n    if (typeof token === 'string') {\n      route += escapeString(token);\n    } else {\n      var prefix = escapeString(token.prefix);\n      var capture = '(?:' + token.pattern + ')';\n\n      keys.push(token);\n\n      if (token.repeat) {\n        capture += '(?:' + prefix + capture + ')*';\n      }\n\n      if (token.optional) {\n        if (!token.partial) {\n          capture = '(?:' + prefix + '(' + capture + '))?';\n        } else {\n          capture = prefix + '(' + capture + ')?';\n        }\n      } else {\n        capture = prefix + '(' + capture + ')';\n      }\n\n      route += capture;\n    }\n  }\n\n  var delimiter = escapeString(options.delimiter || '/');\n  var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;\n\n  // In non-strict mode we allow a slash at the end of match. If the path to\n  // match already ends with a slash, we remove it for consistency. The slash\n  // is valid at the end of a path match, not in the middle. This is important\n  // in non-ending mode, where \"/test/\" shouldn't match \"/test//route\".\n  if (!strict) {\n    route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';\n  }\n\n  if (end) {\n    route += '$';\n  } else {\n    // In non-ending mode, we need the capturing groups to match as much as\n    // possible by using a positive lookahead to the end or next path segment.\n    route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';\n  }\n\n  return attachKeys(new RegExp('^' + route, flags(options)), keys)\n}\n\n/**\n * Normalize the given path string, returning a regular expression.\n *\n * An empty array can be passed in for the keys, which will hold the\n * placeholder key descriptions. For example, using `/user/:id`, `keys` will\n * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.\n *\n * @param  {(string|RegExp|Array)} path\n * @param  {(Array|Object)=}       keys\n * @param  {Object=}               options\n * @return {!RegExp}\n */\nfunction pathToRegexp (path, keys, options) {\n  if (!isarray(keys)) {\n    options = /** @type {!Object} */ (keys || options);\n    keys = [];\n  }\n\n  options = options || {};\n\n  if (path instanceof RegExp) {\n    return regexpToRegexp(path, /** @type {!Array} */ (keys))\n  }\n\n  if (isarray(path)) {\n    return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)\n  }\n\n  return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)\n}\npathToRegexp_1.parse = parse_1;\npathToRegexp_1.compile = compile_1;\npathToRegexp_1.tokensToFunction = tokensToFunction_1;\npathToRegexp_1.tokensToRegExp = tokensToRegExp_1;\n\n/*  */\n\n// $flow-disable-line\nvar regexpCompileCache = Object.create(null);\n\nfunction fillParams (\n  path,\n  params,\n  routeMsg\n) {\n  params = params || {};\n  try {\n    var filler =\n      regexpCompileCache[path] ||\n      (regexpCompileCache[path] = pathToRegexp_1.compile(path));\n\n    // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}\n    // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string\n    if (typeof params.pathMatch === 'string') { params[0] = params.pathMatch; }\n\n    return filler(params, { pretty: true })\n  } catch (e) {\n    if (process.env.NODE_ENV !== 'production') {\n      // Fix #3072 no warn if `pathMatch` is string\n      warn(typeof params.pathMatch === 'string', (\"missing param for \" + routeMsg + \": \" + (e.message)));\n    }\n    return ''\n  } finally {\n    // delete the 0 if it was added\n    delete params[0];\n  }\n}\n\n/*  */\n\nfunction normalizeLocation (\n  raw,\n  current,\n  append,\n  router\n) {\n  var next = typeof raw === 'string' ? { path: raw } : raw;\n  // named target\n  if (next._normalized) {\n    return next\n  } else if (next.name) {\n    next = extend({}, raw);\n    var params = next.params;\n    if (params && typeof params === 'object') {\n      next.params = extend({}, params);\n    }\n    return next\n  }\n\n  // relative params\n  if (!next.path && next.params && current) {\n    next = extend({}, next);\n    next._normalized = true;\n    var params$1 = extend(extend({}, current.params), next.params);\n    if (current.name) {\n      next.name = current.name;\n      next.params = params$1;\n    } else if (current.matched.length) {\n      var rawPath = current.matched[current.matched.length - 1].path;\n      next.path = fillParams(rawPath, params$1, (\"path \" + (current.path)));\n    } else if (process.env.NODE_ENV !== 'production') {\n      warn(false, \"relative params navigation requires a current route.\");\n    }\n    return next\n  }\n\n  var parsedPath = parsePath(next.path || '');\n  var basePath = (current && current.path) || '/';\n  var path = parsedPath.path\n    ? resolvePath(parsedPath.path, basePath, append || next.append)\n    : basePath;\n\n  var query = resolveQuery(\n    parsedPath.query,\n    next.query,\n    router && router.options.parseQuery\n  );\n\n  var hash = next.hash || parsedPath.hash;\n  if (hash && hash.charAt(0) !== '#') {\n    hash = \"#\" + hash;\n  }\n\n  return {\n    _normalized: true,\n    path: path,\n    query: query,\n    hash: hash\n  }\n}\n\n/*  */\n\n// work around weird flow bug\nvar toTypes = [String, Object];\nvar eventTypes = [String, Array];\n\nvar noop = function () {};\n\nvar warnedCustomSlot;\nvar warnedTagProp;\nvar warnedEventProp;\n\nvar Link = {\n  name: 'RouterLink',\n  props: {\n    to: {\n      type: toTypes,\n      required: true\n    },\n    tag: {\n      type: String,\n      default: 'a'\n    },\n    custom: Boolean,\n    exact: Boolean,\n    exactPath: Boolean,\n    append: Boolean,\n    replace: Boolean,\n    activeClass: String,\n    exactActiveClass: String,\n    ariaCurrentValue: {\n      type: String,\n      default: 'page'\n    },\n    event: {\n      type: eventTypes,\n      default: 'click'\n    }\n  },\n  render: function render (h) {\n    var this$1$1 = this;\n\n    var router = this.$router;\n    var current = this.$route;\n    var ref = router.resolve(\n      this.to,\n      current,\n      this.append\n    );\n    var location = ref.location;\n    var route = ref.route;\n    var href = ref.href;\n\n    var classes = {};\n    var globalActiveClass = router.options.linkActiveClass;\n    var globalExactActiveClass = router.options.linkExactActiveClass;\n    // Support global empty active class\n    var activeClassFallback =\n      globalActiveClass == null ? 'router-link-active' : globalActiveClass;\n    var exactActiveClassFallback =\n      globalExactActiveClass == null\n        ? 'router-link-exact-active'\n        : globalExactActiveClass;\n    var activeClass =\n      this.activeClass == null ? activeClassFallback : this.activeClass;\n    var exactActiveClass =\n      this.exactActiveClass == null\n        ? exactActiveClassFallback\n        : this.exactActiveClass;\n\n    var compareTarget = route.redirectedFrom\n      ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)\n      : route;\n\n    classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath);\n    classes[activeClass] = this.exact || this.exactPath\n      ? classes[exactActiveClass]\n      : isIncludedRoute(current, compareTarget);\n\n    var ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null;\n\n    var handler = function (e) {\n      if (guardEvent(e)) {\n        if (this$1$1.replace) {\n          router.replace(location, noop);\n        } else {\n          router.push(location, noop);\n        }\n      }\n    };\n\n    var on = { click: guardEvent };\n    if (Array.isArray(this.event)) {\n      this.event.forEach(function (e) {\n        on[e] = handler;\n      });\n    } else {\n      on[this.event] = handler;\n    }\n\n    var data = { class: classes };\n\n    var scopedSlot =\n      !this.$scopedSlots.$hasNormal &&\n      this.$scopedSlots.default &&\n      this.$scopedSlots.default({\n        href: href,\n        route: route,\n        navigate: handler,\n        isActive: classes[activeClass],\n        isExactActive: classes[exactActiveClass]\n      });\n\n    if (scopedSlot) {\n      if (process.env.NODE_ENV !== 'production' && !this.custom) {\n        !warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\\n<router-link v-slot=\"{ navigate, href }\" custom></router-link>\\n');\n        warnedCustomSlot = true;\n      }\n      if (scopedSlot.length === 1) {\n        return scopedSlot[0]\n      } else if (scopedSlot.length > 1 || !scopedSlot.length) {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(\n            false,\n            (\"<router-link> with to=\\\"\" + (this.to) + \"\\\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.\")\n          );\n        }\n        return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)\n      }\n    }\n\n    if (process.env.NODE_ENV !== 'production') {\n      if ('tag' in this.$options.propsData && !warnedTagProp) {\n        warn(\n          false,\n          \"<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n        );\n        warnedTagProp = true;\n      }\n      if ('event' in this.$options.propsData && !warnedEventProp) {\n        warn(\n          false,\n          \"<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.\"\n        );\n        warnedEventProp = true;\n      }\n    }\n\n    if (this.tag === 'a') {\n      data.on = on;\n      data.attrs = { href: href, 'aria-current': ariaCurrentValue };\n    } else {\n      // find the first <a> child and apply listener and href\n      var a = findAnchor(this.$slots.default);\n      if (a) {\n        // in case the <a> is a static node\n        a.isStatic = false;\n        var aData = (a.data = extend({}, a.data));\n        aData.on = aData.on || {};\n        // transform existing events in both objects into arrays so we can push later\n        for (var event in aData.on) {\n          var handler$1 = aData.on[event];\n          if (event in on) {\n            aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];\n          }\n        }\n        // append new listeners for router-link\n        for (var event$1 in on) {\n          if (event$1 in aData.on) {\n            // on[event] is always a function\n            aData.on[event$1].push(on[event$1]);\n          } else {\n            aData.on[event$1] = handler;\n          }\n        }\n\n        var aAttrs = (a.data.attrs = extend({}, a.data.attrs));\n        aAttrs.href = href;\n        aAttrs['aria-current'] = ariaCurrentValue;\n      } else {\n        // doesn't have <a> child, apply listener to self\n        data.on = on;\n      }\n    }\n\n    return h(this.tag, data, this.$slots.default)\n  }\n};\n\nfunction guardEvent (e) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) { return }\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) { return }\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    var target = e.currentTarget.getAttribute('target');\n    if (/\\b_blank\\b/i.test(target)) { return }\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault();\n  }\n  return true\n}\n\nfunction findAnchor (children) {\n  if (children) {\n    var child;\n    for (var i = 0; i < children.length; i++) {\n      child = children[i];\n      if (child.tag === 'a') {\n        return child\n      }\n      if (child.children && (child = findAnchor(child.children))) {\n        return child\n      }\n    }\n  }\n}\n\nvar _Vue;\n\nfunction install (Vue) {\n  if (install.installed && _Vue === Vue) { return }\n  install.installed = true;\n\n  _Vue = Vue;\n\n  var isDef = function (v) { return v !== undefined; };\n\n  var registerInstance = function (vm, callVal) {\n    var i = vm.$options._parentVnode;\n    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {\n      i(vm, callVal);\n    }\n  };\n\n  Vue.mixin({\n    beforeCreate: function beforeCreate () {\n      if (isDef(this.$options.router)) {\n        this._routerRoot = this;\n        this._router = this.$options.router;\n        this._router.init(this);\n        Vue.util.defineReactive(this, '_route', this._router.history.current);\n      } else {\n        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;\n      }\n      registerInstance(this, this);\n    },\n    destroyed: function destroyed () {\n      registerInstance(this);\n    }\n  });\n\n  Object.defineProperty(Vue.prototype, '$router', {\n    get: function get () { return this._routerRoot._router }\n  });\n\n  Object.defineProperty(Vue.prototype, '$route', {\n    get: function get () { return this._routerRoot._route }\n  });\n\n  Vue.component('RouterView', View);\n  Vue.component('RouterLink', Link);\n\n  var strats = Vue.config.optionMergeStrategies;\n  // use the same hook merging strategy for route hooks\n  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;\n}\n\n/*  */\n\nvar inBrowser = typeof window !== 'undefined';\n\n/*  */\n\nfunction createRouteMap (\n  routes,\n  oldPathList,\n  oldPathMap,\n  oldNameMap,\n  parentRoute\n) {\n  // the path list is used to control path matching priority\n  var pathList = oldPathList || [];\n  // $flow-disable-line\n  var pathMap = oldPathMap || Object.create(null);\n  // $flow-disable-line\n  var nameMap = oldNameMap || Object.create(null);\n\n  routes.forEach(function (route) {\n    addRouteRecord(pathList, pathMap, nameMap, route, parentRoute);\n  });\n\n  // ensure wildcard routes are always at the end\n  for (var i = 0, l = pathList.length; i < l; i++) {\n    if (pathList[i] === '*') {\n      pathList.push(pathList.splice(i, 1)[0]);\n      l--;\n      i--;\n    }\n  }\n\n  if (process.env.NODE_ENV === 'development') {\n    // warn if routes do not include leading slashes\n    var found = pathList\n    // check for missing leading slash\n      .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });\n\n    if (found.length > 0) {\n      var pathNames = found.map(function (path) { return (\"- \" + path); }).join('\\n');\n      warn(false, (\"Non-nested routes must include a leading slash character. Fix the following routes: \\n\" + pathNames));\n    }\n  }\n\n  return {\n    pathList: pathList,\n    pathMap: pathMap,\n    nameMap: nameMap\n  }\n}\n\nfunction addRouteRecord (\n  pathList,\n  pathMap,\n  nameMap,\n  route,\n  parent,\n  matchAs\n) {\n  var path = route.path;\n  var name = route.name;\n  if (process.env.NODE_ENV !== 'production') {\n    assert(path != null, \"\\\"path\\\" is required in a route configuration.\");\n    assert(\n      typeof route.component !== 'string',\n      \"route config \\\"component\\\" for path: \" + (String(\n        path || name\n      )) + \" cannot be a \" + \"string id. Use an actual component instead.\"\n    );\n\n    warn(\n      // eslint-disable-next-line no-control-regex\n      !/[^\\u0000-\\u007F]+/.test(path),\n      \"Route with path \\\"\" + path + \"\\\" contains unencoded characters, make sure \" +\n        \"your path is correctly encoded before passing it to the router. Use \" +\n        \"encodeURI to encode static segments of your path.\"\n    );\n  }\n\n  var pathToRegexpOptions =\n    route.pathToRegexpOptions || {};\n  var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);\n\n  if (typeof route.caseSensitive === 'boolean') {\n    pathToRegexpOptions.sensitive = route.caseSensitive;\n  }\n\n  var record = {\n    path: normalizedPath,\n    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),\n    components: route.components || { default: route.component },\n    alias: route.alias\n      ? typeof route.alias === 'string'\n        ? [route.alias]\n        : route.alias\n      : [],\n    instances: {},\n    enteredCbs: {},\n    name: name,\n    parent: parent,\n    matchAs: matchAs,\n    redirect: route.redirect,\n    beforeEnter: route.beforeEnter,\n    meta: route.meta || {},\n    props:\n      route.props == null\n        ? {}\n        : route.components\n          ? route.props\n          : { default: route.props }\n  };\n\n  if (route.children) {\n    // Warn if route is named, does not redirect and has a default child route.\n    // If users navigate to this route by name, the default child will\n    // not be rendered (GH Issue #629)\n    if (process.env.NODE_ENV !== 'production') {\n      if (\n        route.name &&\n        !route.redirect &&\n        route.children.some(function (child) { return /^\\/?$/.test(child.path); })\n      ) {\n        warn(\n          false,\n          \"Named Route '\" + (route.name) + \"' has a default child route. \" +\n            \"When navigating to this named route (:to=\\\"{name: '\" + (route.name) + \"'}\\\"), \" +\n            \"the default child route will not be rendered. Remove the name from \" +\n            \"this route and use the name of the default child route for named \" +\n            \"links instead.\"\n        );\n      }\n    }\n    route.children.forEach(function (child) {\n      var childMatchAs = matchAs\n        ? cleanPath((matchAs + \"/\" + (child.path)))\n        : undefined;\n      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);\n    });\n  }\n\n  if (!pathMap[record.path]) {\n    pathList.push(record.path);\n    pathMap[record.path] = record;\n  }\n\n  if (route.alias !== undefined) {\n    var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];\n    for (var i = 0; i < aliases.length; ++i) {\n      var alias = aliases[i];\n      if (process.env.NODE_ENV !== 'production' && alias === path) {\n        warn(\n          false,\n          (\"Found an alias with the same value as the path: \\\"\" + path + \"\\\". You have to remove that alias. It will be ignored in development.\")\n        );\n        // skip in dev to make it work\n        continue\n      }\n\n      var aliasRoute = {\n        path: alias,\n        children: route.children\n      };\n      addRouteRecord(\n        pathList,\n        pathMap,\n        nameMap,\n        aliasRoute,\n        parent,\n        record.path || '/' // matchAs\n      );\n    }\n  }\n\n  if (name) {\n    if (!nameMap[name]) {\n      nameMap[name] = record;\n    } else if (process.env.NODE_ENV !== 'production' && !matchAs) {\n      warn(\n        false,\n        \"Duplicate named routes definition: \" +\n          \"{ name: \\\"\" + name + \"\\\", path: \\\"\" + (record.path) + \"\\\" }\"\n      );\n    }\n  }\n}\n\nfunction compileRouteRegex (\n  path,\n  pathToRegexpOptions\n) {\n  var regex = pathToRegexp_1(path, [], pathToRegexpOptions);\n  if (process.env.NODE_ENV !== 'production') {\n    var keys = Object.create(null);\n    regex.keys.forEach(function (key) {\n      warn(\n        !keys[key.name],\n        (\"Duplicate param keys in route with path: \\\"\" + path + \"\\\"\")\n      );\n      keys[key.name] = true;\n    });\n  }\n  return regex\n}\n\nfunction normalizePath (\n  path,\n  parent,\n  strict\n) {\n  if (!strict) { path = path.replace(/\\/$/, ''); }\n  if (path[0] === '/') { return path }\n  if (parent == null) { return path }\n  return cleanPath(((parent.path) + \"/\" + path))\n}\n\n/*  */\n\n\n\nfunction createMatcher (\n  routes,\n  router\n) {\n  var ref = createRouteMap(routes);\n  var pathList = ref.pathList;\n  var pathMap = ref.pathMap;\n  var nameMap = ref.nameMap;\n\n  function addRoutes (routes) {\n    createRouteMap(routes, pathList, pathMap, nameMap);\n  }\n\n  function addRoute (parentOrRoute, route) {\n    var parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined;\n    // $flow-disable-line\n    createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent);\n\n    // add aliases of parent\n    if (parent && parent.alias.length) {\n      createRouteMap(\n        // $flow-disable-line route is defined if parent is\n        parent.alias.map(function (alias) { return ({ path: alias, children: [route] }); }),\n        pathList,\n        pathMap,\n        nameMap,\n        parent\n      );\n    }\n  }\n\n  function getRoutes () {\n    return pathList.map(function (path) { return pathMap[path]; })\n  }\n\n  function match (\n    raw,\n    currentRoute,\n    redirectedFrom\n  ) {\n    var location = normalizeLocation(raw, currentRoute, false, router);\n    var name = location.name;\n\n    if (name) {\n      var record = nameMap[name];\n      if (process.env.NODE_ENV !== 'production') {\n        warn(record, (\"Route with name '\" + name + \"' does not exist\"));\n      }\n      if (!record) { return _createRoute(null, location) }\n      var paramNames = record.regex.keys\n        .filter(function (key) { return !key.optional; })\n        .map(function (key) { return key.name; });\n\n      if (typeof location.params !== 'object') {\n        location.params = {};\n      }\n\n      if (currentRoute && typeof currentRoute.params === 'object') {\n        for (var key in currentRoute.params) {\n          if (!(key in location.params) && paramNames.indexOf(key) > -1) {\n            location.params[key] = currentRoute.params[key];\n          }\n        }\n      }\n\n      location.path = fillParams(record.path, location.params, (\"named route \\\"\" + name + \"\\\"\"));\n      return _createRoute(record, location, redirectedFrom)\n    } else if (location.path) {\n      location.params = {};\n      for (var i = 0; i < pathList.length; i++) {\n        var path = pathList[i];\n        var record$1 = pathMap[path];\n        if (matchRoute(record$1.regex, location.path, location.params)) {\n          return _createRoute(record$1, location, redirectedFrom)\n        }\n      }\n    }\n    // no match\n    return _createRoute(null, location)\n  }\n\n  function redirect (\n    record,\n    location\n  ) {\n    var originalRedirect = record.redirect;\n    var redirect = typeof originalRedirect === 'function'\n      ? originalRedirect(createRoute(record, location, null, router))\n      : originalRedirect;\n\n    if (typeof redirect === 'string') {\n      redirect = { path: redirect };\n    }\n\n    if (!redirect || typeof redirect !== 'object') {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false, (\"invalid redirect option: \" + (JSON.stringify(redirect)))\n        );\n      }\n      return _createRoute(null, location)\n    }\n\n    var re = redirect;\n    var name = re.name;\n    var path = re.path;\n    var query = location.query;\n    var hash = location.hash;\n    var params = location.params;\n    query = re.hasOwnProperty('query') ? re.query : query;\n    hash = re.hasOwnProperty('hash') ? re.hash : hash;\n    params = re.hasOwnProperty('params') ? re.params : params;\n\n    if (name) {\n      // resolved named direct\n      var targetRecord = nameMap[name];\n      if (process.env.NODE_ENV !== 'production') {\n        assert(targetRecord, (\"redirect failed: named route \\\"\" + name + \"\\\" not found.\"));\n      }\n      return match({\n        _normalized: true,\n        name: name,\n        query: query,\n        hash: hash,\n        params: params\n      }, undefined, location)\n    } else if (path) {\n      // 1. resolve relative redirect\n      var rawPath = resolveRecordPath(path, record);\n      // 2. resolve params\n      var resolvedPath = fillParams(rawPath, params, (\"redirect route with path \\\"\" + rawPath + \"\\\"\"));\n      // 3. rematch with existing query and hash\n      return match({\n        _normalized: true,\n        path: resolvedPath,\n        query: query,\n        hash: hash\n      }, undefined, location)\n    } else {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(false, (\"invalid redirect option: \" + (JSON.stringify(redirect))));\n      }\n      return _createRoute(null, location)\n    }\n  }\n\n  function alias (\n    record,\n    location,\n    matchAs\n  ) {\n    var aliasedPath = fillParams(matchAs, location.params, (\"aliased route with path \\\"\" + matchAs + \"\\\"\"));\n    var aliasedMatch = match({\n      _normalized: true,\n      path: aliasedPath\n    });\n    if (aliasedMatch) {\n      var matched = aliasedMatch.matched;\n      var aliasedRecord = matched[matched.length - 1];\n      location.params = aliasedMatch.params;\n      return _createRoute(aliasedRecord, location)\n    }\n    return _createRoute(null, location)\n  }\n\n  function _createRoute (\n    record,\n    location,\n    redirectedFrom\n  ) {\n    if (record && record.redirect) {\n      return redirect(record, redirectedFrom || location)\n    }\n    if (record && record.matchAs) {\n      return alias(record, location, record.matchAs)\n    }\n    return createRoute(record, location, redirectedFrom, router)\n  }\n\n  return {\n    match: match,\n    addRoute: addRoute,\n    getRoutes: getRoutes,\n    addRoutes: addRoutes\n  }\n}\n\nfunction matchRoute (\n  regex,\n  path,\n  params\n) {\n  var m = path.match(regex);\n\n  if (!m) {\n    return false\n  } else if (!params) {\n    return true\n  }\n\n  for (var i = 1, len = m.length; i < len; ++i) {\n    var key = regex.keys[i - 1];\n    if (key) {\n      // Fix #1994: using * with props: true generates a param named 0\n      params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i];\n    }\n  }\n\n  return true\n}\n\nfunction resolveRecordPath (path, record) {\n  return resolvePath(path, record.parent ? record.parent.path : '/', true)\n}\n\n/*  */\n\n// use User Timing api (if present) for more accurate key precision\nvar Time =\n  inBrowser && window.performance && window.performance.now\n    ? window.performance\n    : Date;\n\nfunction genStateKey () {\n  return Time.now().toFixed(3)\n}\n\nvar _key = genStateKey();\n\nfunction getStateKey () {\n  return _key\n}\n\nfunction setStateKey (key) {\n  return (_key = key)\n}\n\n/*  */\n\nvar positionStore = Object.create(null);\n\nfunction setupScroll () {\n  // Prevent browser scroll behavior on History popstate\n  if ('scrollRestoration' in window.history) {\n    window.history.scrollRestoration = 'manual';\n  }\n  // Fix for #1585 for Firefox\n  // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678\n  // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with\n  // window.location.protocol + '//' + window.location.host\n  // location.host contains the port and location.hostname doesn't\n  var protocolAndPath = window.location.protocol + '//' + window.location.host;\n  var absolutePath = window.location.href.replace(protocolAndPath, '');\n  // preserve existing history state as it could be overriden by the user\n  var stateCopy = extend({}, window.history.state);\n  stateCopy.key = getStateKey();\n  window.history.replaceState(stateCopy, '', absolutePath);\n  window.addEventListener('popstate', handlePopState);\n  return function () {\n    window.removeEventListener('popstate', handlePopState);\n  }\n}\n\nfunction handleScroll (\n  router,\n  to,\n  from,\n  isPop\n) {\n  if (!router.app) {\n    return\n  }\n\n  var behavior = router.options.scrollBehavior;\n  if (!behavior) {\n    return\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    assert(typeof behavior === 'function', \"scrollBehavior must be a function\");\n  }\n\n  // wait until re-render finishes before scrolling\n  router.app.$nextTick(function () {\n    var position = getScrollPosition();\n    var shouldScroll = behavior.call(\n      router,\n      to,\n      from,\n      isPop ? position : null\n    );\n\n    if (!shouldScroll) {\n      return\n    }\n\n    if (typeof shouldScroll.then === 'function') {\n      shouldScroll\n        .then(function (shouldScroll) {\n          scrollToPosition((shouldScroll), position);\n        })\n        .catch(function (err) {\n          if (process.env.NODE_ENV !== 'production') {\n            assert(false, err.toString());\n          }\n        });\n    } else {\n      scrollToPosition(shouldScroll, position);\n    }\n  });\n}\n\nfunction saveScrollPosition () {\n  var key = getStateKey();\n  if (key) {\n    positionStore[key] = {\n      x: window.pageXOffset,\n      y: window.pageYOffset\n    };\n  }\n}\n\nfunction handlePopState (e) {\n  saveScrollPosition();\n  if (e.state && e.state.key) {\n    setStateKey(e.state.key);\n  }\n}\n\nfunction getScrollPosition () {\n  var key = getStateKey();\n  if (key) {\n    return positionStore[key]\n  }\n}\n\nfunction getElementPosition (el, offset) {\n  var docEl = document.documentElement;\n  var docRect = docEl.getBoundingClientRect();\n  var elRect = el.getBoundingClientRect();\n  return {\n    x: elRect.left - docRect.left - offset.x,\n    y: elRect.top - docRect.top - offset.y\n  }\n}\n\nfunction isValidPosition (obj) {\n  return isNumber(obj.x) || isNumber(obj.y)\n}\n\nfunction normalizePosition (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : window.pageXOffset,\n    y: isNumber(obj.y) ? obj.y : window.pageYOffset\n  }\n}\n\nfunction normalizeOffset (obj) {\n  return {\n    x: isNumber(obj.x) ? obj.x : 0,\n    y: isNumber(obj.y) ? obj.y : 0\n  }\n}\n\nfunction isNumber (v) {\n  return typeof v === 'number'\n}\n\nvar hashStartsWithNumberRE = /^#\\d/;\n\nfunction scrollToPosition (shouldScroll, position) {\n  var isObject = typeof shouldScroll === 'object';\n  if (isObject && typeof shouldScroll.selector === 'string') {\n    // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]\n    // but at the same time, it doesn't make much sense to select an element with an id and an extra selector\n    var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line\n      ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line\n      : document.querySelector(shouldScroll.selector);\n\n    if (el) {\n      var offset =\n        shouldScroll.offset && typeof shouldScroll.offset === 'object'\n          ? shouldScroll.offset\n          : {};\n      offset = normalizeOffset(offset);\n      position = getElementPosition(el, offset);\n    } else if (isValidPosition(shouldScroll)) {\n      position = normalizePosition(shouldScroll);\n    }\n  } else if (isObject && isValidPosition(shouldScroll)) {\n    position = normalizePosition(shouldScroll);\n  }\n\n  if (position) {\n    // $flow-disable-line\n    if ('scrollBehavior' in document.documentElement.style) {\n      window.scrollTo({\n        left: position.x,\n        top: position.y,\n        // $flow-disable-line\n        behavior: shouldScroll.behavior\n      });\n    } else {\n      window.scrollTo(position.x, position.y);\n    }\n  }\n}\n\n/*  */\n\nvar supportsPushState =\n  inBrowser &&\n  (function () {\n    var ua = window.navigator.userAgent;\n\n    if (\n      (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&\n      ua.indexOf('Mobile Safari') !== -1 &&\n      ua.indexOf('Chrome') === -1 &&\n      ua.indexOf('Windows Phone') === -1\n    ) {\n      return false\n    }\n\n    return window.history && typeof window.history.pushState === 'function'\n  })();\n\nfunction pushState (url, replace) {\n  saveScrollPosition();\n  // try...catch the pushState call to get around Safari\n  // DOM Exception 18 where it limits to 100 pushState calls\n  var history = window.history;\n  try {\n    if (replace) {\n      // preserve existing history state as it could be overriden by the user\n      var stateCopy = extend({}, history.state);\n      stateCopy.key = getStateKey();\n      history.replaceState(stateCopy, '', url);\n    } else {\n      history.pushState({ key: setStateKey(genStateKey()) }, '', url);\n    }\n  } catch (e) {\n    window.location[replace ? 'replace' : 'assign'](url);\n  }\n}\n\nfunction replaceState (url) {\n  pushState(url, true);\n}\n\n// When changing thing, also edit router.d.ts\nvar NavigationFailureType = {\n  redirected: 2,\n  aborted: 4,\n  cancelled: 8,\n  duplicated: 16\n};\n\nfunction createNavigationRedirectedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.redirected,\n    (\"Redirected when going from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (stringifyRoute(\n      to\n    )) + \"\\\" via a navigation guard.\")\n  )\n}\n\nfunction createNavigationDuplicatedError (from, to) {\n  var error = createRouterError(\n    from,\n    to,\n    NavigationFailureType.duplicated,\n    (\"Avoided redundant navigation to current location: \\\"\" + (from.fullPath) + \"\\\".\")\n  );\n  // backwards compatible with the first introduction of Errors\n  error.name = 'NavigationDuplicated';\n  return error\n}\n\nfunction createNavigationCancelledError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.cancelled,\n    (\"Navigation cancelled from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" with a new navigation.\")\n  )\n}\n\nfunction createNavigationAbortedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.aborted,\n    (\"Navigation aborted from \\\"\" + (from.fullPath) + \"\\\" to \\\"\" + (to.fullPath) + \"\\\" via a navigation guard.\")\n  )\n}\n\nfunction createRouterError (from, to, type, message) {\n  var error = new Error(message);\n  error._isRouter = true;\n  error.from = from;\n  error.to = to;\n  error.type = type;\n\n  return error\n}\n\nvar propertiesToLog = ['params', 'query', 'hash'];\n\nfunction stringifyRoute (to) {\n  if (typeof to === 'string') { return to }\n  if ('path' in to) { return to.path }\n  var location = {};\n  propertiesToLog.forEach(function (key) {\n    if (key in to) { location[key] = to[key]; }\n  });\n  return JSON.stringify(location, null, 2)\n}\n\nfunction isError (err) {\n  return Object.prototype.toString.call(err).indexOf('Error') > -1\n}\n\nfunction isNavigationFailure (err, errorType) {\n  return (\n    isError(err) &&\n    err._isRouter &&\n    (errorType == null || err.type === errorType)\n  )\n}\n\n/*  */\n\nfunction runQueue (queue, fn, cb) {\n  var step = function (index) {\n    if (index >= queue.length) {\n      cb();\n    } else {\n      if (queue[index]) {\n        fn(queue[index], function () {\n          step(index + 1);\n        });\n      } else {\n        step(index + 1);\n      }\n    }\n  };\n  step(0);\n}\n\n/*  */\n\nfunction resolveAsyncComponents (matched) {\n  return function (to, from, next) {\n    var hasAsync = false;\n    var pending = 0;\n    var error = null;\n\n    flatMapComponents(matched, function (def, _, match, key) {\n      // if it's a function and doesn't have cid attached,\n      // assume it's an async component resolve function.\n      // we are not using Vue's default async resolving mechanism because\n      // we want to halt the navigation until the incoming component has been\n      // resolved.\n      if (typeof def === 'function' && def.cid === undefined) {\n        hasAsync = true;\n        pending++;\n\n        var resolve = once(function (resolvedDef) {\n          if (isESModule(resolvedDef)) {\n            resolvedDef = resolvedDef.default;\n          }\n          // save resolved on async factory in case it's used elsewhere\n          def.resolved = typeof resolvedDef === 'function'\n            ? resolvedDef\n            : _Vue.extend(resolvedDef);\n          match.components[key] = resolvedDef;\n          pending--;\n          if (pending <= 0) {\n            next();\n          }\n        });\n\n        var reject = once(function (reason) {\n          var msg = \"Failed to resolve async component \" + key + \": \" + reason;\n          process.env.NODE_ENV !== 'production' && warn(false, msg);\n          if (!error) {\n            error = isError(reason)\n              ? reason\n              : new Error(msg);\n            next(error);\n          }\n        });\n\n        var res;\n        try {\n          res = def(resolve, reject);\n        } catch (e) {\n          reject(e);\n        }\n        if (res) {\n          if (typeof res.then === 'function') {\n            res.then(resolve, reject);\n          } else {\n            // new syntax in Vue 2.3\n            var comp = res.component;\n            if (comp && typeof comp.then === 'function') {\n              comp.then(resolve, reject);\n            }\n          }\n        }\n      }\n    });\n\n    if (!hasAsync) { next(); }\n  }\n}\n\nfunction flatMapComponents (\n  matched,\n  fn\n) {\n  return flatten(matched.map(function (m) {\n    return Object.keys(m.components).map(function (key) { return fn(\n      m.components[key],\n      m.instances[key],\n      m, key\n    ); })\n  }))\n}\n\nfunction flatten (arr) {\n  return Array.prototype.concat.apply([], arr)\n}\n\nvar hasSymbol =\n  typeof Symbol === 'function' &&\n  typeof Symbol.toStringTag === 'symbol';\n\nfunction isESModule (obj) {\n  return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')\n}\n\n// in Webpack 2, require.ensure now also returns a Promise\n// so the resolve/reject functions may get called an extra time\n// if the user uses an arrow function shorthand that happens to\n// return that Promise.\nfunction once (fn) {\n  var called = false;\n  return function () {\n    var args = [], len = arguments.length;\n    while ( len-- ) args[ len ] = arguments[ len ];\n\n    if (called) { return }\n    called = true;\n    return fn.apply(this, args)\n  }\n}\n\n/*  */\n\nvar History = function History (router, base) {\n  this.router = router;\n  this.base = normalizeBase(base);\n  // start with a route object that stands for \"nowhere\"\n  this.current = START;\n  this.pending = null;\n  this.ready = false;\n  this.readyCbs = [];\n  this.readyErrorCbs = [];\n  this.errorCbs = [];\n  this.listeners = [];\n};\n\nHistory.prototype.listen = function listen (cb) {\n  this.cb = cb;\n};\n\nHistory.prototype.onReady = function onReady (cb, errorCb) {\n  if (this.ready) {\n    cb();\n  } else {\n    this.readyCbs.push(cb);\n    if (errorCb) {\n      this.readyErrorCbs.push(errorCb);\n    }\n  }\n};\n\nHistory.prototype.onError = function onError (errorCb) {\n  this.errorCbs.push(errorCb);\n};\n\nHistory.prototype.transitionTo = function transitionTo (\n  location,\n  onComplete,\n  onAbort\n) {\n    var this$1$1 = this;\n\n  var route;\n  // catch redirect option https://github.com/vuejs/vue-router/issues/3201\n  try {\n    route = this.router.match(location, this.current);\n  } catch (e) {\n    this.errorCbs.forEach(function (cb) {\n      cb(e);\n    });\n    // Exception should still be thrown\n    throw e\n  }\n  var prev = this.current;\n  this.confirmTransition(\n    route,\n    function () {\n      this$1$1.updateRoute(route);\n      onComplete && onComplete(route);\n      this$1$1.ensureURL();\n      this$1$1.router.afterHooks.forEach(function (hook) {\n        hook && hook(route, prev);\n      });\n\n      // fire ready cbs once\n      if (!this$1$1.ready) {\n        this$1$1.ready = true;\n        this$1$1.readyCbs.forEach(function (cb) {\n          cb(route);\n        });\n      }\n    },\n    function (err) {\n      if (onAbort) {\n        onAbort(err);\n      }\n      if (err && !this$1$1.ready) {\n        // Initial redirection should not mark the history as ready yet\n        // because it's triggered by the redirection instead\n        // https://github.com/vuejs/vue-router/issues/3225\n        // https://github.com/vuejs/vue-router/issues/3331\n        if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {\n          this$1$1.ready = true;\n          this$1$1.readyErrorCbs.forEach(function (cb) {\n            cb(err);\n          });\n        }\n      }\n    }\n  );\n};\n\nHistory.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  var current = this.current;\n  this.pending = route;\n  var abort = function (err) {\n    // changed after adding errors with\n    // https://github.com/vuejs/vue-router/pull/3047 before that change,\n    // redirect and aborted navigation would produce an err == null\n    if (!isNavigationFailure(err) && isError(err)) {\n      if (this$1$1.errorCbs.length) {\n        this$1$1.errorCbs.forEach(function (cb) {\n          cb(err);\n        });\n      } else {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(false, 'uncaught error during route navigation:');\n        }\n        console.error(err);\n      }\n    }\n    onAbort && onAbort(err);\n  };\n  var lastRouteIndex = route.matched.length - 1;\n  var lastCurrentIndex = current.matched.length - 1;\n  if (\n    isSameRoute(route, current) &&\n    // in the case the route map has been dynamically appended to\n    lastRouteIndex === lastCurrentIndex &&\n    route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]\n  ) {\n    this.ensureURL();\n    if (route.hash) {\n      handleScroll(this.router, current, route, false);\n    }\n    return abort(createNavigationDuplicatedError(current, route))\n  }\n\n  var ref = resolveQueue(\n    this.current.matched,\n    route.matched\n  );\n    var updated = ref.updated;\n    var deactivated = ref.deactivated;\n    var activated = ref.activated;\n\n  var queue = [].concat(\n    // in-component leave guards\n    extractLeaveGuards(deactivated),\n    // global before hooks\n    this.router.beforeHooks,\n    // in-component update hooks\n    extractUpdateHooks(updated),\n    // in-config enter guards\n    activated.map(function (m) { return m.beforeEnter; }),\n    // async components\n    resolveAsyncComponents(activated)\n  );\n\n  var iterator = function (hook, next) {\n    if (this$1$1.pending !== route) {\n      return abort(createNavigationCancelledError(current, route))\n    }\n    try {\n      hook(route, current, function (to) {\n        if (to === false) {\n          // next(false) -> abort navigation, ensure current URL\n          this$1$1.ensureURL(true);\n          abort(createNavigationAbortedError(current, route));\n        } else if (isError(to)) {\n          this$1$1.ensureURL(true);\n          abort(to);\n        } else if (\n          typeof to === 'string' ||\n          (typeof to === 'object' &&\n            (typeof to.path === 'string' || typeof to.name === 'string'))\n        ) {\n          // next('/') or next({ path: '/' }) -> redirect\n          abort(createNavigationRedirectedError(current, route));\n          if (typeof to === 'object' && to.replace) {\n            this$1$1.replace(to);\n          } else {\n            this$1$1.push(to);\n          }\n        } else {\n          // confirm transition and pass on the value\n          next(to);\n        }\n      });\n    } catch (e) {\n      abort(e);\n    }\n  };\n\n  runQueue(queue, iterator, function () {\n    // wait until async components are resolved before\n    // extracting in-component enter guards\n    var enterGuards = extractEnterGuards(activated);\n    var queue = enterGuards.concat(this$1$1.router.resolveHooks);\n    runQueue(queue, iterator, function () {\n      if (this$1$1.pending !== route) {\n        return abort(createNavigationCancelledError(current, route))\n      }\n      this$1$1.pending = null;\n      onComplete(route);\n      if (this$1$1.router.app) {\n        this$1$1.router.app.$nextTick(function () {\n          handleRouteEntered(route);\n        });\n      }\n    });\n  });\n};\n\nHistory.prototype.updateRoute = function updateRoute (route) {\n  this.current = route;\n  this.cb && this.cb(route);\n};\n\nHistory.prototype.setupListeners = function setupListeners () {\n  // Default implementation is empty\n};\n\nHistory.prototype.teardown = function teardown () {\n  // clean up event listeners\n  // https://github.com/vuejs/vue-router/issues/2341\n  this.listeners.forEach(function (cleanupListener) {\n    cleanupListener();\n  });\n  this.listeners = [];\n\n  // reset current history route\n  // https://github.com/vuejs/vue-router/issues/3294\n  this.current = START;\n  this.pending = null;\n};\n\nfunction normalizeBase (base) {\n  if (!base) {\n    if (inBrowser) {\n      // respect <base> tag\n      var baseEl = document.querySelector('base');\n      base = (baseEl && baseEl.getAttribute('href')) || '/';\n      // strip full URL origin\n      base = base.replace(/^https?:\\/\\/[^\\/]+/, '');\n    } else {\n      base = '/';\n    }\n  }\n  // make sure there's the starting slash\n  if (base.charAt(0) !== '/') {\n    base = '/' + base;\n  }\n  // remove trailing slash\n  return base.replace(/\\/$/, '')\n}\n\nfunction resolveQueue (\n  current,\n  next\n) {\n  var i;\n  var max = Math.max(current.length, next.length);\n  for (i = 0; i < max; i++) {\n    if (current[i] !== next[i]) {\n      break\n    }\n  }\n  return {\n    updated: next.slice(0, i),\n    activated: next.slice(i),\n    deactivated: current.slice(i)\n  }\n}\n\nfunction extractGuards (\n  records,\n  name,\n  bind,\n  reverse\n) {\n  var guards = flatMapComponents(records, function (def, instance, match, key) {\n    var guard = extractGuard(def, name);\n    if (guard) {\n      return Array.isArray(guard)\n        ? guard.map(function (guard) { return bind(guard, instance, match, key); })\n        : bind(guard, instance, match, key)\n    }\n  });\n  return flatten(reverse ? guards.reverse() : guards)\n}\n\nfunction extractGuard (\n  def,\n  key\n) {\n  if (typeof def !== 'function') {\n    // extend now so that global mixins are applied.\n    def = _Vue.extend(def);\n  }\n  return def.options[key]\n}\n\nfunction extractLeaveGuards (deactivated) {\n  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)\n}\n\nfunction extractUpdateHooks (updated) {\n  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)\n}\n\nfunction bindGuard (guard, instance) {\n  if (instance) {\n    return function boundRouteGuard () {\n      return guard.apply(instance, arguments)\n    }\n  }\n}\n\nfunction extractEnterGuards (\n  activated\n) {\n  return extractGuards(\n    activated,\n    'beforeRouteEnter',\n    function (guard, _, match, key) {\n      return bindEnterGuard(guard, match, key)\n    }\n  )\n}\n\nfunction bindEnterGuard (\n  guard,\n  match,\n  key\n) {\n  return function routeEnterGuard (to, from, next) {\n    return guard(to, from, function (cb) {\n      if (typeof cb === 'function') {\n        if (!match.enteredCbs[key]) {\n          match.enteredCbs[key] = [];\n        }\n        match.enteredCbs[key].push(cb);\n      }\n      next(cb);\n    })\n  }\n}\n\n/*  */\n\nvar HTML5History = /*@__PURE__*/(function (History) {\n  function HTML5History (router, base) {\n    History.call(this, router, base);\n\n    this._startLocation = getLocation(this.base);\n  }\n\n  if ( History ) HTML5History.__proto__ = History;\n  HTML5History.prototype = Object.create( History && History.prototype );\n  HTML5History.prototype.constructor = HTML5History;\n\n  HTML5History.prototype.setupListeners = function setupListeners () {\n    var this$1$1 = this;\n\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    var router = this.router;\n    var expectScroll = router.options.scrollBehavior;\n    var supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    var handleRoutingEvent = function () {\n      var current = this$1$1.current;\n\n      // Avoiding first `popstate` event dispatched in some browsers but first\n      // history route not updated since async guard at the same time.\n      var location = getLocation(this$1$1.base);\n      if (this$1$1.current === START && location === this$1$1._startLocation) {\n        return\n      }\n\n      this$1$1.transitionTo(location, function (route) {\n        if (supportsScroll) {\n          handleScroll(router, route, current, true);\n        }\n      });\n    };\n    window.addEventListener('popstate', handleRoutingEvent);\n    this.listeners.push(function () {\n      window.removeEventListener('popstate', handleRoutingEvent);\n    });\n  };\n\n  HTML5History.prototype.go = function go (n) {\n    window.history.go(n);\n  };\n\n  HTML5History.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(location, function (route) {\n      pushState(cleanPath(this$1$1.base + route.fullPath));\n      handleScroll(this$1$1.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  };\n\n  HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(location, function (route) {\n      replaceState(cleanPath(this$1$1.base + route.fullPath));\n      handleScroll(this$1$1.router, route, fromRoute, false);\n      onComplete && onComplete(route);\n    }, onAbort);\n  };\n\n  HTML5History.prototype.ensureURL = function ensureURL (push) {\n    if (getLocation(this.base) !== this.current.fullPath) {\n      var current = cleanPath(this.base + this.current.fullPath);\n      push ? pushState(current) : replaceState(current);\n    }\n  };\n\n  HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {\n    return getLocation(this.base)\n  };\n\n  return HTML5History;\n}(History));\n\nfunction getLocation (base) {\n  var path = window.location.pathname;\n  var pathLowerCase = path.toLowerCase();\n  var baseLowerCase = base.toLowerCase();\n  // base=\"/a\" shouldn't turn path=\"/app\" into \"/a/pp\"\n  // https://github.com/vuejs/vue-router/issues/3555\n  // so we ensure the trailing slash in the base\n  if (base && ((pathLowerCase === baseLowerCase) ||\n    (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {\n    path = path.slice(base.length);\n  }\n  return (path || '/') + window.location.search + window.location.hash\n}\n\n/*  */\n\nvar HashHistory = /*@__PURE__*/(function (History) {\n  function HashHistory (router, base, fallback) {\n    History.call(this, router, base);\n    // check history fallback deeplinking\n    if (fallback && checkFallback(this.base)) {\n      return\n    }\n    ensureSlash();\n  }\n\n  if ( History ) HashHistory.__proto__ = History;\n  HashHistory.prototype = Object.create( History && History.prototype );\n  HashHistory.prototype.constructor = HashHistory;\n\n  // this is delayed until the app mounts\n  // to avoid the hashchange listener being fired too early\n  HashHistory.prototype.setupListeners = function setupListeners () {\n    var this$1$1 = this;\n\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    var router = this.router;\n    var expectScroll = router.options.scrollBehavior;\n    var supportsScroll = supportsPushState && expectScroll;\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll());\n    }\n\n    var handleRoutingEvent = function () {\n      var current = this$1$1.current;\n      if (!ensureSlash()) {\n        return\n      }\n      this$1$1.transitionTo(getHash(), function (route) {\n        if (supportsScroll) {\n          handleScroll(this$1$1.router, route, current, true);\n        }\n        if (!supportsPushState) {\n          replaceHash(route.fullPath);\n        }\n      });\n    };\n    var eventType = supportsPushState ? 'popstate' : 'hashchange';\n    window.addEventListener(\n      eventType,\n      handleRoutingEvent\n    );\n    this.listeners.push(function () {\n      window.removeEventListener(eventType, handleRoutingEvent);\n    });\n  };\n\n  HashHistory.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(\n      location,\n      function (route) {\n        pushHash(route.fullPath);\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    var ref = this;\n    var fromRoute = ref.current;\n    this.transitionTo(\n      location,\n      function (route) {\n        replaceHash(route.fullPath);\n        handleScroll(this$1$1.router, route, fromRoute, false);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  HashHistory.prototype.go = function go (n) {\n    window.history.go(n);\n  };\n\n  HashHistory.prototype.ensureURL = function ensureURL (push) {\n    var current = this.current.fullPath;\n    if (getHash() !== current) {\n      push ? pushHash(current) : replaceHash(current);\n    }\n  };\n\n  HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n    return getHash()\n  };\n\n  return HashHistory;\n}(History));\n\nfunction checkFallback (base) {\n  var location = getLocation(base);\n  if (!/^\\/#/.test(location)) {\n    window.location.replace(cleanPath(base + '/#' + location));\n    return true\n  }\n}\n\nfunction ensureSlash () {\n  var path = getHash();\n  if (path.charAt(0) === '/') {\n    return true\n  }\n  replaceHash('/' + path);\n  return false\n}\n\nfunction getHash () {\n  // We can't use window.location.hash here because it's not\n  // consistent across browsers - Firefox will pre-decode it!\n  var href = window.location.href;\n  var index = href.indexOf('#');\n  // empty path\n  if (index < 0) { return '' }\n\n  href = href.slice(index + 1);\n\n  return href\n}\n\nfunction getUrl (path) {\n  var href = window.location.href;\n  var i = href.indexOf('#');\n  var base = i >= 0 ? href.slice(0, i) : href;\n  return (base + \"#\" + path)\n}\n\nfunction pushHash (path) {\n  if (supportsPushState) {\n    pushState(getUrl(path));\n  } else {\n    window.location.hash = path;\n  }\n}\n\nfunction replaceHash (path) {\n  if (supportsPushState) {\n    replaceState(getUrl(path));\n  } else {\n    window.location.replace(getUrl(path));\n  }\n}\n\n/*  */\n\nvar AbstractHistory = /*@__PURE__*/(function (History) {\n  function AbstractHistory (router, base) {\n    History.call(this, router, base);\n    this.stack = [];\n    this.index = -1;\n  }\n\n  if ( History ) AbstractHistory.__proto__ = History;\n  AbstractHistory.prototype = Object.create( History && History.prototype );\n  AbstractHistory.prototype.constructor = AbstractHistory;\n\n  AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    this.transitionTo(\n      location,\n      function (route) {\n        this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index + 1).concat(route);\n        this$1$1.index++;\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n    this.transitionTo(\n      location,\n      function (route) {\n        this$1$1.stack = this$1$1.stack.slice(0, this$1$1.index).concat(route);\n        onComplete && onComplete(route);\n      },\n      onAbort\n    );\n  };\n\n  AbstractHistory.prototype.go = function go (n) {\n    var this$1$1 = this;\n\n    var targetIndex = this.index + n;\n    if (targetIndex < 0 || targetIndex >= this.stack.length) {\n      return\n    }\n    var route = this.stack[targetIndex];\n    this.confirmTransition(\n      route,\n      function () {\n        var prev = this$1$1.current;\n        this$1$1.index = targetIndex;\n        this$1$1.updateRoute(route);\n        this$1$1.router.afterHooks.forEach(function (hook) {\n          hook && hook(route, prev);\n        });\n      },\n      function (err) {\n        if (isNavigationFailure(err, NavigationFailureType.duplicated)) {\n          this$1$1.index = targetIndex;\n        }\n      }\n    );\n  };\n\n  AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {\n    var current = this.stack[this.stack.length - 1];\n    return current ? current.fullPath : '/'\n  };\n\n  AbstractHistory.prototype.ensureURL = function ensureURL () {\n    // noop\n  };\n\n  return AbstractHistory;\n}(History));\n\n/*  */\n\n\n\nvar VueRouter = function VueRouter (options) {\n  if ( options === void 0 ) options = {};\n\n  if (process.env.NODE_ENV !== 'production') {\n    warn(this instanceof VueRouter, \"Router must be called with the new operator.\");\n  }\n  this.app = null;\n  this.apps = [];\n  this.options = options;\n  this.beforeHooks = [];\n  this.resolveHooks = [];\n  this.afterHooks = [];\n  this.matcher = createMatcher(options.routes || [], this);\n\n  var mode = options.mode || 'hash';\n  this.fallback =\n    mode === 'history' && !supportsPushState && options.fallback !== false;\n  if (this.fallback) {\n    mode = 'hash';\n  }\n  if (!inBrowser) {\n    mode = 'abstract';\n  }\n  this.mode = mode;\n\n  switch (mode) {\n    case 'history':\n      this.history = new HTML5History(this, options.base);\n      break\n    case 'hash':\n      this.history = new HashHistory(this, options.base, this.fallback);\n      break\n    case 'abstract':\n      this.history = new AbstractHistory(this, options.base);\n      break\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        assert(false, (\"invalid mode: \" + mode));\n      }\n  }\n};\n\nvar prototypeAccessors = { currentRoute: { configurable: true } };\n\nVueRouter.prototype.match = function match (raw, current, redirectedFrom) {\n  return this.matcher.match(raw, current, redirectedFrom)\n};\n\nprototypeAccessors.currentRoute.get = function () {\n  return this.history && this.history.current\n};\n\nVueRouter.prototype.init = function init (app /* Vue component instance */) {\n    var this$1$1 = this;\n\n  process.env.NODE_ENV !== 'production' &&\n    assert(\n      install.installed,\n      \"not installed. Make sure to call `Vue.use(VueRouter)` \" +\n        \"before creating root instance.\"\n    );\n\n  this.apps.push(app);\n\n  // set up app destroyed handler\n  // https://github.com/vuejs/vue-router/issues/2639\n  app.$once('hook:destroyed', function () {\n    // clean out app from this.apps array once destroyed\n    var index = this$1$1.apps.indexOf(app);\n    if (index > -1) { this$1$1.apps.splice(index, 1); }\n    // ensure we still have a main app or null if no apps\n    // we do not release the router so it can be reused\n    if (this$1$1.app === app) { this$1$1.app = this$1$1.apps[0] || null; }\n\n    if (!this$1$1.app) { this$1$1.history.teardown(); }\n  });\n\n  // main app previously initialized\n  // return as we don't need to set up new history listener\n  if (this.app) {\n    return\n  }\n\n  this.app = app;\n\n  var history = this.history;\n\n  if (history instanceof HTML5History || history instanceof HashHistory) {\n    var handleInitialScroll = function (routeOrError) {\n      var from = history.current;\n      var expectScroll = this$1$1.options.scrollBehavior;\n      var supportsScroll = supportsPushState && expectScroll;\n\n      if (supportsScroll && 'fullPath' in routeOrError) {\n        handleScroll(this$1$1, routeOrError, from, false);\n      }\n    };\n    var setupListeners = function (routeOrError) {\n      history.setupListeners();\n      handleInitialScroll(routeOrError);\n    };\n    history.transitionTo(\n      history.getCurrentLocation(),\n      setupListeners,\n      setupListeners\n    );\n  }\n\n  history.listen(function (route) {\n    this$1$1.apps.forEach(function (app) {\n      app._route = route;\n    });\n  });\n};\n\nVueRouter.prototype.beforeEach = function beforeEach (fn) {\n  return registerHook(this.beforeHooks, fn)\n};\n\nVueRouter.prototype.beforeResolve = function beforeResolve (fn) {\n  return registerHook(this.resolveHooks, fn)\n};\n\nVueRouter.prototype.afterEach = function afterEach (fn) {\n  return registerHook(this.afterHooks, fn)\n};\n\nVueRouter.prototype.onReady = function onReady (cb, errorCb) {\n  this.history.onReady(cb, errorCb);\n};\n\nVueRouter.prototype.onError = function onError (errorCb) {\n  this.history.onError(errorCb);\n};\n\nVueRouter.prototype.push = function push (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  // $flow-disable-line\n  if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n    return new Promise(function (resolve, reject) {\n      this$1$1.history.push(location, resolve, reject);\n    })\n  } else {\n    this.history.push(location, onComplete, onAbort);\n  }\n};\n\nVueRouter.prototype.replace = function replace (location, onComplete, onAbort) {\n    var this$1$1 = this;\n\n  // $flow-disable-line\n  if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n    return new Promise(function (resolve, reject) {\n      this$1$1.history.replace(location, resolve, reject);\n    })\n  } else {\n    this.history.replace(location, onComplete, onAbort);\n  }\n};\n\nVueRouter.prototype.go = function go (n) {\n  this.history.go(n);\n};\n\nVueRouter.prototype.back = function back () {\n  this.go(-1);\n};\n\nVueRouter.prototype.forward = function forward () {\n  this.go(1);\n};\n\nVueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {\n  var route = to\n    ? to.matched\n      ? to\n      : this.resolve(to).route\n    : this.currentRoute;\n  if (!route) {\n    return []\n  }\n  return [].concat.apply(\n    [],\n    route.matched.map(function (m) {\n      return Object.keys(m.components).map(function (key) {\n        return m.components[key]\n      })\n    })\n  )\n};\n\nVueRouter.prototype.resolve = function resolve (\n  to,\n  current,\n  append\n) {\n  current = current || this.history.current;\n  var location = normalizeLocation(to, current, append, this);\n  var route = this.match(location, current);\n  var fullPath = route.redirectedFrom || route.fullPath;\n  var base = this.history.base;\n  var href = createHref(base, fullPath, this.mode);\n  return {\n    location: location,\n    route: route,\n    href: href,\n    // for backwards compat\n    normalizedTo: location,\n    resolved: route\n  }\n};\n\nVueRouter.prototype.getRoutes = function getRoutes () {\n  return this.matcher.getRoutes()\n};\n\nVueRouter.prototype.addRoute = function addRoute (parentOrRoute, route) {\n  this.matcher.addRoute(parentOrRoute, route);\n  if (this.history.current !== START) {\n    this.history.transitionTo(this.history.getCurrentLocation());\n  }\n};\n\nVueRouter.prototype.addRoutes = function addRoutes (routes) {\n  if (process.env.NODE_ENV !== 'production') {\n    warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.');\n  }\n  this.matcher.addRoutes(routes);\n  if (this.history.current !== START) {\n    this.history.transitionTo(this.history.getCurrentLocation());\n  }\n};\n\nObject.defineProperties( VueRouter.prototype, prototypeAccessors );\n\nvar VueRouter$1 = VueRouter;\n\nfunction registerHook (list, fn) {\n  list.push(fn);\n  return function () {\n    var i = list.indexOf(fn);\n    if (i > -1) { list.splice(i, 1); }\n  }\n}\n\nfunction createHref (base, fullPath, mode) {\n  var path = mode === 'hash' ? '#' + fullPath : fullPath;\n  return base ? cleanPath(base + '/' + path) : path\n}\n\n// We cannot remove this as it would be a breaking change\nVueRouter.install = install;\nVueRouter.version = '3.6.5';\nVueRouter.isNavigationFailure = isNavigationFailure;\nVueRouter.NavigationFailureType = NavigationFailureType;\nVueRouter.START_LOCATION = START;\n\nif (inBrowser && window.Vue) {\n  window.Vue.use(VueRouter);\n}\n\nvar version = '3.6.5';\n\nexport { NavigationFailureType, Link as RouterLink, View as RouterView, START as START_LOCATION, VueRouter$1 as default, isNavigationFailure, version };\n"
  },
  {
    "path": "docs/.vuepress/components/HomeSponsors.vue",
    "content": "<template>\n  <div id=\"sponsors\">\n    <div class=\"inner\">\n      <HomeSponsorsGroup name=\"Platinum\" size=\"160\" />\n      <HomeSponsorsGroup name=\"Gold\" size=\"140\" />\n      <HomeSponsorsGroup name=\"Silver\" size=\"120\" />\n\n      <a\n        class=\"become-sponsor button white\"\n        href=\"https://github.com/sponsors/posva\"\n      >Become a Sponsor!</a>\n    </div>\n  </div>\n</template>\n\n<script>\nimport HomeSponsorsGroup from './HomeSponsorsGroup.vue'\n\nexport default {\n  name: 'HomeSponsors',\n\n  components: { HomeSponsorsGroup }\n}\n</script>\n\n<style>\n#sponsors {\n  text-align: center;\n  padding: 35px 30px 45px;\n  background-color: #f6f6f6;\n}\n\n@media (min-width: 768px) {\n  #sponsors {\n    padding: 35px 40px 45px;\n    margin: 0 -2rem;\n  }\n}\n\n#sponsors h3 {\n  color: #999;\n  margin: 0 0 10px;\n}\n\n#sponsors a,\n#sponsors img {\n  width: 100px;\n  display: inline-block;\n  vertical-align: middle;\n  margin: 0 2px;\n}\n\n#sponsors img {\n  transition: all 0.3s ease;\n  filter: grayscale(100%);\n  opacity: 0.66;\n}\n\n#sponsors img:hover {\n  filter: none;\n  opacity: 1;\n}\n\n#sponsors .become-sponsor,\n.become-sponsor {\n  margin-top: 40px;\n  font-size: 0.9em;\n  font-weight: 700;\n  width: auto;\n  text-align: center;\n  background-color: transparent;\n  padding: 0.75em 2em;\n  border-radius: 2em;\n  transition: all 0.15s ease;\n  box-sizing: border-box;\n  border: 1px solid #4fc08d;\n}\n\n#sponsors .become-sponsor:hover,\n.become-sponsor:hover {\n  background-color: #4fc08d;\n  color: white;\n}\n\n.sponsors-top .become-sponsor.become-sponsor {\n  font-size: 0.75em;\n  padding: 0.2em;\n  width: auto;\n  max-width: 150px;\n}\n</style>\n"
  },
  {
    "path": "docs/.vuepress/components/HomeSponsorsGroup.vue",
    "content": "<template>\n  <div v-if=\"list && list.length\">\n    <h3>{{ name }} Sponsors</h3>\n\n    <a\n      v-for=\"sponsor in list\"\n      :key=\"sponsor.href\"\n      :href=\"sponsor.href\"\n      target=\"_blank\"\n      rel=\"sponsored noopener\"\n      :style=\"{ width: size + 'px' }\"\n    >\n      <img :src=\"sponsor.imgSrcLight\" :style=\"{ width: size + 'px' }\" />\n    </a>\n    <br />\n    <br />\n  </div>\n</template>\n\n<script>\nimport sponsors from './sponsors.json'\n\nexport default {\n  name: 'HomeSponsorsGroup',\n\n  props: {\n    name: {\n      type: String,\n      required: true\n    },\n    size: {\n      type: [Number, String],\n      default: 140\n    }\n  },\n\n  computed: {\n    list() {\n      return sponsors[this.name.toLowerCase()]\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "docs/.vuepress/components/sponsors.json",
    "content": "{\n  \"platinum\": [],\n  \"gold\": [],\n  \"silver\": [\n    {\n      \"href\": \"https://www.vuemastery.com/\",\n      \"alt\": \"VueMastery\",\n      \"imgSrcLight\": \"https://posva-sponsors.pages.dev/logos/vuemastery-light.svg\",\n      \"imgSrcDark\": \"https://posva-sponsors.pages.dev/logos/vuemastery-dark.png\"\n    },\n    {\n      \"href\": \"https://www.prefect.io/\",\n      \"imgSrcLight\": \"https://posva-sponsors.pages.dev/logos/prefectlogo-light.svg\",\n      \"imgSrcDark\": \"https://posva-sponsors.pages.dev/logos/prefectlogo-dark.svg\",\n      \"alt\": \"Prefect\"\n    }\n  ],\n  \"bronze\": [\n    {\n      \"alt\": \"Stanislas Ormières\",\n      \"href\": \"https://stormier.ninja\",\n      \"imgSrcDark\": \"https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4\",\n      \"imgSrcLight\": \"https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4\"\n    },\n    {\n      \"alt\": \"Antony Konstantinidis\",\n      \"href\": \"https://www.vuejs.de\",\n      \"imgSrcDark\": \"https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4\",\n      \"imgSrcLight\": \"https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4\"\n    },\n    {\n      \"href\": \"https://storyblok.com\",\n      \"imgSrcLight\": \"https://posva-sponsors.pages.dev/logos/storyblok.png\",\n      \"imgSrcDark\": \"https://posva-sponsors.pages.dev/logos/storyblok.png\",\n      \"alt\": \"Storyblok\"\n    },\n    {\n      \"href\": \"https://nuxtjs.org\",\n      \"imgSrcLight\": \"https://posva-sponsors.pages.dev/logos/nuxt-light.svg\",\n      \"imgSrcDark\": \"https://posva-sponsors.pages.dev/logos/nuxt-dark.svg\",\n      \"alt\": \"Nuxt Labs\"\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/.vuepress/config.js",
    "content": "module.exports = ctx => ({\n  locales: {\n    '/': {\n      lang: 'en-US',\n      title: 'Vue Router',\n      description: 'The official router for Vue.js.'\n    },\n    '/zh/': {\n      lang: 'zh-CN',\n      title: 'Vue Router',\n      description: 'Vue.js 官方的路由管理器。'\n    },\n    '/ja/': {\n      lang: 'ja',\n      title: 'Vue Router',\n      description: 'Vue.js の公式ルータ'\n    },\n    '/ru/': {\n      lang: 'ru',\n      title: 'Vue Router',\n      description: 'Официальный маршрутизатор для Vue.js.'\n    },\n    '/kr/': {\n      lang: 'kr',\n      title: 'Vue Router',\n      description: 'Vue.js 공식 라우터'\n    },\n    '/fr/': {\n      lang: 'fr',\n      title: 'Vue Router',\n      description: 'Routeur officiel pour Vue.Js'\n    }\n  },\n  head: [\n    ['link', { rel: 'icon', href: `/logo.png` }],\n    [\n      'meta',\n      { name: 'wwads-cn-verify', content: '7e7757b1e12abcb736ab9a754ffb617a' }\n    ],\n    [\n      'link',\n      { rel: 'apple-touch-icon', href: `/icons/apple-touch-icon-152x152.png` }\n    ],\n    [\n      'link',\n      {\n        rel: 'mask-icon',\n        href: '/icons/safari-pinned-tab.svg',\n        color: '#3eaf7c'\n      }\n    ],\n    [\n      'meta',\n      {\n        name: 'msapplication-TileImage',\n        content: '/icons/msapplication-icon-144x144.png'\n      }\n    ]\n  ],\n  // theme: '@vuepress/vue',\n  plugins: [\n    [\n      '@vuepress/pwa',\n      {\n        serviceWorker: true,\n        updatePopup: true\n      }\n    ]\n  ],\n  themeConfig: {\n    algolia: ctx.isProd\n      ? {\n          appId: 'LI3RW4C4QI',\n          apiKey: '08e7ef7cd3969442874f0dee9dec34be',\n          indexName: 'vue-router'\n        }\n      : null,\n    carbonAds: {\n      carbon: 'CEBICK3I',\n      custom: 'CEBICK3M',\n      placement: 'routervuejsorg'\n    },\n    repo: 'vuejs/vue-router',\n    docsDir: 'docs',\n    smoothScroll: true,\n    locales: {\n      '/': {\n        label: 'English',\n        selectText: 'Languages',\n        editLinkText: 'Edit this page on GitHub',\n        nav: [\n          {\n            text: 'Guide',\n            link: '/guide/'\n          },\n          {\n            text: 'API Reference',\n            link: '/api/'\n          },\n          {\n            text: 'v3.x',\n            items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }]\n          },\n          {\n            text: 'Release Notes',\n            link: 'https://github.com/vuejs/vue-router/releases'\n          }\n        ],\n        sidebar: [\n          '/installation.md',\n          {\n            title: 'Essentials',\n            collapsable: false,\n            children: [\n              '/guide/',\n              '/guide/essentials/dynamic-matching.md',\n              '/guide/essentials/nested-routes.md',\n              '/guide/essentials/navigation.md',\n              '/guide/essentials/named-routes.md',\n              '/guide/essentials/named-views.md',\n              '/guide/essentials/redirect-and-alias.md',\n              '/guide/essentials/passing-props.md',\n              '/guide/essentials/history-mode.md'\n            ]\n          },\n          {\n            title: 'Advanced',\n            collapsable: false,\n            children: [\n              '/guide/advanced/navigation-guards.md',\n              '/guide/advanced/meta.md',\n              '/guide/advanced/transitions.md',\n              '/guide/advanced/data-fetching.md',\n              '/guide/advanced/scroll-behavior.md',\n              '/guide/advanced/lazy-loading.md',\n              '/guide/advanced/navigation-failures.md'\n            ]\n          }\n        ]\n      },\n      '/zh/': {\n        label: '简体中文',\n        selectText: '选择语言',\n        editLinkText: '在 GitHub 上编辑此页',\n        nav: [\n          {\n            text: '指南',\n            link: '/zh/guide/'\n          },\n          {\n            text: 'API 参考',\n            link: '/zh/api/'\n          },\n          {\n            text: 'v3.x',\n            items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org/zh/' }]\n          },\n          {\n            text: '更新记录',\n            link: 'https://github.com/vuejs/vue-router/releases'\n          }\n        ],\n        sidebar: [\n          '/zh/installation.md',\n          {\n            title: '基础',\n            collapsable: false,\n            children: [\n              '/zh/guide/',\n              '/zh/guide/essentials/dynamic-matching.md',\n              '/zh/guide/essentials/nested-routes.md',\n              '/zh/guide/essentials/navigation.md',\n              '/zh/guide/essentials/named-routes.md',\n              '/zh/guide/essentials/named-views.md',\n              '/zh/guide/essentials/redirect-and-alias.md',\n              '/zh/guide/essentials/passing-props.md',\n              '/zh/guide/essentials/history-mode.md'\n            ]\n          },\n          {\n            title: '进阶',\n            collapsable: false,\n            children: [\n              '/zh/guide/advanced/navigation-guards.md',\n              '/zh/guide/advanced/meta.md',\n              '/zh/guide/advanced/transitions.md',\n              '/zh/guide/advanced/data-fetching.md',\n              '/zh/guide/advanced/scroll-behavior.md',\n              '/zh/guide/advanced/lazy-loading.md',\n              '/zh/guide/advanced/navigation-failures.md'\n            ]\n          }\n        ]\n      },\n      '/ja/': {\n        label: '日本語',\n        selectText: '言語',\n        editLinkText: 'GitHub 上でこのページを編集する',\n        nav: [\n          {\n            text: 'ガイド',\n            link: '/ja/guide/'\n          },\n          {\n            text: 'API リファレンス',\n            link: '/ja/api/'\n          },\n          {\n            text: 'v3.x',\n            items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }]\n          },\n          {\n            text: 'リリースノート',\n            link: 'https://github.com/vuejs/vue-router/releases'\n          }\n        ],\n        sidebar: [\n          '/ja/installation.md',\n          {\n            title: '基本的な使い方',\n            collapsable: false,\n            children: [\n              '/ja/guide/',\n              '/ja/guide/essentials/dynamic-matching.md',\n              '/ja/guide/essentials/nested-routes.md',\n              '/ja/guide/essentials/navigation.md',\n              '/ja/guide/essentials/named-routes.md',\n              '/ja/guide/essentials/named-views.md',\n              '/ja/guide/essentials/redirect-and-alias.md',\n              '/ja/guide/essentials/passing-props.md',\n              '/ja/guide/essentials/history-mode.md'\n            ]\n          },\n          {\n            title: '高度な使い方',\n            collapsable: false,\n            children: [\n              '/ja/guide/advanced/navigation-guards.md',\n              '/ja/guide/advanced/meta.md',\n              '/ja/guide/advanced/transitions.md',\n              '/ja/guide/advanced/data-fetching.md',\n              '/ja/guide/advanced/scroll-behavior.md',\n              '/ja/guide/advanced/lazy-loading.md',\n              '/ja/guide/advanced/navigation-failures.md'\n            ]\n          }\n        ]\n      },\n      '/ru/': {\n        label: 'Русский',\n        selectText: 'Переводы',\n        editLinkText: 'Изменить эту страницу на GitHub',\n        nav: [\n          {\n            text: 'Руководство',\n            link: '/ru/guide/'\n          },\n          {\n            text: 'Справочник API',\n            link: '/ru/api/'\n          },\n          {\n            text: 'v3.x',\n            items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }]\n          },\n          {\n            text: 'История изменений',\n            link: 'https://github.com/vuejs/vue-router/releases'\n          }\n        ],\n        sidebar: [\n          '/ru/installation.md',\n          {\n            title: 'Основы',\n            collapsable: false,\n            children: [\n              '/ru/guide/',\n              '/ru/guide/essentials/dynamic-matching.md',\n              '/ru/guide/essentials/nested-routes.md',\n              '/ru/guide/essentials/navigation.md',\n              '/ru/guide/essentials/named-routes.md',\n              '/ru/guide/essentials/named-views.md',\n              '/ru/guide/essentials/redirect-and-alias.md',\n              '/ru/guide/essentials/passing-props.md',\n              '/ru/guide/essentials/history-mode.md'\n            ]\n          },\n          {\n            title: 'Продвинутые темы',\n            collapsable: false,\n            children: [\n              '/ru/guide/advanced/navigation-guards.md',\n              '/ru/guide/advanced/meta.md',\n              '/ru/guide/advanced/transitions.md',\n              '/ru/guide/advanced/data-fetching.md',\n              '/ru/guide/advanced/scroll-behavior.md',\n              '/ru/guide/advanced/lazy-loading.md',\n              '/ru/guide/advanced/navigation-failures.md'\n            ]\n          }\n        ]\n      },\n      '/kr/': {\n        label: '한국어',\n        selectText: '언어',\n        editLinkText: 'GitHub에서 이 문서를 수정하세요',\n        nav: [\n          {\n            text: '가이드',\n            link: '/kr/guide/'\n          },\n          {\n            text: 'API 레퍼런스',\n            link: '/kr/api/'\n          },\n          {\n            text: 'v3.x',\n            items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }]\n          },\n          {\n            text: '릴리즈 노트',\n            link: 'https://github.com/vuejs/vue-router/releases'\n          }\n        ],\n        sidebar: [\n          '/kr/installation.md',\n          {\n            title: '기본 사용법',\n            collapsable: false,\n            children: [\n              '/kr/guide/',\n              '/kr/guide/essentials/dynamic-matching.md',\n              '/kr/guide/essentials/nested-routes.md',\n              '/kr/guide/essentials/navigation.md',\n              '/kr/guide/essentials/named-routes.md',\n              '/kr/guide/essentials/named-views.md',\n              '/kr/guide/essentials/redirect-and-alias.md',\n              '/kr/guide/essentials/passing-props.md',\n              '/kr/guide/essentials/history-mode.md'\n            ]\n          },\n          {\n            title: '고급 사용법',\n            collapsable: false,\n            children: [\n              '/kr/guide/advanced/navigation-guards.md',\n              '/kr/guide/advanced/meta.md',\n              '/kr/guide/advanced/transitions.md',\n              '/kr/guide/advanced/data-fetching.md',\n              '/kr/guide/advanced/scroll-behavior.md',\n              '/kr/guide/advanced/lazy-loading.md'\n            ]\n          }\n        ]\n      },\n      '/fr/': {\n        label: 'Français',\n        selectText: 'Langues',\n        editLinkText: 'Editer cette page sur Github',\n        nav: [\n          {\n            text: 'Guide',\n            link: '/fr/guide/'\n          },\n          {\n            text: 'API',\n            link: '/fr/api/'\n          },\n          {\n            text: 'v3.x',\n            items: [{ text: 'v4.x', link: 'https://next.router.vuejs.org' }]\n          },\n          {\n            text: 'Notes de version',\n            link: 'https://github.com/vuejs/vue-router/releases'\n          }\n        ],\n        sidebar: [\n          '/fr/installation.md',\n          {\n            title: 'Essentiels',\n            collapsable: false,\n            children: [\n              '/fr/guide/',\n              '/fr/guide/essentials/dynamic-matching.md',\n              '/fr/guide/essentials/nested-routes.md',\n              '/fr/guide/essentials/navigation.md',\n              '/fr/guide/essentials/named-routes.md',\n              '/fr/guide/essentials/named-views.md',\n              '/fr/guide/essentials/redirect-and-alias.md',\n              '/fr/guide/essentials/passing-props.md',\n              '/fr/guide/essentials/history-mode.md'\n            ]\n          },\n          {\n            title: 'Avancés',\n            collapsable: false,\n            children: [\n              '/fr/guide/advanced/navigation-guards.md',\n              '/fr/guide/advanced/meta.md',\n              '/fr/guide/advanced/transitions.md',\n              '/fr/guide/advanced/data-fetching.md',\n              '/fr/guide/advanced/scroll-behavior.md',\n              '/fr/guide/advanced/lazy-loading.md'\n            ]\n          }\n        ]\n      }\n    }\n  }\n})\n"
  },
  {
    "path": "docs/.vuepress/public/_redirects",
    "content": "# redirect old urls to root\n\n/en/essentials/getting-started.html /guide/\n/en/essentials/* /guide/essentials/:splat\n/en/advanced/* /guide/advanced/:splat\n/en/api/* /api/\n/en/* /:splat\n\n/zh-cn/essentials/getting-started.html /zh/guide/\n/zh-cn/essentials/* /zh/guide/essentials/:splat\n/zh-cn/advanced/* /zh/guide/advanced/:splat\n/zh-cn/api/* /zh/api/\n/zh-cn/* /zh/:splat\n\n/ru/essentials/getting-started.html /ru/guide/\n/ru/essentials/* /ru/guide/essentials/:splat\n/ru/advanced/* /ru/guide/advanced/:splat\n/ru/api/* /ru/api/\n/ru/* /ru/:splat\n\n/ja/essentials/getting-started.html /ja/guide/\n/ja/essentials/* /ja/guide/essentials/:splat\n/ja/advanced/* /ja/guide/advanced/:splat\n/ja/api/* /ja/api/\n/ja/* /ja/:splat\n\n/kr/essentials/getting-started.html /kr/guide/\n/kr/essentials/* /kr/guide/essentials/:splat\n/kr/advanced/* /kr/guide/advanced/:splat\n/kr/api/* /kr/api/\n/kr/* /kr/:splat\n"
  },
  {
    "path": "docs/.vuepress/styles/index.styl",
    "content": ".bit-sponsor\n  font-weight 600\n  background-color #f3f6f8\n  padding 0.6em 1.2em\n  border-radius 8px\n  display inline-block\n  margin 1em 0 !important\n  a\n    color #999\n  img\n    height 40px\n    margin-left 15px\n  img, span\n    vertical-align middle\n\n\n.vueschool\n  background-color #e7ecf3\n  padding 1em 1.25em\n  border-radius 2px\n  color #486491\n  position relative\n  display flex\n  a\n    color #486491 !important\n    position relative\n    padding-left 36px\n    &:before\n      content ''\n      position absolute\n      display block\n      width 30px\n      height 30px\n      top calc(50% - 15px);\n      left -4px\n      border-radius 50%\n      background-color #73abfe\n    &:after\n      content ''\n      position absolute\n      display block\n      width 0\n      height 0\n      top calc(50% - 5px)\n      left 8px\n      border-top 5px solid transparent\n      border-bottom 5px solid transparent\n      border-left 8px solid #fff\n\n@media (max-width: 719px) {\n  .vueschool {\n    display: inline-flex;\n  }\n}\n"
  },
  {
    "path": "docs/.vuepress/theme/Layout.vue",
    "content": "<template>\n  <div class=\"main-container\" :class=\"{ 'has-top-banner': showTopBanner }\">\n    <div id=\"v3-banner\">\n      <span class=\"hidden-sm\"\n        >Vue Router 3 has reached EOL and is no longer actively\n        maintained.</span\n      >\n      <a href=\"https://router.vuejs.org/\">Upgrade to Vue Router 4</a>\n    </div>\n\n    <BannerTop v-if=\"showTopBanner\" @close=\"closeBannerTop\" />\n    <ParentLayout>\n      <template #page-top>\n        <CarbonAds\n          v-if=\"$site.themeConfig.carbonAds\"\n          :key=\"'ca:' + $page.path\"\n          :code=\"$site.themeConfig.carbonAds.carbon\"\n          :placement=\"$site.themeConfig.carbonAds.placement\"\n        />\n      </template>\n      <template #page-bottom>\n        <BuySellAds\n          v-if=\"$site.themeConfig.carbonAds\"\n          :key=\"'bsa:' + $page.path\"\n          :code=\"$site.themeConfig.carbonAds.custom\"\n          :placement=\"$site.themeConfig.carbonAds.placement\"\n        />\n      </template>\n\n      <template #sidebar-top>\n        <div class=\"sponsors sponsors-top\">\n          <span>Platinum Sponsors</span>\n\n          <template v-if=\"sponsors.platinum.length\">\n            <a\n              v-for=\"sponsor in sponsors.platinum\"\n              :href=\"sponsor.href\"\n              :key=\"sponsor.href\"\n              target=\"_blank\"\n              rel=\"noopener\"\n            >\n              <img :src=\"sponsor.imgSrcLight\" :alt=\"sponsor.alt\" />\n            </a>\n          </template>\n          <a\n            v-else\n            class=\"become-sponsor\"\n            href=\"https://github.com/sponsors/posva\"\n            target=\"_blank\"\n            rel=\"noopener\"\n            alt=\"Your logo here\"\n            >Become a Sponsor!</a\n          >\n        </div>\n      </template>\n\n      <template #sidebar-bottom>\n        <div class=\"sponsors\">\n          <span>Sponsors</span>\n\n          <a\n            v-for=\"sponsor in sponsors.gold\"\n            :href=\"sponsor.href\"\n            :key=\"sponsor.href\"\n            target=\"_blank\"\n            rel=\"noopener\"\n          >\n            <img :src=\"sponsor.imgSrcLight\" :alt=\"sponsor.alt\" />\n          </a>\n        </div>\n      </template>\n    </ParentLayout>\n  </div>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nimport CarbonAds from './components/CarbonAds.vue'\nimport BuySellAds from './components/BuySellAds.vue'\nimport sponsors from '../components/sponsors.json'\n\nexport default {\n  name: 'Layout',\n  components: {\n    ParentLayout,\n    CarbonAds,\n    BuySellAds,\n    BannerTop: () => import('./components/VueSchool/BannerTop.vue'),\n  },\n  data() {\n    return {\n      sponsors,\n      showTopBanner: false,\n    }\n  },\n  mounted() {\n    const now = new Date()\n    const end = new Date('2022-05-04T00:00:00+02:00')\n    this.showTopBanner =\n      !localStorage.getItem('VS_FW_22_BANNER_CLOSED') && now < end\n  },\n  methods: {\n    closeBannerTop() {\n      this.showTopBanner = false\n      localStorage.setItem('VS_FW_22_BANNER_CLOSED', 1)\n    },\n  },\n}\n</script>\n\n<style>\n@media screen and (max-width: 1300px) {\n  .content__default::before {\n    content: '';\n    /* background-color: red; */\n    position: relative;\n    display: block;\n    /* top: 87px; */\n    /* right: -12px; */\n    float: right;\n    height: 221px;\n    /* width: 0; */\n    padding: 0 0 20px 30px;\n    margin-top: 20px;\n    margin-right: -24px;\n  }\n}\n\n@media screen and (max-width: 900px) {\n  #v3-banner .hidden-sm {\n    display: none;\n  }\n}\n\nimg {\n  max-width: 100%;\n}\n\n#v3-banner {\n  background-color: #ffb731;\n  width: 100%;\n  min-height: 40px;\n  padding: 10px 60px;\n  z-index: 19;\n  box-sizing: border-box;\n  text-align: center;\n  color: #333;\n\n  top: 0;\n  position: fixed;\n}\n\n#v3-banner a {\n  color: #34495e;\n  font-weight: bold;\n}\n\nheader.navbar,\naside.sidebar,\nmain.page,\nmain.home {\n  margin-top: 40px;\n}\n</style>\n\n<style scoped>\n.sponsors {\n  margin: 0 0 1rem 1.35rem;\n}\n\n.sponsors-top {\n  margin-top: 1rem;\n  /* workaround padding in vitepress */\n  margin-bottom: -2rem;\n}\n\n.sponsors > span {\n  /* margin: 1.25rem 0; */\n  display: block;\n  color: #999;\n  font-size: 0.8rem;\n}\n\n.sponsors a:last-child {\n  margin-bottom: 20px;\n}\n.sponsors a:first-child {\n  margin-top: 18px;\n}\n\n.sponsors a {\n  margin-top: 10px;\n  width: 125px;\n  display: block;\n}\n</style>\n"
  },
  {
    "path": "docs/.vuepress/theme/components/BuySellAds.vue",
    "content": "<template>\n  <div class=\"bsa-cpc-wrapper\">\n    <div class=\"bsa-cpc\"></div>\n  </div>\n</template>\n\n<script>\n/* global _bsa */\nconst ID = 'bsa-cpc-script'\n\nexport default {\n  name: 'BuySellAds',\n  props: {\n    code: {\n      type: String,\n      required: true\n    },\n    placement: {\n      type: String,\n      required: true\n    }\n  },\n\n  methods: {\n    load() {\n      if (typeof _bsa !== 'undefined' && _bsa) {\n        _bsa.init('default', this.code, `placement:${this.placement}`, {\n          target: '.bsa-cpc',\n          align: 'horizontal',\n          disable_css: 'true'\n        })\n      }\n    }\n  },\n\n  mounted() {\n    if (!document.getElementById(ID)) {\n      const s = document.createElement('script')\n      s.id = ID\n      s.src = `//m.servedby-buysellads.com/monetization.js`\n      document.head.appendChild(s)\n      s.onload = () => {\n        this.load()\n      }\n    } else {\n      this.load()\n    }\n  }\n}\n</script>\n\n<style>\n.bsa-cpc-wrapper {\n  font-size: 0.95rem;\n  /* from Page.vue */\n  max-width: 50rem;\n  margin: 0px auto;\n  padding: 1rem 2rem 0;\n  margin-bottom: -1rem;\n}\n@media (max-width: 419px) {\n  .bsa-cpc-wrapper {\n    padding: 0 1.5rem;\n  }\n}\n.bsa-cpc {\n  font-size: 0.9em;\n  background-color: #f8f8f8;\n  border-radius: 6px;\n}\n\n.bsa-cpc .default-text {\n  display: inline;\n}\n\n.bsa-cpc a._default_ {\n  text-align: left;\n  display: block;\n  text-decoration: none;\n  padding: 10px 15px 12px;\n  margin-bottom: 20px;\n  color: #666;\n  font-weight: 400;\n  line-height: 18px;\n}\n.bsa-cpc a._default_ .default-image img {\n  height: 20px;\n  border-radius: 3px;\n  vertical-align: middle;\n  position: relative;\n  top: -1px;\n}\n.bsa-cpc a._default_ .default-title {\n  font-weight: 600;\n}\n.bsa-cpc a._default_ .default-description:after {\n  font-size: 0.85em;\n  content: 'Sponsored';\n  color: #1c90f3;\n  border: 1px solid #1c90f3;\n  border-radius: 3px;\n  padding: 0 4px 1px;\n  margin-left: 6px;\n}\n.bsa-cpc .default-ad {\n  display: none;\n}\n.bsa-cpc a._default_ .default-image,\n.bsa-cpc a._default_ .default-title,\n.bsa-cpc a._default_ .default-description {\n  display: inline;\n  vertical-align: middle;\n  margin-right: 6px;\n}\n</style>\n"
  },
  {
    "path": "docs/.vuepress/theme/components/CarbonAds.vue",
    "content": "<template>\n  <div class=\"carbon-ads\"></div>\n</template>\n\n<script>\nexport default {\n  name: 'CarbonAds',\n  props: {\n    code: {\n      type: String,\n      required: true\n    },\n    placement: {\n      type: String,\n      required: true\n    }\n  },\n\n  mounted() {\n    const s = document.createElement('script')\n    s.id = '_carbonads_js'\n    s.src = `//cdn.carbonads.com/carbon.js?serve=${this.code}&placement=${this.placement}`\n    this.$el.appendChild(s)\n  }\n}\n</script>\n\n<style>\n.carbon-ads {\n  min-height: 102px;\n  padding: 1.5rem 1.5rem 0;\n  margin-bottom: -0.5rem;\n  font-size: 0.75rem;\n\n  width: 125px;\n  position: fixed;\n  z-index: 1;\n  bottom: 22px;\n  right: 14px;\n  padding: 10px;\n  /* background-color: #fff; */\n  /* border-radius: 3px; */\n  /* font-size: 13px; */\n}\n\n@media screen and (max-width: 1300px) {\n  .carbon-ads {\n    position: relative;\n    top: 87px;\n    right: 12px;\n    float: right;\n    padding: 0 0 20px 30px;\n  }\n}\n\n.carbon-ads a {\n  color: #444;\n  font-weight: normal;\n  display: inline;\n}\n\n.carbon-ads .carbon-img {\n  float: left;\n  margin-right: 1rem;\n  border: 1px solid var(--border-color);\n}\n\n.carbon-ads .carbon-img img {\n  display: block;\n}\n\n.carbon-ads .carbon-poweredby {\n  color: #999;\n  display: block;\n  margin-top: 0.5em;\n}\n\n@media (max-width: 719px) {\n  .carbon-ads .carbon-img img {\n    width: 100px;\n    height: 77px;\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/.vuepress/theme/components/VueSchool/BannerTop.vue",
    "content": "<template>\n  <a\n    id=\"vs\"\n    href=\"https://vueschool.io/sales/price-increase-22?friend=vuerouter\"\n    target=\"_blank\"\n    rel=\"noreferrer\"\n  >\n    <div class=\"vs-logo\">\n      <img src=\"/images/vueschool/vs-iso.svg\" class=\"logo-small\">\n      <img src=\"/images/vueschool/vs-logo.svg\" class=\"logo-big\">\n    </div>\n    <div class=\"vs-core\">\n      <div class=\"vs-slogan\">\n        <div class=\"vs-slogan-title\">\n          Extended for <strong>48 hours!</strong>\n        </div>\n        <div class=\"vs-slogan-subtitle\">\n          Get up to 40% off your Vue School Subscription\n        </div>\n      </div>\n      <div class=\"vs-button\">\n        <div class=\"vs-button-inside\">\n          GET OFFER\n        </div>\n      </div>\n    </div>\n    <div id=\"vs-close\" class=\"vs-close\" @click.stop.prevent=\"$emit('close')\">\n      <img src=\"/images/vueschool/vs-close.svg\" alt=\"Close\">\n    </div>\n  </a>\n</template>\n\n<style lang=\"stylus\">\n@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');\n\n#vs {\n  align-items: center;\n  background-color: #000c19;\n  box-sizing: border-box;\n  color: #fff;\n  display: flex;\n  font-family: 'Roboto', Oxygen, Fira Sans, Helvetica Neue, sans-serif;\n  justify-content: center;\n  position: fixed;\n  padding: 0 10px;\n  left: 0;\n  right: 0;\n  top: 0;\n  z-index: 100;\n  height: 5rem;\n  line-height: 1;\n  background-image: url(/images/vueschool/vs-fw-bg-small.svg);\n  background-size: cover;\n  background-repeat: no-repeat;\n}\n\n#vs:hover {\n  text-decoration: none;\n}\n\n#vs .vs-logo {\n  position: absolute;\n  left: 20px;\n  top: 20px;\n}\n\n#vs .vs-logo .logo-small {\n  width: 30px;\n  margin-left: -5px;\n  margin-top: 5px;\n}\n\n#vs .vs-logo .logo-big {\n  display: none;\n}\n\n#vs:hover .vs-core .vs-button-inside {\n  background: linear-gradient(257deg, #e19b09 99%, #ffca24 6%);\n}\n\n#vs .vs-core .vs-slogan {\n  color: #fff;\n  margin-left: 8px;\n  text-align: center;\n}\n\n#vs .vs-core {\n  width: 190px;\n  align-items: center;\n  display: flex;\n  justify-content: center;\n}\n\n#vs .vs-core .vs-slogan .vs-slogan-subtitle {\n  font-size: 14px;\n  color: #cdc5dc;\n  margin-top: 8px;\n}\n\n#vs .vs-core .vs-slogan .vs-slogan-title {\n  font-size: 16px;\n  font-weight: 800;\n}\n\n#vs .vs-core .vs-slogan .vs-slogan-title strong {\n  color: #fdc722;\n}\n\n#vs .vs-core .vs-button {\n  background: linear-gradient(0deg, #ffdf4c, #e29d0a);\n  padding: 2px;\n  margin-right: 18px;\n  margin-left: 16px;\n  border-radius: 30px;\n  display: none;\n}\n\n#vs .vs-core .vs-button-inside {\n  color: #000;\n  padding: 7px 10px;\n  font-weight: 800;\n  font-size: 22px;\n  white-space: nowrap;\n  border-radius: 30px;\n  background: linear-gradient(90deg, #FFC828, #E19C0E);\n  text-transform: uppercase;\n}\n\n#vs .vs-close {\n  right: 6px;\n  position: absolute;\n}\n\n#vs .vs-close:hover {\n  color: #56d8ff;\n}\n\n@media (min-width: 680px) {\n  #vs {\n    background-image: url(/images/vueschool/vs-fw-bg.svg);\n    background-position: top right -110px;\n  }\n\n  #vs .vs-core .vs-slogan {\n    margin-left: 24px;\n    width: auto;\n  }\n\n  #vs .vs-core .vs-slogan .vs-slogan-subtitle {\n    font-size: 16px;\n  }\n\n  #vs .vs-core .vs-slogan .vs-slogan-title {\n    font-size: 18px;\n  }\n\n  #vs .vs-core .vs-button {\n    display: inline-block;\n    margin-right: 0;\n    margin-left: 22px;\n  }\n\n  #vs .vs-core .vs-button-inside {\n    padding: 8px 24px;\n  }\n\n  #vs .vs-close {\n    padding: 10px;\n    right: 20px;\n  }\n}\n\n@media (min-width: 768px) {\n  #vs .vs-logo .logo-small {\n    display: none;\n  }\n\n  #vs .vs-logo .logo-big {\n    display: inline-block;\n  }\n\n  #vs .vs-core {\n    width: 430px;\n  }\n}\n\n@media (min-width: 1024px) {\n  #vs {\n    background-position: top right;\n  }\n\n  #vs .vs-core .vs-slogan .vs-slogan-title {\n    font-size: 24px;\n  }\n\n  #vs .vs-core .vs-button {\n    margin-left: 69px;\n  }\n\n  #vs .vs-core {\n    width: auto;\n  }\n}\n\n/************************************/\n\n$topBannerHeight ?= 5rem\n$topBannerHeightMobile ?= 5rem\n$navbarHeight ?= 3.6rem\n$contentClass = '.theme-default-content'\n\n// Show banner only if the container has class \"has-top-banner\"\n.main-container.has-top-banner\n  #vs\n    display: flex\n\n// Add margin top to body, navbar and sidebar\n.main-container.has-top-banner\n  margin-top: $topBannerHeightMobile\n  .navbar\n    margin-top: $topBannerHeightMobile\n  .sidebar\n    margin-top: $topBannerHeightMobile\n@media (min-width: 680px)\n  .main-container.has-top-banner\n    margin-top: $topBannerHeight\n    .navbar\n      margin-top: $topBannerHeight\n    .sidebar\n      margin-top: $topBannerHeight\n\n// Adjust titles margin and padding for anchor links\n.main-container.has-top-banner\n  {$contentClass}:not(.custom)\n    h1, h2, h3, h4, h5, h6\n      margin-top (2.5rem - $topBannerHeightMobile - $navbarHeight)\n      padding-top ($navbarHeight + $topBannerHeightMobile + 1rem)\n@media (min-width: 680px)\n  .main-container.has-top-banner\n    {$contentClass}:not(.custom)\n      h1, h2, h3, h4, h5, h6\n        margin-top (2.5rem - $topBannerHeight - $navbarHeight)\n        padding-top ($navbarHeight + $topBannerHeight + 1rem)\n</style>\n"
  },
  {
    "path": "docs/.vuepress/theme/index.js",
    "content": "module.exports = {\n  extend: '@vuepress/theme-default'\n}\n"
  },
  {
    "path": "docs/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Get Started →\nactionLink: /installation.html\nfooter: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote\n---\n\nVue Router is the official router for [Vue.js](http://vuejs.org). It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze. Features include:\n\n- Nested route/view mapping\n- Modular, component-based router configuration\n- Route params, query, wildcards\n- View transition effects powered by Vue.js' transition system\n- Fine-grained navigation control\n- Links with automatic active CSS classes\n- HTML5 history mode or hash mode, with auto-fallback in IE9\n- Customizable Scroll Behavior\n\n[Get started](./guide/) or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see [`README.md`](https://github.com/vuejs/vue-router/) to run them).\n\n<HomeSponsors />\n"
  },
  {
    "path": "docs/api/README.md",
    "content": "---\nsidebar: auto\n---\n\n# API Reference\n\n## `<router-link>`\n\n`<router-link>` is the component for enabling user navigation in a router-enabled app. The target location is specified with the `to` prop. It renders as an `<a>` tag with correct `href` by default, but can be configured with the `tag` prop. In addition, the link automatically gets an active CSS class when the target route is active.\n\n`<router-link>` is preferred over hard-coded `<a href=\"...\">` for the following reasons:\n\n- It works the same way in both HTML5 history mode and hash mode, so if you ever decide to switch mode, or when the router falls back to hash mode in IE9, nothing needs to be changed.\n- In HTML5 history mode, `router-link` will intercept the click event so that the browser doesn't try to reload the page.\n- When you are using the `base` option in HTML5 history mode, you don't need to include it in `to` prop's URLs.\n\n### `v-slot` API (3.1.0+)\n\n`router-link` exposes a low level customization through a [scoped slot](https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots). This is a more advanced API that primarily targets library authors but can come in handy for developers as well, most of the time in a custom component like a _NavLink_ or other.\n\n**When using the `v-slot` API, it is required to pass one single child to `router-link`**. If you don't, `router-link` will wrap its children in a `span` element.\n\n```html\n<router-link\n  to=\"/about\"\n  custom\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <NavLink :active=\"isActive\" :href=\"href\" @click=\"navigate\"\n    >{{ route.fullPath }}</NavLink\n  >\n</router-link>\n```\n\n- `href`: resolved url. This would be the `href` attribute of an `a` element\n- `route`: resolved normalized location\n- `navigate`: function to trigger the navigation. **It will automatically prevent events when necessary**, the same way `router-link` does\n- `isActive`: `true` if the [active class](#active-class) should be applied. Allows to apply an arbitrary class\n- `isExactActive`: `true` if the [exact active class](#exact-active-class) should be applied. Allows to apply an arbitrary class\n\n#### Example: Applying Active Class to Outer Element\n\nSometimes we may want the active class to be applied to an outer element rather than the `<a>` tag itself, in that case, you can wrap that element inside a `router-link` and use the `v-slot` properties to create your link:\n\n```html\n<router-link\n  to=\"/foo\"\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n  custom\n>\n  <li\n    :class=\"[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']\"\n  >\n    <a :href=\"href\" @click=\"navigate\">{{ route.fullPath }}</a>\n  </li>\n</router-link>\n```\n\n:::tip\nIf you add a `target=\"_blank\"` to your `a` element, you must omit the `@click=\"navigate\"` handler.\n:::\n\n## `<router-link>` Props\n\n### to\n\n- type: `string | Location`\n- required\n\n  Denotes the target route of the link. When clicked, the value of the `to` prop will be passed to `router.push()` internally, so the value can be either a string or a location descriptor object.\n\n  ```html\n  <!-- literal string -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- renders to -->\n  <a href=\"home\">Home</a>\n\n  <!-- javascript expression using `v-bind` -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- Omitting `v-bind` is fine, just as binding any other prop -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- same as above -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- named route -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- with query, resulting in `/register?plan=private` -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\"\n    >Register</router-link\n  >\n  ```\n\n### replace\n\n- type: `boolean`\n- default: `false`\n\n  Setting `replace` prop will call `router.replace()` instead of `router.push()` when clicked, so the navigation will not leave a history record.\n\n  ```html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n### append\n\n- type: `boolean`\n- default: `false`\n\n  Setting `append` prop always appends the relative path to the current path. For example, assuming we are navigating from `/a` to a relative link `b`, without `append` we will end up at `/b`, but with `append` we will end up at `/a/b`.\n\n  ```html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n### tag\n\n- type: `string`\n- default: `\"a\"`\n\n  Sometimes we want `<router-link>` to render as another tag, e.g `<li>`. Then we can use `tag` prop to specify which tag to render to, and it will still listen to click events for navigation.\n\n  ```html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- renders as -->\n  <li>foo</li>\n  ```\n\n### active-class\n\n- type: `string`\n- default: `\"router-link-active\"`\n\n  Configure the active CSS class applied when the link is active. Note the default value can also be configured globally via the `linkActiveClass` router constructor option.\n\n### exact\n\n- type: `boolean`\n- default: `false`\n\n  The default active class matching behavior is **inclusive match**. For example, `<router-link to=\"/a\">` will get this class applied as long as the current path starts with `/a/` or is `/a`.\n\n  One consequence of this is that `<router-link to=\"/\">` will be active for every route! To force the link into \"exact match mode\", use the `exact` prop:\n\n  ```html\n  <!-- this link will only be active at `/` -->\n  <router-link to=\"/\" exact></router-link>\n  ```\n\n  Check out more examples explaining active link class [live](https://jsfiddle.net/8xrk1n9f/).\n\n### exact-path\n\n> New in 3.5.0\n\n- type: `boolean`\n- default: `false`\n\n  Allows matching only using the `path` section of the url, effectively ignoring the `query` and the `hash` sections.\n\n  ```html\n  <!-- this link will also be active at `/search?page=2` or `/search#filters` -->\n  <router-link to=\"/search\" exact-path> </router-link>\n  ```\n\n### exact-path-active-class\n\n- type: `string`\n- default: `\"router-link-exact-path-active\"`\n\n  Configure the active CSS class applied when the link is active with exact path match. Note the default value can also be configured globally via the `linkExactPathActiveClass` router constructor option.\n\n### event\n\n- type: `string | Array<string>`\n- default: `'click'`\n\n  Specify the event(s) that can trigger the link navigation.\n\n### exact-active-class\n\n- type: `string`\n- default: `\"router-link-exact-active\"`\n\n  Configure the active CSS class applied when the link is active with exact match. Note the default value can also be configured globally via the `linkExactActiveClass` router constructor option.\n\n### aria-current-value\n\n- type: `'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'`\n- default: `\"page\"`\n\n  Configure the value of `aria-current` when the link is active with exact match. It must be one of the [allowed values for aria-current](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the default of `page` should be the best fit.\n\n## `<router-view>`\n\nThe `<router-view>` component is a functional component that renders the matched component for the given path. Components rendered in `<router-view>` can also contain their own `<router-view>`, which will render components for nested paths.\n\nAny non-name props will be passed along to the rendered component, however most of the time the per-route data is contained in the route's params.\n\nSince it's just a component, it works with `<transition>` and `<keep-alive>`. When using them both together, make sure to use `<keep-alive>` inside:\n\n```html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n\n## `<router-view>` Props\n\n### name\n\n- type: `string`\n- default: `\"default\"`\n\n  When a `<router-view>` has a name, it will render the component with the corresponding name in the matched route record's `components` option. See [Named Views](../guide/essentials/named-views.md) for an example.\n\n## Router Construction Options\n\n### routes\n\n- type: `Array<RouteConfig>`\n\n  Type declaration for `RouteConfig`:\n\n  ```ts\n  interface RouteConfig = {\n    path: string,\n    component?: Component,\n    name?: string, // for named routes\n    components?: { [name: string]: Component }, // for named views\n    redirect?: string | Location | Function,\n    props?: boolean | Object | Function,\n    alias?: string | Array<string>,\n    children?: Array<RouteConfig>, // for nested routes\n    beforeEnter?: (to: Route, from: Route, next: Function) => void,\n    meta?: any,\n\n    // 2.6.0+\n    caseSensitive?: boolean, // use case sensitive match? (default: false)\n    pathToRegexpOptions?: Object // path-to-regexp options for compiling regex\n  }\n  ```\n\n### mode\n\n- type: `string`\n\n- default: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- available values: `\"hash\" | \"history\" | \"abstract\"`\n\n  Configure the router mode.\n\n  - `hash`: uses the URL hash for routing. Works in all Vue-supported browsers, including those that do not support HTML5 History API.\n\n  - `history`: requires HTML5 History API and server config. See [HTML5 History Mode](../guide/essentials/history-mode.md).\n\n  - `abstract`: works in all JavaScript environments, e.g. server-side with Node.js. **The router will automatically be forced into this mode if no browser API is present.**\n\n### base\n\n- type: `string`\n\n- default: `\"/\"`\n\n  The base URL of the app. For example, if the entire single page application is served under `/app/`, then `base` should use the value `\"/app/\"`.\n\n### linkActiveClass\n\n- type: `string`\n\n- default: `\"router-link-active\"`\n\n  Globally configure `<router-link>` default active class. Also see [router-link](#router-link).\n\n### linkExactActiveClass\n\n- type: `string`\n\n- default: `\"router-link-exact-active\"`\n\n  Globally configure `<router-link>` default active class for exact matches. Also see [router-link](#router-link).\n\n### scrollBehavior\n\n- type: `Function`\n\n  Signature:\n\n  ```ts\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    void\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  For more details see [Scroll Behavior](../guide/advanced/scroll-behavior.md).\n\n### parseQuery / stringifyQuery\n\n- type: `Function`\n\n  Provide custom query string parse / stringify functions. Overrides the default.\n\n### fallback\n\n- type: `boolean`\n\n- default: `true`\n\n  Controls whether the router should fallback to `hash` mode when the browser does not support `history.pushState` but mode is set to `history`.\n\n  Setting this to `false` essentially makes every `router-link` navigation a full page refresh in IE9. This is useful when the app is server-rendered and needs to work in IE9, because a hash mode URL does not work with SSR.\n\n## Router Instance Properties\n\n### router.app\n\n- type: `Vue instance`\n\n  The root Vue instance the `router` was injected into.\n\n### router.mode\n\n- type: `string`\n\n  The [mode](./#mode) the router is using.\n\n### router.currentRoute\n\n- type: `Route`\n\n  The current route represented as a [Route Object](#the-route-object).\n\n### router.START_LOCATION (3.5.0+)\n\n- type: `Route`\n\n  Initial route location represented as a [Route Object](#the-route-object) where the router starts at. Can be used in navigation guards to differentiate the initial navigation.\n\n  ```js\n  import VueRouter from 'vue-router'\n\n  const router = new VueRouter({\n    // ...\n  })\n\n  router.beforeEach((to, from) => {\n    if (from === VueRouter.START_LOCATION) {\n      // initial navigation\n    }\n  })\n  ```\n\n## Router Instance Methods\n\n### router.beforeEach\n\n### router.beforeResolve\n\n### router.afterEach\n\nSignatures:\n\n```js\nrouter.beforeEach((to, from, next) => {\n  /* must call `next` */\n})\n\nrouter.beforeResolve((to, from, next) => {\n  /* must call `next` */\n})\n\nrouter.afterEach((to, from) => {})\n```\n\nAdd global navigation guards. See [Navigation Guards](../guide/advanced/navigation-guards.md) for more details.\n\nAll three methods return a function that removes the registered guard/hook.\n\n### router.push\n\n### router.replace\n\n### router.go\n\n### router.back\n\n### router.forward\n\nSignatures:\n\n```js\nrouter.push(location, onComplete?, onAbort?)\nrouter.push(location).then(onComplete).catch(onAbort)\nrouter.replace(location, onComplete?, onAbort?)\nrouter.replace(location).then(onComplete).catch(onAbort)\nrouter.go(n)\nrouter.back()\nrouter.forward()\n```\n\nProgrammatically navigate to a new URL. See [Programmatic Navigation](../guide/essentials/navigation.md) for more details.\n\nThese functions can only be called after installing the Router plugin and passing it to the root Vue instance as shown in the [Getting Started](../guide/README.md).\n\n### router.getMatchedComponents\n\nSignature:\n\n```js\nconst matchedComponents: Array<Component> = router.getMatchedComponents(location?)\n```\n\nReturns an Array of the components (definition/constructor, not instances) matched by the provided location or the current route. This is mostly used during server-side rendering to perform data prefetching.\n\n### router.resolve\n\nSignature:\n\n```js\nconst resolved: {\n  location: Location;\n  route: Route;\n  href: string;\n} = router.resolve(location, current?, append?)\n```\n\nReverse URL resolving. Given location in form same as used in `<router-link/>`.\n\n- `current` is the current Route by default (most of the time you don't need to change this)\n- `append` allows you to append the path to the `current` route (as with [`router-link`](#router-link-props))\n\n### router.addRoutes\n\n_DEPRECATED_: use [`router.addRoute()`](#router-addroute) instead.\n\nSignature:\n\n```ts\nrouter.addRoutes(routes: Array<RouteConfig>)\n```\n\nDynamically add more routes to the router. The argument must be an Array using the same route config format with the `routes` constructor option.\n\n### router.addRoute\n\n> New in 3.5.0\n\nAdd a new route to the router. If the route has a `name` and there is already an existing one with the same one, it overwrites it.\n\nSignature:\n\n```ts\naddRoute(route: RouteConfig): () => void\n```\n\n### router.addRoute\n\n> New in 3.5.0\n\nAdd a new route record as the child of an existing route. If the route has a `name` and there is already an existing one with the same one, it overwrites it.\n\nSignature:\n\n```ts\naddRoute(parentName: string, route: RouteConfig): () => void\n```\n\n### router.getRoutes\n\n> New in 3.5.0\n\nGet the list of all the active route records. **Note only documented properties are considered Public API**, avoid using any other property e.g. `regex` as it doesn't exist on Vue Router 4.\n\nSignature:\n\n```ts\ngetRoutes(): RouteRecord[]\n```\n\n### router.onReady\n\nSignature:\n\n```js\nrouter.onReady(callback, [errorCallback])\n```\n\nThis method queues a callback to be called when the router has completed the initial navigation, which means it has resolved all async enter hooks and async components that are associated with the initial route.\n\nThis is useful in server-side rendering to ensure consistent output on both the server and the client.\n\nThe second argument `errorCallback` is only supported in 2.4+. It will be called when the initial route resolution runs into an error (e.g. failed to resolve an async component).\n\n### router.onError\n\nSignature:\n\n```js\nrouter.onError(callback)\n```\n\nRegister a callback which will be called when an error is caught during a route navigation. Note for an error to be called, it must be one of the following scenarios:\n\n- The error is thrown synchronously inside a route guard function;\n\n- The error is caught and asynchronously handled by calling `next(err)` inside a route guard function;\n\n- An error occurred when trying to resolve an async component that is required to render a route.\n\n## The Route Object\n\nA **route object** represents the state of the current active route. It contains parsed information of the current URL and the **route records** matched by the URL.\n\nThe route object is immutable. Every successful navigation will result in a fresh route object.\n\nThe route object can be found in multiple places:\n\n- Inside components as `this.$route`\n\n- Inside `$route` watcher callbacks\n\n- As the return value of calling `router.match(location)`\n\n- Inside navigation guards as the first two arguments:\n\n  ```js\n  router.beforeEach((to, from, next) => {\n    // `to` and `from` are both route objects\n  })\n  ```\n\n- Inside the `scrollBehavior` function as the first two arguments:\n\n  ```js\n  const router = new VueRouter({\n    scrollBehavior(to, from, savedPosition) {\n      // `to` and `from` are both route objects\n    }\n  })\n  ```\n\n### Route Object Properties\n\n- **\\$route.path**\n\n  - type: `string`\n\n    A string that equals the path of the current route, always resolved as an absolute path. e.g. `\"/foo/bar\"`.\n\n- **\\$route.params**\n\n  - type: `Object`\n\n    An object that contains key/value pairs of dynamic segments and star segments. If there are no params the value will be an empty object.\n\n- **\\$route.query**\n\n  - type: `Object`\n\n    An object that contains key/value pairs of the query string. For example, for a path `/foo?user=1`, we get `$route.query.user == 1`. If there is no query the value will be an empty object.\n\n- **\\$route.meta**\n\n  - type: `Object`\n\n    An object that contains key/value pairs of the route meta object. If there are no meta properties the value will be an empty object.\n\n- **\\$route.hash**\n\n  - type: `string`\n\n    The hash of the current route (with the `#`), if it has one. If no hash is present the value will be an empty string.\n\n- **\\$route.fullPath**\n\n  - type: `string`\n\n    The full resolved URL including query and hash.\n\n- **\\$route.matched**\n\n  - type: `Array<RouteRecord>`\n\n  An Array containing **route records** for all nested path segments of the current route. Route records are the copies of the objects in the `routes` configuration Array (and in `children` Arrays):\n\n  ```js\n  const router = new VueRouter({\n    routes: [\n      // the following object is a route record\n      {\n        path: '/foo',\n        component: Foo,\n        children: [\n          // this is also a route record\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  When the URL is `/foo/bar`, `$route.matched` will be an Array containing both objects (cloned), in parent to child order.\n\n- **\\$route.name**\n\n  The name of the current route, if it has one. (See [Named Routes](../guide/essentials/named-routes.md))\n\n- **\\$route.redirectedFrom**\n\n  The name of the route being redirected from, if there were one. (See [Redirect and Alias](../guide/essentials/redirect-and-alias.md))\n\n## Component Injections\n\n### Component Injected Properties\n\nThese properties are injected into every child component by passing the router instance to the root instance as the `router` option.\n\n- **this.\\$router**\n\n  The router instance.\n\n- **this.\\$route**\n\n  The current active [Route](#the-route-object). This property is read-only and its properties are immutable, but it can be watched.\n\n### Component Enabled Options\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate**\n- **beforeRouteLeave**\n\n  See [In Component Guards](../guide/advanced/navigation-guards.md#in-component-guards).\n"
  },
  {
    "path": "docs/fr/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Get Started →\nactionLink: /fr/installation.html\nfooter: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote\n---\n\nVue Router est le router officiel pour [Vue.js](http://vuejs.org). Il s'intègre aisément avec Vue.js pour faire des applications mono page avec Vue.js. Fonctionnalités incluses:\n\n- Vues et routes imbriquées\n- Modulaire, configuration basée sur les composants\n- Paramètres de route, de requête\n- Effets de transition de vues basées sur le systeme de transition de Vue.js\n- Gestion fine de la navigation\n- Classes CSS pour liens actifs\n- Mode HTML5 de la gestion de l'historique ou mode par hash, avec solution de repli automatique pour IE9\n- Gestion du scroll\n\n[Pour commencer](./guide/) ou jouer avec les [exemples](https://github.com/vuejs/vue-router/tree/dev/examples) (voir [`README.md`](https://github.com/vuejs/vue-router/) pour les faire fonctionner).\n\n<HomeSponsors />\n"
  },
  {
    "path": "docs/fr/api/README.md",
    "content": "---\nsidebar: auto\n---\n\n# API\n\n## `<router-link>`\n\n`<router-link>` est le composant pour activer la navigation utilisateur dans une application où le routeur est activé. La localisation cible est spécifiée grâce à la prop `to`. Il est rendu en tant que balise `<a>` avec le `href` correct par défaut, mais peut être configuré grâce à la prop `tag`. De plus, le lien se verra attribuer une classe CSS active lorsque la route cible est active.\n\n`<router-link>` est préféré par rapport au `<a href=\"...\">` en dur dans le code pour les raisons suivantes :\n\n- Cela fonctionne de la même manière qu'on soit dans le mode historique HTML5 ou le mode hash, donc si vous avez décidé de changer de mode, ou alors que le routeur se replie sur le mode hash pour IE9, rien n'a besoin d'être changé.\n\n- Dans le mode historique HTML5, `router-link` interceptera l'évènement du clic, comme ça le navigateur n'essaiera pas de rafraichir la page.\n\n- En utilisant l'option `base` dans le mode historique HTML5, vous n'avez pas besoin de l'inclure dans la prop `to`\n\n### `v-slot` API (3.1.0+)\n\n`router-link` est fortement personnalisable via une [slot avec portée](https://fr.vuejs.org/v2/guide/components-slots.html#Slots-avec-portee). C'est une API qui cible principalement les créateurs de bibliothèque, mais elle peut aussi servir pour les développeurs, le plus souvent dans des composants personnalisés tel qu'un _NavLink_ et autre.\n\n**Lors de l'utilisation `v-slot` API, il faut obligatoirement passer un composant enfant unique au `router-link`**. Si vous ne le faites pas, `router-link` va entourer ses enfants avec une balise `span`.\n\n```html\n<router-link\n  to=\"/about\"\n  custom\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <NavLink :active=\"isActive\" :href=\"href\" @click=\"navigate\"\n    >{{ route.fullPath }}</NavLink\n  >\n</router-link>\n```\n\n- `href`: URL résolue. Ce serait l'attribut `href` d'une balise `a`\n- `route`: localisation normalisée et résolue\n- `navigate`: fonction pour lancer la navigation. **En cas de nécessité il va automatiquement empêcher les événements**, de la même façon que `router-link`\n- `isActive`: `true` si [active class](#active-class) devrait être appliqué. Permet d'appliquer une classe arbitraire\n- `isExactActive`: `true` si [exact active class](#exact-active-class) devrait être appliqué. Permet d'appliquer une classe arbitraire\n\n### Appliquer la classe active à l'élément extérieur\n\nParfois, on voudrait que la classe active soit appliquée à un élément extérieur au lieu de l'élément `<a>` lui-même, dans ce cas, vous pouvez faire le rendu de cet élément extérieur en utilisant `<router-link>` et en entourant le tag `<a>` :\n\n```html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\nDans ce cas, `<a>` sera le lien actuel (et récupèrera le bon `href`), mais la classe active sera appliquée à l'élément extérieur `<li>`.\n\n## `<router-link>` Props\n\n### to\n\n- type : `string | Location`\n- requis\n\n  Désigne la route cible du lien. Lorsqu'il est cliqué, la valeur de la prop `to` va être passée de manière interne à `router.push`, donc la valeur peut soit être une chaine de caractères, ou alors un objet décrivant une localisation.\n\n  ```html\n  <!--  chaine littérale  -->\n  <router-link to=\"home\">Accueil</router-link>\n  <!-- rend -->\n  <a href=\"home\">Accueil</a>\n\n  <!-- expression JavaScript en utilisant `v-bind` -->\n  <router-link v-bind:to=\"'home'\">Accueil</router-link>\n\n  <!-- Omettre `v-bind` est OK, tout comme une autre prop -->\n  <router-link :to=\"'home'\">Accueil</router-link>\n\n  <!-- pareil qu'au-dessus -->\n  <router-link :to=\"{ path: 'home' }\">Accueil</router-link>\n\n  <!-- route nommée -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\"\n    >Utilisateur</router-link\n  >\n\n  <!-- avec une requête, résulte en `/register?plan=private` -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\"\n    >S'enregistrer</router-link\n  >\n  ```\n\n### replace\n\n- type : `boolean`\n- défaut : `false`\n\n  Configurer la prop `replace` appellera `router.replace()` au lieu de `router.push()` lors du clic, comme ça, la navigation ne laissera pas un enregistrement dans l'historique.\n\n  ```html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n### append\n\n- type : `boolean`\n- défaut : `false`\n\n  Configurer la propriété `append` suffixe toujours le chemin relatif au chemin courant. Par exemple, assumons que nous naviguons de `/a` à un lien relatif `b`, sans `append` on finira sur `/b`, mais avec `append` on finira sur `/a/b`.\n\n  ```html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n### tag\n\n- type : `string`\n- défaut : `\"a\"`\n\n  Parfois, on veut que `<router-link>` soit rendu avec une balise différente, ex : `<li>`. On peut alors utiliser la prop `tag` pour modifier la balise qui sera rendue, et elle écoutera toujours les évènements de clic pour la navigation.\n\n  ```html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- rend -->\n  <li>foo</li>\n  ```\n\n### active-class\n\n- type : `string`\n- défaut : `\"router-link-active\"`\n\n  Configure la classe CSS active qui sera appliquée lorsque le lien sera actif. Notez que la valeur par défaut peut aussi être configurée de manière globale via l'option `linkActiveClass` du constructeur du routeur.\n\n### exact\n\n- type : `boolean`\n- défaut : `false`\n\nLe comportement par défaut de la correspondance de classe active est une **correspondance inclusive**. Par exemple, `<router-link to=\"/a\">` verra cette classe appliquée tant que le chemin courant commencera par `/a/` ou `/a`.\n\nUne conséquence de cela est que `<router-link to=\"/\">` sera actif pour toutes les routes ! Pour forcer le lien dans un « mode correspondance exacte », utilisez la prop `exact`.\n\n```html\n<!-- ce lien sera uniquement actif à `/` -->\n<router-link to=\"/\" exact></router-link>\n```\n\nAllez voir les exemples expliquant la classe active pour les liens [ici](https://jsfiddle.net/8xrk1n9f/).\n\n### event\n\n- type : `string | Array<string>`\n- défaut : `'click'`\n\n  Spécifie les évènement(s) que peu(ven)t lancer la navigation de lien.\n\n### exact-active-class\n\n- type : `string`\n- défaut : `\"router-link-exact-active\"`\n\n  Configure la classe CSS active qui sera appliquée lorsqu'un lien sera actif avec une correspondance exacte. Notez que la valeur par défaut peut aussi être configurée de manière globale via l'option `linkExactActiveClass` du constructeur du routeur.\n\n## `<router-view>`\n\nLe composant `<router-view>` est un composant fonctionnel qui fait le rendu du composant correspondant au chemin donné. Les composants rendus dans `<router-view>` peuvent aussi contenir leur propre `<router-view>`, qui fera le rendu des composants pour les chemins imbriqués.\n\n## `<router-view>` Props\n\n### name\n\n- type : `string`\n- défaut : `\"default\"`\n\n  Lorsqu'un `<router-view>` a un nom, il fera le rendu du composant correspondant à ce nom dans les itinéraires de route correspondant à l'option `components`. Voir les [Routes nommées](../guide/essentials/named-views.md) pour un exemple.\n\n## Options de construction du routeur\n\n### routes\n\n- type: `Array<RouteConfig>`\n\n  Déclaration de type pour `RouteConfig` :\n\n  ```js\n  declare type RouteConfig = {\n    path: string,\n    component?: Component,\n    name?: string, // pour les routes nommées\n    components?: { [name: string]: Component }, // pour les vues nommées\n    redirect?: string | Location | Function,\n    props?: boolean | string | Function,\n    alias?: string | Array<string>,\n    children?: Array<RouteConfig>, // pour les routes imbriquées\n    beforeEnter?: (to: Route, from: Route, next: Function) => void,\n    meta?: any,\n\n    // 2.6.0+\n    caseSensitive?: boolean, // use case sensitive match? (default: false)\n    pathToRegexpOptions?: Object // path-to-regexp options for compiling regex\n  }\n  ```\n\n### mode\n\n- type : `string`\n\n- défaut : `\"hash\" (dans le navigateur) | \"abstract\" (en Node.js)`\n\n- valeurs disponibles : `\"hash\" | \"history\" | \"abstract\"`\n\n  Configure le mode du routeur.\n\n  - `hash` : utilise le hash de l'URL pour le routage. Fonctionne dans tous les navigateurs supportés par Vue, ainsi que ceux qui ne supportent pas l'API History d'HTML5.\n\n  - `history` : nécessite l'API History d'HTML 5 et la configuration du serveur. Voir [Mode historique de HTML5](../guide/essentials/history-mode.md).\n\n  - `abstract` : fonctionne dans tous les environnements JavaScript, ex. côté serveur avec Node.js. **Le routeur sera automatiquement forcé d'utiliser ce mode si aucune API navigateur n'est présente.**\n\n### base\n\n- type : `string`\n\n- défaut : `\"/\"`\n\n  L'URL de base de l'application. Par exemple, si l'application monopage entière est distribuée sous `/app/`, alors `base` doit utiliser la valeur `\"/app/\"`.\n\n### linkActiveClass\n\n- type : `string`\n\n- défaut : `\"router-link-active\"`\n\n  Configure de manière globale la classe active par défaut de `<router-link>`. Voir aussi [router-link](./#router-link).\n\n### linkExactActiveClass\n\n- type : `string`\n\n- default : `\"router-link-exact-active\"`\n\n  Configure de manière globale la classe active par défaut de `<router-link>` lors d'une correspondance exacte. Voir aussi [router-link](./#router-link).\n\n### scrollBehavior\n\n- type : `Function`\n\n  Signature :\n\n  ```ts\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    void\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  Pour plus de détails, voir [Comportement du Scroll](../guide/advanced/scroll-behavior.md).\n\n### parseQuery / stringifyQuery\n\n- type : `Function`\n\n  Permettent de spécifier des fonctions personnalisées pour formater en objet ou en chaîne de caractères la requête. Surcharge les fonctions par défaut.\n\n### fallback\n\n- type : `boolean`\n\n  Contrôle comment le routeur devrait passer en mode `hash` quand le navigateur ne supporte pas `history.pushState`. Par défaut à `true`.\n\n  Passer cette valeur à `false` va essentiellement faire que la navigation via `router-link` va réclamer un rechargement de page dans IE9. Ceci est utile quand l'application est rendue côté serveur et à besoin de fonctionner dans IE9, car le mode hash ne fonctionne pas avec du SSR.\n\n## L'instance du routeur\n\n### router.app\n\n- type: `instance de Vue`\n\nL'instance racine de Vue dans laquelle l'instance de `routeur` a été injectée.\n\n### router.mode\n\n- type: `string`\n\n  Le [mode](./#mode) que le routeur utilise.\n\n### router.currentRoute\n\n- type: `Route`\n\n  La route actuelle représentée en tant qu'un [objet route](./#proprietes-de-l-objet-route).\n\n## Méthodes\n\n### router.beforeEach\n\n### router.beforeResolve\n\n### router.afterEach\n\nAjout des interceptions globales de navigation. Voir les [Intercepteurs de navigation](../guide/advanced/navigation-guards.md).\n\nDans la version 2.5.0+, ces trois méthodes retournent une fonction qui enlève les fonctions d'interception et hooks enregistrés.\n\n### router.push\n\n### router.replace\n\n### router.go\n\n### router.back\n\n### router.forward\n\nNavigue à une nouvelle URL de façon programmée. Voir [Navigation de façon programmée](../guide/essentials/navigation.md).\n\n### router.getMatchedComponents\n\nRetourne un tableau de composants (définition/constructeur et non les instances) correspondant à la `location` passée en paramètre, ou alors de la route actuelle. Cette fonction est principalement utilisée pendant le rendu côté serveur afin d'effectuer une prérécupération des données.\n\n### router.resolve\n\nInverse la résolution d'URL. La `location` doit avoir la même forme qu'utilisée dans `<router-link>`, retourne un objet avec les propriétés suivantes :\n\n```js\n{\n  location: Location\n  route: Route\n  href: string\n}\n```\n\n- `current` is the current Route by default (most of the time you don't need to change this)\n- `append` allows you to append the path to the `current` route (as with [`router-link`](./#router-link-props))\n\n### router.addRoutes\n\nPermet d'ajouter dynamiquement des routes au routeur. L'argument doit être un tableau utilisant le même format de configuration que l'option `routes` du constructeur.\n\n### router.onReady\n\nCette méthode met en file d'attente une fonction de rappel qui sera appelée lorsque le routeur aura complété la navigation initiale, ce qui signifie qu'il a résolu tous les hooks d'entrées asynchrones et composants asynchrones qui sont associés à la route initiale.\n\nC'est utile pendant un rendu côté serveur pour assurer une sortie consistance sur le serveur et le client.\n\nLe deuxième argument `errorCallback` est uniquement supporté à partir de la version 2.4. Il sera appelé lorsque la résolution de la route initiale résultera en une erreur (ex. : la résolution d'un composant asynchrone qui a échoué).\n\n### router.onError\n\nEnregistre une fonction de rappel qui sera appelée lorsqu'une erreur sera capturée pendant la navigation vers une route. Notez que pour qu'une erreur soit appelée, cela doit correspondre à l'un des scénarios suivants :\n\n- L'erreur est lancée de manière synchrone à l'intérieur d'une fonction d'interception de route ;\n\n- L'erreur est capturée et traitée de manière asynchrone en appelant `next(err)` à l'intérieur d'une fonction d'interception de route ;\n\n- Une erreur est survenue pendant la résolution d'un composant asynchrone qui est requis pour faire le rendu d'une route.\n\n# L'objet `Route`\n\nUn **objet `Route`** représente l'état actuel de la route active. Il contient des informations analysées à propos de l'URL courant et **les itinéraires de route** appariés par l'URL.\n\nL'objet `Route` est immutable. Chaque navigation qui se déroule avec succès résultera en un nouvel objet `Route`.\n\nL'objet `Route` peut être trouvé à plusieurs endroits :\n\n- À l'intérieur des composants en tant que `this.$route`\n\n- À l'intérieur des fonctions de rappel des observateurs de `$route`\n\n- Comme valeur de retour après l'appel de `router.match(location)`\n\n- À l'intérieur des fonctions d'interception de la navigation, dans les deux premiers paramètres de la fonction :\n\n  ```js\n  router.beforeEach((to, from, next) => {\n    // `to` et `from` sont tous les deux des objets Route\n  })\n  ```\n\n- À l'intérieur de la fonction `scrollBehavior` dans les deux premiers arguments :\n\n  ```js\n  const router = new VueRouter({\n    scrollBehavior(to, from, savedPosition) {\n      // `to` et `from` sont tous les deux des objets Route\n    }\n  })\n  ```\n\n### Propriétés de l'objet `Route`\n\n- **\\$route.path**\n\n  - type : `string`\n\n    Une chaine de caractères représentant le chemin de la route en cours, toujours résolue en tant que chemin absolu, ex : `\"/foo/bar\"`.\n\n- **\\$route.params**\n\n  - type : `Object`\n\n    Un objet qui contient des pairs clé/valeur de segments dynamiques et segments _star_. S'il n'y a pas de paramètres, alors la valeur sera un objet vide.\n\n- **\\$route.query**\n\n  - type : `Object`\n\n    Un objet qui contient des pairs clé/valeur de la requête au format d'une chaine de caractères. Par exemple, pour un chemin `/foo?user=1`, on aura `$route.query.user == 1`. S'il n'y a pas de requête, alors la valeur sera un objet vide.\n\n- **\\$route.hash**\n\n  - type : `string`\n\n    Le hash de la route courante (avec le `#`), s'il y en a un. S'il n'y a pas de hash, alors la valeur sera une chaine de caractères vide.\n\n- **\\$route.fullPath**\n\n  - type : `string`\n\n    L'URL entièrement résolu, incluant la requête et le hash.\n\n- **\\$route.matched**\n\n  - type : `Array<RouteRecord>`\n\n    Un `Array` contenant les **les itinéraires de la route** pour chaque segment de chemin imbriqué de la route courante. Les itinéraires de la route sont des copies des objets dans le tableau de configuration `routes` (et dans les tableaux `children`).\n\n  ```js\n  const router = new VueRouter({\n    routes: [\n      // l'objet qui suit est un itinéraire de route\n      {\n        path: '/foo',\n        component: Foo,\n        children: [\n          // c'est aussi un itinéraire\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  Lorsque l'URL sera `/foo/bar`, `$route.matched` sera un `Array` contenant les deux objets (clonés), dans l'ordre parent à l'enfant.\n\n- **\\$route.name**\n\n  Le nom de la route courante, si elle en a un. (Voir [Routes nommées](../guide/essentials/named-routes.md)).\n\n- **\\$route.redirectedFrom**\n\n  Le nom de la route d'où la page a été redirigée, si elle en a un. (Voir [Redirection et alias](../guide/essentials/redirect-and-alias.md)).\n\n## Injections de composant\n\n### Propriétés injectées\n\nCes propriétés sont injectées dans chacun des composants enfants, en passant l'instance du routeur à l'application racine de Vue en tant qu'option `router`.\n\n- **\\$router**\n\n  L'instance du routeur.\n\n- **\\$route**\n\nLa [Route](./#proprietes-de-l-objet-route) actuellement active. C'est une propriété en lecture seule et ses propriétés sont immutables, mais elles restent malgré tout observables.\n\n### Options activées\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate** (ajouté en 2.2)\n- **beforeRouteLeave**\n\n  Voir l'[interception par composant](../guide/advanced/navigation-guards.md#securisation-par-composant).\n"
  },
  {
    "path": "docs/fr/guide/README.md",
    "content": "# Pour commencer\n\n::: tip Note\nNous utiliserons [ES2015](https://github.com/lukehoban/es6features) dans les exemples de code dans ce guide.\nTous les exemples utiliseront la version complète de Vue pour rendre l'analyse de template possible. Plus de détails [ici](https://fr.vuejs.org/guide/installation.html#Runtime-Compiler-vs-Runtime-seul).\n:::\n\nCréer une application monopage avec Vue + Vue Router est vraiment simple. Avec Vue.js, nous concevons déjà notre application avec des composants. En ajoutant vue-router dans notre application, tout ce qu'il nous reste à faire est de relier nos composants aux routes, et de laisser vue-router faire le rendu. Voici un exemple de base :\n\n## HTML\n\n```html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Bonjour l'application !</h1>\n  <p>\n    <!-- utilisez le composant router-link pour la navigation. -->\n    <!-- spécifiez le lien en le passant à la prop `to` -->\n    <!-- `<router-link>` sera rendu en tag `<a>` par défaut -->\n    <router-link to=\"/foo\">Aller à Foo</router-link>\n    <router-link to=\"/bar\">Aller à Bar</router-link>\n  </p>\n  <!-- balise pour le composant router-view -->\n  <!-- le composant correspondant à la route sera rendu ici -->\n  <router-view></router-view>\n</div>\n```\n\n## JavaScript\n\n```js\n// 0. Si vous utilisez un système de module (par ex. via vue-cli), il faut importer Vue et Vue Router et ensuite appeler `Vue.use(VueRouter)`.\n\n// 1. Définissez les composants de route.\n// Ces derniers peuvent être importés depuis d'autre fichier\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Définissez des routes.\n// Chaque route doit correspondre à un composant. Le « composant » peut\n// soit être un véritable composant créé via `Vue.extend()`, ou juste un\n// objet d'options.\n// Nous parlerons plus tard des routes imbriquées.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Créez l'instance du routeur et passez l'option `routes`.\n// Vous pouvez également passer des options supplémentaires,\n// mais nous allons faire simple pour l'instant.\nconst router = new VueRouter({\n  routes // raccourci pour `routes: routes`\n})\n\n// 5. Créez et montez l'instance de Vue.\n// Soyez sûr d'injecter le routeur avec l'option `router` pour\n// permettre à l'application tout entière d'être à l'écoute du routeur.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// L'application est maintenant en marche !\n```\n\nEn injectant le routeur, nous y avons accès à travers `this.$router`. Nous avons également accès à la route courante derrière `this.$route` depuis n'importe quel composant :\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username() {\n      // Nous verrons ce que représente `params` dans un instant.\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack() {\n      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')\n    }\n  }\n}\n```\n\nDans les documentations, nous allons souvent utiliser l'instance `router`. Gardez à l'esprit que l'utilisation de `this.$router` est exactement la même chose que celle de `router`. La raison pour laquelle nous utilisons `this.$router` est la possibilité ainsi offerte de ne pas avoir à importer le routeur dans chaque fichier de composant ayant besoin d'accéder au routage.\n\nVous pouvez aussi regarder cet [exemple](https://jsfiddle.net/yyx990803/xgrjzsup/).\n\nNotez qu'un `<router-link>` obtiendra automatiquement la classe `.router-link-active` lorsque sa route cible correspond à la route actuelle. Vous pouvez en apprendre plus à propos de cela dans sa [documentation d'API](../api/#router-link).\n"
  },
  {
    "path": "docs/fr/guide/advanced/data-fetching.md",
    "content": "# Récupération de données\n\nParfois vous avez besoin de récupérer des données depuis le serveur lorsqu'une route est activée. Par exemple, avant de faire le rendu d'un profil utilisateur, vous avez besoin de récupérer les données de l'utilisateur depuis le serveur. Nous pouvons y parvenir de deux façons différentes :\n\n- **Récupération de données après la navigation** : effectue la navigation en premier, et récupère les données dans le hook entrant du cycle de vie d'un composant. Affiche un état de chargement pendant que les données sont en train d'être récupérées.\n\n- **Récupération de données avant la navigation** : récupère les données avant la navigation dans la fonction d'interception d'entrée de la route, et effectue la navigation après que les données aient été récupérées.\n\nTechniquement, les deux choix sont valides. Cela dépend de l'expérience utilisateur que vous souhaitez apporter.\n\n## Récupération de données après la navigation\n\nEn utilisant cette approche, nous naviguons et faisons immédiatement le rendu du composant et récupérons les données via le hook `created` du composant. Cela nous donne l'opportunité d'afficher un état de chargement pendant que les données sont récupérées à travers le réseau, et nous pouvons aussi gérer le chargement différemment pour chaque vue.\n\nAssumons que nous ayons un composant `Post` qui a besoin de récupérer des données pour un billet identifié par `$route.params.id` :\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Chargement...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // récupérer les données lorsque la vue est créée et\n    // que les données sont déjà observées\n    this.fetchData()\n  },\n  watch: {\n    // appeler encore la méthode si la route change\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // remplacer `getPost` par une fonction de récupération de données\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Récupération de données avant la navigation\n\nAvec cette approche, nous récupèrerons les données avant de naviguer vers la nouvelle route. Nous pouvons effectuer la récupération de données dans la fonction d'interception `beforeRouteEnter` du composant à venir, et seulement appeler `next` lorsque la récupération est terminée :\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // quand la route change et que ce composant est déjà rendu,\n  // la logique est un peu différente\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\nL'utilisateur va rester sur la vue précédente pendant que la ressource est en train d'être récupérée pour la vue à venir. Il est cependant recommandé d'afficher une barre de progression ou un autre type d'indicateur pendant que les données sont en train d'être récupérées. Si la récupération échoue, il est aussi recommandé d'afficher une sorte de message d'erreur global.\n"
  },
  {
    "path": "docs/fr/guide/advanced/lazy-loading.md",
    "content": "# Chargement à la volée\n\nPendant la construction d'applications avec un empaqueteur (« bundler »), le paquetage JavaScript peut devenir un peu lourd, et donc cela peut affecter le temps de chargement de la page. Il serait plus efficace si l'on pouvait séparer chaque composant de route dans des fragments séparés, et de les charger uniquement lorsque la route est visitée.\n\nEn combinant la [fonctionnalité de composant asynchrone](https://fr.vuejs.org/v2/guide/components.html#Composants-asynchrones) de Vue et la [fonctionnalité de scission de code](https://webpack.js.org/guides/code-splitting-async/) de webpack, il est très facile de charger à la volée les composants de route.\n\nPremièrement, un composant asynchrone peut définir une fonction fabrique qui retourne une Promesse (qui devrait résoudre le composant lui-même) :\n\n```js\nconst Foo = () =>\n  Promise.resolve({\n    /* définition du composant */\n  })\n```\n\nDeuxièmement, avec webpack 2, nous pouvons utiliser la syntaxe d'[import dynamique](https://github.com/tc39/proposal-dynamic-import) pour indiquer un point de scission de code :\n\n```js\nimport('./Foo.vue') // returns a Promise\n```\n\n::: tip Note\nsi vous utilisez Babel, vous aurez besoin d'ajouter le plugin [syntax-dynamic-import](http://babeljs.io/docs/plugins/syntax-dynamic-import/) de façon à ce que Babel puisse analyser correctement la syntaxe.\n:::\n\nEn combinant les deux, on définit un composant asynchrone qui sera automatiquement scindé par webpack :\n\n```js\nconst Foo = () => import('./Foo.vue')\n```\n\nRien n'a besoin d'être modifié dans la configuration de la route, utilisez `Foo` comme d'habitude.\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/foo', component: Foo }]\n})\n```\n\n## Grouper des composants dans le même fragment\n\nParfois on aimerait grouper tous les composants imbriqués sous la même route, dans un seul et même fragment asynchrone. Pour arriver à cela, nous avons besoin d'utiliser les [fragments nommés](https://webpack.js.org/api/module-methods/#magic-comments) en donnant un nom au fragment en utilisant une syntaxe de commentaire spéciale (requires webpack > 2.4) :\n\n```js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nwebpack groupera tous les modules asynchrones avec le même nom de fragment dans le même fragment asynchrone.\n"
  },
  {
    "path": "docs/fr/guide/advanced/meta.md",
    "content": "# Champs meta de route\n\nVous pouvez inclure un champ `meta` quand vous définissez une route :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // un champ `meta`\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nComment maintenant accéder à ce champ `meta` ?\n\nTout d'abord, chaque objet route dans la configuration de `routes` est appelé un **registre de route**. Les registres de route peuvent être imbriqués. Par conséquent, quand une route concorde, elle peut potentiellement concorder avec plus d'un registre de route.\n\nPar exemple, avec la configuration de route ci-dessous, l'URL `/foo/bar` va concorder avec le registre parent et le registre enfant.\n\nTous les registres concordants avec une route sont exposés dans l'objet `$route` (ainsi que les objets de route dans les sécurisations de navigation) dans le tableau `$route.matched`. Donc, nous devons itérer à travers `$route.matched` pour vérifier les champs meta dans les registres de route.\n\nUn exemple concret est la vérification d'un champ meta dans une interception de navigation globale :\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // cette route demande une autorisation, vérifions si l'utilisateur est logué.\n    // sinon, redirigeons le sur la page de login.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // assurez vous de toujours appeler `next()` !\n  }\n})\n```\n"
  },
  {
    "path": "docs/fr/guide/advanced/navigation-guards.md",
    "content": "# Intercepteurs de navigation\n\nComme le nom le suggère, l'interception de navigation fournie par `vue-router` est principalement utilisée pour intercepter la navigation avec des redirections ou des annulations d'accès. Il y a plusieurs hooks disponibles lors du processus de navigation : globaux, par route ou par composant.\n\nSouvenez-vous de cela : **le changement de paramètre ou de query ne va pas lancer d'interception d'entrée ou de sortie de navigation**. Vous pouvez toujours [observer l'objet `$route`](../essentials/dynamic-matching.md#reacting-to-params-changes) pour réagir à ces changements, ou utiliser la fonction `beforeRouteUpdate` d'une interception par composant.\n\n## Interception globale\n\nVous pouvez abonner une interception d'entrée en utilisant `router.beforeEach` :\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nLes interceptions d'entrées globales sont appelées lors de l'ordre de création, chaque fois qu'une navigation est déclenchée. Les interceptions peuvent être résolues de manière asynchrone, et la navigation est considérée comme **en attente** avant que tous les hooks ne soient résolus.\n\nChaque fonction d'interception reçoit trois arguments :\n\n- **`to: Route`**: L'[objet `Route`](../../api/#the-route-object) cible vers lequel on navigue.\n\n- **`from: Route`**: la route courante depuis laquelle nous venons de naviguer.\n\n- **`next: Function`**: cette fonction doit être appelée pour **résoudre** le hook. L'action dépend des arguments fournis à `next`:\n\n  - **`next()`**: se déplacer jusqu'au prochain hook du workflow. S'il ne reste aucun hook, la navigation est **confirmée**.\n\n  - **`next(false)`**: annuler la navigation courante. Si l'URL du navigateur avait changé (manuellement par l'utilisateur ou via le bouton retour du navigateur), il sera remis à sa valeur de route de `from`.\n\n  - **`next('/')` ou `next({ path: '/' })`**: redirige vers le nouvel URL. La navigation courante va être arrêtée et une nouvelle va se lancer. Vous pouvez passer n'importe quel objet à `next`, vous permettant ainsi de spécifier des options comme `replace: true`, `name: 'home'` et n'importe quelles options dans [la prop `to` du `router-link`](../../api/#to) ou [`router.push`](../../api/#routeur-push).\n\n  - **`next(error)`**: (2.4.0+) si l'argument passé à `next` est une instance de `Error`, la navigation va s'arrêter et l'erreur sera passée aux fonctions de rappel enregistrées via [`router.onError()`](../../api/#router-onerror).\n\n**Assurez-vous de toujours appeler la fonction `next`, sinon le hook ne sera jamais résolu.**\n\n## Résolutions des interceptions globales\n\nVous pouvez abonner une interception globale avec `router.beforeResolve`. Ceci est similaire a `router.beforeEach`, mais la différence est qu'elle sera appelée juste après que la navigation soit confirmée, **après que toutes les interceptions par composants et les composants de route asynchrone ait été résolu**.\n\n## Hooks de sortie globaux\n\nVous pouvez également abonner des hooks de sortie, cependant, à la différence des interceptions, ces hooks ne fournissent pas de fonction `next` et n'affecte pas la navigation :\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n## Interception par route\n\nVous pouvez définir l'interception `beforeEnter` directement sur l'objet de configuration d'une route :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nCes interceptions ont exactement le même effet que les interceptions globales d'entrée.\n\n## Interception par composant\n\nEnfin, vous pouvez directement définir une interception de navigation a l'intérieur du composant lui-même (celui passé à la configuration du routeur) avec les options suivantes :\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate`\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // appelée avant que la route vers le composant soit confirmée.\n    // cette fonction n'a pas accès à l'instance du composant avec `this`,\n    // car le composant n'a pas encore été créé quand cette interception est appelée !\n  },\n  beforeRouteUpdate (to, from, next) {\n    // appelée quand la route qui fait le rendu de ce composant change,\n    // mais que ce composant est utilisé de nouveau dans la nouvelle route.\n    // Par exemple, pour une route avec le paramètre dynamique `/foo/:id`, quand nous\n    // naviguons entre `/foo/1` et `/foo/2`, la même instance du composant `Foo`\n    // va être réutilisée, et ce hook va être appelé quand cela arrivera.\n    // ce hook a accès à l'instance de ce composant via `this`.\n  },\n  beforeRouteLeave (to, from, next) {\n    // appelée quand la route qui fait le rendu de ce composant est sur le point\n    // d'être laissée en faveur de la prochaine route.\n    // elle a accès à l'instance de ce composant via `this`.\n  }\n}\n```\n\nL'interception `beforeRouteEnter` **n'a PAS** accès à `this`, car l'interception est appelée avant que la navigation soit confirmée, et le nouveau composant entrant n'a même pas encore été créé.\n\nCependant, vous pouvez accéder à l'instance en passant dans la fonction de rappel `next`. Cette fonction de rappel va être appelée quand la navigation sera confirmée, et l'instance du composant sera passée à la fonction de rappel en tant qu'argument :\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // accès à l'instance du composant via `vm`\n  })\n}\n```\n\nNotez que `beforeRouteEnter` est la seule interception qui supporte une fonction de rappelle dans `next`. Pour `beforeRouteUpdate` et `beforeRouteLeave`, `this` est déjà disponible. Le passage d'une fonction de rappel n'étant pas nécessaire, il n'est donc pas *supporté* :\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // utiliser juste `this`\n  this.name = to.params.name\n  next()\n}\n```\n\nL'**interception de sortie** est habituellement utilisée pour empécher l'utilisateur de quitter la route sans avoir sauvegardé ses changements. La navigation peut être annulée en appelant `next(false)`.\n\n```js\nbeforeRouteLeave (to, from , next) {\n  const answer = window.confirm('Voulez-vous vraiment quitter cette page ? Vos changements seront perdus.')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\n## Le flux de résolution de navigation complet\n\n1. La navigation est demandée.\n2. Appel de l'interception de sortie des composants désactivés.\n3. Appel des interceptions globales `beforeEach`.\n4. Appel des interceptions `beforeRouteUpdate` pour les composants réutilisés.\n5. Appel de `beforeEnter` dans la configuration de route.\n6. Résolution des composants de route asynchrones.\n7. Appel de `beforeRouteEnter` dans les composants activés.\n8. Appel des interceptions `beforeResolve`.\n9. Confirmation de la navigation.\n10. Appel des hooks globaux `afterEach`.\n11. Modification du DOM demandée.\n12. Appel des fonctions de rappel passées à `next` dans l'interception `beforeRouteEnter` avec l'instance instanciée.\n"
  },
  {
    "path": "docs/fr/guide/advanced/scroll-behavior.md",
    "content": "# Comportement du défilement\n\nEn utilisant le routage côté client, nous pourrions vouloir faire défiler la page jusqu'en haut lorsqu'on navigue vers une nouvelle route, ou alors préserver la position du défilement des entrées de l'historique comme le ferait une page réelle. `vue-router` vous permet de faire cela et, encore mieux, vous permet de changer le comportement du défilement pendant la navigation.\n\n**Note : cette fonctionnalité ne fonctionne que si le navigateur supporte `history.pushState`.**\n\nPendant la création de l'instance du routeur, vous pouvez renseigner la fonction `scrollBehavior` :\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // retourner la position désirée\n  }\n})\n```\n\nLa fonction `scrollBehavior` reçoit les objets de route `to` et `from`. Le troisième argument, `savedPosition`, est disponible uniquement si c'est une navigation `popstate` (déclenchée par les boutons précédent/suivant du navigateur).\n\nLa fonction peut retourner un objet décrivant la position du défilement. L'objet peut être de la forme :\n\n-  `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset seulement supporté pour les versions 2.6.0+)\n\nSi une valeur équivalente à `false` ou un objet vide est retourné, aucun défilement ne sera produit.\n\nPar exemple :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nCela permettra de défiler au haut de page à chaque navigation à travers les routes.\n\nRetourner l'objet `savedPosition` résultera en un comportement quasi natif en naviguant avec les boutons précédents/suivants :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nSi vous voulez simuler le comportement « aller à l'ancre » :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nOn peut aussi utiliser les [champs meta de route](meta.md) pour implémenter un contrôle bien précis pour le comportement du défilement. Allez voir un exemple complet [ici](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js).\n\n## Défilement asynchrone\n\n> Nouveau dans la 2.8.0+\n\nVous pouvez également retourner une promesse pour résoudre la description de position souhaitée :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nIl est possible de relier les événements d'un composant de transition au niveau de la page pour que le comportement de défilement soit bien adapté à vos transitions de pages. Cependant, en raison de la variance et de la complexité des cas d'utilisation, nous fournissons simplement ce code primitif pour permettre aux utilisateurs de faire les implémentations spécifiques.\n"
  },
  {
    "path": "docs/fr/guide/advanced/transitions.md",
    "content": "# Transitions\n\nVu que `<router-view>` est essentiellement un composant dynamique, on peut lui appliquer certains effets de transitions en utilisant le composant `<transition>` :\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[Tout à propos de `<transition>`](https://fr.vuejs.org/v2/guide/transitions.html) fonctionne également ici de la même manière.\n\n## Transition par route\n\nL'utilisation du dessus applique la même transition pour chaque route. Si vous voulez que les composants de route aient des transitions différentes, vous pouvez utiliser à la place `<transition>` avec des noms différents à l'intérieur de chaque composant de route :\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n## Transition dynamique basée sur la route\n\nIl est aussi possible de déterminer la transition à utiliser en se basant sur la relation entre la route cible et la route actuelle :\n\n``` html\n<!-- utiliser un nom de transition dynamique -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// et dans le composant parent,\n// observer la `$route` pour déterminer la transition à utiliser\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nVoir un exemple complet [ici](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).\n"
  },
  {
    "path": "docs/fr/guide/essentials/dynamic-matching.md",
    "content": "# Concordance dynamique de route\n\nVous allez très souvent associer des routes avec un motif donné à un même composant. Par exemple nous pourrions avoir le composant `User` qui devrait être rendu pour tous les utilisateurs mais avec différents identifiants. Avec `vue-router` nous pouvons utiliser des segments dynamiques dans le chemin de la route pour réaliser cela :\n\n``` js\nconst User = {\n  template: '<div>Utilisateur</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // Les segments dynamiques commencent avec la ponctuation deux-points\n    { path: '/utilisateur/:id', component: User }\n  ]\n})\n```\n\nMaintenant des URL comme `/utilisateur/foo` et `/utilisateur/bar` seront chacun associé à la même route.\n\nUn segment dynamique se repère avec les deux-points `:`. Quand une route concorde, la valeur du segment dynamique est exposée via `this.$route.params` dans tous les composants. Et donc, nous pouvons faire le rendu de l'identifiant de l'utilisateur courant en mettant à jour le template de `User` ainsi :\n\n``` js\nconst User = {\n  template: '<div>Utilisateur {{ $route.params.id }}</div>'\n}\n```\n\nVous pouvez regarder un exemple en ligne [ici](https://jsfiddle.net/yyx990803/4xfa2f19/).\n\nVous pouvez avoir plusieurs segments dynamiques pour une même route, et ils seront associés aux champs associés dans `$route.params`. Des exemples :\n\n| motif                                  | chemin concordant            | $route.params                        |\n| -------------------------------------- | ---------------------------- | ------------------------------------ |\n| /utilisateur/:username                 | /utilisateur/evan            | `{ username: 'evan' }`               |\n| /utilisateur/:username/billet/:post_id | /utilisateur/evan/billet/123 | `{ username: 'evan', post_id: 123 }` |\n\nEn plus de `$route.params`, l'objet `$route` expose également d'autres informations utiles comme la `$route.query` (s'il y a une requête dans l'URL), `$route.hash`, etc. Vous pouvez accéder à tous les détails de cela dans la [référence de l'API](../../api/#the-route-object).\n\n## Réactivité aux changements de paramètres\n\nUne chose à noter quand vous utilisez des routes avec des paramètres (segments), c'est que lors de la navigation de l'utilisateur de `/utilisateur/foo` vers `/utilisateur/bar`, **la même instance de composant va être réutilisée**. Puisque les deux routes font le rendu du même composant, cela est plus performant que de détruire l'ancienne instance et d'en créer une nouvelle. **Cependant, cela signifie également que les hooks de cycle de vie ne seront pas appelés**.\n\nPour réagir aux changements de paramètres dans le même composant, vous pouvez simplement observer l'objet `$route` :\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // réagir au changement de route...\n    }\n  }\n}\n```\n\nOu utiliser la [fonction d'interception](../advanced/navigation-guards.html) `beforeRouteUpdate` introduite avec la 2.2 :\n\n``` js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // réagir au changement de route...\n    // n'oubliez pas d'appeler `next()`\n  }\n}\n```\n\n## Motifs de concordance avancés\n\n`vue-router` utilise [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) comme moteur de concordance de chemin, il supporte donc plusieurs motifs de concordance avancés tels que la présence optionnelle de segments dynamiques, aucun ou plusieurs motifs, plus d'options par motifs, et même des motifs d'expressions régulières personnalisés. Consultez cette [documentation](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) pour utiliser ces motifs avancés et [cet exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) pour les utiliser avec `vue-router`.\n\n## Priorité de concordance\n\nParfois la même URL peut être adressé par de multiples routes. Dans ce cas, la priorité de concordance est déterminée par l'ordre de la définition des routes : plus la route est définie tôt, plus sa priorité est élevée.\n"
  },
  {
    "path": "docs/fr/guide/essentials/history-mode.md",
    "content": "# Mode historique de HTML5\n\nLe mode par défaut de `vue-router` est le _mode hash_. Il utilise la partie hash de l'URL pour simuler un URL complet et ainsi ne pas recharger la page quand l'URL change.\n\nPour nous passer du hash, nous pouvons utiliser le **mode historique** qui utilisera l'API `history.pushState` afin de permettre une navigation sans rechargement de page :\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nQuand vous utilisez le mode historique, l'URL ressemblera à n'importe quel URL normal. Par ex. `http://oursite.com/user/id`. Magnifique !\n\nCependant, un problème apparait si votre application est une application monopage cliente. Sans une configuration serveur adaptée, les utilisateurs tomberont sur une page d'erreur 404 en tentant d'accéder à `http://oursite.com/user/id` directement dans leur navigateur. Maintenant ça craint.\n\nNe vous inquiétez pas. Pour résoudre ce problème, il vous suffit d'ajouter une route à votre serveur prenant en compte toutes les adresses demandées. Si l'URL demandée ne concorde avec aucun fichier statique, alors il doit toujours renvoyer la page `index.html` qui contient le code de votre application. De nouveau magnifique !\n\n## Exemple de configurations serveur\n\n### Apache\n\n```apache\n<IfModule mod_negotiation.c>\n  Options -MultiViews\n</IfModule>\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\nAu lieu de `mod_rewrite`, vous pouvez également utiliser [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource).\n\n### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n### Node.js natif\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp\n  .createServer((req, res) => {\n    fs.readFile('index.html', 'utf-8', (err, content) => {\n      if (err) {\n        console.log(`Impossible d'ouvrir le fichier \"index.html\"`)\n      }\n\n      res.writeHead(200, {\n        'Content-Type': 'text/html; charset=utf-8'\n      })\n\n      res.end(content)\n    })\n  })\n  .listen(httpPort, () => {\n    console.log('Le serveur écoute à : http://localhost:%s', httpPort)\n  })\n```\n\n### Node.js avec Express\n\nPour Node.js avec Express, vous pouvez utiliser le [middleware connect-history-api-fallback](https://github.com/bripkens/connect-history-api-fallback).\n\n### Internet Information Services (IIS)\n\n1. Instaler [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite)\n2. Créer un fichier `web.config` dans le répertoire racine de votre site avec le contenu suivant :\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n### Hébergement Firebase\n\nAjouter ceci à votre fichier `firebase.json` :\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## Limitation\n\nIl y a une limitation a tout ceci. Votre serveur ne renverra plus les erreurs 404 des chemins qui ne sont pas trouvés puisqu'il va servir à présent le fichier `index.html`. Pour contourner ce problème, vous pouvez implémenter une route concordant avec toutes les adresses en 404 dans votre application Vue :\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [{ path: '*', component: NotFoundComponent }]\n})\n```\n\nUne alternative possible, si vous utilisez un serveur Node.js, est d'implémenter ce mécanisme de substitution en utilisant le routeur côté serveur pour vérifier la concordance des demandes d'URL entrant. Si la route ne concorde avec rien, la page est inexistante. Consultez l'[utilisation de Vue côté serveur](https://ssr.vuejs.org/fr/) pour plus d'informations.\n"
  },
  {
    "path": "docs/fr/guide/essentials/named-routes.md",
    "content": "# Routes nommées\n\nParfois il est plus pratique d'identifier une route avec un nom, tout particulièrement quand on souhaite attacher cette route ou exécuter des actions de navigation. Vous pouvez donner un nom à une route dans les options `routes` pendant la création de l'instance du routeur :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/utilisateur/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nPour attacher une route nommée, vous pouvez passer un objet à la prop `to` du composant `router-link` :\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">Utilisateur</router-link>\n```\n\nC'est exactement le même objet à utiliser programmatiquement avec `router.push()` :\n\n``` js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nDans les deux cas, le routeur va naviguer vers le chemin `/utilisateur/123`.\n\nUn exemple complet se trouve [ici](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs/fr/guide/essentials/named-views.md",
    "content": "# Vues nommées\n\nParfois vous avez besoin d'afficher différentes vues en même temps plutôt que de les imbriquer, c.-à-d. créer un affichage avec une vue `sidebar` et une vue `main` par exemple. C'est ici que les routes nommées entrent en jeu. Au lieu d'avoir une seule balise de vue, vous pouvez en avoir une multitude et donner à chacune d'entre elles un nom. Un `router-view` sans nom aura comme nom par défaut : `default`.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nUne vue est rendue en utilisant un composant, donc de multiples vues nécessitent de multiples composants pour une même route. Assurez-vous d'utiliser l'option `components` (avec un s) :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nUne démo de cet exemple peut-être trouvée [ici](https://jsfiddle.net/posva/6du90epg/).\n\n## Vues nommées imbriquées\n\nIl est possible de créer des dispositions complexes en utilisant les vues nommées avec les vues imbriquées. Quand vous le faites, vous devez nommer les composants imbriqués de `router-view` utilisés. Voyons cela avec un panneau de configuration exemple :\n\n```\n/parametres/emails                                     /parametres/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` est juste un composant standard.\n- `UserSettings` est un composant de vue.\n- `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` sont des composants de vue imbriqués.\n\n**Note** : _mettons de côté la partie HTML / CSS de cette disposition et concentrons nous sur le composant utilisé en lui-même._\n\nLa section `<template>` pour le composant `UserSettings` de la disposition ci-dessus devrait ressembler à quelque chose comme cela :\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>Paramètres utilisateurs</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_Le composant de vue imbriqué est omis ici mais vous pouvez le trouver dans le code source complet de l'exemple ci-dessus [ici](https://jsfiddle.net/posva/22wgksa3/)._\n\nPuis vous pouvez achever la disposition ci-dessus avec la configuration de route :\n\n```js\n{\n  path: '/parametres',\n  // Vous pouvez également avoir des vues nommées à la racine\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nUne démo de cet exemple peut-être trouvée [ici](https://jsfiddle.net/posva/22wgksa3/).\n"
  },
  {
    "path": "docs/fr/guide/essentials/navigation.md",
    "content": "---\nsidebarDepth: 0\n---\n\n# Navigation programmatique\n\nEn complément du l'utilisation de `<router-link>` pour créer des balises ancres pour la navigation déclarative, nous pouvons le faire de manière programmatique en utilisant les méthodes de l'instance du routeur.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**Note : Dans une instance Vue, vous pouvez accéder à l'instance du routeur via `$router`. Vous pouvez donc appeler `this.$router.push`.**\n\nPour naviguer vers un URL différent, utilisez `router.push`. Cette méthode ajoute une nouvelle entrée dans la pile de l'historique. Ainsi quand un utilisateur clique sur le bouton retour de son navigateur, il retournera à l'URL précédent.\n\nCette méthode est appelée en interne quand vous cliquez sur `<router-link>`, donc cliquer sur `<router-link :to=\"...\">` est équivalent à appeler `router.push(...)`.\n\n| Déclarative               | Programmatique     |\n| ------------------------- | ------------------ |\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\nL'argument peut être une chaine de caractère représentant un chemin, ou un objet de description de destination. Des exemples :\n\n``` js\n// chaine de caractère représentant un chemin\nrouter.push('home')\n\n// objet\nrouter.push({ path: 'home' })\n\n// route nommée\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// avec une requête « query » résultant de `/register?plan=private`\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n**Note :** `params` est ignoré si `path` est fourni, ce qui n'est pas le cas pour `query`, comme démontré dans l'exemple ci-dessous. À la place, vous devez fournir le `name` de la route ou manuellement spécifier le `path` complet avec tous les paramètres :\n\n```js\nconst userId = 123\nrouter.push({ name: 'user', params: { userId }}) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// Ceci ne va PAS fonctionner\nrouter.push({ path: '/user', params: { userId }}) // -> /user\n```\n\nLes mêmes règles s'appliquent pour la propriété `to` du composant `router-link`.\n\nDans la version 2.2.0+, vous pouvez optionnellement fournir les fonctions de rappel `onComplete` et `onAbort` à `router.push` ou `router.replace` en tant que deuxième et troisième arguments. Ces fonctions de rappel seront appelées quand la navigation sera respectivement ; complétée avec succès (après la résolution de tous les hooks asynchrones), ou arrêtée (navigation vers la même route ou vers une route différente avant que la navigation courante ne soit achevée).\n\n**Note :** si la destination est la même que la route courante et que seuls les paramètres ont changés (par ex. naviguer d'un profil à l'autre `/utilisateurs/1` -> `/utilisateurs/2`), vous devrez utiliser [`beforeRouteUpdate`](./dynamic-matching.md#réactivité-aux-changements-de-paramètres) pour réagir aux changements (par ex. récupérer les informations de l'utilisateur).\n\n## `router.replace(location, onComplete?, onAbort?)`\n\nIl agit comme `router.push`. La seule différence est que la navigation se fait sans ajouter de nouvelle entrée dans la pile de l'historique. Comme son nom l'indique, il remplace l'entrée courante.\n\n| Déclarative                       | Programmatique        |\n| --------------------------------- | --------------------- |\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n## `router.go(n)`\n\nCette méthode prend un seul nombre en tant que paramètre. Celui-ci indique de combien d'entrées vers l'avant ou vers l'arrière il faut naviguer dans la pile de l'historique, de la même manière qu'avec `window.history.go(n)`.\n\nDes exemples\n\n``` js\n// avancer d'une entrée, identique à `history.forward()`\nrouter.go(1)\n\n// retourner d'une entrée en arrière, identique à `history.back()`\nrouter.go(-1)\n\n// avancer de trois entrées\nrouter.go(3)\n\n// échoue silencieusement s'il n'y a pas assez d'entrées.\nrouter.go(-100)\nrouter.go(100)\n```\n\n## Manipulation de l'historique\n\nVous avez peut être remarqué que `router.push`, `router.replace` et `router.go` sont des équivalents de [`window.history.pushState`, `window.history.replaceState` et `window.history.go`](https://developer.mozilla.org/fr-FR/docs/Web/API/History), et qu'ils imitent les APIs de `window.history`.\n\nDonc, si vous utilisez déjà l'[API History des navigateurs](https://developer.mozilla.org/fr-FR/docs/Web/API/History_API), manipuler l'historique sera très simple avec vue-router.\n\nIl n'est pas nécessaire de préciser que les méthodes de navigation (`push`, `replace`, `go`) fonctionnent de la même manière dans tous les modes de routage (`history`, `hash` et `abstract`).\n"
  },
  {
    "path": "docs/fr/guide/essentials/nested-routes.md",
    "content": "# Routes imbriquées\n\nLes vraies interfaces utilisateurs d'application sont faites de composants imbriqués à de multiples niveaux de profondeur. Il est aussi très commun que les segments d'URL correspondent à une certaine structure de composants imbriqués, par exemple :\n\n```\n/utilisateur/foo/profil                  /utilisateur/foo/billets\n+---------------------+                  +--------------------+\n| User                |                  | User               |\n| +-----------------+ |                  | +----------------+ |\n| | Profile         | |  +------------>  | | Posts          | |\n| |                 | |                  | |                | |\n| +-----------------+ |                  | +----------------+ |\n+---------------------+                  +--------------------+\n```\n\nAvec `vue-router`, il est vraiment très simple d'exprimer cette relation en utilisant des configurations de route imbriquées.\n\nReprenons l'application créée au chapitre précédent :\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>Utilisateur {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User }\n  ]\n})\n```\n\nIci le `<router-view>` est une balise de premier niveau. Il fait le rendu des composants qui concordent avec une route de premier niveau. De la même façon, un composant de rendu peut contenir également sa propre balise `<router-view>` imbriquée. Par exemple, ajoutons en une à l'intérieur du template du composant `User` :\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>Utilisateur {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nPour faire le rendu de composants à l'intérieur des balises imbriquées, nous avons besoin d'utiliser l'option `children` dans la configuration du constructeur de `VueRouter` :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User,\n      children: [\n        {\n          // `UserProfile` va être rendu à l'intérieur du `<router-view>` de `User`\n          // quand `/utilisateur/:id/profil` concorde\n          path: 'profil',\n          component: UserProfile\n        },\n        {\n          // `UserPosts` va être rendu à l'intérieur du `<router-view>` de `User`\n          // quand `/utilisateur/:id/billets` concorde\n          path: 'billets',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Notez que les chemins imbriqués commençants par `/` vont être traités comme des chemins partant de la racine. Cela vous permet d'adresser des composants imbriqués sans avoir à utiliser un URL imbriqué.**\n\nComme vous pouvez le voir, l'option `children` n'est qu'un autre tableau d'objet de configuration de route comme dans `routes`. Et donc, vous pouvez garder les vues imbriquées au plus près de vos besoins.\n\nÀ ce niveau, avec la configuration ci-dessus, quand vous visitez `/utilisateur/foo`, rien ne sera rendu dans la partie `User`, car aucune sous route ne concorde. Peut-être voudriez-vous afficher quelque chose ici. Dans ce cas, vous pouvez fournir une sous route vide :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/utilisateur/:id', component: User,\n      children: [\n        // `UserHome` va être rendu à l'intérieur du `<router-view>` de `User`\n        // quand `/utilisateur/:id` concorde\n        { path: '', component: UserHome },\n\n        // ...autres sous routes\n      ]\n    }\n  ]\n})\n```\n\nUne démo de fonctionnement de cet exemple peut-être trouvée [ici](https://jsfiddle.net/yyx990803/L7hscd8h/).\n"
  },
  {
    "path": "docs/fr/guide/essentials/passing-props.md",
    "content": "# Passage de props aux composants de route\n\nUtiliser `$route` dans vos composants crée un couplage fort à la route qui va limiter la flexibilité du composant qui ne pourra être utilisé que par certains URL.\n\nPour découpler un composant de son routeur, utilisez les props :\n\n**Plutôt que de coupler avec `$route`**\n\n``` js\nconst User = {\n  template: '<div>Utilisateur {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User }\n  ]\n})\n```\n\n**Découplez avec les `props`**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>Utilisateur {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User, props: true },\n\n    // pour les routes avec vues nommées, vous devez définir l'option `props` pour chaque vue nommée :\n    {\n      path: '/utilisateur/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nCela vous permet d'utiliser le composant n'importe où, ce qui le rend plus facile à réutiliser et à tester.\n\n## Mode booléen\n\nQuand `props` est mis à `true`, le `route.params` est remplis en tant que props du composant.\n\n## Mode objet\n\nQuand `props` est un objet, cela alimente les props de celui-ci. Utile quand les props sont statiques.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n## Mode fonction\n\nVous pouvez créer une fonction qui va retourner les props. Cela vous permet de caster des paramètres dans un autre type, de combiner les valeurs statiques avec les valeurs des routes, etc.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\nL'URL `/search?q=vue` passerait `{query: 'vue'}` comme `props` au composant `SearchUser`.\n\nEssayez de garder la fonction de `props` sans état, car il n'est évalué que sur les changements de route. Utilisez un composant englobant si vous avez besoin d'état pour définir les props, ainsi la vue pourra réagir au changement d'état.\n\nPour une utilisation avancée, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).\n"
  },
  {
    "path": "docs/fr/guide/essentials/redirect-and-alias.md",
    "content": "# Redirection et alias\n\n## Redirection\n\nLes redirections peuvent aussi être faites depuis la configuration de `routes`. Pour rediriger `/a` vers `/b` :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nLa redirection peut également être effectuée en ciblant une route nommée :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nOu on peut même utiliser une fonction pour les redirections dynamiques :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // la fonction reçoit la route cible en tant qu'argument\n      // retournez le chemin vers la nouvelle route ici.\n    }}\n  ]\n})\n```\n\nNotez que les [intercepteurs de navigation](../advanced/navigation-guards.md) ne sont pas appliqués sur les routes d'où à lieu la redirection mais uniquement sur les routes cibles. Dans l'exemple ci-dessous, ajouter une interception `beforeEnter` à la route `/a` n'aura aucun effet.\n\nPour d'autres utilisations avancées, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n## Alias\n\nUne redirection signifie que si l'utilisateur visite `/a`, l'URL va être remplacé par `/b` et concordé avec `/b`. Mais qu'est-ce qu'un alias ?\n\n**Un alias de `/a` en tant que `/b` signifie que lorsque l'utilisateur va visiter `/b`, l'URL va rester `/b`, mais la concordance va se faire comme si l'utilisateur visitait `/a`.**\n\nLa phase du dessus peut être exprimée dans la configuration de la route de la manière suivante :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nUn alias vous donne la liberté d'associer une structure d'interface utilisateur à un URL arbitraire, au lieu d'être contraint par une configuration de structure.\n\nPour d'autres utilisations avancées, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js).\n"
  },
  {
    "path": "docs/fr/installation.md",
    "content": "# Installation\n\n## Téléchargement direct / CDN\n\n[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) fournit des liens CDN basés sur npm. Le lien ci-dessus pointera toujours vers la dernière version sur npm. Vous pouvez aussi utiliser un tag ou une version spécifique via un URL comme `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js`.\n<!--/email_off-->\n\nIncluez `vue-router` après Vue et l'installation sera automatique :\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n## npm\n\n``` bash\nnpm install vue-router\n```\n\nLorsqu'il est utilisé avec un système de module, vous devez explicitement installer le router via `Vue.use()` :\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nVous n'avez pas besoin de faire cela lors de l'utilisation des balises de script globales (`<script>`).\n\n## Build de développement\n\nVous aurez besoin de cloner directement `vue-router` depuis GitHub et le compiler vous-même si vous souhaitez utiliser le dernier build de développement.\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs/guide/README.md",
    "content": "# Getting Started\n\n::: tip Note\nYou are reading the documentation of Vue Router 3 **for Vue 2**. If you are working with Vue 3, use the [Vue Router 4 documentation](https://next.router.vuejs.org) instead.\n\nWe will be using [ES2015](https://github.com/lukehoban/es6features) in the code samples in the guide.\n\nAlso, all examples will be using the full version of Vue to make on-the-fly template compilation possible. See more details [here](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only).\n:::\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nCreating a Single-page Application with Vue + Vue Router feels natural: with Vue.js, we are already composing our application with components. When adding Vue Router to the mix, all we need to do is map our components to the routes and let Vue Router know where to render them. Here's a basic example:\n\n## HTML\n\n```html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- use router-link component for navigation. -->\n    <!-- specify the link by passing the `to` prop. -->\n    <!-- `<router-link>` will be rendered as an `<a>` tag by default -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- route outlet -->\n  <!-- component matched by the route will render here -->\n  <router-view></router-view>\n</div>\n```\n\n## JavaScript\n\n```js\n// 0. If using a module system (e.g. via vue-cli), import Vue and VueRouter\n// and then call `Vue.use(VueRouter)`.\n\n// 1. Define route components.\n// These can be imported from other files\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Define some routes\n// Each route should map to a component. The \"component\" can\n// either be an actual component constructor created via\n// `Vue.extend()`, or just a component options object.\n// We'll talk about nested routes later.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Create the router instance and pass the `routes` option\n// You can pass in additional options here, but let's\n// keep it simple for now.\nconst router = new VueRouter({\n  routes // short for `routes: routes`\n})\n\n// 4. Create and mount the root instance.\n// Make sure to inject the router with the router option to make the\n// whole app router-aware.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// Now the app has started!\n```\n\nBy injecting the router, we get access to it as `this.$router` as well as the current route as `this.$route` inside of any component:\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username() {\n      // We will see what `params` is shortly\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack() {\n      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')\n    }\n  }\n}\n```\n\nThroughout the docs, we will often use the `router` instance. Keep in mind that `this.$router` is exactly the same as using `router`. The reason we use `this.$router` is because we don't want to import the router in every single component that needs to manipulate routing.\n\nYou can also check out this example [live](https://jsfiddle.net/yyx990803/xgrjzsup/).\n\nNotice that a `<router-link>` automatically gets the `.router-link-active` class when its target route is matched. You can learn more about it in its [API reference](../api/#router-link).\n"
  },
  {
    "path": "docs/guide/advanced/data-fetching.md",
    "content": "# Data Fetching\n\nSometimes you need to fetch data from the server when a route is activated. For example, before rendering a user profile, you need to fetch the user's data from the server. We can achieve this in two different ways:\n\n- **Fetching After Navigation**: perform the navigation first, and fetch data in the incoming component's lifecycle hook. Display a loading state while data is being fetched.\n\n- **Fetching Before Navigation**: Fetch data before navigation in the route enter guard, and perform the navigation after data has been fetched.\n\nTechnically, both are valid choices - it ultimately depends on the user experience you are aiming for.\n\n## Fetching After Navigation\n\nWhen using this approach, we navigate and render the incoming component immediately, and fetch data in the component's `created` hook. It gives us the opportunity to display a loading state while the data is being fetched over the network, and we can also handle loading differently for each view.\n\nLet's assume we have a `Post` component that needs to fetch the data for a post based on `$route.params.id`:\n\n``` html\n<template>\n  <div class=\"post\">\n    <div v-if=\"loading\" class=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // fetch the data when the view is created and the data is\n    // already being observed\n    this.fetchData()\n  },\n  watch: {\n    // call again the method if the route changes\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      const fetchedId = this.$route.params.id\n      // replace `getPost` with your data fetching util / API wrapper\n      getPost(fetchedId, (err, post) => {\n        // make sure this request is the last one we did, discard otherwise\n        if (this.$route.params.id !== fetchedId) return\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Fetching Before Navigation\n\nWith this approach we fetch the data before actually navigating to the new\nroute. We can perform the data fetching in the `beforeRouteEnter` guard in the incoming component, and only call `next` when the fetch is complete:\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // when route changes and this component is already rendered,\n  // the logic will be slightly different.\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\nThe user will stay on the previous view while the resource is being fetched for the incoming view. It is therefore recommended to display a progress bar or some kind of indicator while the data is being fetched. If the data fetch fails, it's also necessary to display some kind of global warning message.\n"
  },
  {
    "path": "docs/guide/advanced/lazy-loading.md",
    "content": "# Lazy Loading Routes\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-lazy-load-routes-with-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to increase performance by lazy loading routes on Vue School\">Learn how to lazy load routes with a free lesson on Vue School</a></div>\n\nWhen building apps with a bundler, the JavaScript bundle can become quite large, and thus affect the page load time. It would be more efficient if we can split each route's components into a separate chunk, and only load them when the route is visited.\n\nCombining Vue's [async component feature](https://vuejs.org/guide/components.html#Async-Components) and webpack's [code splitting feature](https://webpack.js.org/guides/code-splitting-async/), it's trivially easy to lazy-load route components.\n\nFirst, an async component can be defined as a factory function that returns a Promise (which should resolve to the component itself):\n\n```js\nconst Foo = () =>\n  Promise.resolve({\n    /* component definition */\n  })\n```\n\nSecond, in webpack 2, we can use the [dynamic import](https://github.com/tc39/proposal-dynamic-import) syntax to indicate a code-split point:\n\n```js\nimport('./Foo.vue') // returns a Promise\n```\n\n::: tip Note\nif you are using Babel, you will need to add the [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/) plugin so that Babel can properly parse the syntax.\n:::\n\nCombining the two, this is how to define an async component that will be automatically code-split by webpack:\n\n```js\nconst Foo = () => import('./Foo.vue')\n```\n\nNothing needs to change in the route config, just use `Foo` as usual:\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/foo', component: Foo }]\n})\n```\n\n## Grouping Components in the Same Chunk\n\nSometimes we may want to group all the components nested under the same route into the same async chunk. To achieve that we need to use [named chunks](https://webpack.js.org/api/module-methods/#magic-comments) by providing a chunk name using a special comment syntax (requires webpack > 2.4):\n\n```js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nwebpack will group any async module with the same chunk name into the same async chunk.\n"
  },
  {
    "path": "docs/guide/advanced/meta.md",
    "content": "# Route Meta Fields\n\nSometimes, you might want to attach arbitrary information to routes like transition names, who can access the route, etc. This can be achieved through the `meta` property which accepts an object of properties and can be accessed on the route location and navigation guards. You can define `meta` properties like this:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // a meta field\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nSo how do we access this `meta` field?\n\nFirst, each route object in the `routes` configuration is called a **route record**. Route records may be nested. Therefore when a route is matched, it can potentially match more than one route record.\n\nFor example, with the above route config, the URL `/foo/bar` will match both the parent route record and the child route record.\n\nAll route records matched by a route are exposed on the `$route` object (and also route objects in navigation guards) as the `$route.matched` Array. Therefore, we will need to iterate over `$route.matched` to check for meta fields in route records.\n\nAn example use case is checking for a meta field in the global navigation guard:\n\n```js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // this route requires auth, check if logged in\n    // if not, redirect to login page.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // make sure to always call next()!\n  }\n})\n```\n"
  },
  {
    "path": "docs/guide/advanced/navigation-failures.md",
    "content": "# Navigation Failures\n\n> New in 3.4.0\n\nWhen using `router-link`, Vue Router calls `router.push` to trigger a navigation. While the expected behavior for most links is to navigate a user to a new page, there are a few situations where users will remain on the same page:\n\n- Users are already on the page that they are trying to navigate to\n- A [navigation guard](./navigation-guards.md) aborts the navigation by calling `next(false)`\n- A [navigation guard](./navigation-guards.md) throws an error or calls `next(new Error())`\n\nWhen using a `router-link` component, **none of these failures will log an error**. However, if you are using `router.push` or `router.replace`, you might come across an _\"Uncaught (in promise) Error\"_ message followed by a more specific message in your console. Let's understand how to differentiate _Navigation Failures_.\n\n::: tip Background story\nIn v3.2.0, _Navigation Failures_ were exposed through the two optional callbacks of `router.push`: `onComplete` and `onAbort`. Since version 3.1.0, `router.push` and `router.replace` return a _Promise_ if no `onComplete`/`onAbort` callback is provided. This _Promise_ resolves instead of invoking `onComplete` and rejects instead of invoking `onAbort`.\n:::\n\n## Detecting Navigation Failures\n\n_Navigation Failures_ are `Error` instances with a few extra properties. To check if an error comes from the Router, use the `isNavigationFailure` function:\n\n```js\nimport VueRouter from 'vue-router'\nconst { isNavigationFailure, NavigationFailureType } = VueRouter\n\n// trying to access the admin page\nrouter.push('/admin').catch(failure => {\n  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n    // show a small notification to the user\n    showToast('Login in order to access the admin panel')\n  }\n})\n```\n\n::: tip\nIf you omit the second parameter: `isNavigationFailure(failure)`, it will only check if the error is a _Navigation Failure_.\n:::\n\n## `NavigationFailureType`\n\n`NavigationFailureType` help developers to differentiate between the various types of _Navigation Failures_. There are four different types:\n\n- `redirected`: `next(newLocation)` was called inside of a navigation guard to redirect somewhere else.\n- `aborted`: `next(false)` was called inside of a navigation guard to the navigation.\n- `cancelled`: A new navigation completely took place before the current navigation could finish. e.g. `router.push` was called while waiting inside of a navigation guard.\n- `duplicated`: The navigation was prevented because we are already at the target location.\n\n## _Navigation Failures_'s properties\n\nAll navigation failures expose `to` and `from` properties to reflect the target and current location respectively for the navigation that failed:\n\n```js\n// trying to access the admin page\nrouter.push('/admin').catch(failure => {\n  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n    failure.to.path // '/admin'\n    failure.from.path // '/'\n  }\n})\n```\n\nIn all cases, `to` and `from` are normalized route locations.\n"
  },
  {
    "path": "docs/guide/advanced/navigation-guards.md",
    "content": "# Navigation Guards\n\nAs the name suggests, the navigation guards provided by `vue-router` are primarily used to guard navigations either by redirecting it or canceling it. There are a number of ways to hook into the route navigation process: globally, per-route, or in-component.\n\nRemember that **params or query changes won't trigger enter/leave navigation guards**. You can either [watch the `$route` object](../essentials/dynamic-matching.md#reacting-to-params-changes) to react to those changes, or use the `beforeRouteUpdate` in-component guard.\n\n## Global Before Guards\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-configure-an-authentication-middleware-route-guard-with-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to create an authentication middleware with a global route guard on Vue School\">Learn how navigation guards works with a free lesson on Vue School</a></div>\n\nYou can register global before guards using `router.beforeEach`:\n\n```js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nGlobal before guards are called in creation order, whenever a navigation is triggered. Guards may be resolved asynchronously, and the navigation is considered **pending** before all hooks have been resolved.\n\nEvery guard function receives three arguments:\n\n- **`to: Route`**: the target [Route Object](../../api/#the-route-object) being navigated to.\n\n- **`from: Route`**: the current route being navigated away from.\n\n- **`next: Function`**: this function must be called to **resolve** the hook. The action depends on the arguments provided to `next`:\n\n  - **`next()`**: move on to the next hook in the pipeline. If no hooks are left, the navigation is **confirmed**.\n\n  - **`next(false)`**: abort the current navigation. If the browser URL was changed (either manually by the user or via back button), it will be reset to that of the `from` route.\n\n  - **`next('/')` or `next({ path: '/' })`**: redirect to a different location. The current navigation will be aborted and a new one will be started. You can pass any location object to `next`, which allows you to specify options like `replace: true`, `name: 'home'` and any option used in [`router-link`'s `to` prop](../../api/#to) or [`router.push`](../../api/#router-push)\n\n  - **`next(error)`**: (2.4.0+) if the argument passed to `next` is an instance of `Error`, the navigation will be aborted and the error will be passed to callbacks registered via [`router.onError()`](../../api/#router-onerror).\n\n**Make sure that the `next` function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.** Here is an example of redirecting to user to `/login` if they are not authenticated:\n\n```js\n// BAD\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  // if the user is not authenticated, `next` is called twice\n  next()\n})\n```\n\n```js\n// GOOD\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  else next()\n})\n```\n\n## Global Resolve Guards\n\nYou can register a global guard with `router.beforeResolve`. This is similar to `router.beforeEach`, with the difference that resolve guards will be called right before the navigation is confirmed, **after all in-component guards and async route components are resolved**.\n\n## Global After Hooks\n\nYou can also register global after hooks, however unlike guards, these hooks do not get a `next` function and cannot affect the navigation:\n\n```js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n## Per-Route Guard\n\nYou can define `beforeEnter` guards directly on a route's configuration object:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nThese guards have the exact same signature as global before guards.\n\n## In-Component Guards\n\nFinally, you can directly define route navigation guards inside route components (the ones passed to the router configuration) with the following options:\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate`\n- `beforeRouteLeave`\n\n```js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter(to, from, next) {\n    // called before the route that renders this component is confirmed.\n    // does NOT have access to `this` component instance,\n    // because it has not been created yet when this guard is called!\n  },\n  beforeRouteUpdate(to, from, next) {\n    // called when the route that renders this component has changed.\n    // This component being reused (by using an explicit `key`) in the new route or not doesn't change anything.\n    // For example, for a route with dynamic params `/foo/:id`, when we\n    // navigate between `/foo/1` and `/foo/2`, the same `Foo` component instance\n    // will be reused (unless you provided a `key` to `<router-view>`), and this hook will be called when that happens.\n    // has access to `this` component instance.\n  },\n  beforeRouteLeave(to, from, next) {\n    // called when the route that renders this component is about to\n    // be navigated away from.\n    // has access to `this` component instance.\n  }\n}\n```\n\nThe `beforeRouteEnter` guard does **NOT** have access to `this`, because the guard is called before the navigation is confirmed, thus the new entering component has not even been created yet.\n\nHowever, you can access the instance by passing a callback to `next`. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument:\n\n```js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // access to component instance via `vm`\n  })\n}\n```\n\nNote that `beforeRouteEnter` is the only guard that supports passing a callback to `next`. For `beforeRouteUpdate` and `beforeRouteLeave`, `this` is already available, so passing a callback is unnecessary and therefore _not supported_:\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // just use `this`\n  this.name = to.params.name\n  next()\n}\n```\n\nThe **leave guard** is usually used to prevent the user from accidentally leaving the route with unsaved edits. The navigation can be canceled by calling `next(false)`.\n\n```js\nbeforeRouteLeave (to, from, next) {\n  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\nIf you are using mixins that add in-component navigation guards, make sure to add the mixin **after installing the router plugin**:\n\n```js\nVue.use(Router)\n\nVue.mixin({\n  beforeRouteUpdate(to, from, next) {\n    // ...\n  }\n})\n```\n\n## The Full Navigation Resolution Flow\n\n1. Navigation triggered.\n2. Call `beforeRouteLeave` guards in deactivated components.\n3. Call global `beforeEach` guards.\n4. Call `beforeRouteUpdate` guards in reused components.\n5. Call `beforeEnter` in route configs.\n6. Resolve async route components.\n7. Call `beforeRouteEnter` in activated components.\n8. Call global `beforeResolve` guards.\n9. Navigation confirmed.\n10. Call global `afterEach` hooks.\n11. DOM updates triggered.\n12. Call callbacks passed to `next` in `beforeRouteEnter` guards with instantiated instances.\n"
  },
  {
    "path": "docs/guide/advanced/scroll-behavior.md",
    "content": "# Scroll Behavior\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-control-the-scroll-behavior-of-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to control the scroll behavior on Vue School\">Learn to control the scroll behavior with a free lesson on Vue School</a></div>\n\nWhen using client-side routing, we may want to scroll to top when navigating to a new route, or preserve the scrolling position of history entries just like real page reload does. `vue-router` allows you to achieve these and even better, allows you to completely customize the scroll behavior on route navigation.\n\n**Note: this feature only works if the browser supports `history.pushState`.**\n\nWhen creating the router instance, you can provide the `scrollBehavior` function:\n\n```js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // return desired position\n  }\n})\n```\n\nThe `scrollBehavior` function receives the `to` and `from` route objects. The third argument, `savedPosition`, is only available if this is a `popstate` navigation (triggered by the browser's back/forward buttons).\n\nThe function can return a scroll position object. The object could be in the form of:\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset only supported in 2.6.0+)\n\nIf a falsy value or an empty object is returned, no scrolling will happen.\n\nFor example:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nThis will simply make the page scroll to top for all route navigations.\n\nReturning the `savedPosition` will result in a native-like behavior when navigating with back/forward buttons:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nIf you want to simulate the \"scroll to anchor\" behavior:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nWe can also use [route meta fields](meta.md) to implement fine-grained scroll behavior control. Check out a full example [here](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js).\n\n## Async Scrolling\n\n> New in 2.8.0\n\nYou can also return a Promise that resolves to the desired position descriptor:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nIt's possible to hook this up with events from a page-level transition component to make the scroll behavior play nicely with your page transitions, but due to the possible variance and complexity in use cases, we simply provide this primitive to enable specific userland implementations.\n\n## Smooth Scrolling\n\nYou can enable native smooth scrolling for [browsers supporting it](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior) by simply adding the `behavior` option to the object returned inside `scrollBehavior`:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash,\n      behavior: 'smooth',\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/guide/advanced/transitions.md",
    "content": "# Transitions\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-create-route-transitions-with-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to create route transitions on Vue School\">Learn how to create route transitions with a free lesson on Vue School</a></div>\n\nSince the `<router-view>` is essentially a dynamic component, we can apply transition effects to it the same way using the `<transition>` component:\n\n```html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[All transition APIs](https://v2.vuejs.org/v2/guide/transitions.html) work the same here.\n\n## Per-Route Transition\n\nThe above usage will apply the same transition for all routes. If you want each route's component to have different transitions, you can instead use `<transition>` with different names inside each route component:\n\n```js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n## Route-Based Dynamic Transition\n\nIt is also possible to determine the transition to use dynamically based on the relationship between the target route and current route:\n\n```html\n<!-- use a dynamic transition name -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n```js\n// then, in the parent component,\n// watch the `$route` to determine the transition to use\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nSee full example [here](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).\n"
  },
  {
    "path": "docs/guide/essentials/dynamic-matching.md",
    "content": "# Dynamic Route Matching\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/vue-router-dynamic-routes?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to match dynamic routes with Vue School\">Learn how to match dynamic routes with a free lesson on Vue School</a></div>\n\nVery often we will need to map routes with the given pattern to the same component. For example we may have a `User` component which should be rendered for all users but with different user IDs. In `vue-router` we can use a dynamic segment in the path to achieve that:\n\n```js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // dynamic segments start with a colon\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nNow URLs like `/user/foo` and `/user/bar` will both map to the same route.\n\nA dynamic segment is denoted by a colon `:`. When a route is matched, the value of the dynamic segments will be exposed as `this.$route.params` in every component. Therefore, we can render the current user ID by updating `User`'s template to this:\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\nYou can check out a live example [here](https://jsfiddle.net/yyx990803/4xfa2f19/).\n\nYou can have multiple dynamic segments in the same route, and they will map to corresponding fields on `$route.params`. Examples:\n\n| pattern                       | matched path        | \\$route.params                         |\n| ----------------------------- | ------------------- | -------------------------------------- |\n| /user/:username               | /user/evan          | `{ username: 'evan' }`                 |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\nIn addition to `$route.params`, the `$route` object also exposes other useful information such as `$route.query` (if there is a query in the URL), `$route.hash`, etc. You can check out the full details in the [API Reference](../../api/#the-route-object).\n\n## Reacting to Params Changes\n\nOne thing to note when using routes with params is that when the user navigates from `/user/foo` to `/user/bar`, **the same component instance will be reused**. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one. **However, this also means that the lifecycle hooks of the component will not be called**.\n\nTo react to params changes in the same component, you can simply watch the `$route` object:\n\n```js\nconst User = {\n  template: '...',\n  watch: {\n    $route(to, from) {\n      // react to route changes...\n    }\n  }\n}\n```\n\nOr, use the `beforeRouteUpdate` [navigation guard](../advanced/navigation-guards.html) introduced in 2.2:\n\n```js\nconst User = {\n  template: '...',\n  beforeRouteUpdate(to, from, next) {\n    // react to route changes...\n    // don't forget to call next()\n  }\n}\n```\n\n## Catch all / 404 Not found Route\n\nRegular params will only match characters in between url fragments, separated by `/`. If we want to match **anything**, we can use the asterisk (`*`):\n\n```js\n{\n  // will match everything\n  path: '*'\n}\n{\n  // will match anything starting with `/user-`\n  path: '/user-*'\n}\n```\n\nWhen using _asterisk_ routes, make sure to correctly order your routes so that _asterisk_ ones are at the end.\nThe route `{ path: '*' }` is usually used to 404 client side. If you are using _History mode_, make sure to [correctly configure your server](./history-mode.md) as well.\n\nWhen using an _asterisk_, a param named `pathMatch` is automatically added to `$route.params`. It contains the rest of the url matched by the _asterisk_:\n\n```js\n// Given a route { path: '/user-*' }\nthis.$router.push('/user-admin')\nthis.$route.params.pathMatch // 'admin'\n\n// Given a route { path: '*' }\nthis.$router.push('/non-existing')\nthis.$route.params.pathMatch // '/non-existing'\n```\n\n## Advanced Matching Patterns\n\n`vue-router` uses [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) as its path matching engine, so it supports many advanced matching patterns such as optional dynamic segments, zero or more / one or more requirements, and even custom regex patterns. Check out its [documentation](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) for these advanced patterns, and [this example](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) of using them in `vue-router`.\n\n## Matching Priority\n\nSometimes the same URL may be matched by multiple routes. In such a case the matching priority is determined by the order of route definition: the earlier a route is defined, the higher priority it gets.\n"
  },
  {
    "path": "docs/guide/essentials/history-mode.md",
    "content": "# HTML5 History Mode\n\nThe default mode for `vue-router` is _hash mode_ - it uses the URL hash to simulate a full URL so that the page won't be reloaded when the URL changes.\n\nTo get rid of the hash, we can use the router's **history mode**, which leverages the `history.pushState` API to achieve URL navigation without a page reload:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nWhen using history mode, the URL will look \"normal,\" e.g. `http://oursite.com/user/id`. Beautiful!\n\nHere comes a problem, though: Since our app is a single page client side app, without a proper server configuration, the users will get a 404 error if they access `http://oursite.com/user/id` directly in their browser. Now that's ugly.\n\nNot to worry: To fix the issue, all you need to do is add a simple catch-all fallback route to your server. If the URL doesn't match any static assets, it should serve the same `index.html` page that your app lives in. Beautiful, again!\n\n## Example Server Configurations\n\n**Note**: The following examples assume you are serving your app from the root folder. If you deploy to a subfolder, you should use [the `publicPath` option of Vue CLI](https://cli.vuejs.org/config/#publicpath) and the related [`base` property of the router](https://router.vuejs.org/api/#base). You also need to adjust the examples below to use the subfolder instead of the root folder (e.g. replacing `RewriteBase /` with `RewriteBase /name-of-your-subfolder/`).\n\n#### Apache\n\n```apache\n<IfModule mod_negotiation.c>\n  Options -MultiViews\n</IfModule>\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\nInstead of `mod_rewrite`, you could also use [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource).\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Native Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile('index.html', 'utf-8', (err, content) => {\n    if (err) {\n      console.log('We cannot open \"index.html\" file.')\n    }\n\n    res.writeHead(200, {\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log('Server listening on: http://localhost:%s', httpPort)\n})\n```\n\n#### Express with Node.js\n\nFor Node.js/Express, consider using [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback).\n\n#### Internet Information Services (IIS)\n\n1. Install [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite)\n2. Create a `web.config` file in the root directory of your site with the following:\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy v2\n\n```\ntry_files {path} /\n```\n\n#### Caddy v1\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Firebase hosting\n\nAdd this to your `firebase.json`:\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## Caveat\n\nThere is a caveat to this: Your server will no longer report 404 errors as all not-found paths now serve up your `index.html` file. To get around the issue, you should implement a catch-all route within your Vue app to show a 404 page:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { \n      path: '/:catchAll(.*)', \n      component: NotFoundComponent,\n      name: 'NotFound'\n    }\n  ]\n})\n```\n\nAlternatively, if you are using a Node.js server, you can implement the fallback by using the router on the server side to match the incoming URL and respond with 404 if no route is matched. Check out the [Vue server side rendering documentation](https://ssr.vuejs.org/en/) for more information.\n"
  },
  {
    "path": "docs/guide/essentials/named-routes.md",
    "content": "# Named Routes\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/vue-router-named-routes-and-params?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to work with named routes and params with Vue School\">Learn how to use named routes and params with a free lesson on Vue School</a></div>\n\nSometimes it is more convenient to identify a route with a name, especially when linking to a route or performing navigations. You can give a route a name in the `routes` options while creating the Router instance:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nTo link to a named route, you can pass an object to the `router-link` component's `to` prop:\n\n```html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\nThis is the exact same object used programmatically with `router.push()`:\n\n```js\nrouter.push({ name: 'user', params: { userId: 123 } })\n```\n\nIn both cases, the router will navigate to the path `/user/123`.\n\nFull example [here](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs/guide/essentials/named-views.md",
    "content": "# Named Views\n\nSometimes you need to display multiple views at the same time instead of nesting them, e.g. creating a layout with a `sidebar` view and a `main` view. This is where named views come in handy. Instead of having one single outlet in your view, you can have multiple and give each of them a name. A `router-view` without a name will be given `default` as its name.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nA view is rendered by using a component, therefore multiple views require multiple components for the same route. Make sure to use the `components` (with\nan s) option:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nA working demo of this example can be found [here](https://jsfiddle.net/posva/6du90epg/).\n\n## Nested Named Views\n\nIt is possible to create complex layouts using named views with nested views. When doing so, you will also need to name nested `router-view` components used. Let's take a Settings panel example:\n\n```\n/settings/emails                                       /settings/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` is just a regular component\n- `UserSettings` is the view component\n- `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` are nested view components\n\n**Note**: _Let's forget about how the HTML/CSS should look like to represent such layout and focus on the components used._\n\nThe `<template>` section for `UserSettings` component in the above layout would look something like this:\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>User Settings</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_The nested view components are omitted here but you can find the complete source code for the example above [here](https://jsfiddle.net/posva/22wgksa3/)._\n\nThen you can achieve the layout above with this route configuration:\n\n```js\n{\n  path: '/settings',\n  // You could also have named views at the top\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nA working demo of this example can be found [here](https://jsfiddle.net/posva/22wgksa3/).\n"
  },
  {
    "path": "docs/guide/essentials/navigation.md",
    "content": "---\nsidebarDepth: 0\n---\n\n# Programmatic Navigation\n\nAside from using `<router-link>` to create anchor tags for declarative navigation, we can do this programmatically using the router's instance methods.\n\n## `router.push(location, onComplete?, onAbort?)`\n\n**Note: Inside of a Vue instance, you have access to the router instance as `$router`. You can therefore call `this.$router.push`.**\n\nTo navigate to a different URL, use `router.push`. This method pushes a new entry into the history stack, so when the user clicks the browser back button they will be taken to the previous URL.\n\nThis is the method called internally when you click a `<router-link>`, so clicking `<router-link :to=\"...\">` is the equivalent of calling `router.push(...)`.\n\n| Declarative               | Programmatic       |\n| ------------------------- | ------------------ |\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\nThe argument can be a string path, or a location descriptor object. Examples:\n\n```js\n// literal string path\nrouter.push('home')\n\n// object\nrouter.push({ path: 'home' })\n\n// named route\nrouter.push({ name: 'user', params: { userId: '123' } })\n\n// with query, resulting in /register?plan=private\nrouter.push({ path: 'register', query: { plan: 'private' } })\n```\n\n**Note**: `params` are ignored if a `path` is provided, which is not the case for `query`, as shown in the example above. Instead, you need to provide the `name` of the route or manually specify the whole `path` with any parameter:\n\n```js\nconst userId = '123'\nrouter.push({ name: 'user', params: { userId } }) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// This will NOT work\nrouter.push({ path: '/user', params: { userId } }) // -> /user\n```\n\nThe same rules apply for the `to` property of the `router-link` component.\n\nIn 2.2.0+, optionally provide `onComplete` and `onAbort` callbacks to `router.push` or `router.replace` as the 2nd and 3rd arguments. These callbacks will be called when the navigation either successfully completed (after all async hooks are resolved), or aborted (navigated to the same route, or to a different route before current navigation has finished), respectively.\nIn 3.1.0+, you can omit the 2nd and 3rd parameter and `router.push`/`router.replace` will return a promise instead if Promises are supported.\n\n**Note:** If the destination is the same as the current route and only params are changing (e.g. going from one profile to another `/users/1` -> `/users/2`), you will have to use [`beforeRouteUpdate`](./dynamic-matching.md#reacting-to-params-changes) to react to changes (e.g. fetching the user information).\n\n## `router.replace(location, onComplete?, onAbort?)`\n\nIt acts like `router.push`, the only difference is that it navigates without pushing a new history entry, as its name suggests - it replaces the current entry.\n\n| Declarative                       | Programmatic          |\n| --------------------------------- | --------------------- |\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n## `router.go(n)`\n\nThis method takes a single integer as parameter that indicates by how many steps to go forwards or go backwards in the history stack, similar to `window.history.go(n)`.\n\nExamples\n\n```js\n// go forward by one record, the same as history.forward()\nrouter.go(1)\n\n// go back by one record, the same as history.back()\nrouter.go(-1)\n\n// go forward by 3 records\nrouter.go(3)\n\n// fails silently if there aren't that many records.\nrouter.go(-100)\nrouter.go(100)\n```\n\n## History Manipulation\n\nYou may have noticed that `router.push`, `router.replace` and `router.go` are counterparts of [`window.history.pushState`, `window.history.replaceState` and `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History), and they do imitate the `window.history` APIs.\n\nTherefore, if you are already familiar with [Browser History APIs](https://developer.mozilla.org/en-US/docs/Web/API/History_API), manipulating history will be super easy with Vue Router.\n\nIt is worth mentioning that Vue Router navigation methods (`push`, `replace`, `go`) work consistently in all router modes (`history`, `hash` and `abstract`).\n"
  },
  {
    "path": "docs/guide/essentials/nested-routes.md",
    "content": "# Nested Routes\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/vue-router-nested-routes?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to work with nested routes with Vue School\">Learn how to work with nested routes with a free lesson on Vue School</a></div>\n\nReal app UIs are usually composed of components that are nested multiple levels deep. It is also very common that the segments of a URL corresponds to a certain structure of nested components, for example:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\nWith `vue-router`, it is very simple to express this relationship using nested route configurations.\n\nGiven the app we created in the last chapter:\n\n```html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [{ path: '/user/:id', component: User }]\n})\n```\n\nThe `<router-view>` here is a top-level outlet. It renders the component matched by a top level route. Similarly, a rendered component can also contain its own, nested `<router-view>`. For example, if we add one inside the `User` component's template:\n\n```js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nTo render components into this nested outlet, we need to use the `children` option in `VueRouter` constructor config:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        {\n          // UserProfile will be rendered inside User's <router-view>\n          // when /user/:id/profile is matched\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // UserPosts will be rendered inside User's <router-view>\n          // when /user/:id/posts is matched\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Note that nested paths that start with `/` will be treated as a root path. This allows you to leverage the component nesting without having to use a nested URL.**\n\nAs you can see the `children` option is just another Array of route configuration objects like `routes` itself. Therefore, you can keep nesting views as much as you need.\n\nAt this point, with the above configuration, when you visit `/user/foo`, nothing will be rendered inside `User`'s outlet, because no sub route is matched. Maybe you do want to render something there. In such case you can provide an empty subroute path:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        // UserHome will be rendered inside User's <router-view>\n        // when /user/:id is matched\n        { path: '', component: UserHome }\n\n        // ...other sub routes\n      ]\n    }\n  ]\n})\n```\n\nA working demo of this example can be found [here](https://jsfiddle.net/yyx990803/L7hscd8h/).\n"
  },
  {
    "path": "docs/guide/essentials/passing-props.md",
    "content": "# Passing Props to Route Components\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-pass-vue-router-params-as-props-to-components?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to pass props to route components with Vue School\">Learn how to pass props to route components with a free lesson on Vue School</a></div>\n\nUsing `$route` in your component creates a tight coupling with the route which limits the flexibility of the component as it can only be used on certain URLs.\n\nTo decouple this component from the router use option `props`:\n\n**Instead of coupling to `$route`:**\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [{ path: '/user/:id', component: User }]\n})\n```\n\n**Decouple it by using `props`**\n\n```js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // for routes with named views, you have to define the `props` option for each named view:\n    {\n      path: '/user/:id',\n      components: {\n        default: User,\n        sidebar: Sidebar\n      },\n      props: {\n        default: true,\n        // function mode, more about it below\n        sidebar: route => ({ search: route.query.q })\n      }\n    }\n  ]\n})\n```\n\nThis allows you to use the component anywhere, which makes the component easier to reuse and test.\n\n## Boolean mode\n\nWhen `props` is set to `true`, the `route.params` will be set as the component props.\n\n## Object mode\n\nWhen `props` is an object, this will be set as the component props as-is. Useful for when the props are static.\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/promotion/from-newsletter',\n      component: Promotion,\n      props: { newsletterPopup: false }\n    }\n  ]\n})\n```\n\n## Function mode\n\nYou can create a function that returns props. This allows you to cast parameters into other types, combine static values with route-based values, etc.\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/search',\n      component: SearchUser,\n      props: route => ({ query: route.query.q })\n    }\n  ]\n})\n```\n\nThe URL `/search?q=vue` would pass `{query: 'vue'}` as props to the `SearchUser` component.\n\nTry to keep the `props` function stateless, as it's only evaluated on route changes. Use a wrapper component if you need state to define the props, that way vue can react to state changes.\n\nFor advanced usage, check out the [example](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).\n"
  },
  {
    "path": "docs/guide/essentials/redirect-and-alias.md",
    "content": "# Redirect and Alias\n\n## Redirect\n\nRedirecting is also done in the `routes` configuration. To redirect from `/a` to `/b`:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nThe redirect can also be targeting a named route:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nOr even use a function for dynamic redirecting:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // the function receives the target route as the argument\n      // return redirect path/location here.\n    }}\n  ]\n})\n```\n\nNote that [Navigation Guards](../advanced/navigation-guards.md) are not applied on the route that redirects, only on its target. In the example below, adding a `beforeEnter` guard to the `/a` route would not have any effect.\n\nFor other advanced usage, checkout the [example](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n## Alias\n\nA redirect means when the user visits `/a`, the URL will be replaced by `/b`, and then matched as `/b`. But what is an alias?\n\n**An alias of `/a` as `/b` means when the user visits `/b`, the URL remains `/b`, but it will be matched as if the user is visiting `/a`.**\n\nThe above can be expressed in the route configuration as:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nAn alias gives you the freedom to map a UI structure to an arbitrary URL, instead of being constrained by the configuration's nesting structure.\n\nFor advanced usage, check out the [example](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js).\n"
  },
  {
    "path": "docs/installation.md",
    "content": "# Installation\n\n## Direct Download / CDN\n\n[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) provides npm-based CDN links. The above link will always point to the latest release on npm. You can also use a specific version/tag via URLs like `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js`.\n<!--/email_off-->\n\nInclude `vue-router` after Vue and it will install itself automatically:\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n## npm\n\n``` bash\nnpm install vue-router\n```\n\nWhen used with a module system, you must explicitly install the router via `Vue.use()`:\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nYou don't need to do this when using global script tags.\n\n## Vue CLI\n\nIf you have a project using [Vue CLI](https://cli.vuejs.org/) you can add Vue Router as a plugin. You can let the CLI generate the code above for you as well as two sample routes. **It will also overwrite your `App.vue`** so make sure to backup the file before running the following command inside your project:\n\n```sh\nvue add router\n```\n\n## Dev Build\n\nYou will have to clone directly from GitHub and build `vue-router` yourself if\nyou want to use the latest dev build.\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n\n"
  },
  {
    "path": "docs/ja/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Get Started →\nactionLink: /ja/installation.html\nfooter: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote\n---\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nVue Router は [Vue.js](http://vuejs.org) 公式ルータです。これは Vue.js のコアと深く深く統合されており、Vue.js でシングルページアプリケーションを構築します。機能は次の通りです:\n\n- ネストされたルート/ビューマッピング\n- モジュール式、コンポーネントベースのルータ構造\n- ルートパラメータ、クエリ、ワイルドカード\n- Vue.js の transition 機能による、transition エフェクトの表示\n- 細かいナビゲーションコントロール\n- 自動で付与される active CSS クラス\n- HTML5 history モードまたは hash モードと IE9 の互換性\n- カスタマイズ可能なスクロール動作\n\n[はじめに](./guide/) または [例](https://github.com/vuejs/vue-router/tree/dev/examples) から試してください。 ([`README.md`](https://github.com/vuejs/vue-router/)を参照してください。).\n\n<HomeSponsors />\n"
  },
  {
    "path": "docs/ja/api/README.md",
    "content": "---\nsidebar: auto\n---\n\n# API リファレンス\n\n## `<router-link>`\n\n`<router-link>` はルーターが使用可能になっているアプリケーションでユーザーのナビゲーションを有効にするためのコンポーネントです。対象とする location は `to` プロパティを使って指定します。デフォルトでは正しい `href` と共に `<a>` タグとして描画しますが、 `tag` プロパティを設定することも可能です。さらに、対象のルートがアクティブの時に、そのリンクは自動的にアクティブな CSS クラスが当てられます。\n\n下記の理由により `<router-link>` はハードコードする `<a href=\"...\">` よりも好ましいです。\n\n- HTML5 history モードでも hash モードでも同じ方法で動作します。もしあなたがモードを切り替えたりする場合や、IE9 で hash モードにフォールバックする場合に、何も変更する必要はありません。\n\n- HTML5 history モードにおいて、ブラウザがページのリロードをしないように `router-link` はクリックイベントに割り込みます。\n\n- HTML5 history モードで `base` オプションを使っている時に、 `to` プロパティの URL にそれを含める必要がありません。\n\n### `v-slot` API (3.1.0 以降)\n\n`router-link` は[スコープ付きスロット](https://jp.vuejs.org/v2/guide/components-slots.html#%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97%E4%BB%98%E3%81%8D%E3%82%B9%E3%83%AD%E3%83%83%E3%83%88)を通して低レベルなカスタマイズを提供しています。これは、主にライブラリ作者をターゲットにした高度な API ですが、ほとんどの場合 _NavLink_ などのようなカスタムコンポーネントでも同様に開発者にとっても大変便利です。\n\n**`v-slot` API を使うとき、それは単一の子を `router-link` に通す必要があります。** そうしない場合は、 `router-link` は `span` 要素で子をラップします。\n\n```html\n<router-link\n  to=\"/about\"\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <NavLink :active=\"isActive\" :href=\"href\" @click=\"navigate\"\n    >{{ route.fullPath }}</NavLink\n  >\n</router-link>\n```\n\n- `href`: 解決された url。これは、`a` 要素の `href` 属性になります\n- `route`: 解決された正規化済みロケーション\n- `navigate`: ナビゲーションをトリガーするための関数。`router-link` と同じように、**必要なときに自動的にイベントが起こらないようにします。**\n- `isActive`: [アクティブクラス (active class)](#active-class) が適用されるとき、`true` になります。任意のクラスを適用できます。\n- `isExactActive`: `true` if the [正確なアクティブクラス (exact active class)](#exact-active-class) が適用されるとき、`true` になります。 任意のクラスを適用できます。\n\n#### 例: アクティブクラスを外部要素へ適用\n\nアクティブクラスを `<a>` タグ自身よりも、外側の要素に対して適用したいことがあるでしょう。その場合、`<router-link>` 内の要素を `v-slot` を使ってリンクを作成することでラップできます。\n\n```html\n<router-link\n  to=\"/foo\"\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <li\n    :class=\"[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']\"\n  >\n    <a :href=\"href\" @click=\"navigate\">{{ route.fullPath }}</a>\n  </li>\n</router-link>\n```\n\n:::tip\n`target=\"_blank\"` を `a` 要素に追加する場合、`@click=\"navigate\"` ハンドラを省略しなければなりません。\n:::\n\n## `<router-link>` Props\n\n### to\n\n  - 型: `string | Location`\n  - 必須\n\n　リンクする対象のルートを表します。クリックされた時に `to` プロパティの値が内部的に `router.push()` に渡されます。つまり、この値は文字列でも location を記述するオブジェクトでも構いません。\n\n  ``` html\n  <!-- 文字列 -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- 次のように描画される -->\n  <a href=\"home\">Home</a>\n\n  <!-- `v-bind` を使った javascript 式-->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- 他のプロパティのバインディングのような `v-bind` の省略表現 -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- 上記と同じ -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- 名前付きルート -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- 結果的に `/register?plan=private` になるクエリ-->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n### replace\n\n  - 型: `boolean`\n  - デフォルト: `false`\n\n  `replace` プロパティを設定するとクリックされた時に `router.push()` の代わりに `router.replace()` が呼ばれます。したがって、ナビゲーションは history レコードに残りません。\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n### append\n\n  - 型: `boolean`\n  - デフォルト: `false`\n\n  `append` プロパティを設定すると現在のパスに対して常に相対パスを追加します。例えば、 `/a` から相対リンクの `b` へ遷移するのを想定した時に、 `append` がない場合は `/b` に、`append` がある場合は `/a/b` になります。\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n### tag\n\n  - 型: `string`\n  - デフォルト: `\"a\"`\n\n  しばしば `<router-link>` を `<li>` などの他のタグとして描画したい時があるでしょう。そこで、どのタグとして描画するかを指定するために `tag` プロパティを使うことができます。そして、依然ナビゲーションのためのクリックイベントを listen します。\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- 以下のように描画されます -->\n  <li>foo</li>\n  ```\n\n### active-class\n\n  - 型: `string`\n  - デフォルト: `\"router-link-active\"`\n\n  リンクがアクティブな時に適用されるアクティブ CSS クラスの設定です。デフォルト値はルーターコンストラクタオプションの `linkActiveClass` でグローバルに設定可能です。\n\n### exact\n\n  - 型: `boolean`\n  - デフォルト: `false`\n\n  デフォルトのアクティブクラスのマッチングの振る舞いは **包含的なマッチ** です。 例えば、現在のパスが `/a/` または `/a` から始まる限りは、`<router-link to=\"/a\">` にアクティブクラスが適用されます。\n\n  この結果として `<router-link to=\"/\">` は全てのルートに対してアクティブになります! リンクに対して \"正確なマッチモード\" を強制するために、 `exact` プロパティを使ってください。\n\n  ``` html\n  <!-- このリンクは `/` だけにアクティブになります -->\n  <router-link to=\"/\" exact></router-link>\n  ```\n\n  アクティブリンククラスをより説明している例としてこちらの [動作](https://jsfiddle.net/8xrk1n9f/) を確認してください。\n\n### event\n\n  - 型: `string | Array<string>`\n  - デフォルト: `'click'`\n\n  リンクナビゲーションをトリガーできるイベントを指定します。\n\n### exact-active-class\n\n  - 型 `string`\n  - デフォルト: `\"router-link-exact-active\"`\n\n  完全一致によってリンクがアクティブになっているときに適用されるアクティブな CSS クラスを設定します。デフォルト値は `linkExactActiveClass` ルーターコンストラクタのオプション経由でグローバルに設定することもできます。\n\n### aria-current-value\n\n- 型: `'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'`\n- デフォルト: `\"page\"`\n\n  完全一致によってリンクがアクティブになっているときに `aria-current` の値を設定します。ARIA spec において[aria-current で許可されている値](https://www.w3.org/TR/wai-aria-1.2/#aria-current)の1つでなければなりません。ほとんどの場合、デフォルト`page` が最適です。\n\n## `<router-view>`\n\n`<router-view>` コンポーネントは与えられたパスに対してマッチしたコンポーネントを描画する関数型コンポーネントです。`<router-view>` の中で描画されるコンポーネント自身もまた、ネストされたパスに対してコンポーネントを描画するための `<router-view>` を持つことができます。\n\nname ではないプロパティも描画されるコンポーネントに渡されますが、ほとんどの場合ルート単位のデータはルートのパラメーターに含まれています。\n\nこれは普通のコンポーネントなので、 `<transition>` と `<keep-alive>` と共に動作します。両方を同時に使用する場合は `<keep-alive>` を内側にするようにしてください。\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n\n## `<router-view>` Props\n\n### name\n\n  - 型: `string`\n  - デフォルト: `\"default\"`\n\n  `<router-view>` が名前を持つ時、マッチしたルートレコードの `components` オプション内で対応する名前のコンポーネントを描画します。例は [名前付きビュー](../guide/essentials/named-views.md) をご参照ください。\n\n## ルーターコンストラクタオプション\n\n### routes\n\n- 型: `Array<RouteConfig>`\n\n  `RouteConfig` の型宣言:\n\n  ``` ts\n  interface RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // 名前付きルート用\n    components?: { [name: string]: Component }; // 名前付き view 用\n    redirect?: string | Location | Function;\n    props?: boolean | Object | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // ネストされたルート用\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n\n    // 2.6.0+\n    caseSensitive?: boolean; // センシティブマッチをケースとして使用するかどうか? (デフォルト: false)\n    pathToRegexpOptions?: Object; // 正規表現のコンパイルとして path-to-regexp オプション\n  }\n  ```\n\n### mode\n\n- 型: `string`\n\n- デフォルト: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- 利用可能な値: `\"hash\" | \"history\" | \"abstract\"`\n\n  ルーターモードの設定。\n\n  - `hash`: ルーティングに URL hash を使います。HTML5 History API をサポートしていないブラウザ含めて、全ての Vue がサポートしているブラウザで動作します。\n\n  - `history`: HTML5 History API とサーバーの設定が必要です。[HTML5 History モード](../guide/essentials/history-mode.md) を参照してください。\n\n  - `abstract`: 全ての JavaScript の環境で動作します。 e.g. Node.js を使ったサーバーサイド。 **もしブラウザの API が存在しない場合、ルーターは自動的にこのモードに強制されます。**\n\n### base\n\n- 型: `string`\n\n- デフォルト: `\"/\"`\n\n  アプリケーションのベース URL です。例えば、 `/app/` 配下で完全なシングルページアプリケーションを提供する場合、 `base` は `\"/app/\"` の値が使われるべきです。\n\n### linkActiveClass\n\n- 型: `string`\n\n- デフォルト: `\"router-link-active\"`\n\n  グローバルに設定される `<router-link>` のデフォルトのアクティブクラスです。こちらの [router-link](#router-link) も参照してください。\n\n### linkExactActiveClass\n\n- 型: `string`\n\n- デフォルト: `\"router-link-exact-active\"`\n\n  完全一致に対してグローバルな `<router-link>` デフォルトアクティブクラスを設定します。[router-link](#router-link) も参照してください。\n\n### scrollBehavior\n\n- 型: `Function`\n\n  シグネチャ:\n\n  ```ts\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    void\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  より詳細については [スクロールの振る舞い](../guide/advanced/scroll-behavior.md) を参照してください。\n\n### parseQuery / stringifyQuery\n\n- 型: `Function`\n\n  カスタムクエリ構文解析関数 / 文字列化関数を提供します。デフォルトを上書きします。\n\n### fallback\n\n- 型: `boolean`\n- デフォルト: `true`\n\n  `history.pushState` がサポートされていないブラウザにおいて、モードが `history` に設定されているとき、ルーターを `hash` モードにフォールバックかどうか制御します。\n\n  これを `false` に設定すると、本質的に全ての `router-link` ナビゲーションが IE9 においてフルページリフレッシュになります。これは、サーバサイドレンダリングでハッシュモードの URL が機能しないため、IE9 で動作する必要がある場合に便利です。\n\n## ルーターインスタンスプロパティ\n\n### router.app\n\n- 型: `Vue インスタンス`\n\n  `router` が注入される root の Vue インスタンス\n\n### router.mode\n\n- 型: `string`\n\n  ルーターが使う [モード](#mode) 。\n\n### router.currentRoute\n\n- 型: `Route`\n\n  [ルーターオブジェクト](#ルートオブジェクト) として表される現在のルート。\n\n## メソッド\n\n### router.beforeEach\n### router.beforeResolve\n### router.afterEach\n\nシグネチャ:\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  /* `next` を呼び出さなければならない */\n})\n\nrouter.beforeResolve((to, from, next) => {\n  /* `next` を呼び出さなければならない */\n})\n\nrouter.afterEach((to, from) => {})\n```\n\n  グローバルなナビゲーションガードの追加。[ナビゲーションガード](../guide/advanced/navigation-guards.md) をご参照ください。\n\n  2.5.0 以降では、3 つのメソッドすべてが、登録されたガード/フックを削除する関数を返します。\n\n### router.push\n### router.replace\n### router.go\n### router.back\n### router.forward\n\nシグネチャ:\n\n``` js\nrouter.push(location, onComplete?, onAbort?)\nrouter.push(location).then(onComplete).catch(onAbort)\nrouter.replace(location, onComplete?, onAbort?)\nrouter.replace(location).then(onComplete).catch(onAbort)\nrouter.go(n)\nrouter.back()\nrouter.forward()\n```\n\n  プログラムによる新しい URL へのナビゲーション。 [プログラムによるナビゲーション](../guide/essentials/navigation.md) をご参照ください。\n\n### router.getMatchedComponents\n\nシグネチャ:\n\n``` js\nconst matchedComponents: Array<Component> = router.getMatchedComponents(location?)\n```\n\n  現在のルートまたは提供されたロケーションにマッチしているコンポーネント (インスタンスではなく定義 / コンストラクタ) の配列を返します。これは大抵の場合データ取得を行うサーバーサイドレンダリングで使用されます。\n\n### router.resolve\n\nシグネチャ:\n\n``` js\nconst resolved: {\n  location: Location;\n  route: Route;\n  href: string;\n} = router.resolve(location, current?, append?)\n```\n\n  逆 URL 解決します。`<router-link/>` で使われているものと同じ形式の location が与えられた場合は、以下の解決されたプロパティを返します。\n\n - `current` はデフォルトによる現在のルートです(ほとんどの場合、これを変更する必要はありません)\n - `append` は `current` ルートにパスを追加できます([`router-link`](#router-link-props)と同様に)\n\n### router.addRoutes\n\nシグネチャ:\n\n``` js\nrouter.addRoutes(routes: Array<RouteConfig>)\n```\n\n  動的にルートをルーターに追加します。引数は `routes` コンストラクタオプションで同じルート設定形式を使用する配列でなければなりません。\n\n### router.onReady\n\nシグネチャ:\n\n``` js\nrouter.onReady(callback, [errorCallback])\n```\n\n  このメソッドは、ルーターが初期ナビゲーションを完了したときに呼び出されるコールバックをキューに入れます。つまり、初期ルートに関連付けられているすべての非同期 enter フックと非同期コンポーネントを解決したことを意味します。\n\n  これは、サーバーとクライアントの両方で一貫した出力を保証するために、サーバーサイドレンダリングに役立ちます。\n\n  第 2 引数 `errorCallback` は 2.4 以降でのみサポートされます。初期ルート解決がエラーの時に、呼び出されます (例: 非同期コンポーネントの解決が失敗)。\n\n### router.onError\n\nシグネチャ:\n\n``` js\nrouter.onError(callback)\n```\n\n  ルートナビゲーション中にエラーが検出されたときに呼び出されるコールバックを登録します。エラーを呼び出すには、次のいずれかのシナリオが必要であることに注意してください:\n\n  - エラーがルートガード関数内で同期的に投げられる;\n\n  - エラーが補足され、ルートガード関数内で `next(err)` を呼び出すことによって非同期に処理される;\n\n  - ルートを描画するために必須な非同期コンポーネントを解決しようとする時に発生したエラー;\n\n## ルートオブジェクト\n\n**ルートオブジェクト**は現在のアクティブなルートの状態を表現しています。現在の URL をパースした情報と、その URL とマッチした**ルートレコード**を保持しています。\n\nルートオブジェクトは変更不可です。成功した全てのナビゲーションは結果的に新たなルートオブジェクトになります。\n\nルートオブジェクトは複数の場所に存在します。\n\n- コンポーネント内での `this.$route`\n\n- `$route` watcher コールバック内部\n\n- `router.match(location)` を呼び出した時の返り値\n\n- ナビゲーションガード内での第 1 引数、第 2 引数として:\n\n  ``` js\n  router.beforeEach((to, from, next) => {\n    // `to` と `from` は両方ともルートオブジェクト\n  })\n  ```\n\n- `scrollBehavior` 関数内の第 1 引数、第 2 引数として:\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n      // `to` と `from` は両方ともルートオブジェクト\n    }\n  })\n  ```\n\n### ルートオブジェクトプロパティ\n\n- **$route.path**\n\n  - 型: `string`\n\n    現在のルートのパスに等しい文字列。常に絶対パスとして解釈されます。e.g. `\"/foo/bar\"`\n\n- **$route.params**\n\n  - 型: `Object`\n\n    動的セグメントとスターセグメントの key/value ペアを保持するオブジェクト。もしパラメーターがない場合、この値は空オブジェクトになります。\n\n- **$route.query**\n\n  - 型: `Object`\n\n    クエリ文字列の key/value ペアを保持するオブジェクト。例えば `/foo?user=1` というパスの場合、`$route.query.user == 1` となります。もしクエリがない場合は、この値は空オブジェクトになります。\n\n- **$route.hash**\n\n  - 型: `string`\n\n    hash がある時の現在のルートの hash (# 有り) です。もし hash がない場合、この値は空オブジェクトになります。\n\n- **$route.fullPath**\n\n  - 型: `string`\n\n    クエリや hash を含む完全に解決された URL です。\n\n- **$route.matched**\n\n  - 型: `Array<RouteRecord>`\n\n  現在のルートのネストされた全パスセグメントに対しての **ルートレコード** を保持している配列です。ルートレコードは `routes` 設定の配列 (と `children` 配列) 内のオブジェクトのコピーです。\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // 以下のオブジェクトがルートレコード\n      { path: '/foo',\n        component: Foo,\n        children: [\n          // こちらもルートレコード\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  URL が `/foo/bar` である時、 `$route.matched` は親から子の順番で両方の (クローンされた) オブジェクトを含む配列になります。\n\n- **$route.name**\n\n  名前がある場合の現在のルートの名前です。(詳しくは [名前付きルート](../guide/essentials/named-routes.md) をご参照ください)\n\n- **$route.redirectedFrom**\n\n  もしあれば、リダイレクト元の名前。(参照[リダイレクトとエイリアス](../guide/essentials/redirect-and-alias.md))\n\n## コンポーネント注入\n\n### 注入されるプロパティ\n\nルーターインスタンスを root インスタンスに `router` オプションとして渡すことによって、全ての子コンポーネントに以下のプロパティが注入されます。\n\n- **this.$router**\n\n  ルーターインスタンス\n\n- **this.$route**\n\n  現在のアクティブな [ルート](#ルートオブジェクト) 。このプロパティは読み出しのみ可能かつ変更不可ですが、watch は可能です。\n\n### 有効になるオプション\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate**\n- **beforeRouteLeave**\n\n  [コンポーネント内ガード](../guide/advanced/navigation-guards.md#コンポーネント内ガード) をご参照ください。\n"
  },
  {
    "path": "docs/ja/guide/README.md",
    "content": "# はじめに\n\n::: tip Note\nガイド内のコードのサンプルは [ES2015](https://github.com/lukehoban/es6features) を使っています。\n\nすべての example では、vue の完全バージョンを使用してテンプレートを解析可能にしています。詳細は[こちら](https://jp.vuejs.org/v2/guide/installation.html#ランタイム-コンパイラとランタイム限定の違い)を参照してください。\n:::\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nVue.js と vue-router を使ったシングルページアプリケーションの構築は驚くほど簡単です。Vue.js のコンポーネントを使ってアプリケーションを既に構成しています。vue-router を混ぜ込むには、コンポーネントとルートをマッピングさせて vue-router にどこで描画するかを知らせるだけです。以下が基本的な例です。\n\n## HTML\n\n```html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- ナビゲーションに router-link コンポーネントを使う -->\n    <!-- リンク先を `to` プロパティに指定します -->\n    <!-- デフォルトで `<router-link>` は `<a>` タグとして描画されます -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- ルートアウトレット -->\n  <!-- ルートとマッチしたコンポーネントがここへ描画されます -->\n  <router-view></router-view>\n</div>\n```\n\n## JavaScript\n\n```js\n// 0. モジュールシステムを使っている場合 (例: vue-cli 経由で)、Vue と VueRouter をインポートし、`Vue.use(VueRouter)` を呼び出します。\n\n// 1. ルートコンポーネントを定義します\n// 他のファイルからインポートすることもできます\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. ルートをいくつか定義します\n// 各ルートは 1 つのコンポーネントとマッピングされる必要があります。\n// このコンポーネントは実際の `Vue.extend()`、\n// またはコンポーネントオプションのオブジェクトでも構いません。\n// ネストされたルートに関しては後で説明します\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. ルーターインスタンスを作成して、ルートオプションを渡します\n// 追加のオプションをここで指定できますが、\n// この例ではシンプルにしましょう\nconst router = new VueRouter({\n  routes // `routes: routes` の短縮表記\n})\n\n// 4. root となるインスタンスを作成してマウントします\n// アプリケーション全体がルーターを認知できるように、\n// ルーターをインジェクトすることを忘れないでください。\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// これで開始です!\n```\n\nルーターを注入することによって、`this.$router` と同様、任意のコンポーネント内部で現在のルートを `this.$route` としてアクセスすることができます:\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username() {\n      // `params` が表示される\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack () {\n      window.history.length > 1\n        ? this.$router.go(-1)\n        : this.$router.push('/')\n    }\n  }\n}\n```\n\nドキュメントを通して、しばしば `router` インスタンスを使用することがよくあります。`this.$router` は `router` を使用するのと全く同じです。`this.$router` を使用する理由は、ルーティング操作する必要がある全てのコンポーネントにルーターをインポートしたくないからです。\n\n[動作](https://jsfiddle.net/yyx990803/xgrjzsup/) の例も確認してみてください.\n\n`<router-link>` は対象のルートがマッチした時に自動的に `.router-link-active` が付与されるのにお気づきでしょうか。\nより詳細については [API リファレンス](../api/#router-link) をご参照ください。\n"
  },
  {
    "path": "docs/ja/guide/advanced/data-fetching.md",
    "content": "# データ取得\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nルートが有効化された時にサーバーからデータを取得する必要がしばしばあります。例えば、ユーザープロフィールを描画する前に、サーバーからユーザーデータを取得する必要があります。これを実現するためには 2 種類の方法があります。\n\n- **ナビゲーション後の取得**: ナビゲーションを先に実行し、その後次に入ってくるコンポーネントのライフサイクルフック内でデータを取得します。データ取得中にローディングを表示します。\n\n- **ナビゲーション前の取得**: ルートに入るガード内でナビゲーション前にデータ取得をします。そして、データ取得後にナビゲーションを実行します。\n\n技術的にはどちらも正当な選択肢です。究極的にはあなたが目指しているユーザーエクスペリエンスに依存します。\n\n## ナビゲーション後の取得\n\nこのアプローチを取る時は次に来るコンポーネントが即座にナビゲーションされ、描画されます。そして、コンポーネントの `created` フックの中でデータを取得します。この方法ではネットワーク越しにデータを取得している間にローディング状態を表示する機会があります。また、各 view に対して、異なるローディングの対応をすることもできます。\n\n`$route.params.id` を元にポストのデータを取得する必要がある `Post` コンポーネントを想定してみましょう。\n\n```html\n<template>\n  <div class=\"post\">\n    <div v-if=\"loading\" class=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n```js\nexport default {\n  data() {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created() {\n    // view が作られた時にデータを取得し、\n    // そのデータは既に監視されています\n    this.fetchData()\n  },\n  watch: {\n    // ルートが変更されたらこのメソッドを再び呼び出します\n    $route: 'fetchData'\n  },\n  methods: {\n    fetchData() {\n      this.error = this.post = null\n      this.loading = true\n      // `getPost` をあなたのデータ取得用 util や API ラッパーに置き換えてください\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## ナビゲーション前の取得\n\nこちらのアプローチでは新しいルートへ実際にナビゲーションする前にデータを取得します。次に入ってくるコンポーネント内の `beforeRouteEnter` ガードでデータ取得を実行できます。データ取得が完了したら `next` を呼ぶだけです。\n\n```js\nexport default {\n  data() {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter(route, redirect, next) {\n    getPost(route.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // コンポーネントが既に描画されている際のルート変更時は\n  // ロジックが少し異なります\n  beforeRouteUpdate(to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData(err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\n次に入ってくる view へのリソースを取得している間、ユーザーは前の view に滞在します。したがって、データ取得中にプログレスバーや何らかの指標を表示することをオススメします。また、もしデータ取得が失敗した場合、何かグローバルな警告メッセージのようなものを表示する必要があります。\n"
  },
  {
    "path": "docs/ja/guide/advanced/lazy-loading.md",
    "content": "# 遅延ローディングルート\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nバンドラーを使ってアプリケーションを構築している時、バンドルされる JavaScript が非常に大きいものになり得ます。結果的にページのロード時間に影響を与えてしまいます。もし各ルートコンポーネントごとに別々のチャンクにして、訪れたルートの時だけロードできればより効率的でしょう。\n\nVue の [非同期コンポーネント機能](http://jp.vuejs.org/guide/components.html#非同期コンポーネント) と webpack の [コード分割機能](https://webpack.js.org/guides/code-splitting-async/) を組み合わせることでとても簡単に遅延ロードするルートコンポーネントができます。\n\n最初に、非同期コンポーネントは Promise (コンポーネント自身解決する必要がある) を返すファクトリ関数として定義できます:\n\n```js\nconst Foo = () =>\n  Promise.resolve({\n    /* component definition */\n  })\n```\n\n次に、webpack 2 において [動的 import](https://github.com/tc39/proposal-dynamic-import) 構文を使用して、コード分割ポイントを示すことができます:\n\n```js\nimport('./Foo.vue') // returns a Promise\n```\n\n> Note: Babel を使用している場合、Babel が構文を正しく解析するために [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/) プラグインを追加する必要があります。\n\n2 つを組み合わせることで、これは、webpack によって自動的にコード分割される非同期コンポーネントを定義する方法です:\n\n```js\nconst Foo = () => import('./Foo.vue')\n```\n\n## 同じチャンク内でのコンポーネントグループ化\n\nしばしば同じ非同期のチャンクに、そのルート配下のネストされた全てのコンポーネントをグループ化したいと思うかもしれません。それを実現するためには、 特別なコメント構文 (webpack > 2.4 必須)を使用してチャンクの名前を提供する [名前付きチャンク](https://webpack.js.org/api/module-methods/#magic-comments) を使う必要があります。\n\n```js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nwebpack は同じチャンク名のどんな非同期のモジュールも同じ非同期のチャンクにグループします。\n"
  },
  {
    "path": "docs/ja/guide/advanced/meta.md",
    "content": "# ルートメタフィールド\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nルートの定義をする際に `meta` フィールドを含めることができます。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // メタフィールド\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nではどのように `meta` フィールドにアクセスしましょう？\n\nまず、 `routes` 設定の中の各ルートオブジェクトは**ルートレコード**と呼ばれます。ルートレコードはネストされているかもしれません。したがって、ルートがマッチした時に、潜在的には 1 つ以上のルートレコードがマッチされる可能性があります。\n\n例えば上記のルート設定で、 `/foo/bar` という URL は親のルートレコードにも子のルートレコードにもマッチします。\n\nルートにマッチした全てのルートレコードは `$route.matched` 配列として `$route` オブジェクト上で (また、ナビゲーションガード上のルートオブジェクトでも) アクセス可能になります。\n\nメタフィールドをグローバルナビゲーションガードで確認するユースケースの例:\n\n```js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // このルートはログインされているかどうか認証が必要です。\n    // もしされていないならば、ログインページにリダイレクトします。\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // next() を常に呼び出すようにしてください!\n  }\n})\n```\n"
  },
  {
    "path": "docs/ja/guide/advanced/navigation-failures.md",
    "content": "# ナビゲーションの失敗\n\n> 3.4.0の新機能\n\n`router-link` を使用すると、ナビゲーションを開始するためにVue Routerは `router.push` を呼び出します。ほとんどのリンクはユーザーを新しいページに移動させますが、ユーザーが同じページに留まる状況もいくつかあります。\n\n- すでにユーザーが移動したいページにいる\n- [ナビゲーションガード](./navigation-guards.md)が `next(false)` の呼び出しによって移動を中止した\n- [ナビゲーションガード](./navigation-guards.md)がエラーを投げた、または `next(new Error())` を呼び出した\n\n`router-link` コンポーネントを使用している場合、**これらの失敗はエラーとして記録されません**。しかし、 `router.push` または `router.replace` を使用している場合は、 _\"Uncaught (in promise) Error\"_ に続いて具体的なメッセージがコンソールに表示されることがあります。_ナビゲーションの失敗_ を区別する方法を理解しましょう。\n\n::: tip 背景\nv3.2.0では、router.pushの2つのオプションのコールバック（ `onComplete` と `onAbort` ）を通して _ナビゲーションの失敗_ が明らかになっていました。バージョン3.1.0以降、 `onComplete` / `onAbort` コールバックが提供されていない場合、 `router.push` と `router.replace` は _Promise_ を返します。この _Promise_ は `onComplete` の代わりにResolvedとなり、 `onAbort` の代わりにRejectedとなります。\n:::\n\n## ナビゲーションの失敗を検出する\n\n_Navigation Failures_ はいくつかの追加プロパティをもつ `Error` インスタンスです。ルーターからエラーが発生したかを確認するには、 `isNavigationFailure` 関数を使用します。\n\n```js\nimport VueRouter from 'vue-router'\nconst { isNavigationFailure, NavigationFailureType } = VueRouter\n\n// 管理画面にアクセス\nrouter.push('/admin').catch(failure => {\n  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n    // ユーザーに小さな通知を表示\n    showToast('Login in order to access the admin panel')\n  }\n})\n```\n\n::: tip\n`isNavigationFailure(failure)` のように2番目のパラメータを省略すると、エラーが _Navigation Failure_ かどうかのチェックのみが行われます。\n:::\n\n## `NavigationFailureType`\n\n`NavigationFailureType` は開発者がさまざまな種類の _Navigation Failures_ を区別するのに役立ちます。次の4つの種類があります。\n\n- `redirected`: 別の場所にリダイレクトするために、ナビゲーションガードの中で `next(newLocation)` が呼び出された\n- `aborted`: ナビゲーションガードの中で `next(false)` が呼び出された\n- `cancelled`: 現在のナビゲーションが終了する前に、新しいナビゲーションが実行された。例：ナビゲーションガード内で待機中に `router.push` が呼び出された\n- `duplicated`: すでに目的の場所にいるため、ナビゲーションが妨げられた\n\n## _Navigation Failures_ のプロパティ\n\n全てのナビゲーションの失敗は、そのナビゲーションのターゲットと現在地を反映した `to` と `from` のプロパティを公開します。\n\n```js\n// 管理画面にアクセス\nrouter.push('/admin').catch(failure => {\n  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n    failure.to.path // '/admin'\n    failure.from.path // '/'\n  }\n})\n```\n\n全ての場合において、 `to` と `from` は正規化されたルートの場所です。\n"
  },
  {
    "path": "docs/ja/guide/advanced/navigation-guards.md",
    "content": "# ナビゲーションガード\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nこの名前が示すように、 `vue-router` によって提供されるナビゲーションガードは、リダイレクトもしくはキャンセルによって遷移をガードするために主に使用されます。ルートナビゲーション処理 (グローバル、ルート単位、コンポーネント内) をフックする多くの方法があります。\n\n**パラメータまたはクエリの変更は enter/leave ナビゲーションガードをトリガーしない** ということを覚えておいてください。それらの変更に対応するために [`$route` オブジェクトを監視する](../essentials/dynamic-matching.md#reacting-to-params-changes)、またはコンポーネント内ガード `beforeRouteUpdate` を使用するかの、どちらかができます。\n\n## グローバルビフォーガード\n\n`router.beforeEach` を使ってグローバル before ガードを登録できます。\n\n```js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nいつナビゲーションがトリガーされようとも、グローバル before ガードは作られた順番で呼び出されます。ガードは非同期に解決されるかもしれません。そしてそのナビゲーションは全てのフックが解決されるまで **未解決状態** として扱われます。\n\n全てのガード関数は 3 つの引数を受け取ります。\n\n- **`to: Route`**: 次にナビゲーションされる対象の [ルートオブジェクト](../../api/#ルートオブジェクト)。\n\n- **`from: Route`**: ナビゲーションされる前の現在のルートです。\n\n- **`next: Function`**: フックを **解決** するためにこの関数を呼ぶ必要があります。この振る舞いは `next` に渡される引数に依存します:\n\n- **`next()`**: パイプラインの次のフックに移動します。もしフックが残っていない場合は、このナビゲーションは **確立** されます。\n\n- **`next(false)`**: 現在のナビゲーションを中止します。もしブラウザの URL が変化した場合は（ユーザーが手動で変更した場合でも、戻るボタンの場合でも）、 `from` ルートの URL にリセットされます。\n\n- **`next('/')` または `next({ path: '/' })`**: 異なる場所へリダイレクトします。現在のナビゲーションは中止され、あたらしいナビゲーションが始まります。任意のロケーションオブジェクトを `next` に渡すことができます。この `next` には、`replace: true`、 `name: 'home'` のようなオプション、そして [`router-link`、`to` プロパティ](../../api/#router-link)または [`router.push`](../../api/#ルーターインスタンスプロパティ)で使用される任意のオプションを指定することができます。\n\n- **`next(error)`**: (2.4.0+) `next` に渡された引数が `Error` インスタンスである場合、ナビゲーションは中止され、エラーは `router.onError()` を介して登録されたコールバックに渡されます。\n\n**与えられたナビゲーションガードを通過する任意のパスにおいて、常に 1 回だけ `next` 関数が呼び出されるようにしてください。それは 1 回以上出現することがありますが、論理パスが重ならないときだけで、そうしないないとフックは決して解決されない、またはエラーが発生します。** 以下は、ユーザーが認証されていない場合、`/login` にリダレクトするための例です:\n\n```js\n// BAD\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  // ユーザーが認証されていない場合、 `next` は2回呼ばれる\n  next()\n})\n```\n\n```js\n// GOOD\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  else next()\n})\n```\n\n## グローバル解決ガード\n\n> New in 2.5.0\n\n2.5.0 以降では、`router.beforeResolve` によってグローバルガードを登録できます。これは `router.beforeEach` に似ていますが、**すべてのコンポーネント内ガードと非同期ルートコンポーネントが解決された後**、ナビゲーションが解決される直前に解決ガードが呼び出されるという違いがあります。\n\n## グローバルな After フック\n\nグローバル after フックを登録することもできます。しかしながら、ガードとは異なり、これらのフックは `next` 関数を受け取らず、ナビゲーションに影響しません。\n\n```js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n## ルート単位ガード\n\n直接ルート設定オブジェクトの `beforeEnter` ガードを定義することができます。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nこれらのガードはグローバル before ガードと全く同じシグネチャを持ちます。\n\n### コンポーネント内ガード\n\n最後に、 以下のオプションでルートコンポーネント(ルータ設定に渡されるもの)の内側でルートナビゲーションガードを直接定義することができます。\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (2.2 で追加)\n- `beforeRouteLeave`\n\n```js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter(to, from, next) {\n    // このコンポーネントを描画するルートが確立する前に呼ばれます。\n    // `this` でのこのコンポーネントへのアクセスはできません。\n    // なぜならばこのガードが呼び出される時にまだ作られていないからです!\n  },\n  beforeRouteUpdate(to, from, next) {\n    // このコンポーネントを描画するルートが変更されたときに呼び出されますが、\n    // このコンポーネントは新しいルートで再利用されます。\n    // たとえば、動的な引数 `/foo/:id` を持つルートの場合、`/foo/1` と `/foo/2` の間を移動すると、\n    // 同じ `Foo` コンポーネントインスタンスが再利用され、そのときにこのフックが呼び出されます。\n    // `this` でコンポーネントインスタンスにアクセスできます。\n  },\n  beforeRouteLeave(to, from, next) {\n    // このコンポーネントを描画するルートが間もなく\n    // ナビゲーションから離れていく時に呼ばれます。\n    // `this` でのコンポーネントインスタンスへのアクセスができます。\n  }\n}\n```\n\nこの `beforeRouteEnter` ガードは `this` へのアクセスは**できない**です。なぜならば、ナビゲーションが確立する前にガードが呼び出されるからです。したがって、新しく入ってくるコンポーネントはまだ作られていないです。\n\nしかしながら、 `next` にコールバックを渡すことでインスタンスにアクセスすることができます。このコールバックはナビゲーションが確立した時に呼ばれ、コンポーネントインスタンスはそのコールバックの引数として渡されます。\n\n```js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // `vm` を通じてコンポーネントインスタンスにアクセス\n  })\n}\n```\n\nコールバックを `next` に渡すことをサポートするのは、`beforeRouteEnter` ガードだけであるということに注意してください。`beforeRouteUpdate` と `beforeRouteLeave` の場合、 `this` は既に利用可能です。したがって、コールバックを渡す必要はないので、_サポートされません_:\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // `this` を使用\n  this.name = to.params.name\n  next()\n}\n```\n\n**leave ガード**は、通常、ユーザが保存されていない編集内容で誤って経路を離れるのを防ぐために使用されます。ナビゲーションは `next(false)` を呼び出すことで取り消すことができます。\n\n```js\nbeforeRouteLeave (to, from, next) {\n  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\n## 完全なナビゲーション解決フロー\n\n1. ナビゲーションがトリガされる\n2. 非アクティブ化されたコンポーネントで `beforeRouteLeave` ガードを呼ぶ\n3. グローバル `beforeEach` ガードを呼ぶ\n4. 再利用されるコンポーネントで `beforeRouteUpdate` ガードを呼ぶ (2.2 以降)\n5. ルート設定内の `beforeEnter` を呼ぶ\n6. 非同期ルートコンポーネントを解決する\n7. アクティブ化されたコンポーネントで `beforeRouteEnter` を呼ぶ\n8. グローバル `beforeResolve` ガードを呼ぶ (2.5 以降)\n9. ナビゲーションが確定される\n10. グローバル `afterEach` フックを呼ぶ\n11. DOM 更新がトリガされる\n12. インスタンス化されたインスンタンスによって `beforeRouteEnter` ガードで `next` に渡されたコールバックを呼ぶ\n"
  },
  {
    "path": "docs/ja/guide/advanced/scroll-behavior.md",
    "content": "# スクロールの振る舞い\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nクライアントサイドのルーティングを使っている時に、新しいルートに対してスクロールをトップへ移動させたいかもしれません、もしくは実際のページリロードがしているように history 要素のスクロールポジションを保持したいこともあるかもしれません。 `vue-router` ではこれらをさらによく実現できます。ルートナビゲーションにおけるスクロールの挙動を完全にカスタマイズすることができます。\n\n**注意: この機能は ブラウザが `history.pushState` をサポートしている場合のみ動作します。**\n\nルーターインスタンスを作る時に、 `scrollBehavior` 関数を提供できます。\n\n```js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // 望みのポジションを返す\n  }\n})\n```\n\n`scrollBehavior` 関数は `to` と `from` のルートオブジェクトを受け取ります。第 3 引数の `savedPosition` は `popstate` ナビゲーション (ブラウザの戻る/進むボタンがトリガーされた) 時のみ利用可能です。\n\nこの関数はスクロールポジションオブジェクトを返すことができます。そのオブジェクトは以下のような形式です。\n\n- `{ x: number, y: number }`\n- `{ selector: string }`\n- `{ selector: string, offset? : { x: number, y: number }}` (2.6.0 以降においてだけ offset はサポート)\n\nもし falsy な値や空のオブジェクトが返った場合、何もスクロールは起きません。\n\n例:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nこれは単純に全てのルートナビゲーションに対してページスクロールをトップにします。\n\n`savedPosition` を返すことは結果的に戻る/進むボタンを押してナビゲーションした時にネイティブのような挙動になります。\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nもし\"アンカーへスクロール\"の振る舞いをシミュレートしたい場合は以下のようにしてください。\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nきめの細かいスクロールの挙動コントロールを実装するために [ルートメタフィールド](meta.md) も利用可能です。詳細な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js) をご参照ください。\n\n## 非同期なスクローリング\n\n> 2.8.0 で新規\n\n期待する位置記述子 (position descriptor) に解決されるプロミスを返すこともできます:\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nスクロールの振る舞いをページの遷移とうまく合わせるために、ページレベルのトランジションコンポーネントからのイベントにフックすることは可能ですが、ユースケースにおいて可能性のある食い違いと複雑さのために、単純に特定のユーザランド実装を可能にするために、このプリミティブな機能を提供します。\n"
  },
  {
    "path": "docs/ja/guide/advanced/transitions.md",
    "content": "# トランジション\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\n基本的に `<router-view>` は動的コンポーネントなので、 `<transition>` コンポーネントを使うのと同じ方法でトランジションを適用することができます。\n\n```html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[全てのトランジション API は](http://jp.vuejs.org/guide/transitions.html) はここでも動作します。\n\n## ルート単位のトランジション\n\n上記の使い方では全てのトランジションが全てのルートに対して適用されます。もし各ルートコンポーネントにそれぞれ違うトランジションを持たせたい場合は、代わりにルーターコンポーネント内で異なる名前で `<transition>` を使うことができます。\n\n```js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n## ルートベースの動的トランジション\n\n対象のルートと現在のルートの関係を元に動的にトランジションを決定することも可能です。\n\n```html\n<!-- 動的なトランジション名の使用 -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n```js\n// そして親コンポーネントの中で、\n// `$route` を watch して使用するトランジションを決定します\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\n完全な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js) をご参照ください。\n"
  },
  {
    "path": "docs/ja/guide/essentials/dynamic-matching.md",
    "content": "# 動的ルートマッチング\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nパターンを使って同じコンポーネントにルートをマップする必要がしばしばあるでしょう。例えば、 `User` コンポーネントは全てのユーザーに対して描画されるべきであるが、それぞれ異なるユーザー ID を持つ場合などです。`vue-router` ではパスの中の動的なセグメントを使用して実現できます。\n\n```js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // コロンで始まる動的セグメント\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nこれで `/user/foo` や `/user/bar` などの URL 両方とも同じルートにマッチします。\n\n動的セグメントはコロン `:` を使って表されます。ルートがマッチした時、この動的セグメントの値は全てのコンポーネント内で `this.$route.params` として利用可能になります。したがって、現在の `User` のテンプレートを次のように更新することで現在のユーザー ID を表示することができます。\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\n[こちら](https://jsfiddle.net/yyx990803/4xfa2f19/) のデモの例も確認してみてください。\n\n1 つのルートが複数の動的なセグメントを持つこともできます。そして、それらは `$route.params` の一致したフィールドとマップされます。例:\n\n| パターン                      | マッチしたパス      | \\$route.params                         |\n| ----------------------------- | ------------------- | -------------------------------------- |\n| /user/:username               | /user/evan          | `{ username: 'evan' }`                 |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\n`$route.params` に加えて、`$route` オブジェクトでは `$route.query` (もし URL 上にクエリがあるなら) や `$route.hash` など便利な情報も利用可能です。それらの詳細については [API リファレンス](../../api/#the-route-object) でご確認ください。\n\n## パラメーター変更の検知\n\nルートのパラメーターを使う際に特筆すべき点は、ユーザーが `/user/foo` から `/user/bar` へ遷移するときに**同じコンポーネントインスタンスが再利用される**ということです。 両方のルートが同じコンポーネントを描画するため、古いインスタンスを破棄して新しいものを生成するよりも効率的です。**しかしながら、これはコンポーネントのライフサイクルフックが呼ばれないことを意味しています。**\n\n同じコンポーネントでパラメーター変更を検知するためには、 `$route` オブジェクトを watch するだけです。\n\n```js\nconst User = {\n  template: '...',\n  watch: {\n    $route(to, from) {\n      // ルートの変更の検知...\n    }\n  }\n}\n```\n\nまたは、2.2 で導入された `beforeRouteUpdate` [ナビゲーションガード](../advanced/navigation-guards.html)を使用します:\n\n```js\nconst User = {\n  template: '...',\n  beforeRouteUpdate(to, from, next) {\n    // ルート変更に反応する...\n    // next() を呼び出すのを忘れないでください\n  }\n}\n```\n\n## すべてキャッチするルート / 404 Not found ルート\n\n通常のパラメータは、`/` で区切られた url フラグメントの間にある文字だけにマッチします。**何でも**一致させたい場合は、アスタリスク(`*`)を使うことができます:\n\n```js\n{\n  // 全てにマッチします\n  path: '*'\n}\n{\n  // `/user-`から始まる任意のものにマッチします\n  path: '/user-*'\n}\n```\n\n_アスタリスク_ ルートを使用するときは、_アスタリスク_ ルートが最後になるようにルートを正しく順序付けてください。\n`{ path: '*' }` ルートは、通常クライアントサイドの 404 ページで使われます。_History モード_ を使用する場合は、[正しいサーバの設定](./history-mode.md)も同様にしっかりしてください。\n\n_アスタリスク_ を使用するときは、 `pathMatch` と名付けられたパラメータは、自動的に `$route.params` に追加されます。_アスタリスク_ によってマッチされた url の残りを含みます:\n\n```js\n// { path: '/user-*' } というルートが与えられた\nthis.$router.push('/user-admin')\nthis.$route.params.pathMatch // 'admin'\n// { path: '*' } というルートが与えられた\nthis.$router.push('/non-existing')\nthis.$route.params.pathMatch // '/non-existing'\n```\n\n## 高度なマッチングパターン\n\n`vue-router` はパスのマッチングエンジンとして [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) を使っています。これは Optional による動的なセグメント、Zero or more / One or more に対する要求、また、カスタム正規表現パターンまでもサポートしています。 これらの高度なパターンについてはこちらの [ドキュメンテーション](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters) または、 `vue-router` の中でそれらを使っている [こちらの例](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) をご参照ください。\n\n## マッチングの優先度\n\nしばしば同じ URL で複数のルートがマッチすることがあります。そのようなケースではマッチングの優先度はルートの定義された順番によって決定されます。先に定義されたルートほど優先度が高くなります。\n"
  },
  {
    "path": "docs/ja/guide/essentials/history-mode.md",
    "content": "# HTML5 History モード\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\n`vue-router` のデフォルトは _hash モード_ です - 完全な URL を hash を使ってシミュレートし、 URL が変更された時にページのリロードが起きません。\n\nその hash を取り除くために、ページのリロード無しに URL 遷移を実現する `history.pushState` API を利用したルーターの **history モード** を使うことができます。\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nhistory モードを使用する時は、URL は \"普通\" に見えます e.g. `http://oursite.com/user/id`。美しいですね!\n\nしかしながら一点問題があります。シングルページのクライアントサイドアプリケーションなので、適切なサーバーの設定をしないと、ユーザーがブラウザで直接 `http://oursite.com/user/id` にアクセスした場合に 404 エラーが発生します。\n\n心配する必要はありません。この問題を直すためには、単純な catch-all フォールバックのためのルートをサーバー側で追加するだけです。もし URL がどの静的なアセットにもマッチしなかった時はあなたのアプリケーションが動作しているのと同じ `index.html` ページで受け付けましょう。これも美しいですね!\n\n## サーバーの設定例\n\n#### Apache\n\n```apache\n<IfModule mod_negotiation.c>\n  Options -MultiViews\n</IfModule>\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n`mod_rewrite`の代わりに、[`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource) も使用することができます。\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Native Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp\n  .createServer((req, res) => {\n    fs.readFile('index.html', 'utf-8', (err, content) => {\n      if (err) {\n        console.log('We cannot open \"index.html\" file.')\n      }\n\n      res.writeHead(200, {\n        'Content-Type': 'text/html; charset=utf-8'\n      })\n\n      res.end(content)\n    })\n  })\n  .listen(httpPort, () => {\n    console.log('Server listening on: http://localhost:%s', httpPort)\n  })\n```\n\n#### Node.js (Express)\n\nNode.js/Express では [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback) の利用を検討してください。\n\n#### Internet Information Services (IIS)\n\n1. [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite) をインストール\n2. 以下によるサイトのルートディレクトリに `web.config` ファイルを作成\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Firebase のホスティング\n\n以下を `firebase.json` に追加します:\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## 注意\n\nこの点に関して注意があります。全ての not-found パスが `index.html` を提供するため、もはや 404 エラーをサーバーがレポートしなくなります。回避策として、Vue アプリケーション内で 404 ページを表示するために catch-all ルートを実装すべきです。\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [{ path: '*', component: NotFoundComponent }]\n})\n```\n\n他の方法として、もしあなたが Node.js サーバーを使っている場合、入ってきた URL とマッチさせて、マッチしなかった場合に 404 を返答するサーバーサイドのルーターを使って fallback を実装することもできます。詳細については [Vue サーバサイドレンダリングのドキュメント](https://ssr.vuejs.org/ja/) を参照してください。\n"
  },
  {
    "path": "docs/ja/guide/essentials/named-routes.md",
    "content": "# 名前付きルート\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nしばしば、名前を使ってルートを特定できるとより便利です。特にルートにリンクするときやナビゲーションを実行するときなどです。Router インスタンスを作成するときに `routes` オプションの中でルートに名前を付けることができます。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\n名前を付けたルートにリンクするには、 `router-link` コンポーネントの `to` プロパティにオブジェクトを渡します。\n\n```html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\nこれはプログラムで `router.push()` を呼び出すときに使われるオブジェクトと全く同じです。\n\n```js\nrouter.push({ name: 'user', params: { userId: 123 } })\n```\n\nどちらのケースもルーターは `/user/123` のパスにナビゲーションします。\n\n完全な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js) です。\n"
  },
  {
    "path": "docs/ja/guide/essentials/named-views.md",
    "content": "# 名前付きビュー\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nしばしば、ネストをさせずに同時に複数の view を表示する必要があるでしょう。例えば、`sidebar` view と `main` view を使ったレイアウトを作成する時です。そんな時に名前付きビューは便利です。あなたの view に 1 つのアウトレットを持つのではなく、複数のそれぞれが名前付きの view を持つことができます。名前を持たない `router-view` はその名前として `default` が付与されます。\n\n```html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\n1 つの view は 1 つのコンポーネントを使って描画されます。したがって、同じルートに対する複数の view には複数のコンポーネントが必須になります。この `components` (s が付いている) オプションに注意してください。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nこの例の動作しているデモは\n[こちら](https://jsfiddle.net/posva/6du90epg/) です。\n\n## ネストされた名前付きビュー\n\nネストされたビューを持つ名前付きビューを使用して複雑なレイアウトを作成することができます。そうする際に、ネストされた `router-view` コンポーネントを使用するために名前をつける必要があります。設定パネルの例を見てみましょう:\n\n```\n/settings/emails                                       /settings/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` は普通のコンポーネントです\n- `UserSettings` はビューコンポーネントです\n- `UserEmailsSubscriptions` 、`UserProfile` 、`UserProfilePreview` はネストされたビューコンポーネントです\n\n**Note**: _そのようなレイアウトに HTML/CSS がどのように表示されるのか、そして使用されるコンポーネントに焦点を当てる方法については、ここでは忘れましょう_\n\n上記レイアウトでの `UserSettings` コンポーネントの `<template>` セクションは次のようになります:\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>User Settings</h1>\n  <NavBar />\n  <router-view />\n  <router-view name=\"helper\" />\n</div>\n```\n\n_ここではネストされたビューコンポーネントは省略されていますが、上記例の完全なソースコードを[ここ](https://jsfiddle.net/posva/22wgksa3/)で見ることができます_\n\nそれから、以下のルート設定で上記のレイアウトを表現することができます:\n\n```js\n{ path: '/settings',\n  // トップで名前付きビューを持つこともできます\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nこの例の動作するデモは、[ここ](https://jsfiddle.net/posva/22wgksa3/)に見ることができます。\n"
  },
  {
    "path": "docs/ja/guide/essentials/navigation.md",
    "content": "# プログラムによるナビゲーション\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\n宣言的なナビゲーションとしてアンカータグを作成する `<router-link>` がありますが、ルーターのインスタンスメソッドを使ったプログラムによる方法でもそれは可能です。\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**注意: Vue インスタンスの内部では、`$router` としてルーターインスタンスにアクセスできます。従って、`this.$router.push` で呼ぶことができます。**\n\n異なる URL へ遷移するときに `router.push` が使えます。このメソッドは history スタックに新しいエントリを追加します。それによってユーザーがブラウザの戻るボタンをクリックした時に前の URL に戻れるようになります。\n\nこのメソッドは `<router-link>` をクリックした時に内部的に呼ばれています。つまり `<router-link :to=\"...\">` をクリックすることは `router.push(...)` を呼ぶことと等価です。\n\n| 宣言的                    | プログラム的       |\n| ------------------------- | ------------------ |\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\n引数は文字列のパス、もしくは、location を記述するオブジェクトが使えます。例:\n\n```js\n// 文字列パス\nrouter.push('home')\n\n// オブジェクト\nrouter.push({ path: 'home' })\n\n// 名前付きルート\nrouter.push({ name: 'user', params: { userId: '123' } })\n\n// 結果的に /register?plan=private になる query\nrouter.push({ path: 'register', query: { plan: 'private' } })\n```\n\n**注意**: `path` が渡された場合は `params` は無視されます（`query` は上の例の通り無視されません）。代わりに `name` でルート名を渡すか、`path` にすべてのパラメータを含める必要があります:\n\n```js\nconst userId = '123'\nrouter.push({ name: 'user', params: { userId } }) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// これは動作\"しません\"\nrouter.push({ path: '/user', params: { userId } }) // -> /user\n```\n\n同じルールが、`router-link` コンポーネントの `to` プロパティに対して適用されます。\n\n2.2.0 以降では、必要に応じて、第 2 引数と第 3 引数として `router.push` または `router.replace` に `onComplete` と `onAbort` コールバックを指定します。これらのコールバックは、ナビゲーションが正常に完了したとき(すべての非同期フックが解決された後)に呼び出されるか、またはそれぞれ中止されます(現在のナビゲーションが終了する前に同じルートまたは別のルートにナビゲートされた)\n\n**注意:** ルートの行き先が現在のルートと同じで、かつパラメータのみが変更されている場合(例: `/users/1` -> `/users/2` のようにあるプロファイルから他へ)、変更(例: ユーザー情報の取得など)に反応するために[beforeRouteUpdate](./dynamic-matching.html#パラメーター変更の検知) を使用しなければなりません。\n\n#### `router.replace(location, onComplete?, onAbort?)`\n\nこれは `router.push` のように動作しますが、異なる点は新しい history エントリを追加しないで遷移することです。この名前から推定されるように、現在のエントリを置換します。\n\n| 宣言的                            | プログラム的          |\n| --------------------------------- | --------------------- |\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n#### `router.go(n)`\n\nこのメソッドは、history スタックの中でどのくらいステップを進めるか、もしくは戻るのか、を表す 1 つの integer をパラメーターとして受け取ります。`window.history.go(n)` と類似しています。\n\n例\n\n```js\n// 1 つレコードを進める。history.forward() と同じ\nrouter.go(1)\n\n// 1 つレコードを戻す。history.back() と同じ\nrouter.go(-1)\n\n// 3 つレコードを進める\nrouter.go(3)\n\n// もし多くのレコードが存在しない場合、サイレントに失敗します\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### History 操作\n\nもしかすると `router.push`、`router.replace`、`router.go` は [`window.history.pushState`、`window.history.replaceState`、`window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History) と対応することにお気づきかもしれません。これらは `window.history` API を模倣しています。\n\nしたがって、もしあなたが既に [Browser History APIs](https://developer.mozilla.org/en-US/docs/Web/API/History_API) について詳しい場合は、vue-router による History 操作はとても簡単です。\n\nvue-router のナビゲーションメソッド (`push`、`replace`、`go`) は全てのモード (`history`、`hash`、`abstract`) で一貫して動作することは特筆すべき点です。\n"
  },
  {
    "path": "docs/ja/guide/essentials/nested-routes.md",
    "content": "# ネストされたルート\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\n実際のアプリケーションの UI では通常複数のレベルの階層的にネストしたコンポーネントで構成されます。ネストされたコンポーネントの特定の構造に対して URL のセグメントを対応させることはよくあります。例:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\n`vue-router` を使えば、これらのネストされたルートの設定を使って関連付けをシンプルに表現することができます。\n\n前の章で作ったアプリケーションを考えてみましょう。\n\n```html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [{ path: '/user/:id', component: User }]\n})\n```\n\nここでの `<router-view>` はトップレベルのアウトレットです。トップレベルのルートによってマッチしたコンポーネントが描画されます。同様に描画されたコンポーネントもまた自身のネストされた `<router-view>` を持つことができます。`User` コンポーネントのテンプレート内部に 1 つ追加する例です。\n\n```js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nこのネストされたアウトレットに対してコンポーネントを描画するためには、 `VueRouter` のコンストラクタの設定で `children` オプションを使用する必要があります。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        {\n          // /user/:id/profile がマッチした時に\n          // UserProfile は User の <router-view> 内部で描画されます\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // /user/:id/posts がマッチした時に\n          // UserPosts は User の <router-view> 内部で描画されます\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**`/` から始まるネストされたパスは root パスとして扱われることに注意してください。これによってネストされた URL を指定しなくてもコンポーネントをネストすることができます。**\n\n`children` オプションを見るとわかる通り、これは `routes` 自身と同じようなルート設定オブジェクトの配列です。したがって、ネストしている view を必要なだけ保持することができます。\n\nここまでの点では、上記の設定で `/user/foo` に訪れた時に `User` アウトレット内部で何も描画されません。なぜならば、サブルートにマッチしていないからです。そこに何か描画したい場合は、空のサブルートパスを設定できます。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        // /user/:id がマッチした時に\n        // UserHome は User の <router-view> 内部で描画されます\n        { path: '', component: UserHome }\n\n        // 他のサブルートも同様に...\n      ]\n    }\n  ]\n})\n```\n\nこの例の動作デモは [こちら](https://jsfiddle.net/yyx990803/L7hscd8h/) です。\n"
  },
  {
    "path": "docs/ja/guide/essentials/passing-props.md",
    "content": "# ルートコンポーネントにプロパティを渡す\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\nコンポーネントで `$route` を使うとコンポーネントとルートの間に密結合が生まれ、コンポーネントが特定の URL でしか使用できないなど柔軟性が制限されます。\n\nコンポーネントをルーターから分離するために `props` オプションを使います:\n\n**`$route` に結合**\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [{ path: '/user/:id', component: User }]\n})\n```\n\n**`props` による分離**\n\n```js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // 名前付きビューによるルートに対しては、名前付きビューごとに `props` オプションを定義しなければなりません:\n    {\n      path: '/user/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nこれにより、コンポーネントをどこからでも使用できるようになり、コンポーネントの再利用とテストが容易になります。\n\n### Boolean モード\n\n`props` を `true` に設定すると、`route.params` がコンポーネントのプロパティとして設定されます。\n\n### Object モード\n\n`props` がオブジェクトの場合、これはコンポーネントプロパティとしてそのまま設定されます。プロパティが静的なときに便利です。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/promotion/from-newsletter',\n      component: Promotion,\n      props: { newsletterPopup: false }\n    }\n  ]\n})\n```\n\n### Function モード\n\nプロパティを返す関数を作成することができます。これにより、パラメータを他のタイプにキャストし、静的な値をルートベースの値などと組み合わせることができます。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/search',\n      component: SearchUser,\n      props: route => ({ query: route.query.q })\n    }\n  ]\n})\n```\n\nURL `/search?q=vue` は `{query: 'vue'}` をプロパティとして `SearchUser` コンポーネントに渡します。\n\nルート変更時にのみ評価されるため、`props` 関数はステートレスにしてください。プロパティを定義するために状態を必要とする場合はラッパーコンポーネントを使用してください。その方法で vue は状態変更に対応することができます。\n\n高度な使い方については、[example](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js)を参照してください。\n"
  },
  {
    "path": "docs/ja/guide/essentials/redirect-and-alias.md",
    "content": "# リダイレクトとエイリアス\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">Watch a free video course about Vue Router on Vue School</a></div>\n\n### リダイレクト\n\n`routes` 設定でリダイレクトが可能です。`/a` から `/b` へリダイレクトする例:\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/a', redirect: '/b' }]\n})\n```\n\n名前付きルートに対してリダイレクトすることもできます。\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/a', redirect: { name: 'foo' } }]\n})\n```\n\nまた、function を使った動的なリダイレクトもできます。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/a',\n      redirect: to => {\n        // この function は対象のルートを引数として受け取ります\n        // ここではリダイレクト先の path もしくは location を返します\n      }\n    }\n  ]\n})\n```\n\n[ナビゲーションガード](../advanced/navigation-guards.md)はリダイレクトするルートに提供されず、ターゲット上のみに適用されるということに注意してください。例では、`beforeEnter` ガードを `/a` ルートに追加しても効果がありません。\n\nその他の高度な使い方として、[例](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js) をご参照ください。\n\n### エイリアス\n\nリダイレクトが意図するところは、ユーザーが `/a` に訪問した時に URL を `/b` に置換し、そして `/b` にマッチさせます。ではエイリアスは何でしょうか?\n\n**`/b` として扱う `/a` のエイリアスは、ユーザーが `/b` に訪問した時に URL は `/b` のままになります。しかし、それはまるでユーザーが `/a` に訪問したかのようにマッチされます。**\n\n上記はルートの設定で以下のように表現されます。\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/a', component: A, alias: '/b' }]\n})\n```\n\n設定のネスト構造による制約とは異なり、エイリアスは UI 構造に任意の URL をマップするための自由さがあります。\n\n高度な使い方に関しては、 [例](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js) をご参照ください。\n"
  },
  {
    "path": "docs/ja/installation.md",
    "content": "# インストール\n\n### 直接ダウンロード / CDN\n\n[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) は npm ベースの CDN リンクです。 上記のリンクは常に NPM 上の最新のリリースを指します。 `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js` のような URL を利用することで特定のバージョンやタグを指定することもできます。\n<!--/email_off-->\n\nVue の後に `vue-router` を含めると自動的にインストールされます。\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### npm\n\n``` bash\nnpm install vue-router\n```\n\nモジュールシステムを使う場合、`Vue.use()` を使って明示的にルーターをインストールする必要があります。\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nグローバルな script タグを使っている場合は必要ありません。\n\n## Vue CLI\n\n[Vue CLI](https://cli.vuejs.org/) を使用している場合、 Vue Router をプラグインで追加することができます。2つのサンプルルートと同様、上記のコードを CLI に生成させることができます。**`App.vue`もまた上書きされるため、** プロジェクト内で以下のコマンドを実行する前にファイルをバックアップしておいてください:\n\n```sh\nvue add router\n```\n\n### 開発用ビルド\n\nもし最新の開発用ビルドを使用したい場合は、GitHub から直接クローンして `vue-router` をご自身でビルドしてください。\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs/kr/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Get Started →\nactionLink: /kr/installation.html\nfooter: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote\n---\n\nVue 라우터는 [Vue.js](http://vuejs.org)의 공식 라우터입니다.\nVue.js를 사용한 싱글 페이지 앱을 쉽게 만들 수 있도록 Vue.js의 코어와 긴밀히 통합되어 있습니다.\n\n아래의 기능을 포함합니다.\n\n- 중첩된 라우트/뷰 매핑\n- 모듈화된, 컴포넌트 기반의 라우터 설정\n- 라우터 파라미터, 쿼리, 와일드카드\n- Vue.js의 트랜지션 시스템을 이용한 트랜지션 효과\n- 세밀한 네비게이션 컨트롤\n- active CSS 클래스를 자동으로 추가해주는 링크\n- HTML5 히스토리 모드 또는 해시 모드(IE9에서 자동으로 폴백)\n- 사용자 정의 가능한 스크롤 동작\n\n[시작하기](./guide/) 또는 [예제](https://github.com/vuejs/vue-router/tree/dev/examples)를 참고하세요. ([`README.md`](https://github.com/vuejs/vue-router/)에서 사용법을 확인할 수 있습니다).\n\n<HomeSponsors />\n"
  },
  {
    "path": "docs/kr/api/README.md",
    "content": "---\nsidebar: auto\n---\n\n# API 레퍼런스\n\n## `<router-link>`\n\n`<router-link>`는 라우터 지원 앱에서 사용자 네비게이션을 가능하게하는 컴포넌트입니다. 목표 위치는 `to` prop로 지정됩니다. 기본적으로 올바른 `href`를 갖는 `<a>`태그로 렌더링 되지만 `tag` prop로 구성 될 수 있습니다. 또한 대상 라우트가 활성화되어 있으면 링크가 자동으로 active CSS 클래스를 가져옵니다.\n\n`<router-link>`는 다음과 같은 이유로 하드 코드 된 `<a href=\"...\">`보다 선호됩니다.\n\n- HTML5 히스토리 모드와 해시 모드에서 모두 동일한 방식으로 작동하므로 모드를 트랜지션하기로 결정하거나 라우터가 IE9에서 해시 모드로 트랜지션 한 경우 변경할 필요가 없습니다.\n\n- HTML5 히스토리 모드에서, `router-link`는 클릭 이벤트를 차단하여 브라우저가 페이지를 다시 로드하지 않도록합니다.\n\n- HTML5 히스토리 모드에서 `base` 옵션을 사용할 때 `to` prop의 URL에 이를 포함 할 필요가 없습니다.\n\n## Props\n\n### to\n\n  - 자료형: `string | Location`\n\n  - 필수\n\n  링크의 대상 라우트를 나타냅니다. 클릭하면, `to` prop의 값은 내부적으로 `router.push()`에 전달 될 것이므로 값은 문자열이나 위치 디스크립터 객체가 될 수 있습니다.\n\n  ``` html\n  <!-- 리터럴 string -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- 이렇게 렌더링 됩니다. -->\n  <a href=\"home\">Home</a>\n\n  <!-- `v-bind`를 이용한 표현식 -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- `v-bind`를 생략하면 다른 prop를 바인딩 하는 것과 같습니다. -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- 위와 같습니다. -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- 이름을 가지는 라우트 -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- 쿼리가 있으면, `/register?plan=private` 이 됩니다. -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n### replace\n\n  - 자료형: `boolean`\n\n  - 기본값: `false`\n\n  `replace` prop를 설정하면 클릭할 때 `router.push()` 대신 `router.replace()`를 호출할 것이므로 내비게이션은 히스토리 레코드를 남기지 않을 것입니다.\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n### append\n\n  - 자료형: `boolean`\n\n  - 기본값: `false`\n\n  `append` prop를 설정하면 항상 상대 경로가 현재 경로에 추가됩니다. 예를 들어`/a`에서 상대 링크 `b`로 이동한다고 가정하면 `append`없이 `/b`에서 끝나지만 `append`로 `/a/b`에서 끝납니다 .\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n### tag\n\n  - 자료형: `string`\n\n  - 기본값: `\"a\"`\n\n  때때로 우리는 `<router-link>`를 `<li>`과 같은 다른 태그로 렌더링되길 바랍니다. 그런 다음 `tag` prop를 사용하여 렌더링할 태그를 지정할 수 있으며 탐색을 위해 클릭 이벤트를 계속 수신합니다.\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- 이렇게 렌더링됩니다 -->\n  <li>foo</li>\n  ```\n\n### active-class\n\n  - 자료형: `string`\n\n  - 기본값: `\"router-link-active\"`\n\n  링크가 활성화 되어 있을 때 적용된 active CSS 클래스를 구성합니다. 기본값은 `linkActiveClass` 라우터 생성자 옵션을 통해 전역적으로 설정될 수 있습니다.\n\n### exact\n\n  - 자료형: `boolean`\n\n  - 기본값: `false`\n\n  기본 활성 클래스 매치 동작은 **포괄적인 매칭** 입니다. 예를 들어, `<router-link to=\"/a\">`는 현재 경로가 `/a` 또는 `/a/`로 시작하는 한 이 클래스를 적용합니다.\n\n  이것의 결과는 `<router-link to=\"/\">`가 모든 라우터에 대해 활성화 될 것입니다! 링크를 \"완전 일치 모드\"로 강제하려면 `exact` prop를 사용하십시오.\n\n  ``` html\n  <!-- 이 링크는 `/` 에서만 active 됩니다 -->\n  <router-link to=\"/\" exact>\n  ```\n\n  active 링크 클래스를 설명하는 추가 [예제](https://jsfiddle.net/8xrk1n9f/)를 확인 하십시오.\n\n### event\n\n  > 2.1.0+\n\n  - 자료형: `string | Array<string>`\n\n  - 기본값: `'click'`\n\n  링크 네비게이션을 트리거 할 수있는 이벤트를 지정합니다.\n\n### exact-active-class\n\n  > 2.5.0+\n  - 자료형: `string`\n  - 기본값: `\"router-link-exact-active\"`\n\n 정확하게 일치하는 링크가 활성된 상태일 때 적용되는 CSS 클래스를 지정합니다. 기본값은`linkExactActiveClass` 라우터 생성자 옵션을 통해 전역으로 설정 될 수 있습니다.\n\n\n### 외부 엘리먼트에 active 클래스 적용하기\n\n때로 우리는 active 클래스가 `<a>` 태그 자체가 아닌 외부 엘리먼트에 적용되는 것을 원할 수 있습니다. 이 경우 `<router-link>` 를 사용하여 외부 엘리먼트를 렌더링하고 원시 `<a>`는 내부에 작성합니다.\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\n이 경우 `<a>`는 실제 링크가 될 것이고(올바른 `href`를 얻습니다.), 활성 클래스는 바깥 쪽 `<li>`에 적용됩니다.\n\n## `<router-view>`\n\n`<router-view>` 컴포넌트는 주어진 라우트에 대해 일치하는 컴포넌트를 렌더링하는 함수형 컴포넌트입니다. `<router-view>`에서 렌더링된 컴포넌트는 자체 `<router-view>`를 포함 할 수 있으며, 이는 중첩 된 라우트를 위해 컴포넌트를 렌더링합니다.\n\n## `<router-view>` props\n\n### name**\n\n  - 자료형: `string`\n\n  - 기본값: `\"default\"`\n\n  `<router-view>`가 이름을 가지고있을 때, 그것은 일치된 라우트 레코드의 `components` 옵션에서 해당 이름으로 컴포넌트를 렌더링 할 것입니다. 예제는 [이름을 가지는 뷰](../guide/essentials/named-views.md)를 참조하십시오.\n\n### 동작\n\n이름이없는 모든 props는 렌더링된 컴포넌트로 전달되지만 대부분의 경우 라우트 별 데이터는 라우트 매개 변수에 포함됩니다.\n\n이것은 단지 컴포넌트이므로 `<transition>` 및 `<keep-alive>`와 함께 작동합니다. 양쪽 모두를 사용할 때는 `<keep-alive>`를 다음과 같이 사용하십시오.\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n\n## 라우터 인스턴스\n\n### router.app\n\n- 자료형: `Vue instance`\n\n  `router`가 주입 된 루트 Vue 인스턴스.\n\n### router.mode\n\n- 자료형: `string`\n\n  라우터가 사용하는 [mode](./#mode).\n\n### router.currentRoute\n\n- 자료형: `Route`\n\n  [라우트 객체](#the-route-object)로 표시된 현재 라우트.\n\n## Methods\n\n### router.beforeEach\n### router.beforeResolve\n### router.afterEach\n\n전역 네비게이션 가드 추가. [네비게이션 가드](../guide/advanced/navigation-guards.md)를 보십시오.\n\n2.5.0이상에서 세 가지 메소드 모두 등록된 guard / hook을 제거하는 함수를 반환합니다.\n\n### router.push\n### router.replace\n### router.go\n### router.back\n### router.forward\n\n  프로그래밍 방식으로 새 URL로 이동합니다. [프로그래밍 방식 네비게이션](../guide/essentials/navigation.md)을 참조하십시오.\n\n### router.getMatchedComponents\n\n  지정된 위치 또는 현재의 라우트에 일치하는 컴퍼넌트(인스턴스는 아니고 정의/생성자)의 배열을 반환합니다. 이는 주로 데이터를 프리페치(prefetching)하기 위해 서버 측 렌더링 동안 사용됩니다.\n\n### router.resolve\n\n  > 2.1.0+\n\n  역방향 URL 해석. `<router-link/>`에서 사용된 것과 같은 형식의 위치가 주어지면 다음과 같이 처리된 속성을 가진 객체를 반환합니다.\n\n  ``` js\n  {\n    location: Location;\n    route: Route;\n    href: string;\n  }\n  ```\n\n- `current` 현재 라우트를 나타냅니다. (대부분의 경우에 변경할 일이 없습니다.)\n\n- `append`는 `current` 라우트에 추가할 수 있도록 합니다 ([`router-link`](#router-link-props)처럼)\n\n### router.addRoutes\n\n  > 2.2.0+\n\n  라우터에 동적으로 더 많은 라우트를 추가할 수 있습니다. 전달인자는 `routes` 생성자 옵션과 동일한 경로 설정 포맷을 사용하는 배열이어야 합니다.\n\n### router.onReady\n\n  > 2.2.0+\n\n  이 메소드는 라우터가 초기 탐색을 완료할 때 호출하는 콜백을 대기시킵니다. 즉, 초기 라우트와 연결된 모든 비동기 입력 훅 및 비동기 컴포넌트를 해결합니다.\n\n  이는 서버와 클라이언트 모두 일관된 출력을 보장하기 위해 서버측 렌더링을 사용할 때 유용합니다.\n\n### router.onError\n\n  > 2.4.0+\n\n라우트 탐색 중에 에러가 발견되면 호출 될 콜백을 등록하십시오. 호출 할 에러에 유의하십시오. 에러는 다음 시나리오 중 하나이어야합니다.\n\n  - 에러는 라우트 가드 기능 내에서 동기적으로 발생한 경우.\n  - 에러는 라우트 가드 함수 내에서 `next(err)`를 호출하여 캐치한 경우\n  - 라우트를 렌더링하는데 필요한 비동기 컴포넌트를 처리하려고 할 때 에러가 발생한 경우.\n\n## 컴포넌트 주입\n\n### 주입된 속성\n\n이러한 프로퍼티는 라우터 인스턴스를 루트 인스턴스에 `router` 옵션으로 전달함으로써 모든 자식 컴포넌트에 주입됩니다.\n\n- #### $router\n\n  라우터 인스턴스\n\n- #### $route\n\n  현재 활성화 된 [Route](#the-route-object)입니다. 이 속성은 읽기 전용이며 해당 속성은 변경할 수는 없지만 감시 할 수 있습니다.\n\n### 활성화된 옵션\n\n  - beforeRouteEnter\n  - beforeRouteUpdate\n  - beforeRouteLeave\n\n  [컴포넌트 내부 가드](../guide/advanced/navigation-guards.md#incomponent-guards)를 확인하세요.\n"
  },
  {
    "path": "docs/kr/guide/README.md",
    "content": "# 시작하기\n\n::: tip 참고\n이 가이드는 코드샘플에 [ES2015](https://github.com/lukehoban/es6features)를 사용합니다.\n\n또한 모든 예제는 Vue 정식 버전을 이용해 바로 컴파일 할 수 있습니다. 더 자세한 내용은 [여기](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only)를 확인하세요.\n:::\n\nVue와 Vue 라우터를 이용해 싱글 페이지 앱을 만드는 것은 매우 쉽습니다. Vue.js를 사용한다면 이미 컴포넌트로 앱을 구성하고 있을 것입니다. Vue 라우터를 함께 사용할 때 추가로 해야하는 것은 라우트에 컴포넌트를 매핑한 후, 어떤 주소에서 렌더링할 지 알려주는 것 뿐입니다.\n\n아래는 기본 예제입니다.\n\n## HTML\n\n``` html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- 네비게이션을 위해 router-link 컴포넌트를 사용합니다. -->\n    <!-- 구체적인 속성은 `to` prop을 이용합니다. -->\n    <!-- 기본적으로 `<router-link>`는 `<a>` 태그로 렌더링됩니다.-->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- 라우트 아울렛 -->\n  <!-- 현재 라우트에 맞는 컴포넌트가 렌더링됩니다. -->\n  <router-view></router-view>\n</div>\n```\n\n## JavaScript\n\n``` js\n// 0. 모듈 시스템 (예: vue-cli)을 이용하고 있다면, Vue와 Vue 라우터를 import 하세요\n// 그리고 `Vue.use(VueRouter)`를 호출하세요\n\n\n// 1. 라우트 컴포넌트를 정의하세요.\n// 아래 내용들은 다른 파일로부터 가져올 수 있습니다.\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. 라우트를 정의하세요.\n// Each route should map to a component. The \"component\" can\n// 각 라우트는 반드시 컴포넌트와 매핑되어야 합니다.\n// \"component\"는 `Vue.extend()`를 통해 만들어진\n// 실제 컴포넌트 생성자이거나 컴포넌트 옵션 객체입니다.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. `routes` 옵션과 함께 router 인스턴스를 만드세요.\n// 추가 옵션을 여기서 전달해야합니다.\n// 지금은 간단하게 유지하겠습니다.\nconst router = new VueRouter({\n  routes // `routes: routes`의 줄임\n})\n\n// 4. 루트 인스턴스를 만들고 mount 하세요.\n// router와 router 옵션을 전체 앱에 주입합니다.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// 이제 앱이 시작됩니다!\n```\n\n라우터를 주입하였으므로 `this.$router`와 현재 라우트를 `this.$route`로 접근할 수 있습니다.\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username () {\n      // 곧 `params` 확인할 수 있습니다.\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack () {\n      window.history.length > 1\n        ? this.$router.go(-1)\n        : this.$router.push('/')\n    }\n  }\n}\n```\n\n문서 전체에서 `router`를 자주 사용했습니다. `this.$router`는 정확히 `router`와 동일합니다. `this.$router`를 사용하는 이유는 라우터를 조작해야하는 모든 컴포넌트에서 라우트 객체를 가져올 필요가 없기 때문입니다.\n\n\n이 [예제](https://jsfiddle.net/yyx990803/xgrjzsup/)에서 바로 확인해볼 수 있습니다.\n\n`<router-link>`는 현재 라우트와 일치할 때 자동으로 `.router-link-active` 클래스가 추가됩니다. [API 레퍼런스](../api/#router-link)를 확인하세요.\n"
  },
  {
    "path": "docs/kr/guide/advanced/data-fetching.md",
    "content": "# 데이터 가져오기\n\n때로는 라우트가 활성화될 때 서버에서 데이터를 가져와야 합니다. 예를 들어, 사용자 프로필을 렌더링하기 전에 서버에서 사용자의 데이터를 가져와야 합니다. 우리는 두 가지 방법을 사용할 수 있습니다.\n\n- **탐색 후 가져오기**: 먼저 탐색하고 들어오는 컴포넌트의 라이프 사이클 훅에서 데이터를 가져옵니다. 데이터를 가져오는 동안 로드 상태를 표시합니다.\n\n- **탐색하기 전에 가져오기**: 라우트 가드에서 경로를 탐색하기 전에 데이터를 가져오고 그 후에 탐색을 수행합니다.\n\n엄밀히 말하면 두 가지 모두 유효한 선택입니다. 궁극적인 목표는 사용자 경험에 달려 있습니다.\n\n## 탐색 후 가져오기\n\n이 방법을 사용하면 들어오는 컴포넌트를 즉시 탐색하고 렌더링하며 컴포넌트의 `created` 훅에서 데이터를 가져옵니다. 네트워크를 통해 데이터를 가져 오는 동안 로드 상태를 표시 할 수 있는 기회를 제공하며 각 뷰 마다 로드를 다르게 처리 할 수도 있습니다.\n\n`$route.params.id`를 기반으로 한 게시물의 데이터를 가져와야하는 `Post` 컴포넌트가 있다고 가정 해 봅시다 :\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // 뷰가 생성되고 데이터가 이미 감시 되고 있을 때 데이터를 가져온다.\n    this.fetchData()\n  },\n  watch: {\n    // 라우트가 변경되면 메소드를 다시 호출됩니다.\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // `getPost`를 데이터 가져오기 위한 유틸리티/API 래퍼로 변경합니다.\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## 탐색하기 전에 가져오기\n\n이 접근 방식을 사용하면 실제로 새 경로로 이동하기 전에 데이터를 가져옵니다.\n들어오는 컴포넌트에서 `beforeRouteEnter` 가드에서 데이터를 가져올 수 있으며 페치가 완료되면 `next`만 호출 할 수 있습니다.\n\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  watch: {\n    // 라우트가 변경되면 메소드를 다시 호출합니다\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // `getPost`를 데이터 페치 유틸리티/API 래퍼로 바꿉니다.\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n다음 뷰에 대한 리소스를 가져 오는 동안 사용자는 현재 뷰를 유지합니다. 따라서 데이터를 가져 오는 동안 진행률 표시줄이나 일종의 표시기를 표시하는 것을 추천합니다. 데이터 가져오기가 실패하면 일종의 전역 경고 메시지를 표시해야합니다.\n"
  },
  {
    "path": "docs/kr/guide/advanced/lazy-loading.md",
    "content": "# 지연된 로딩\n\n번들러를 이용하여 앱을 제작할 때 JavaScript 번들이 상당히 커져 페이지로드 시간에 영향을 줄 수 있습니다. 각 라우트의 컴포넌트를 별도의 단위로 분할하고 경로를 방문할 때 로드하는 것이 효율적일 것입니다.\n\nVue의 [비동기 컴포넌트](http://vuejs.org/guide/components.html#Async-Components)와 Webpack의 [코드 분할](https://webpack.js.org/guides/code-splitting-async/)을 결합합니다. 라우트 컴포넌트를 쉽게 불러올 수 있습니다.\n\n첫째, 비동기 컴포넌트는 Promise를 반환하는 팩토리 함수로 정의할 수 있습니다 (컴포넌트가 resolve 되어야함).\n\n```js\nconst Foo = () =>\n  Promise.resolve({\n    /* 컴포넌트 정의 */\n  })\n```\n\n둘째, Webpack 2에서 [dynamic import](https://github.com/tc39/proposal-dynamic-import)를 사용하여 코드 분할 포인트를 지정할 수 있습니다.\n\n```js\nimport('./Foo.vue') // returns a Promise\n```\n\n> 참고: Babel을 사용하고 있는 경우 올바른 구문 분석을 위해 [syntax-dynamic-import](http://babeljs.io/docs/plugins/syntax-dynamic-import/) 플러그인을 추가해야합니다.\n\n이 두 가지를 결합하여 Webpack에 의해 자동으로 코드 분할될 비동기 컴포넌트를 정의하는 방법입니다.\n\n```js\nconst Foo = () => import('./Foo.vue')\n```\n\n라우트 설정에서 아무것도 바꿀 필요가 없습니다. `Foo`만 사용하면 됩니다.\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/foo', component: Foo }]\n})\n```\n\n### 같은 묶음으로 컴포넌트 그룹화하기\n\n때로는 동일한 라우트 아래에 중첩된 모든 컴포넌트를 동일한 비동기 묶음으로 그룹화 할 수 있습니다. 이를 위해 특수 주석 문법을 사용하는 이름(Webpack 2.4 이상 지원)을 제공하여 [이름을 가진 묶음](https://webpack.js.org/api/module-methods/#magic-comments)을 사용해야합니다.\n\n```js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nWebpack은 동일한 이름의 묶음을 가진 비동기 모듈을 동일한 비동기 묶음으로 그룹화합니다.\n"
  },
  {
    "path": "docs/kr/guide/advanced/meta.md",
    "content": "# 라우트 메타 필드\n\n라우트를 정의 할 때 `meta` 필드를 포함시킬 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // 메타 필드\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\n그렇다면 이 `메타`필드에 어떻게 접근할까요?\n\n첫째,`routes` 설정의 각 라우트 객체를 **라우트 레코드** 라고합니다. 라우트 레코드는 중첩 될 수 있습니다. 따라서 라우트가 일치하면 둘 이상의 라우트 레코드와 잠재적으로 일치 할 수 있습니다.\n\n예를 들어, 위의 라우트 구성에서 URL `/foo/bar`는 상위 라우트 레코드와 하위 라우트 레코드 모두와 일치합니다.\n\n라우트와 일치하는 모든 라우트 레코드는 `$route` 객체(그리고 네비게이션 가드의 라우트 객체)에 `$route.matched` 배열로 노출됩니다. 그러므로 우리는 `$route.matched`를 반복하여 라우트 레코드의 메타 필드를 검사 할 필요가 있습니다.\n\n예제 사용 사례는 글로벌 네비게이션 가드에서 메타 필드를 확인하는 것입니다.\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // 이 라우트는 인증이 필요하며 로그인 한 경우 확인하십시오.\n    // 그렇지 않은 경우 로그인 페이지로 리디렉션하십시오.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // 반드시 next()를 호출하십시오!\n  }\n})\n```\n"
  },
  {
    "path": "docs/kr/guide/advanced/navigation-guards.md",
    "content": "# 네비게이션 가드\n\n이름에서 알 수 있듯이 `vue-router`가 제공하는 네비게이션 가드는 주로 리디렉션하거나 취소하여 네비게이션을 보호하는 데 사용됩니다. 라우트 탐색 프로세스에 연결하는 방법에는 전역, 라우트별 또는 컴포넌트가 있습니다.\n\n**Params 또는 쿼리를 변경하면 네비게이션 가드가 실행되지 않습니다**. 단순히 [`$route` 객체를 감시](../essentials/dynamic-matching.md#reacting-to-params-changes)하고 그 변화에 반응하십시오. 또는 컴포넌트 가드의 `beforeRouteUpdate`를 사용하십시오\n\n### 전역 가드\n\n`router.beforeEach`를 사용하여 보호하기 이전에 전역 등록을 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\n네비게이션이 트리거될 때마다 가드가 작성 순서에 따라 호출되기 전의 모든 경우에 발생합니다. 가드는 비동기식으로 실행 될 수 있으며 네비게이션은 모든 훅이 해결되기 전까지 **보류 중** 으로 간주됩니다.\n\n모든 가드 기능은 세 가지 전달인자를 받습니다.\n\n- **`to: 라우트`**: 대상 [Route 객체](../../api/#the-route-object) 로 이동합니다.\n\n- **`from: 라우트`**: 현재 라우트로 오기전 라우트 입니다.\n\n- **`next: 함수`**: 이 함수는 **훅을 해결하기 위해** 호출 되어야 합니다. 액션은 `next`에 제공된 전달인자에 달려 있습니다.\n\n  - **`next()`**: 파이프라인의 다음 훅으로 이동하십시오. 훅이 없는 경우 네비게이션은 **승인**됩니다.\n\n  - **`next(false)`**: 현재 네비게이션을 중단합니다. 브라우저 URL이 변경되면(사용자 또는 뒤로 버튼을 통해 수동으로 변경됨) `from`경로의 URL로 재설정됩니다.\n\n  - **`next('/')` 또는 `next({ path: '/' })`**: 다른 위치로 리디렉션합니다. 현재 네비게이션이 중단되고 새 네비게이션이 시작됩니다.\n\n  - **`next(error)`**: (2.4.0 이후 추가) `next`에 전달된 인자가 `Error` 의 인스턴스이면 탐색이 중단되고 `router.onError()`를 이용해 등록 된 콜백에 에러가 전달됩니다.\n\n\n**항상 `next` 함수를 호출하십시오. 그렇지 않으면 훅이 절대 불러지지 않습니다.**\n\n### Global Resolve Guards\n\n> 2.5.0에서 추가됨\n\n2.5.0 이후로 `router.beforeResolve`를 사용하여 글로벌 가드를 등록 할 수 있습니다. 이는 `router.beforeEach`와 유사합니다. 모든 컴포넌트 가드와 비동기 라우트 컴포넌트를 불러온 후 네비게이션 가드를 확인하기 전에 호출된다는 차이가 있습니다\n\n### Global After Hooks\n\n전역 훅을 등록 할 수도 있지만, 가드와 달리 이 훅은 `next` 함수를 얻지 못하며 네비게이션에 영향을 줄 수 없습니다.\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### 라우트 별 가드\n\n`beforeEnter` 가드를 라우트의 설정 객체에 직접 정의 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\n이러한 가드는 전역 이전 가드와 동일한 서명을 가집니다.\n\n### 컴포넌트 내부 가드\n\n마지막으로 `beforeRouteEnter` 와 `beforeRouteLeave`를 사용하여 라우트 컴포넌트(라우터 설정으로 전달되는 컴포넌트) 안에 라우트 네비게이션 가드를 직접 정의 할 수 있습니다.\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (2.2 버전에 추가)\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // 이 컴포넌트를 렌더링하는 라우트 앞에 호출됩니다.\n    // 이 가드가 호출 될 때 아직 생성되지 않았기 때문에\n    // `this` 컴포넌트 인스턴스에 접근 할 수 없습니다!\n  },\n  beforeRouteLeave (to, from, next) {\n    // 이 컴포넌트를 렌더링하는 라우트가 이전으로 네비게이션 될 때 호출됩니다.\n    // `this` 컴포넌트 인스턴스에 접근 할 수 있습니다.\n  }\n}\n```\n\n`beforeRouteEnter` 가드는 네비게이션이 확인되기 전에 가드가 호출되어서 새로운 엔트리 컴포넌트가 아직 생성되지 않았기 때문에 `this`에 접근하지 **못합니다.**\n\n그러나 콜백을 `next`에 전달하여 인스턴스에 액세스 할 수 있습니다. 네비게이션이 확인되고 컴포넌트 인스턴스가 콜백에 전달인자로 전달 될 때 콜백이 호출됩니다.\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // `vm`을 통한 컴포넌트 인스턴스 접근\n  })\n}\n```\n\n`beforeRouteLeave` 안에서 `this`에 직접 접근 할 수 있습니다. leave 가드는 일반적으로 사용자가 저장하지 않은 편집 내용을 두고 실수로 라우트를 떠나는 것을 방지하는데 사용됩니다. 탐색은 `next(false)`를 호출하여 취소할 수 있습니다.\n\n### 전체 네비게이션 시나리오\n\n1. 네비게이션이 트리거됨.\n2. 비활성화될 컴포넌트에서 가드를 호출.\n3. 전역 `beforeEach` 가드 호출.\n4. 재사용되는 컴포넌트에서 `beforeRouteUpdate` 가드 호출. (2.2 이상)\n5. 라우트 설정에서 `beforeEnter` 호출.\n6. 비동기 라우트 컴포넌트 해결.\n7. 활성화된 컴포넌트에서 `beforeRouteEnter` 호출.\n8. 전역 `beforeResolve` 가드 호출. (2.5이상)\n9. 네비게이션 완료.\n10. 전역 `afterEach` 훅 호출.\n11. DOM 갱신 트리거 됨.\n12. 인스턴스화 된 인스턴스들의 `beforeRouteEnter`가드에서 `next`에 전달 된 콜백을 호출합니다.\n"
  },
  {
    "path": "docs/kr/guide/advanced/scroll-behavior.md",
    "content": "# 스크롤 동작\n\n클라이언트 측 라우팅을 사용할 때 새로운 경로로 이동할 때 맨 위로 스크롤하거나 실제 페이지를 다시 로드하는 것처럼 컨텐츠 항목의 스크롤 위치를 유지할 수 있습니다. `vue-router`는 이러한 것들을 할 수 있으며, 라우트 탐색에서 스크롤 동작을 완전히 사용자 정의할 수 있게합니다.\n\n**참고: 이 기능은 HTML5 히스토리 모드에서만 작동합니다.**\n\n라우터 인스턴스를 생성 할 때 `scrollBehavior` 함수를 제공 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // 원하는 위치로 돌아가기\n  }\n})\n```\n\n`scrollBehavior` 함수는 `to`와 `from` 라우트 객체를받습니다. 세 번째 전달인자인 `savedPosition`은 브라우저의 뒤로/앞으로 버튼으로 트리거되는 `popstate` 네비게이션인 경우에만 사용할 수 있습니다.\n\n이 함수는 스크롤 위치 객체를 반환 할 수 있습니다. 객체는 다음과 같은 형태 일 수 있습니다.\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset은 2.6.0 이상만 지원)\n\n잘못된 값이나 빈 객체가 반환되면 스크롤이 발생하지 않습니다.\n\n예제:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\n그러면 모든 라우트 네비게이션에 대해 페이지가 맨 위로 스크롤됩니다.\n\n`savedPosition`을 반환하면 뒤로/앞으로 버튼으로 탐색할 때 네이티브와 같은 동작이 발생합니다.\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\n\"anchor로 스크롤\" 동작을 시뮬레이트하려면 다음을 수행하십시오.\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\n또한 [라우트 메타 필드](meta.md)를 사용하여 세밀한 스크롤 동작 제어를 구현할 수 있습니다. 전체 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js)를 확인하십시오.\n"
  },
  {
    "path": "docs/kr/guide/advanced/transitions.md",
    "content": "# 트랜지션\n\n`<router-view>`는 본질적으로 동적인 컴포넌트이기 때문에 `<transition>` 컴포넌트를 사용하는 것과 같은 방식으로 트랜지션 효과를 적용할 수 있습니다.\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[`<transition>`에 대한 모든 것](http://vuejs.org/guide/transitions.html) 을 확인하십시오.\n\n### 라우트 별 트랜지션\n\n위의 사용법은 모든 라우트에 대해 동일한 트랜지션을 적용합니다. 각 라우트의 컴포넌트가 서로 다른 트랜지션을 갖도록 하려면 각 라우트 컴포넌트 내에서 다른 이름으로 `<transition>`을 사용할 수 있습니다.\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n### 라우트 기반 동적 트랜지션\n\n또한 대상 라우트와 현재 라우트 간의 관계를 기반으로 동적으로 사용할 트랜지션을 결정할 수도 있습니다.\n\n``` html\n<!-- 동적 트랜지션을 위한 name을 지정합니다. -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// 그런 다음 부모 구성 요소에서 `$route`를 보고 사용할 트랜지션을 결정합니다\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\n전체 예제는 [여기](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js)에 있습니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/dynamic-matching.md",
    "content": "# 동적 라우트 매칭\n\n주어진 패턴을 가진 라우트를 동일한 컴포넌트에 매핑해야하는 경우가 자주 있습니다. 예를 들어 모든 사용자에 대해 동일한 레이아웃을 가지지만 하지만 다른 사용자 ID로 렌더링되어야하는 `User` 컴포넌트가 있을 수 있습니다. `vue-router`에서 우리는 경로에서 동적 세그먼트를 사용하여 다음을 할 수 있습니다.\n\n``` js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // 동적 세그먼트는 콜론으로 시작합니다.\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n이제 `/user/foo`와 `/user/bar` 같은 URL은 모두 같은 경로에 매핑됩니다.\n\n동적 세그먼트는 콜론 `:`으로 표시됩니다. 라우트가 일치하면 동적 세그먼트의 값은 모든 컴포넌트에서 `this.$route.params`로 표시됩니다. 그러므로 `User`의 템플릿을 다음과 같이 갱신하여 현재 사용자 ID를 표현할 수 있습니다 :\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\n실제 예제는 [여기](http://jsfiddle.net/yyx990803/4xfa2f19/)에 있습니다.\n\n동일한 라우트에 여러 동적 세그먼트를 가질 수 있으며, `$route.params`의 해당 필드에 매핑됩니다.\n\n예:\n\n| 패턴 | 일치하는 패스 | $route.params |\n|---------|------|--------|\n| /user/:username | /user/evan | `{ username: 'evan' }` |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\n`$route.params` 외에도 `$route` 객체는 `$route.query` (URL에 쿼리가 있는 경우), `$route.hash` 등의 유용한 정보를 제공합니다. [API 레퍼런스](../../api/#the-route-object)에서 전체 세부 정보를 확인할 수 있습니다.\n\n### Params 변경 사항에 반응하기\n\n매개 변수와 함께 라우트를 사용할 때 주의 해야할 점은 사용자가 `/user/foo`에서 `/user/bar`로 이동할 때 **동일한 컴포넌트 인스턴스가 재사용된다는 것입니다.** 두 라우트 모두 동일한 컴포넌트를 렌더링하므로 이전 인스턴스를 삭제 한 다음 새 인스턴스를 만드는 것보다 효율적입니다. **그러나 이는 또한 컴포넌트의 라이프 사이클 훅이 호출되지 않음을 의미합니다.**\n\n동일한 컴포넌트의 params 변경 사항에 반응하려면 `$route` 객체를 보면됩니다.\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // 경로 변경에 반응하여...\n    }\n  }\n}\n```\n\n또는 2.2에서 소개된 `beforeRouteUpdate` 가드를 사용하십시오.\n```js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // react to route changes...\n    // don't forget to call next()\n  }\n}\n```\n\n### 고급 매칭 패턴\n\n`vue-router`는 라우트 매칭 엔진으로 [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0)를 사용하기 때문에 선택적 동적 세그먼트, 0개 이상/하나 이상의 요구 사항, 심지어 커스텀 정규식 패턴과 같은 많은 고급 매칭 패턴을 지원합니다. 이 고급 패턴들과 `vue-router`에서 사용하는 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js)에 대한 [문서](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters)를 확인하십시오.\n\n### 매칭 우선순위\n\n동일한 URL이 여러 라우트와 일치하는 경우가 있습니다. 이 경우 일치하는 우선 순위는 라우트 정의의 순서에 따라 결정됩니다. 즉, 경로가 더 먼저 정의 될수록 우선 순위가 높아집니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/getting-started.md",
    "content": "# 시작하기\n\n> 가이드의 샘플 코드는[ES2015](https://github.com/lukehoban/es6features)를 사용합니다.\n\nVue.js와 vue-router로 단일 페이지 애플리케이션을 만드는 것은 간단합니다. Vue.js를 통해 우리는 이미 컴포넌트로 애플리케이션을 구성하고 있습니다. vue-router를 추가 할 때, 우리가해야 할 일은 우리의 컴포넌트를 route에 매핑하고 vue-router가 어디서 렌더링할 지 지정하는 것입니다. 다음은 기본적인 예입니다.\n\n> 모든 예제는 Vue의 전체 버전을 사용하여 템플릿 구문 분석을 가능하게합니다. 자세한 내용은 [여기](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only) 있습니다.\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- 탐색을 위해 라우터 링크 구성 요소를 사용하십시오. -->\n    <!-- `to` prop를 전달하여 링크를 지정하십시오. -->\n    <!-- `<router-link>`는 기본적으로`<a>`태그로 렌더링 될 것입니다 -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- route outlet -->\n  <!-- 라우트와 일치하는 컴포넌트가 여기 렌더링됩니다. -->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. 모듈 시스템을 사용하는 경우 (예: vue-cli를 이용해서), Vue 및 VueRouter를 가져온 다음 `Vue.use(VueRouter)`를 호출하십시오.\n\n// 1. 라우트 컴포넌트를 정의하십시오.\n// 다른 파일에서 가져올 수 있습니다.\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. 라우트를 정의합니다.\n// 일부 라우트 정의 각 라우트는 컴포넌트에 맵핑되어야합니다.\n// \"컴포넌트\"는 `Vue.extend()`를 통해 생성된\n// 실제 컴포넌트 생성자이거나 컴포넌트 옵션 객체 일 수 있습니다.\n// 나중에 중첩 된 라우트에 대해 이야기하겠습니다.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. 라우터 인스턴스를 생성하고 `routes` 옵션을 전달하십시오.\n// 여기에 추가 옵션을 전달할 수 있지만, 지금은 간단하게 하겠습니다.\nconst router = new VueRouter({\n  routes // routes: routes 의 약어\n})\n\n// 4. 루트 인스턴스를 만들고 마운트하십시오.\n// 라우터 옵션을 라우터에 삽입하여\n// 전체 응용 프로그램을 라우터가 인식하도록 하십시오.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// 이제 앱을 시작 해보세요!\n```\n\n이 [예제](http://jsfiddle.net/yyx990803/xgrjzsup/)를 확인하십시오.\n\n`<router-link>`는 가리키는 라우트가 일치 할 때 자동으로 `.router-link-active` 클래스를 얻습니다. API 레퍼런스에서 더 많은 것을 배울 수 있습니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/history-mode.md",
    "content": "# HTML5 히스토리 모드\n\n`vue-router`의 기본 모드는 _hash mode_ 입니다. URL 해시를 사용하여 전체 URL을 시뮬레이트하므로 URL이 변경될 때 페이지가 다시 로드 되지 않습니다.\n\n해시를 제거하기 위해 라우터의 **history 모드** 를 사용할 수 있습니다. `history.pushState` API를 활용하여 페이지를 다시 로드하지 않고도 URL 탐색을 할 수 있습니다.\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\n히스토리 모드를 사용하면 URL이 \"정상\"으로 보입니다. `http://oursite.com/user/id`. 멋집니다!\n\n그러나 문제는 다음과 같습니다. 우리의 앱이 적절한 서버 설정이 없는 단일 페이지 클라이언트 앱이기 때문에 사용자가 직접 `http://oursite.com/user/id` 에 접속하면 404 오류가 발생합니다.\n\n걱정하지 않아도됩니다. 문제를 해결하려면 서버에 간단하게 포괄적인 대체 경로를 추가하기만 하면됩니다. URL이 정적 에셋과 일치하지 않으면 앱이 있는 동일한 `index.html`페이지를 제공해야 합니다.\n\n## 서버 설정 예제\n\n#### Apache\n\n```apache\n<IfModule mod_negotiation.c>\n  Options -MultiViews\n</IfModule>\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Native Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp\n  .createServer((req, res) => {\n    fs.readFile('index.html', 'utf-8', (err, content) => {\n      if (err) {\n        console.log('We cannot open \"index.html\" file.')\n      }\n\n      res.writeHead(200, {\n        'Content-Type': 'text/html; charset=utf-8'\n      })\n\n      res.end(content)\n    })\n  })\n  .listen(httpPort, () => {\n    console.log('Server listening on: http://localhost:%s', httpPort)\n  })\n```\n\n#### Express와 Node.js\n\nNode.js/Express의 경우 [connect-history-api-fallback 미들웨어](https://github.com/bripkens/connect-history-api-fallback)를 고려해보세요.\n\n#### Internet Information Services (IIS)\n\n```\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n <system.webServer>\n   <rewrite>\n     <rules>\n       <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n         <match url=\"(.*)\" />\n         <conditions logicalGrouping=\"MatchAll\">\n           <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n           <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n         </conditions>\n         <action type=\"Rewrite\" url=\"index.html\" />\n       </rule>\n     </rules>\n   </rewrite>\n     <httpErrors>\n         <remove statusCode=\"404\" subStatusCode=\"-1\" />\n         <remove statusCode=\"500\" subStatusCode=\"-1\" />\n         <error statusCode=\"404\" path=\"/survey/notfound\" responseMode=\"ExecuteURL\" />\n         <error statusCode=\"500\" path=\"/survey/error\" responseMode=\"ExecuteURL\" />\n     </httpErrors>\n     <modules runAllManagedModulesForAllRequests=\"true\"/>\n </system.webServer>\n</configuration>\n```\n\n## 주의 사항\n\n주의 사항이 있습니다. 여러분의 서버는 404 에러를 보고하지 않을 것입니다. 왜냐하면 모든 발견되지 않은 경로가 이제 `index.html` 파일을 제공하기 때문입니다. 이 문제를 해결하려면 Vue 앱에서 catch-all 라우트를 구현하여 404 페이지를 표시해야합니다.\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [{ path: '*', component: NotFoundComponent }]\n})\n```\n\n또는 Node.js 서버를 사용하는 경우 서버 측의 라우터를 사용하여 들어오는 URL을 일치시키고 라우트가 일치하지 않으면 404로 응답하여 폴백을 구현할 수 있습니다. 더 자세한 설명은 [Vue 서버사이드 렌더링 문서](https://ssr.vuejs.org/en/)을 읽어보세요\n"
  },
  {
    "path": "docs/kr/guide/essentials/named-routes.md",
    "content": "# 이름을 가지는 라우트\n\n때로는 라우트에 연결하거나 탐색을 수행 할 때 이름이 있는 라우트를 사용하는 것이 더 편리합니다. Router 인스턴스를 생성하는 동안 `routes` 옵션에 라우트를 지정할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\n이름을 가진 라우트에 링크하려면, 객체를 `router-link`, 컴포넌트의 `to` prop로 전달할 수 있습니다.\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\n이것은 `router.push()`와 프로그램적으로 사용되는 것과 정확히 같은 객체입니다.\n\n```js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\n두 경우 모두 라우터는 `/user/123` 경로로 이동합니다.\n\n전체 예제는 [여기](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js)에 있습니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/named-views.md",
    "content": "# 이름을 가지는 뷰\n\n때로는 여러 개의 뷰를 중첩하지 않고 동시에 표시해야 하는 경우가 있습니다. `sidebar` 뷰와 `main` 뷰로 레이아웃을 생성합니다. 이름이 지정된 뷰가 편리한 경우 입니다. 뷰에 하나의 outlet이 있는 대신 여러 개를 사용하여 각 outlet에 이름을 지정할 수 있습니다. 이름이 없는 `router-view`는 이름으로 `default`가 주어집니다.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\n뷰는 컴포넌트를 사용하여 렌더링 되므로 여러 뷰에는 동일한 라우트에 대해 여러 컴포넌트가 필요합니다. `components`(s를 붙입니다) 옵션을 사용해야합니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\n이 예제는 [여기](https://jsfiddle.net/posva/6du90epg/)에서 확인할 수 있습니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/navigation.md",
    "content": "# 프로그래밍 방식 네비게이션\n\n`<router-link>`를 사용하여 선언적 네비게이션용 anchor 태그를 만드는 것 외에도 라우터의 인스턴스 메소드를 사용하여 프로그래밍으로 이를 수행 할 수 있습니다.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**참고: Vue 인스턴스 내부에서 라우터 인스턴스에 `$router`로 액세스 할 수 있습니다. 그러므로`this.$router.push`를 사용 할 수 있습니다.**\n\n다른 URL로 이동하려면 `router.push`를 사용하십시오. 이 메소드는 새로운 항목을 히스토리 스택에 넣기 때문에 사용자가 브라우저의 뒤로 가기 버튼을 클릭하면 이전 URL로 이동하게된다.\n\n이것은 `<router-link>`를 클릭 할 때 내부적으로 호출되는 메소드이므로 `<router-link :to=\"...\">`를 클릭하면 `router.push(...)`를 호출하는 것과 같습니다.\n\n| 선언적 방식 | 프로그래밍 방식 |\n|-------------|--------------|\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\n전달인자는 문자열 경로 또는 로케이션 디스크립터 객체가 될 수 있습니다.\n\n예:\n\n``` js\n// 리터럴 string\nrouter.push('home')\n\n// object\nrouter.push({ path: 'home' })\n\n// 이름을 가지는 라우트\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// 쿼리와 함께 사용, 결과는 /register?plan=private 입니다.\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n2.2.0 버전이후로 선택적으로 `router.push` 또는 `router.replace`에 두번째와 세번째 전달인자로 `onComplete`와 `onAbort` 콜백을 제공합니다.\n이 콜백은 탐색이 성공적으로 완료되거나(모든 비동기 훅이 해결된 후) 또는 중단(현재 탐색이 완료되기 전에 동일한 경로로 이동하거나 다른 경로 이동)될 때 호출 됩니다.\n\n#### `router.replace(location)`\n\n`router.push`와 같은 역할을 하지만 유일한 차이는 새로운 히스토리 항목에 추가하지 않고 탐색한다는 것입니다. 이름에서 알 수 있듯이 현재 항목을 대체합니다.\n\n| 선언적 방식   | 프로그래밍 방식 |\n|-------------|--------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n#### `router.go(n)`\n\n이 메소드는 `window.history.go(n)`와 비슷하게 히스토리 스택에서 앞으로 또는 뒤로 이동하는 단계를 나타내는 하나의 정수를 매개 변수로 사용합니다.\n\n예제\n\n``` js\n// 한 단계 앞으로 갑니다. history.forward()와 같습니다. history.forward()와 같습니다.\nrouter.go(1)\n\n// 한 단계 뒤로 갑니다. history.back()와 같습니다.\nrouter.go(-1)\n\n// 3 단계 앞으로 갑니다.\nrouter.go(3)\n\n// 지정한 만큼의 기록이 없으면 자동으로 실패 합니다.\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### History 조작\n\n`router.push`, `router.replace` 및 `router.go`는 [`window.history.pushState`,`window.history.replaceState` 및 `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History)와 상응합니다. 그들은 `window.history` API를 모방합니다.\n\n따라서 [브라우저 히스토리 API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)에 이미 익숙하다면 vue-router를 사용하여 히스토리를 손쉽게 조작 할 수 있습니다.\n\nvue-router 네비게이션 메소드(`push`,`replace`,`go`)는 모든 라우터 모드(`history`,`hash` 및`abstract`)에서 일관되게 작동합니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/nested-routes.md",
    "content": "# 중첩된 라우트\n\n실제 앱 UI는 일반적으로 여러 단계로 중첩 된 컴포넌트로 이루어져 있습니다. URL의 세그먼트가 중첩 된 컴포넌트의 특정 구조와 일치한다는 것은 매우 일반적입니다. 예를 들면 다음과 같습니다.\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\n`vue-router`를 사용하면 중첩 된 라우트 구성을 사용하여이 관계를 표현하는 것이 매우 간단합니다.\n\n이전 장에서 만든 앱을 생각해보십시오.\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n여기에있는 `<router-view>`는 최상위 outlet입니다. 최상위 경로와 일치하는 컴포넌트를 렌더링합니다. 비슷하게 렌더링 된 컴포넌트는 자신의 중첩 된 `<router-view>`를 포함 할 수도 있습니다. 다음은 `User` 컴포넌트의 템플릿 안에 하나를 추가하는 예 입니다.\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\n이 중첩 outlet에 컴포넌트를 렌더링하려면 `children`을 사용해야합니다.\n`VueRouter` 생성자의 옵션 config:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User,\n      children: [\n        {\n          // /user/:id/profile 과 일치 할 때\n          // UserProfile은 User의 <router-view> 내에 렌더링 됩니다.\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // /user/:id/posts 과 일치 할 때\n          // UserPosts가 User의 <router-view> 내에 렌더링 됩니다.\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**`/`로 시작하는 중첩 된 라우트는 루트 경로로 취급됩니다. 이렇게하면 중첩 된 URL을 사용하지 않고도 컴포넌트 중첩을 활용할 수 있습니다.**\n\n여러분이 볼 수 있듯이 `children` 옵션은 `routes`와 같은 라우트 설정 객체의 또 다른 배열입니다. 따라서 필요한만큼 중첩 된 뷰를 유지할 수 있습니다.\n\n이 시점에서, 위의 설정으로, `/user/foo`를 방문했을 때 하위 라우트가 매치되지 않았기 때문에 `User`의 outlet에 아무것도 출력되지 않습니다. 어쩌면 거기에 무언가를 렌더링하고 싶을지도 모릅니다. 이 경우 빈 서브 루트 경로를 제공 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id', component: User,\n      children: [\n        // UserHome은 /user/:id 가 일치 할 때\n        // User의 <router-view> 안에 렌더링됩니다.\n        { path: '', component: UserHome },\n\n        // ...또 다른 서브 라우트\n      ]\n    }\n  ]\n})\n```\n\n이 예제의 작업 데모는 [이 곳](http://jsfiddle.net/yyx990803/L7hscd8h/)에서 찾을 수 있습니다.\n"
  },
  {
    "path": "docs/kr/guide/essentials/passing-props.md",
    "content": "# 라우트 컴포넌트에 속성 전달\n\n컴포넌트에서 `$route`를 사용하면 특정 URL에서만 사용할 수 있는 컴포넌트의 유연성을 제한하는 라우트와 강한 결합을 만듭니다.\n\n컴포넌트와 라우터 속성을 분리하려면 다음과 같이 하십시오.\n\n**$route에 의존성 추가**\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n**속성에 의존성 해제**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n  ]\n})\n```\n\n이를 통해 어디서나 컴포넌트를 사용할 수 있으므로 컴포넌트 재사용 및 테스트하기가 더 쉽습니다.\n\n### Boolean 모드\n\n`props`를 `true`로 설정하면 `route.params`가 컴포넌트 `props`로 설정됩니다.\n\n### 객체 모드\n\n`props`가 객체일때 컴포넌트 `props`가 있는 그대로 설정됩니다.\n`props`가 정적일 때 유용합니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n### 함수 모드\n\n`props`를 반환하는 함수를 만들 수 있습니다. 이를 통해 전달인자를 다른 타입으로 캐스팅하고 적정인 값을 라우트 기반 값과 결합됩니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\n`/search?q=vue`는 `{query: \"vue\"}`를 `SearchUser` 컴포넌트에 전달합니다.\n\n라우트 변경시에만 평가되므로 `props` 함수는 상태를 저장하지 않도록 합니다.\n`props`를 정의할 상태가 필요한 경우 래퍼 컴포넌트를 사용하면 상태가 변경될 때마다 응답할 수 있습니다.\n\n고급 사용예를 보려면 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js)를 확인하세요.\n"
  },
  {
    "path": "docs/kr/guide/essentials/redirect-and-alias.md",
    "content": "# 리다이렉트와 별칭\n\n### 리다이렉트\n\n리디렉션은 `routes` 설정에서도 할 수 있습니다. `/a`에서 `/b`로 리디렉션하려면\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\n리디렉션은 이름이 지정된 라우트를 지정할 수도 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\n또는 동적 리디렉션을 위한 함수를 사용할 수도 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // 함수는 인수로 대상 라우트를 받습니다.\n      // 여기서 path/location 반환합니다.\n    }}\n  ]\n})\n```\n기타 고급 사용법은 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js)를 확인 하십시오.\n\n### 별칭\n\n리다이렉트는 사용자가 `/a`를 방문했을 때 URL이 `/b`로 대체 된 다음 `/b`로 매칭된다는 것을 의미합니다. 하지만 별칭이란 무엇입니까?\n\n**`/a`의 별칭은 `/b`는 사용자가 `/b`를 방문했을 때 URL은 `/b`을 유지하지만 사용자가 `/a`를 방문한 것처럼 매칭합니다.**\n\n위는 라우트 구성에서 다음과 같이 표현할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\n별칭을 사용하면 구성의 중첩 구조에 의해 제약을 받는 대신 UI 구조를 임의의 URL에 매핑 할 수 있습니다.\n\n기타 고급 사용법은 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js)를 확인 하십시오.\n"
  },
  {
    "path": "docs/kr/installation.md",
    "content": "# 설치\n\n### 직접 다운로드 / CDN\n\n[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com)은 NPM 기반 CDN 링크를 제공합니다. 위의 링크는 항상 NPM의 최신 릴리스를 가리킵니다. `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js`와 같이 URL을 통해 특정 버전 / 태그를 사용할 수도 있습니다.\n<!--/email_off-->\n\nVue 다음에 `vue-router`를 포함하면 자동으로 설치됩니다.\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### NPM\n\n``` bash\nnpm install vue-router\n```\n\n모듈 시스템에서 사용하면 `Vue.use()`를 통해 명시적으로 라우터를 추가해야합니다.\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\n전역 스크립트 태그를 사용할 때는 이 작업을 하지 않아도 됩니다.\n\n### 개발용 빌드\n\n최신 dev 빌드를 사용하고 싶은 경우 GitHub에서 직접 복제하고 `vue-router`를 직접 빌드 해야 합니다.\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs/ru/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Начать знакомство →\nactionLink: /ru/installation.html\nfooter: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote\n---\n\nVue Router — официальная библиотека маршрутизации для [Vue.js](https://ru.vuejs.org/). Она глубоко интегрируется с Vue.js и позволяет легко создавать SPA-приложения. Включает следующие возможности:\n\n- Вложенные маршруты/представления\n- Модульная конфигурация маршрутизатора\n- Доступ к параметрам маршрута, query, wildcards\n- Анимация переходов представлений на основе Vue.js\n- Удобный контроль навигации\n- Автоматическое проставление активного CSS класса для ссылок\n- Режимы работы HTML5 history или хэш, с авто-переключением в IE9\n- Настраиваемое поведение прокрутки страницы\n\n[Начать знакомство](./guide/) или поиграться с [примерами](https://github.com/vuejs/vue-router/tree/dev/examples) (см. [`README.md`](https://github.com/vuejs/vue-router/) для их запуска).\n\n<HomeSponsors />\n"
  },
  {
    "path": "docs/ru/api/README.md",
    "content": "---\nsidebar: auto\n---\n\n# Справочник API\n\n## `<router-link>`\n\n`<router-link>` — это компонент предназначенный для навигации пользователя в приложении с клиентской маршрутизацией. Путь назначения указывается входным параметром `to`. По умолчанию компонент рендерится в тег `<a>` с корректным значением `href`, но это можно изменить входным параметром `tag`. Кроме того, ссылка автоматически получает активный класс CSS при переходе на путь назначения.\n\n`<router-link>` предпочтительнее `<a href=\"...\">` по следующим причинам:\n\n- Он работает одинаково вне зависимости от режима работы (HTML5 history или хэш), поэтому если вы решите переключить режим, или маршрутизатор для совместимости переключится обратно в режим хэша в IE9, ничего не потребуется изменять.\n- В режиме HTML5 history, `router-link` будет перехватывать событие click, чтобы браузер не пытался перезагрузить страницу.\n- При использовании опции `base` в режиме работы HTML5 history, вам не потребуется добавлять её в URL входного параметра `to`.\n\n### `v-slot` API (3.1.0+)\n\n`router-link` предоставляет возможность более низкоуровневой настройки с помощью [слота с ограниченной областью видимости](https://ru.vuejs.org/v2/guide/components-slots.html#%D0%A1%D0%BB%D0%BE%D1%82%D1%8B-%D1%81-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9-%D0%BE%D0%B1%D0%BB%D0%B0%D1%81%D1%82%D1%8C%D1%8E-%D0%B2%D0%B8%D0%B4%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D0%B8). Это более продвинутое API ориентировано в первую очередь на создателей библиотек, но может пригодиться и разработчикам, к примеру для создании пользовательских компонентов таких как _NavLink_ или подобных.\n\n**При использовании API `v-slot` необходимо передавать один дочерний элемент в `router-link`**. Если этого не сделать, `router-link` обернёт все дочерние элементы в `span`.\n\n```html\n<router-link\n  to=\"/about\"\n  custom\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <NavLink :active=\"isActive\" :href=\"href\" @click=\"navigate\">\n    {{ route.fullPath }}\n  </NavLink>\n</router-link>\n```\n\n- `href`: разрешённый URL. Это будет атрибутом `href` для элемента `a`\n- `route`: разрешённый нормализованный маршрут\n- `navigate`: функция для запуска навигации. **Она автоматически предотвращает события, когда это необходимо**, аналогичным способом, как это делает `router-link`\n- `isActive`: `true` если [активный класс](#active-class) должен применяться. Позволяет применить произвольный класс\n- `isExactActive`: `true` если [активный класс при точном совпадении пути](#exact-active-class) должен применяться. Позволяет применить произвольный класс\n\n### Пример: Добавление активного класса к внешнему элементу\n\nИногда может потребоваться применять активный класс к внешнему элементу, а не к тегу `<a>`, в этом случае можно обернуть этот элемент в `<router-link>` и использовать свойства `v-slot` для создания ссылки:\n\n```html\n<router-link\n  to=\"/foo\"\n  custom\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <li\n    :class=\"[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']\"\n  >\n    <a :href=\"href\" @click=\"navigate\">{{ route.fullPath }}</a>\n  </li>\n</router-link>\n```\n\n:::tip ПРИМЕЧАНИЕ\nПри добавлении `target=\"_blank\"` на элемент `a`, необходимо опустить обработчик `@click=\"navigate\"`.\n:::\n\n## Входные параметры `<router-link>`\n\n### to\n\n- тип: `string | Location`\n- обязательный\n\n  Определяет итоговый маршрут ссылки. При нажатии, значение входного параметра `to` будет передано в `router.push()` — поэтому это значение может быть как строкой, так и объектом описывающим маршрут.\n\n  ```html\n  <!-- строка -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- отобразится в -->\n  <a href=\"home\">Home</a>\n\n  <!-- javascript-выражение с использованием `v-bind` -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- можно опустить `v-bind`, аналогично другим входным параметрам -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- даст тот же результат -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- именованный маршрут -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- с использованием query-строки, получим `/register?plan=private` -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">\n    Регистрация\n  </router-link>\n  ```\n\n### replace\n\n- тип: `boolean`\n- по умолчанию: `false`\n\n  Указание входного параметра `replace` вызовет `router.replace()` вместо `router.push()` при нажатии на ссылку, поэтому навигация не оставит записи в истории переходов.\n\n  ```html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n### append\n\n- тип: `boolean`\n- по умолчанию: `false`\n\n  Указание входного параметра `append` будет добавлять относительный путь к текущему. Например, если мы переходим от `/a` к относительной ссылке `b`, то без `append` будет адрес `/b`, а вместе с `append` получится `/a/b`.\n\n  ```html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n### tag\n\n- тип: `string`\n- по умолчанию: `\"a\"`\n\n  Иногда необходимо чтобы `<router-link>` отображался другим тегом, например `<li>`. В таком случае мы можем использовать входной параметр `tag`, чтобы указать нужный тег, и он всё равно будет прослушивать события click для навигации.\n\n  ```html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- отобразится как -->\n  <li>foo</li>\n  ```\n\n### active-class\n\n- тип: `string`\n- по умолчанию: `\"router-link-active\"`\n\n  Указание активного CSS класса, который применяется когда ссылка активна. Обратите внимание, что значение по умолчанию можно задать глобально в опции `linkActiveClass` конструктора маршрутизатора.\n\n### exact\n\n- тип: `boolean`\n- по умолчанию: `false`\n\n  Стандартное поведение сопоставления, когда выставляется активный класс, основывается на **совпадениях по включению**. Например, `<router-link to=\"/a\">` будет получать класс активности и когда текущий путь начинается с `/a/` и когда с `/a`.\n\n  Обратите внимание, поэтому `<router-link to=\"/\">` будет активным для каждого маршрута! Для «режима точного соответствия» укажите в ссылке входной параметр `exact`:\n\n  ```html\n  <!-- эта ссылка будет активной только для адреса `/` -->\n  <router-link to=\"/\" exact></router-link>\n  ```\n\n  Ознакомьтесь с другими примерами активных классов ссылок [вживую](https://jsfiddle.net/8xrk1n9f/).\n\n### exact-path\n\n> Добавлено в версии 3.5.0\n\n- тип: `boolean`\n- по умолчанию: `false`\n\n  Позволяет использовать сопоставление только на секции `path` в URL, позволяя эффективно игнорировать секции `query` и `hash`.\n\n  ```html\n  <!-- ссылка будет активной для `/search?page=2` или `/search#filters` -->\n  <router-link to=\"/search\" exact-path> </router-link>\n  ```\n\n### exact-path-active-class\n\n- тип: `string`\n- по умолчанию: `\"router-link-exact-path-active\"`\n\n  Указание активного CSS класса, который применяется когда ссылка активна по сопоставлению `path`. Обратите внимание, что значение по умолчанию можно задать глобально в опции `linkExactPathActiveClass` конструктора маршрутизатора.\n\n### event\n\n- тип: `string | Array<string>`\n- по умолчанию: `'click'`\n\n  Определение события (событий), которые будут вызывать навигацию по ссылке.\n\n### exact-active-class\n\n- тип: `string`\n- по умолчанию: `\"router-link-exact-active\"`\n\n  Указание активного CSS класса, который применяется когда ссылка активна с точным соответствием пути. Обратите внимание, что значение по умолчанию можно задать глобально в опции `linkExactActiveClass` конструктора маршрутизатора.\n\n### aria-current-value\n\n- тип: `'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'`\n- по умолчанию: `\"page\"`\n\n  Настройка значения `aria-current` когда ссылка активна по точному (exact) совпадению. Это должно быть одно из [разрешённых значений для aria-current](https://www.w3.org/TR/wai-aria-1.2/#aria-current) спецификации ARIA. В большинстве случаев наиболее подходящим значением будет `page`.\n\n## `<router-view>`\n\nФункциональный компонент `<router-view>` отображает компонент соответствующий данному маршруту. Компоненты внутри `<router-view>` также могут содержать в шаблоне собственный `<router-view>` (он будет использован для отображения компонентов вложенных маршрутов).\n\nВсе остальные входные параметры передаются в отображаемый компонент, однако данные маршрута удобнее получать из `$route.params` текущего маршрута.\n\nПоскольку это всего лишь компонент, он работает вместе с `<transition>` и `<keep-alive>`. При одновременном использовании обоих обязательно располагайте `<keep-alive>` внутри:\n\n```html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n\n## Входные параметры `<router-view>`\n\n### name\n\n- тип: `string`\n- по умолчанию: `\"default\"`\n\n  Наличие имени у `<router-view>` определяет отображение компонента с соответствующим именем из опции `components` сопоставленного маршрута. Подробности и примеры использования этой возможности в разделе [именованных представлений](../guide/essentials/named-views.md).\n\n## Опции конструктора Router\n\n### routes\n\n- тип: `Array<RouteConfig>`\n\n  Декларация типа для `RouteConfig`:\n\n  ```ts\n  interface RouteConfig = {\n    path: string,\n    component?: Component,\n    name?: string, // для именованных маршрутов\n    components?: { [name: string]: Component }, // для именованных представлений\n    redirect?: string | Location | Function,\n    props?: boolean | Object | Function,\n    alias?: string | Array<string>,\n    children?: Array<RouteConfig>, // для вложенных маршрутов\n    beforeEnter?: (to: Route, from: Route, next: Function) => void,\n    meta?: any,\n\n    // Добавлено в версии 2.6.0+\n    caseSensitive?: boolean, // учитывать регистр при сравнении? (по умолчанию: false)\n    pathToRegexpOptions?: Object // настройки path-to-regexp для компиляции regex\n  }\n  ```\n\n### mode\n\n- тип: `string`\n\n- по умолчанию: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- возможные значения: `\"hash\" | \"history\" | \"abstract\"`\n\n  Определяет режим работы маршрутизатора.\n\n  - `hash`: используется хэш URL для маршрутизации. Работает во всех совместимых с Vue браузерами, даже тех, что не поддерживают HTML5 History API.\n\n  - `history`: требует поддержки HTML5 History API и конфигурации сервера. Подробнее в разделе [Режим HTML5 History](../guide/essentials/history-mode.md).\n\n  - `abstract`: работает во всех JavaScript-окружениях, например при серверном рендеринге с помощью Node.js. **Маршрутизатор автоматически переключается в этот режим, если не обнаружит API браузера.**\n\n### base\n\n- тип: `string`\n\n- по умолчанию: `\"/\"`\n\n  Базовый URL приложения. Например, если SPA расположено по пути `/app/`, тогда `base` должно иметь значение `\"/app/\"`.\n\n### linkActiveClass\n\n- тип: `string`\n\n- по умолчанию: `\"router-link-active\"`\n\n  Глобальная настройка активного класса по умолчанию для `<router-link>`. Подробнее в опции [router-link](#router-link).\n\n### linkExactActiveClass\n\n- тип: `string`\n\n- по умолчанию: `\"router-link-exact-active\"`\n\n  Глобальная настройка активного класса по умолчанию при точном совпадении маршрута для `<router-link>`. Подробнее в опции [router-link](#router-link).\n\n### scrollBehavior\n\n- тип: `Function`\n\n  Сигнатура:\n\n  ```ts\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    void\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  Подробнее в разделе настройки [поведения прокрутки страницы](../guide/advanced/scroll-behavior.md).\n\n### parseQuery / stringifyQuery\n\n- тип: `Function`\n\n  Указание пользовательских функций для парсинга строки запроса / приведения к строке запроса (stringify). Переопределяют реализации по умолчанию.\n\n### fallback\n\n- тип: `boolean`\n\n- по умолчанию: `true`\n\n  Определяет, должен ли маршрутизатор возвращаться в режим `hash`, когда браузер не поддерживает `history.pushState`.\n\n  Установка этой опции в `false` будет приводить к полному обновлению страницы в IE9 для каждой навигации через `<router-link>`. Это полезно, когда приложение рендерится на стороне сервера (SSR) и должно работать в IE9, потому что режим `hash` не работает с серверным рендерингом.\n\n## Свойства экземпляра Router\n\n### router.app\n\n- тип: `Vue instance`\n\n  Корневой экземпляр Vue, в который внедряется `router`.\n\n### router.mode\n\n- тип: `string`\n\n  [Режим работы](./#mode), используемый маршрутизатором.\n\n### router.currentRoute\n\n- тип: `Route`\n\n  Текущий маршрут в виде [объекта Route](#объект-route).\n\n### router.START_LOCATION\n\n- тип: `Route`\n\n  Первоначальная навигация будет [объектом Route](#объект-route) с которого запускается маршрутизатор. Можно использовать в навигационных хуках для определения стартовой навигации.\n\n  ```js\n  import VueRouter from 'vue-router'\n\n  const router = new VueRouter({\n    // ...\n  })\n\n  router.beforeEach((to, from) => {\n    if (from === VueRouter.START_LOCATION) {\n      // первоначальная навигация\n    }\n  })\n  ```\n\n## Методы экземпляра Router\n\n### router.beforeEach\n\n### router.beforeResolve\n\n### router.afterEach\n\nСигнатуры:\n\n```js\nrouter.beforeEach((to, from, next) => {\n  /* необходимо вызывать `next` */\n})\n\nrouter.beforeResolve((to, from, next) => {\n  /* необходимо вызывать `next` */\n})\n\nrouter.afterEach((to, from) => {})\n```\n\nДобавляют глобальные навигационные хуки. Подробнее в разделе [Навигационные хуки](../guide/advanced/navigation-guards.md).\n\nВсе три метода возвращают функцию для удаления зарегистрированного хука.\n\n### router.push\n\n### router.replace\n\n### router.go\n\n### router.back\n\n### router.forward\n\nСигнатуры:\n\n```js\nrouter.push(location, onComplete?, onAbort?)\nrouter.push(location).then(onComplete).catch(onAbort)\nrouter.replace(location, onComplete?, onAbort?)\nrouter.replace(location).then(onComplete).catch(onAbort)\nrouter.go(n)\nrouter.back()\nrouter.forward()\n```\n\nПрограммная навигация на новый URL. Подробнее в разделе [программная навигация](../guide/essentials/navigation.md).\n\n### router.getMatchedComponents\n\nСигнатура:\n\n```js\nconst matchedComponents: Array<Component> = router.getMatchedComponents(location?)\n```\n\nВозвращает массив компонентов (определение/конструктор, не экземпляры) сопоставленные для указанного адреса или текущего маршрута. В основном это используется для рендеринга на стороне сервера, чтобы выполнить предварительную загрузку данных.\n\n### router.resolve\n\nСигнатура:\n\n```js\nconst resolved: {\n  location: Location;\n  route: Route;\n  href: string;\n} = router.resolve(location, current?, append?)\n```\n\nОбратное разрешение URL, чтобы получить местоположение в формате, аналогичном используемому в `<router-link/>`.\n\n- `current` текущий маршрут по умолчанию (в большинстве случаев не требуется это менять)\n- `append` позволяет вам добавить путь к маршруту `current` (как и в [`router-link`](#router-link-props))\n\n### router.addRoutes\n\n_УСТАРЕВШИЙ_: используйте вместо метод [`router.addRoute()`](#router-addroute).\n\nСигнатура:\n\n```ts\nrouter.addRoutes(routes: Array<RouteConfig>)\n```\n\nДинамически добавляет дополнительные маршруты в маршрутизатор. Аргумент должен быть массивом маршрутов в таком же формате, как и в опции `routes` конструктора.\n\n### router.addRoute\n\n> Добавлено в версии 3.5.0\n\nДобавляет новый маршрут в маршрутизатор. Если у маршрута указан `name` и уже существует маршрут с таким же именем, то он будет перезаписан.\n\nСигнатура:\n\n```ts\naddRoute(route: RouteConfig): () => void\n```\n\n### router.addRoute\n\n> Добавлено в версии 3.5.0\n\nДобавляет новый маршрут в качестве дочернего для существующего маршрута. Если у маршрута указан `name` и уже существует маршрут с таким же именем, то он будет перезаписан.\n\nСигнатура:\n\n```ts\naddRoute(parentName: string, route: RouteConfig): () => void\n```\n\n### router.getRoutes\n\n> Добавлено в версии 3.5.0\n\nПолучение списка записей всех активных маршрутов. **Обратите внимание, что только задокументированные свойства считаются публичным API**, поэтому следует избегать использования любых других свойств, например `regex`, так как их уже не будет в Vue Router 4.\n\nСигнатура:\n\n```ts\ngetRoutes(): RouteRecord[]\n```\n\n### router.onReady\n\nСигнатура:\n\n```js\nrouter.onReady(callback, [errorCallback])\n```\n\nРегистрирует коллбэк, который будет вызван когда маршрутизатор завершит начальную навигацию, когда будут завершены все асинхронные хуки и готовы асинхронные компоненты, связанные с начальным маршрутом.\n\nПригодится при рендеринге на стороне сервера, чтобы обеспечить консистентный результат как на сервере, так и на клиенте.\n\nВторой аргумент `errorCallback` поддерживается только в версиях 2.4+. Он вызывается когда начальное разрешение маршрута заканчивается ошибкой (например, не удалось разрешить асинхронный компонент).\n\n### router.onError\n\nСигнатура:\n\n```js\nrouter.onError(callback)\n```\n\nРегистрирует коллбэк, который будет вызван при обнаружении ошибок во время навигации по маршруту. Обратите внимание, что он вызывается в одном из следующих сценариев:\n\n- Ошибка произошла синхронно внутри функции маршрута;\n\n- Ошибка фиксируется и асинхронно обрабатывается с помощью `next(err)` внутри функции навигационного хука;\n\n- Произошла ошибка при попытке разрешить асинхронный компонент, необходимый для отображения маршрута.\n\n## Объект Route\n\n**Объект Route** представляет собой состояние текущего активного маршрута. Он содержит информацию о текущем URL и **записи маршрутов**, сопоставленные с ним.\n\nОбъект маршрута иммутабелен. Каждая успешная навигация создаёт новый объект маршрута.\n\nОбъект маршрута встречается в нескольких местах:\n\n- Внутри компонентов как `this.$route`\n\n- Внутри коллбэка при отслеживании изменений `$route`\n\n- Как возвращаемое значение при вызове `router.match(location)`\n\n- В качестве двух первых параметров навигационных хуков:\n\n  ```js\n  router.beforeEach((to, from, next) => {\n    // как `to` так и `from` являются объектами маршрута\n  })\n  ```\n\n- В качестве двух первых параметров функции `scrollBehavior`:\n\n  ```js\n  const router = new VueRouter({\n    scrollBehavior(to, from, savedPosition) {\n      // как `to` так и `from` являются объектами маршрута\n    }\n  })\n  ```\n\n### Свойства объекта Route\n\n- **\\$route.path**\n\n  - тип: `string`\n\n    Строка пути текущего маршрута, всегда в абсолютном формате, например `\"/foo/bar\"`.\n\n- **\\$route.params**\n\n  - тип: `Object`\n\n    Объект, который содержит пары ключ/значение динамических сегментов маршрута (включая \\*-сегменты). Если параметров нет, то значением будет пустой объект.\n\n- **\\$route.query**\n\n  - тип: `Object`\n\n    Объект, который содержит пары ключ/значение строки запроса (query string). Например, для пути `/foo?user=1` получим `$route.query.user == 1`. Если строки запроса нет, то значением будет пустой объект.\n\n- **\\$route.meta**\n\n  - тип: `Object`\n\n    Объект, который содержит пары ключ/значение объекта meta для маршрута. Если у объекте meta нет свойств, то значением будет пустой объект.\n\n- **\\$route.hash**\n\n  - тип: `string`\n\n    Хэш текущего маршрута (вместе с символом `#`) при его наличии. Если хэша нет, то значением будет пустая строка.\n\n- **\\$route.fullPath**\n\n  - тип: `string`\n\n    Полная запись URL-адреса, включая строку запроса и хэш.\n\n- **\\$route.matched**\n\n  - тип: `Array<RouteRecord>`\n\n  Массив с **записями маршрутов** для всех вложенных сегментов текущего маршрута. Записи маршрутов — это копии объектов из опции `routes` (и вложенных массивов `children`):\n\n  ```js\n  const router = new VueRouter({\n    routes: [\n      // объект ниже — это запись маршрута\n      {\n        path: '/foo',\n        component: Foo,\n        children: [\n          // это — тоже запись маршрута\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\nДля URL `/foo/bar`, значение `$route.matched` будет массивом, содержащим копии объектов (клоны), в порядке сортировки от родителя к потомку.\n\n- **\\$route.name**\n\n  Имя текущего маршрута, если было указано. (Подробнее в разделе [именованные маршруты](../guide/essentials/named-routes.md))\n\n- **\\$route.redirectedFrom**\n\n  Имя маршрута с которого произошло перенаправление, если было указано. (Подробнее в разделе [перенаправления и псевдонимы](../guide/essentials/redirect-and-alias.md))\n\n## Интеграция в компоненты\n\n### Внедряемые в компоненты свойства\n\nЭти свойства внедряются в каждый дочерний компонент, передавая экземпляр маршрутизатора в корневой экземпляр в качестве опции `router`.\n\n- **this.\\$router**\n\n  Экземпляр маршрутизатора.\n\n- **this.\\$route**\n\n  Текущий активный [маршрут](#объект-route). Это свойство только для чтения и все его свойства иммутабельны, но можно отслеживать их изменения.\n\n### Добавляемые опции в компонент\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate**\n- **beforeRouteLeave**\n\n  Подробнее в разделе [Навигационные хуки компонентов](../guide/advanced/navigation-guards.md#incomponent-guards).\n"
  },
  {
    "path": "docs/ru/guide/README.md",
    "content": "# Начало работы\n\n::: tip Примечание\nМы будем использовать синтаксис [ES2015](https://github.com/lukehoban/es6features) в примерах кода в этом руководстве.\n\nКроме того, все примеры будут использовать полную сборку Vue, чтобы позволить компиляцию шаблонов на лету. Подробнее о различиях сборок читайте [здесь](https://ru.vuejs.org/v2/guide/installation.html#Runtime-Компилятор-vs-Runtime-only).\n:::\n\nСоздавать одностраничные приложения (SPA) используя Vue + Vue Router очень просто: с помощью Vue.js, мы уже компонуем своё приложение из компонентов. Добавляя Vue Router, мы просто сопоставляем наши компоненты с маршрутами и объясняем Vue Router где их отображать. Вот простой пример:\n\n## HTML\n\n```html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Первое приложение!</h1>\n  <p>\n    <!-- используем компонент router-link для навигации -->\n    <!-- входной параметр `to` определяет URL для перехода -->\n    <!-- `<router-link>` по умолчанию отображается тегом `<a>` -->\n    <router-link to=\"/foo\">Перейти к Foo</router-link>\n    <router-link to=\"/bar\">Перейти к Bar</router-link>\n  </p>\n  <!-- отображаем тут компонент, для которого совпадает маршрут -->\n  <router-view></router-view>\n</div>\n```\n\n## JavaScript\n\n```js\n// 0. Если используем модульную систему (например через vue-cli),\n// импортируем Vue и VueRouter и затем вызываем `Vue.use(VueRouter)`.\n\n// 1. Определяем компоненты для маршрутов.\n// Они могут быть импортированы из других файлов\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Определяем несколько маршрутов\n// Каждый маршрут должен указывать на компонент.\n// \"Компонентом\" может быть как конструктор компонента, созданный\n// через `Vue.extend()`, так и просто объект с опциями компонента.\n// Мы поговорим о вложенных маршрутах позднее.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Создаём экземпляр маршрутизатора и передаём маршруты в опции `routes`\n// Вы можете передавать и дополнительные опции, но пока не будем усложнять.\nconst router = new VueRouter({\n  routes // сокращённая запись для `routes: routes`\n})\n\n// 4. Создаём и монтируем корневой экземпляр приложения.\n// Убедитесь, что передали экземпляр маршрутизатора в опции\n// `router`, чтобы позволить приложению знать о его наличии.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// Всё, приложение работает! ;)\n```\n\nВнедряя маршрутизатор, мы сможем получить к нему доступ через `this.$router`, а также к текущему маршруту через `this.$route` внутри любого компонента:\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username() {\n      // Мы скоро разберём что такое `params`\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack() {\n      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')\n    }\n  }\n}\n```\n\nВ документации мы будем часто использовать экземпляр `router` (маршрутизатора). Имейте ввиду, что `this.$router` в точности то же самое, что и `router`. Причина, почему используем `this.$router` заключается в том, что мы не хотим импортировать маршрутизатор в каждом компоненте, в котором потребуется управлять маршрутизацией.\n\nВы также можете увидеть этот пример вживую [здесь](https://jsfiddle.net/yyx990803/xgrjzsup/).\n\nОбратите внимание, что `<router-link>` автоматически получает класс `.router-link-active` при совпадении маршрута. Подробнее об этом можно узнать в [справочнике API](../api/#router-link).\n"
  },
  {
    "path": "docs/ru/guide/advanced/data-fetching.md",
    "content": "# Загрузка данных\n\nНередко при переходе между маршрутами требуется получить от сервера какие-либо данные. Например, перед отображением профиля пользователя нужно загрузить данные о нём. Этой цели можно достичь двумя различными путями:\n\n- **Загрузить данные после перехода**: сначала перейти к новому маршруту, затем загрузить данные в хуке жизненного цикла целевого компонента. По мере загрузки данных отобразить индикатор состояния загрузки.\n\n- **Загрузить данные перед переходом**: загрузить данные в навигационном хуке роутера, и завершить навигацию уже когда они будут получены.\n\nС технической точки зрения, оба способа годятся — выбор зависит от того, какой UX вы хотите получить.\n\n## Загрузка данных после перехода\n\nПри использовании этого подхода, мы осуществляем переход и рендеринг целевого компонента сразу же, а данные запрашиваем в хуке `created` компонента. Это позволяет нам отобразить состояние загрузки, пока данные подтягиваются по сети, причём имея возможность сделать это различным образом для разных компонентов.\n\nПредположим, у нас есть компонент `Post`, которому требуется загрузить с сервера данные, соответствующие id поста из `$route.params.id`:\n\n```html\n<template>\n  <div class=\"post\">\n    <div v-if=\"loading\" class=\"loading\">\n      Загрузка...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n```js\nexport default {\n  data() {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created() {\n    // загружаем данные, когда представление создано\n    // и данные реактивно отслеживаются\n    this.fetchData()\n  },\n  watch: {\n    // при изменениях маршрута запрашиваем данные снова\n    $route: 'fetchData'\n  },\n  methods: {\n    fetchData() {\n      this.error = this.post = null\n      this.loading = true\n      // замените `getPost` используемым методом получения данных / доступа к API\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Загрузка данных перед переходом\n\nИспользуя этот подход, мы запрашиваем данные до завершения перехода к новому маршруту. Запрос данных выполняется в навигационном хуке `beforeRouteEnter` компонента, который вызывает `next`, когда данные получены:\n\n```js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter(to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // если путь изменяется, а компонент уже отображён,\n  // то логика будет немного иной\n  beforeRouteUpdate(to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\nПользователь останется на предыдущей странице, пока не загрузятся данные новой. По этой причине мы советуем отображать какой-нибудь индикатор загрузки. Кроме того, если загрузка данных не удастся, следует отобразить глобальное сообщение об ошибке.\n"
  },
  {
    "path": "docs/ru/guide/advanced/lazy-loading.md",
    "content": "# Ленивая загрузка маршрутов\n\nПри использовании модульной системы, итоговая JavaScript-сборка может оказаться довольно большой, что негативно отразится на времени загрузки страницы. В некоторых случаях было бы эффективнее разделить компоненты каждого маршрута на отдельные фрагменты, и подгружать их только при переходе к соответствующему маршруту.\n\nСовместное использование [асинхронной загрузки компонентов](https://ru.vuejs.org/v2/guide/components-dynamic-async.html#Асинхронные-компоненты) Vue и [возможностей по разделению кода](https://webpack.js.org/guides/code-splitting-async/) Webpack делает реализацию ленивой загрузки компонентов в зависимости от маршрутов тривиальной.\n\nВо-первых, асинхронный компонент можно определить как функцию-фабрику, которая возвращает Promise (который должен разрешиться самим компонентом):\n\n```js\nconst Foo = () =>\n  Promise.resolve({\n    /* определение компонента */\n  })\n```\n\nВо-вторых, с Webpack 2 мы можем использовать синтаксис [динамических импортов](https://github.com/tc39/proposal-dynamic-import) для указания точек разделения кода:\n\n```js\nimport('./Foo.vue') // возвращает Promise\n```\n\n::: tip Примечание\nЕсли вы используете Babel, то необходимо добавить плагин [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/), чтобы Babel смог корректно обработать синтаксис.\n:::\n\nЭти два пункта — всё необходимое, чтобы определить асинхронный компонент, который Webpack автоматически выделит в отдельный фрагмент:\n\n```js\nconst Foo = () => import('./Foo.vue')\n```\n\nВ конфигурации маршрута ничего менять не нужно, можно использовать `Foo` как обычно:\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/foo', component: Foo }]\n})\n```\n\n## Группировка компонентов в одном фрагменте\n\nИногда может понадобиться объединить в одном фрагменте все компоненты, расположенные по определённому маршруту. Для этого можно указывать [имена фрагментов Webpack](https://webpack.js.org/api/module-methods/#magic-comments), используя специальный синтаксис комментариев (в версиях Webpack > 2.4):\n\n```js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nWebpack сгруппирует все одноимённые асинхронные модули в одном фрагменте.\n"
  },
  {
    "path": "docs/ru/guide/advanced/meta.md",
    "content": "# Метаданные маршрутов\n\nИногда может быть удобным добавить дополнительную информацию к маршрутам, например имена анимаций переходов, кто может получить доступ к маршруту и т.д. Этого можно достичь с помощью свойства `meta`, которое принимает объект свойств и к которому можно получить доступ на странице маршрута или в навигационных хуках. Свойства `meta` можно объявить так:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // метаданные\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nКак получить к нему доступ?\n\nПрежде всего, каждый объект маршрута в конфигурации `routes` называется **записью маршрута**. Записи маршрутов могут быть вложенными. Поэтому, при совпадении маршрута, потенциально могут быть активированы несколько записей маршрутов.\n\nНапример, для конфигурации выше, URL `/foo/bar` совпадёт как с родительской, так и с дочерней записями маршрутов.\n\nВсе совпавшие записи маршрутов оказываются доступны через объект `$route` (а также через объекты маршрутов в сторожевых хуках), в виде массива `$route.matched`. Таким образом, для проверки метаданных в записях маршрутов нам понадобится обойти `$route.matched` в цикле.\n\nВ качестве примера можно привести проверку метаданных в глобальном навигационном хуке:\n\n```js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // этот путь требует авторизации, проверяем залогинен ли\n    // пользователь, и если нет, перенаправляем на страницу логина\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // всегда так или иначе нужно вызвать next()!\n  }\n})\n```\n"
  },
  {
    "path": "docs/ru/guide/advanced/navigation-failures.md",
    "content": "# Сбои при навигации\n\n> Добавлено в версии 3.4.0\n\nПри использовании `router-link` Vue Router вызывает `router.push` для запуска навигации. В большинстве случаев ожидаемое поведение ссылок заключается в переходе на новую страницу, но есть несколько ситуаций при которых пользователь остаётся на той же странице:\n\n- Пользователь уже находится на странице, на которую пытается перейти\n- [Навигационный хук](./navigation-guards.md) прерывает навигацию вызовом `next(false)`\n- [Навигационный хук](./navigation-guards.md) выбрасывает ошибку или вызывает `next(new Error())`\n\nПри использовании компонента `router-link` **ни один из этих случаев не будет логироваться как ошибка**. Однако при использовании `router.push` или `router.replace` можно столкнуться с сообщением _\"Uncaught (in promise) Error\"_ после которого в консоли последует более конкретное сообщение. Давайте разберемся как отличать _сбои навигации_.\n\n::: tip История вопроса\nВ версии 3.2.0, _навигационные сбои_ доступны через два необязательных коллбэка `router.push`: `onComplete` и `onAbort`. Начиная с версии 3.1.0, `router.push` и `router.replace` возвращают _Promise_ если не указаны коллбэки `onComplete`/`onAbort`. Этот _Promise_ разрешается вместо вызова `onComplete` и отклоняется вместо вызова `onAbort`.\n :::\n\n## Обнаружение сбоев навигации\n\n_Сбой навигации_ будет экземпляром `Error` с парой дополнительных свойств. Проверить произошла ли ошибка в маршрутизаторе можно с помощью функции `isNavigationFailure`:\n\n```js\nimport VueRouter from 'vue-router'\nconst { isNavigationFailure, NavigationFailureType } = VueRouter\n\n// попытка перехода к странице администрирования\nrouter\n  .push('/admin')\n  .catch(failure => {\n    if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n      // отображение уведомления пользователю\n      showToast('Необходимо авторизоваться для доступа к панели администрирования')\n    }\n  })\n```\n\n::: tip СОВЕТ\nЕсли опустить второй параметр в `isNavigationFailure(failure)`, то будет проверяться только, является ли ошибка _сбоем навигации_.\n:::\n\n## Тип `NavigationFailureType`\n\nТип `NavigationFailureType` поможет разработчикам определять тип _навигационного сбоя_. Существует 4 различных типа:\n\n- `redirected`: внутри навигационного хука был вызван `next(newLocation)` для перенаправления в другое место.\n- `aborted`: внутри навигационного хука был вызван `next(false)` для отмены навигации.\n- `cancelled`: произошла полностью новая навигация до того, как текущая могла закончиться. Например, во время ожидания внутри навигационного хука был вызван `router.push`.\n- `duplicated`: навигация была предотвращена, потому что уже находимся в месте назначения.\n\n## Свойства _ошибок навигации_\n\nВсе сбои навигации предоставляют доступ к свойствам `to` и `from`, отображающие для навигации в которой произошёл сбой местоположение места назначения и текущее местоположение соответственно:\n\n```js\n// попытка получения доступа к странице администрирования\nrouter\n  .push('/admin')\n  .catch(failure => {\n    if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n      console.log(failure.to.path) // '/admin'\n      console.log(failure.from.path) // '/'\n    }\n  })\n```\n\nВо всех случаях значения `to` и `from` будут объектами нормализованных маршрутов.\n"
  },
  {
    "path": "docs/ru/guide/advanced/navigation-guards.md",
    "content": "# Навигационные хуки\n\nКак следует из названия, навигационные хуки `vue-router` используются для перенаправлений или отмены навигационных переходов. Есть несколько способов внедрить навигационный хук: глобально, для конкретного маршрута, или для конкретного компонента.\n\nСледует помнить, что **изменение параметров маршрута не вызывает выполнения навигационных хуков enter/leave**. Вы можете добавить [watch на объект `$route`](../essentials/dynamic-matching.md#отсnеживание-изменений-параметров) для отслеживания этих изменений, или использовать хук `beforeRouteUpdate`.\n\n## Глобальные хуки (до навигационных хуков)\n\nГлобальный хук можно зарегистрировать через `router.beforeEach`:\n\n```js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nГлобальные навигационные хуки вызываются в порядке их создания при каждом навигационном переходе. Допускается асинхронное разрешение хуков — в этом случае переход считается **незавершённым** до тех пор, пока не будут разрешены все хуки.\n\nВ каждый навигационный хук передаётся три параметра:\n\n- **`to: Route`**: целевой [объект Route](../../api/#объект-route), к которому осуществляется переход.\n\n- **`from: Route`**: текущий маршрут, с которого осуществляется переход к новому.\n\n- **`next: Function`**: функция, вызов которой **разрешает** хук. В зависимости от переданных в `next` аргументов, результатом будет:\n\n  - **`next()`**: переход к следующему хуку в цепочке. Если хуков больше нет, переход считается **подтверждённым**.\n\n  - **`next(false)`**: отмена перехода. Если URL был изменён (вручную пользователем, или кнопкой \"назад\"), он будет сброшен на соответствующий маршрут `from`.\n\n  - **`next('/')` или `next({ path: '/' })`**: перенаправление на другой маршрут. Текущий переход будет отменён, и процесс начнётся заново для нового маршрута. Вы можете передать любой объект местоположения в `next`, который позволяет вам указывать опции такие как `replace: true`, `name: 'home'` и любой другой параметр используемый во [входном параметре `to` компонента `router-link`](../../api/#to) или [`router.push`](../../api/#router-push)\n\n  - **`next(error)`**: (добавлено в версии 2.4.0+) если аргумент, переданный `next` является экземпляром `Error`, навигация будет прервана и ошибка будет передана в коллбэк, зарегистрированный через [`router.onError()`](../../api/#router-onerror).\n\n**Убедитесь, что функция `next` будет вызываться в навигационном хуке только 1 раз в любом случае. Вызовы могут встречаться несколько раз, но важно чтобы они не пересекались логически, иначе хук никогда не разрешится или выдаст ошибки.** Вот пример перенаправления пользователя на страницу `/login` если он не авторизован:\n\n```js\n// ПЛОХО\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  // если пользователь не авторизован, то `next` будет вызываться дважды\n  next()\n})\n```\n\n```js\n// ХОРОШО\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  else next()\n})\n```\n\n## Глобальные хуки разрешения перехода\n\nВы можете зарегистрировать глобальный хук с помощью `router.beforeResolve`. Это похоже на `router.beforeEach`, с той разницей, что разрешающий хук будет вызван непосредственно перед подтверждением навигации, **после того, как будут разрешены все хуки компонента и асинхронные компоненты для маршрута**.\n\n## Глобальные хуки завершения перехода\n\nМожно также зарегистрировать глобальные хуки, вызываемые после завершения перехода. Однако, в отличие от сторожевых хуков, в них не передаётся функция `next`, и на навигацию они повлиять не могут:\n\n```js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n## Хуки для конкретных маршрутов\n\nНавигационные хуки `beforeEnter` можно указать напрямую для конкретного маршрута в его конфигурации:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nЭти хуки имеют точно такую же сигнатуру, как и глобальные хуки.\n\n## Хуки для конкретных компонентов\n\nНаконец, навигационный хук можно указать и непосредственно в компоненте (том, что указан в конфигурации маршрута), используя следующие опции:\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate`\n- `beforeRouteLeave`\n\n```js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter(to, from, next) {\n    // вызывается до подтверждения пути, соответствующего этому компоненту.\n    // НЕ ИМЕЕТ доступа к контексту экземпляра компонента `this`,\n    // так как к моменту вызова экземпляр ещё не создан!\n  },\n  beforeRouteUpdate(to, from, next) {\n    // вызывается когда маршрут, что рендерит этот компонент изменился,\n    // но этот компонент будет повторно использован в новом маршруте.\n    // Например, для маршрута с динамическими параметрами `/foo/:id`, когда мы\n    // перемещаемся между `/foo/1` и `/foo/2`, экземпляр того же компонента `Foo`\n    // будет использован повторно, и этот хук будет вызван когда это случится.\n    // Также имеется доступ в `this` к экземпляру компонента.\n  },\n  beforeRouteLeave(to, from, next) {\n    // вызывается перед переходом от пути, соответствующего текущему компоненту;\n    // имеет доступ к контексту экземпляра компонента `this`.\n  }\n}\n```\n\nХук `beforeRouteEnter` **НЕ ИМЕЕТ** доступа к `this`, так как к моменту его вызова навигация ещё не подтверждена, а значит и экземпляр компонента ещё не создан.\n\nТем не менее, доступ к экземпляру можно получить, передав коллбэк в `next`. Эта функция будет вызвана после подтверждения навигации, а экземпляр компонента будет передан в неё в качестве параметра:\n\n```js\nbeforeRouteEnter(to, from, next) {\n  next(vm => {\n    // экземпляр компонента доступен как `vm`\n  })\n}\n```\n\nОбратите внимание, что `beforeRouteEnter` — единственный хук, который поддерживает передачу коллбэка в `next`. Для `beforeRouteUpdate` и `beforeRouteLeave`, `this` уже доступен, поэтому передача коллбэка не требуется и поэтому _не поддерживается_:\n\n```js\nbeforeRouteUpdate(to, from, next) {\n  // просто используйте `this`\n  this.name = to.params.name\n  next()\n}\n```\n\n**Навигационный хук ухода со страницы** обычно используется для предотвращения случайного ухода пользователя со страницы с несохранёнными изменениями. Навигацию можно отменить вызовом `next(false)`.\n\n```js\nbeforeRouteLeave(to, from, next) {\n  const answer = window.confirm('Вы хотите уйти? У вас есть несохранённые изменения!')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\nПри использовании примесей, которые будут добавлять навигационные хуки для компонента, убедитесь, что объявляете примесь **после установки плагина vue-router**:\n\n```js\nVue.use(Router)\n\nVue.mixin({\n  beforeRouteUpdate(to, from, next) {\n    // ...\n  }\n})\n```\n\n## Полная цепочка обработки навигации\n\n1. Срабатывание навигации.\n2. Вызов `beforeRouteLeave` хуков в деактивируемых компонентах.\n3. Вызов глобальных `beforeEach` хуков.\n4. Вызов `beforeRouteUpdate` хука в переиспользуемых компонентах.\n5. Вызов `beforeEnter` в конфигурации маршрута.\n6. Разрешение асинхронных компонентов для маршрута.\n7. Вызов `beforeRouteEnter` в активируемых компонентах.\n8. Вызов глобальных `beforeResolve` хуков.\n9. Навигация подтверждена.\n10. Вызов глобальных `afterEach` хуков.\n11. Выполняется обновление DOM.\n12. Вызов коллбэков, переданных в `next` в `beforeRouteEnter` хуке с созданными экземплярами.\n"
  },
  {
    "path": "docs/ru/guide/advanced/scroll-behavior.md",
    "content": "# Поведение прокрутки страницы\n\nПри переходе между страницами в рамках клиентской маршрутизации, можно сохранять позицию прокрутки для каждой записи в истории (что обычно делают браузеры при работе с традиционными приложениями), или же прокручивать страницу наверх. `vue-router` позволяет использовать оба варианта, и даже более того — позволяет полностью настроить поведение прокрутки при навигации.\n\n**Примечание: эта возможность работает если браузер поддерживает `history.pushState`.**\n\nПри создании экземпляра маршрутизатора, вы можете указать функцию `scrollBehavior`:\n\n```js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior(to, from, savedPosition) {\n    // возвращаем требуемую позицию прокрутки\n  }\n})\n```\n\nФункция `scrollBehavior` получает объекты маршрутов `to` и `from`. В третьем параметре, `savedPosition`, передаётся сохранённая в истории браузера позиция прокрутки (только в случае `popstate`-перехода, вызванного нажатием кнопок вперёд/назад в браузере).\n\nФункция возвращает объект позиции прокрутки. Он может иметь одну из двух форм:\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset поддерживается в 2.6.0+)\n\nЕсли возвращается пустой объект или значение, приводимое к ложному, прокрутки не будет.\n\nНапример:\n\n```js\nscrollBehavior(to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nТаким образом мы заставим браузер прокручивать к началу каждой открытой страницы.\n\nВозврат `savedPosition` позволяет эмулировать нативное поведение браузера при использовании кнопок назад/вперёд:\n\n```js\nscrollBehavior(to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nЭмулировать поведение \"прокрутки к якорю\" на странице можно так:\n\n```js\nscrollBehavior(to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nМожно также использовать [метаданные путей](meta.md) для более сложного управления прокруткой. Полную реализацию этого подхода можно посмотреть в [этом примере](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js).\n\n## Асинхронная прокрутка\n\n> Добавлено в версии 2.8.0\n\nМожно также вернуть Promise, который разрешится объектом с желаемой позицией прокрутки:\n\n```js\nscrollBehavior(to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nЭто можно связать с событиями компонента transition на уровне страницы, чтобы реализовать такое поведение прокрутки, которое сочетается с анимациями перехода между страницами, но из-за множества возможных вариантов и комплексности примеров, мы просто предоставляем этот простой пример, чтобы показать где можно разместить собственную реализацию.\n\n## Плавная прокрутка\n\nМожно включить нативную плавную прокрутку для [браузеров, которые поддерживают её](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior), просто добавив опцию `behavior` к объекту, возвращаемому из `scrollBehavior`:\n\n```js\nscrollBehavior(to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash,\n      behavior: 'smooth',\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/ru/guide/advanced/transitions.md",
    "content": "# Анимация переходов\n\nПоскольку `<router-view>` — это просто динамический компонент, к нему можно применять анимацию перехода с помощью `<transition>`:\n\n```html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\nВсё, [что сказано о `<transition>` в документации Vue](https://ru.vuejs.org/v2/guide/transitions.html), применимо и здесь.\n\n## Анимация переходов для конкретных маршрутов\n\nСинтаксис выше применяет одну и ту же анимацию перехода для всех маршрутов. Если для различных маршрутов хочется указать разные анимационные эффекты, можно использовать разноимённые `<transition>` непосредственно в шаблонах компонентов:\n\n```js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n## Динамическая анимация для маршрутов\n\nМожно также определять анимацию перехода для маршрутов динамически, в зависимости от соотношения между старым и новым маршрутом:\n\n```html\n<!-- используем динамическое имя анимационного перехода -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n```js\n// затем, в родительском компоненте, будем следить за переменной `$route`,\n// чтобы определить, какой анимационный переход применять\nwatch: {\n  $route(to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nПолный пример можно посмотреть [здесь](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).\n"
  },
  {
    "path": "docs/ru/guide/essentials/dynamic-matching.md",
    "content": "# Динамические пути\n\nОчень часто нам требуется сопоставить маршруты с заданным шаблоном с одним и тем же компонентом. Например, у нас может быть компонент `User`, который должен отображаться для всех пользователей, но с разными ID пользователей. Во `vue-router` мы можем использовать динамический сегмент в маршруте, чтобы достичь этого:\n\n```js\nconst User = {\n  template: '<div>Пользователь</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // динамические сегменты начинаются с двоеточия\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nТеперь все URL вида `/user/foo` и `/user/bar` будут соответствовать одному маршруту.\n\nДинамический сегмент обозначается двоеточием `:`. При сопоставлении маршрута, значение динамического сегмента можно получить через `this.$route.params` в каждом компоненте. Теперь мы можем отобразить ID текущего пользователя, обновив шаблон компонента `User`:\n\n```js\nconst User = {\n  template: '<div>Пользователь {{ $route.params.id }}</div>'\n}\n```\n\nВы можете посмотреть этот пример вживую [здесь](https://jsfiddle.net/yyx990803/4xfa2f19/).\n\nМожет быть несколько динамических сегментов в одном маршруте. Для каждого сегмента появится соответствующее свойство в `$route.params`. Например:\n\n| Шаблон                        | Совпадающий путь    | $route.params                          |\n| ----------------------------- | ------------------- | -------------------------------------- |\n| /user/:username               | /user/evan          | `{ username: 'evan' }`                 |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\nКроме `$route.params`, объект `$route` предоставляют и другую полезную информацию, например `$route.query` (если URL содержит строку запроса), `$route.hash`, и т.д. Подробнее в [справочнике API](../../api/#объект-route).\n\n## Отслеживание изменений параметров\n\nВажно отметить, что при переходе от `/user/foo` к `/user/bar` **будет повторно использован тот же самый экземпляр компонента**. Поскольку оба маршрута указывают на один и тот же компонент, этот подход эффективнее, чем уничтожение и повторное создание экземпляра. **Но это означает, что хуки жизненного цикла компонента при этом вызываться не будут**.\n\nЧтобы реагировать на изменения параметров маршрута в рамках одного компонента, достаточно просто отслеживать изменения в объекте `$route`:\n\n```js\nconst User = {\n  template: '...',\n  watch: {\n    $route(to, from) {\n      // обрабатываем изменение параметров маршрута...\n    }\n  }\n}\n```\n\nИли можно воспользоваться [хуком `beforeRouteUpdate`](../advanced/navigation-guards.md), добавленным в версии 2.2:\n\n```js\nconst User = {\n  template: '...',\n  beforeRouteUpdate(to, from, next) {\n    // обрабатываем изменение параметров маршрута...\n    // не забываем вызвать next()\n  }\n}\n```\n\n## Страница ошибки 404 / отслеживание ненайденных путей\n\nОбычные параметры соответствуют символам между фрагментами URL, разделёнными `/`. При необходимости чтобы совпадало **что угодно** можно воспользоваться звёздочкой (`*`):\n\n```js\n{\n  // сопоставляется со всем\n  path: '*'\n}\n{\n  // сопоставляется со всем, начинающимся с `/user-`\n  path: '/user-*'\n}\n```\n\nЕсли используете маршруты со _звёздочкой_, убедитесь в их правильном порядке, чтобы они были в конце.\nМаршрут `{ path: '*' }` обычно используют для страницы ошибки 404 на стороне клиента. При использовании _Режима HTML5 History_ также проверьте что [правильно сконфигурировали сервер](./history-mode.md).\n\nПри наличии _звёздочки_ в `$route.params` автоматически добавляется свойство `pathMatch`. Оно будет содержать оставшуюся часть URL-адреса, сопоставленную со _звёздочкой_:\n\n```js\n// Существует маршрут { path: '/user-*' }\nthis.$router.push('/user-admin')\nthis.$route.params.pathMatch // 'admin'\n\n// Существует маршрут { path: '*' }\nthis.$router.push('/non-existing')\nthis.$route.params.pathMatch // '/non-existing'\n```\n\n## Продвинутые возможности сопоставления\n\n`vue-router` использует [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) в качестве движка для проверки совпадения маршрутов, что позволяет задействовать многие продвинутые возможности, включая опциональные динамические сегменты и регулярные выражения. Подробнее об этих продвинутых возможностях можно изучить в [документации библиотеки](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters), а на [примере](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) узнать как использовать их совместно с `vue-router`.\n\n## Приоритеты при сопоставлении маршрутов\n\nИногда один и тот же URL может совпасть с несколькими маршрутами. В таких случаях приоритет определяется порядком определения маршрутов: чем раньше определён маршрут, тем выше у него приоритет.\n"
  },
  {
    "path": "docs/ru/guide/essentials/history-mode.md",
    "content": "# Режим HTML5 History\n\nПо умолчанию `vue-router` работает в режиме _хэша_ — он использует хэш URL для симуляции полного URL-адреса, что позволяет избежать перезагрузки страницы при изменении URL.\n\nМы можем обойтись без хэша, используя **режим history**, который работает с API `history.pushState` для достижения той же цели:\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nПри использовании этого URL выглядит естественно, например: `http://oursite.com/user/id`. Прекрасно!\n\nВозникает, однако, и проблема: поскольку наше приложение — одностраничное, не сконфигурировав соответствующим образом сервер мы заставим пользователей получать ошибку 404, если они перейдут по `http://oursite.com/user/id` напрямую. Вот это уже прекрасным не назвать.\n\nНе спешите расстраиваться: всё, что нужно — единственная \"резервная\" запись в конфигурации сервера. Если URL не совпадает ни с одним статическим файлом, сервер должен просто отдать `index.html`, в котором и живёт наше приложение. И снова, прекрасно!\n\n## Примеры конфигурирования серверов\n\n**Примечание**: В примерах ниже предполагается, что приложение публикуется в корневой каталог. При необходимости публикации во вложенный каталог нужно определить [опцию `publicPath` в Vue CLI](https://cli.vuejs.org/ru/config/#publicpath) и соответствующее [свойство маршрутизатора `base`](../../api/#base). Также необходимо внести изменения в примерах ниже чтобы использовать вложенный каталог вместо корневого (например, заменить `RewriteBase /` на `RewriteBase /name-of-your-subfolder/`).\n\n#### Apache\n\n```apache\n<IfModule mod_negotiation.c>\n  Options -MultiViews\n</IfModule>\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\nВместо `mod_rewrite`, вы также можете использовать [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource).\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile('index.html', 'utf-8', (err, content) => {\n    if (err) {\n      console.log('Невозможно открыть файл \"index.html\".')\n    }\n\n    res.writeHead(200, {\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log('Сервер запущен на: http://localhost:%s', httpPort)\n})\n```\n\n#### Node.js c использованием Express\n\nПри использовании Node.js/Express, мы рекомендуем пользоваться [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback).\n\n#### Internet Information Services (IIS)\n\n1. Установить [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite)\n2. Создать файл `web.config` в корневом каталоге вашего сайта со следующим содержимым:\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Хостинг Firebase\n\nДобавьте в файл `firebase.json`:\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## Предостережение\n\nПри таком подходе возникает одно неприятное последствие: ваш сервер больше не будет сообщать об ошибках 404, поскольку все найденные пути теперь возвращают `index.html`. Чтобы обойти эту проблему, вы должны реализовать специальный маршрут в своём приложении Vue, чтобы показывать страницу 404:\n\n```js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\nВ качестве альтернативы, если вы используете сервер Node.js, вы можете реализовать fallback, используя маршрутизатор на стороне сервера, чтобы сопоставлять поступающие URL и отвечать с помощью 404, если не найдено сопоставлений маршруту. Ознакомьтесь с [руководством по серверному рендерингу Vue.js](https://ssr.vuejs.org/ru/) для получения дополнительной информации.\n"
  },
  {
    "path": "docs/ru/guide/essentials/named-routes.md",
    "content": "# Именованные маршруты\n\nИногда удобнее определять маршрут по имени, особенно при привязке к маршруту или выполнении навигации. Вы можете указать для маршрута имя в опции `routes` при создании экземпляра  маршрутизатора:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nЧтобы создать ссылку на именованный маршрут, вы можете передать объект во входной параметр `to` компонента `router-link`:\n\n```html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">Пользователь</router-link>\n```\n\nТот же самый объект можно использовать и для программного вызова `router.push()`:\n\n```js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nВ обоих случаях в результате переход будет происходить на путь `/user/123`.\n\nПолный пример можно посмотреть [здесь](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs/ru/guide/essentials/named-views.md",
    "content": "# Именованные представления\n\nИногда вам необходимо отображать сразу несколько представлений, а не вкладывать одно из них в другое — например, при создании шаблона с представлением `sidebar` для боковой панели и представлением `main` для основного содержимого. В этой ситуации будет удобно использовать именованные представления. Вместо указания единственного `<router-view>`, можно использовать несколько, присвоив каждому собственное имя. Безымянный `router-view` автоматически получает имя `default`.\n\n```html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nПри использовании нескольких представлений, вместо единственного компонента при описании пути необходимо указывать объект. Убедитесь, что в ключе `components` используете окончание множественного числа (`s`):\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nРабочую демонстрацию этого примера можно найти [здесь](https://jsfiddle.net/posva/6du90epg/).\n\n## Вложенные именованные представления\n\nВозможно и создание более сложных шаблонов, используя именованные представления с вложенными представлениями. При этом вам также нужно будет именовать используемые вложенные компоненты `router-view`. Разберём на примере панели настроек:\n\n```\n/settings/emails                                       /settings/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` это просто обычный компонент\n- `UserSettings` компонент представления\n- `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` вложенные компоненты представлений\n\n**Примечание**: _Давайте опустим как должен выглядеть HTML/CSS для реализации подобного шаблона и сосредоточимся на используемых компонентах._\n\nСекция `<template>` компонента `UserSettings` будет выглядеть примерно так:\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>Настройки пользователя</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_Вложенные компоненты представлений в примере опущены, но вы можете посмотреть их полные исходные коды [здесь](https://jsfiddle.net/posva/22wgksa3/)._\n\nЗатем вы можете скомпоновать шаблона выше в конфигурации маршрута:\n\n```js\n{\n  path: '/settings',\n  // Вы могли также иметь именованные представления выше\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nРабочую демонстрацию этого примера можно найти [здесь](https://jsfiddle.net/posva/22wgksa3/).\n"
  },
  {
    "path": "docs/ru/guide/essentials/navigation.md",
    "content": "---\nsidebarDepth: 0\n---\n\n# Программная навигация\n\nПомимо декларативного использования `<router-link>` для создания ссылок в шаблоне, можно использовать маршрутизатор и программно вызывать методы его экземпляра.\n\n## `router.push(location, onComplete?, onAbort?)`\n\n**Примечание: Внутри экземпляра Vue у вас есть доступ к экземпляру маршрутизатора через `$router`. Поэтому вы можете вызвать `this.$router.push`.**\n\nДля перехода к новому URL, используйте `router.push`. Этот метод добавляет новую запись в историю навигации, что позволяет клику пользователя по кнопке \"назад\" в браузере сработать привычным образом.\n\nПри клике на `<router-link>` этот метод вызывается автоматически. Клик по `<router-link :to=\"...\">` эквивалентен программному вызову `router.push(...)`.\n\n| Декларативная запись      | Программная запись |\n| ------------------------- | ------------------ |\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\nВ качестве аргумента можно передать строку или объект, описывающий маршрут. Например:\n\n```js\n// строка\nrouter.push('home')\n\n// объект\nrouter.push({ path: 'home' })\n\n// именованный маршрут\nrouter.push({ name: 'user', params: { userId: '123' } })\n\n// со строкой запроса, получится /register?plan=private\nrouter.push({ path: 'register', query: { plan: 'private' } })\n```\n\n**Примечание**: `params` игнорируются, если указан `path`, что не является случаем с `query` приведённым в примере выше. Вместо этого, вам нужно указать `name` маршрута или вручную указать весь `path` с необходимыми параметрами:\n\n```js\nconst userId = '123'\nrouter.push({ name: 'user', params: { userId } }) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// Это НЕ БУДЕТ работать\nrouter.push({ path: '/user', params: { userId } }) // -> /user\n```\n\nТакие же правила применяются и к входному параметру `to` компонента `router-link`.\n\nС версии 2.2.0+ можно опционально указать коллбэки `onComplete` и `onAbort` в `router.push` или `router.replace` в качестве 2-го и 3-го аргументов. Эти коллбэки будут вызываться когда навигация либо успешно завершена (после того как все асинхронные хуки будут завершены), или прервана (переходом на этот же маршрут, или на другой маршрут прежде чем текущая навигация будет завершена), соответственно.\n\nС версии 3.1.0+ можно опустить 2-й и 3-й аргументы, в таком случае `router.push`/`router.replace` будут возвращать Promise, если они поддерживаются окружением.\n\n**Примечание:** если путь назначения совпадает с текущим маршрутом и меняются только параметры (например, переход из одного профиля в другой `/users/1` -> `/users/2`), вам потребуется использовать [`beforeRouteUpdate`](./dynamic-matching.md#отсnеживание-изменений-параметров) для отслеживания изменений (например, загрузки информации о пользователе).\n\n## `router.replace(location, onComplete?, onAbort?)`\n\nДействует как `router.push`, с той лишь разницей, что переход осуществляется без добавления новой записи в историю навигации, а заменяет текущую запись в нём.\n\n| Декларативная запись              | Программная запись    |\n| --------------------------------- | --------------------- |\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n## `router.go(n)`\n\nЭтот метод принимает параметром целое число, которое указывает на сколько шагов необходимо перейти по истории навигации, аналогично `window.history.go(n)`.\n\nПримеры:\n\n```js\n// перейти на одну запись вперёд, эквивалентно history.forward()\nrouter.go(1)\n\n// перейти на одну запись назад, эквивалентно history.back()\nrouter.go(-1)\n\n// перейти на 3 записи вперёд\nrouter.go(3)\n\n// если записей в истории недостаточно много, переход просто не произойдёт\nrouter.go(-100)\nrouter.go(100)\n```\n\n## Манипулирование историей переходов\n\nВы могли заметить, что `router.push`, `router.replace` и `router.go` соответствуют [`window.history.pushState`, `window.history.replaceState` и `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History), имитируя таким образом API `window.history`.\n\nПо этой причине, если вы уже знакомы с [API истории переходов браузера](https://developer.mozilla.org/en-US/docs/Web/API/History_API), то и со Vue router неожиданностей не возникнет.\n\nСтоит отметить, что методы навигации Vue router'а (`push`, `replace`, `go`) работают одинаково во всех режимах (`history`, `hash` и `abstract`).\n"
  },
  {
    "path": "docs/ru/guide/essentials/nested-routes.md",
    "content": "# Вложенные маршруты\n\nПользовательский интерфейс реальных приложений обычно представлен многоуровневой иерархией компонентов. Столь же обычно и соответствие сегментов URL некоторой структуре вложенности компонентов, например:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\nИспользуя `vue-router`, мы можем с лёгкостью выразить эти взаимоотношения при помощи вложенных путей.\n\nРассмотрим созданное в предыдущем разделе приложение:\n\n```html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n```js\nconst User = {\n  template: '<div>Пользователь {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nЗдесь `<router-view>` — это точка, в которой будет отображён компонент, соответствующий маршруту верхнего уровня. Аналогичным образом, отображаемый там компонент может и сам содержать вложенный `<router-view>`. Изменим немного шаблон компонента `User`:\n\n```js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>Пользователь {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nДля отображения компонентов в этой вложенной точке, нам понадобится опция `children` в конфигурации конструктора `VueRouter`:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        {\n          // при совпадении пути с шаблоном /user/:id/profile\n          // в <router-view> компонента User будет показан UserProfile\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // при совпадении пути с шаблоном /user/:id/posts\n          // в <router-view> компонента User будет показан UserPosts\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Обратите внимание, что вложенные пути, начинающиеся с `/`, считаются корневыми. Это позволяет задействовать вложенную структуру компонентов независимо от структуры URL.**\n\nКак вы могли заметить, опция `children` принимает обычный массив объектов конфигурации маршрутов, такой же как и сам `routes`. Таким образом, вложенность путей в теории по глубине ничем не ограничена.\n\nС текущим кодом, если перейти по пути `/user/foo`, внутри компонента `User` ничего не будет отображаться, так как не произойдёт совпадения по второй части пути. Может быть, что-то в таких случаях отобразить всё же захочется — тогда стоит указать пустой путь:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        // при совпадении пути с шаблоном /user/:id\n        // в <router-view> компонента User будет показан UserHome\n        { path: '', component: UserHome }\n\n        // ...остальные вложенные маршруты\n      ]\n    }\n  ]\n})\n```\n\nРабочую демонстрацию этого примера можно найти [здесь](https://jsfiddle.net/yyx990803/L7hscd8h/).\n"
  },
  {
    "path": "docs/ru/guide/essentials/passing-props.md",
    "content": "# Передача входных параметров в компоненты маршрута\n\nИспользование `$route` в вашем компоненте создаёт жёсткую связь с маршрутом, что ограничивает гибкость компонента, потому что он может быть использован только для определённых URL-адресов.\n\nДля разделения компонента от маршрутизатора можно использовать входные параметры (`props`):\n\n**Вместо жёсткой связи с `$route`**\n\n```js\nconst User = {\n  template: '<div>Пользователь {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n**Разделяем с помощью входных параметров**\n\n```js\nconst User = {\n  props: ['id'],\n  template: '<div>Пользователь {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // для маршрутов с именованными представлениями необходимо\n    // указывать опцию `props` для каждого именованного представления:\n    {\n      path: '/user/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nЭто позволяет использовать компонент в любом месте, а также облегчает его повторное использование и тестирование.\n\n## Булево значение\n\nКогда `props` установлено в значение `true`, значения `route.params` будут устанавливаться входными параметрами компонента.\n\n## Объект\n\nКогда `props` объект, они будут устанавливаться входными параметрами компонента как есть. Полезно, когда входные параметры являются статическими данными.\n\n```js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n## Функция\n\nВы можете создать функцию, которая вернёт объект с входными параметрами. Это позволяет вам приводить параметры к другим типам, комбинировать статические значения с значениями из маршрута, и т.д.\n\n```js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\nURL `/search?q=vue` также передаст `{query: 'vue'}` в качестве входных параметров в компонент `SearchUser`.\n\nСтарайтесь держать функции генерации входных параметров независимыми от состояния, потому что они вызываются только при изменениях маршрута. Используйте компонент обёртку, если вам нужно состояние для определения входных параметров, в таком случае Vue сможет реагировать на изменения состояния.\n\nДля более продвинутого использования, смотрите [пример](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).\n"
  },
  {
    "path": "docs/ru/guide/essentials/redirect-and-alias.md",
    "content": "# Перенаправления и псевдонимы\n\n## Перенаправления\n\nПеренаправления также определяются в конфигурации маршрутов в опции `routes`. Например, чтобы перенаправить с `/a` на `/b`:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nПеренаправление может осуществляться и на именованный маршрут:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nИли даже можно указать функцию для организации динамического перенаправления:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // в функцию в качестве аргумента передаётся маршрут\n      // возвращаемым значением должна быть строка или объект пути\n    }}\n  ]\n})\n```\n\nОбратите внимание, что [навигационные хуки](../advanced/navigation-guards.md) не применяются на маршруте, который служит для перенаправления, только на его цель. В приведённом ниже примере добавление хуков `beforeEnter` на маршрут `/a` не будет иметь никакого эффекта.\n\nДля демонстрации более сложных возможностей, обратите внимание на [этот пример](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n## Псевдонимы\n\nПри перенаправлении, если пользователь переходит по пути `/a`, то URL заменяется на `/b` и затем уже `/b` рассматривается как основной путь. В чём отличие псевдонимов?\n\n**В случае, когда псевдонимом `/a` является `/b`, при переходе пользователя на `/b`, URL останется равным `/b`, но маршрутизатор выполнит все действия так, как если бы он был равен `/a`.**\n\nВ виде конфигурации маршрутизатора вышесказанное может быть выражено так:\n\n```js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nПсевдонимы позволяют не ограничиваться вложенными структурами организуя связи URL и UI.\n\nЭтот [пример](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js) демонстрирует более продвинутое использование возможностей.\n"
  },
  {
    "path": "docs/ru/installation.md",
    "content": "# Установка\n\n## Скачивание напрямую / CDN\n\n[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) предоставляет CDN-ссылки для NPM-пакетов. Ссылка выше всегда указывает на самую последнюю версию Vue-router на NPM. Вы можете также использовать конкретную версию, используя ссылки вида  `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js`.\n<!--/email_off-->\n\nПодключите `vue-router` после Vue, и установка произойдёт автоматически:\n\n```html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n## npm\n\n```bash\nnpm install vue-router\n```\n\nПри использовании модульной системы, необходимо явно обозначить использование роутера при помощи `Vue.use()`:\n\n```js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nЭто не требуется при подключении через глобальный тег `script`.\n\n## Vue CLI\n\nЕсли проект развернут с использованием [Vue CLI](https://cli.vuejs.org/ru/), то можно добавить Vue Router в качестве плагина. Это позволит CLI сгенерировать код подключения, приведённый выше, а также добавить два маршрута для примера. **Операция установки перезапишет `App.vue`** в проекте, поэтому убедитесь что сделали резервную копию перед запуском команды:\n\n```sh\nvue add router\n```\n\n## Версия для разработки\n\nЕсли вы хотите использовать самую новую dev-сборку `vue-router`, то придётся вручную склонировать репозиторий с GitHub и запустить сборку:\n\n```bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs/zh/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Get Started →\nactionLink: /zh/installation.html\nfooter: MIT Licensed | Copyright © 2014-present Evan You, Eduardo San Martin Morote\n---\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">观看 Vue School 的关于 Vue Router 的免费视频课程 (英文)</a></div>\n\nVue Router 是 [Vue.js](http://cn.vuejs.org) 官方的路由管理器。它和 Vue.js 的核心深度集成，让构建单页面应用变得易如反掌。包含的功能有：\n\n- 嵌套的路由/视图表\n- 模块化的、基于组件的路由配置\n- 路由参数、查询、通配符\n- 基于 Vue.js 过渡系统的视图过渡效果\n- 细粒度的导航控制\n- 带有自动激活的 CSS class 的链接\n- HTML5 历史模式或 hash 模式，在 IE9 中自动降级\n- 自定义的滚动条行为\n\n现在开始[起步](./guide/)或尝试一下我们的[示例](https://github.com/vuejs/vue-router/tree/dev/examples)吧 (查看仓库的 [`README.md`](https://github.com/vuejs/vue-router/) 来运行它们)。\n\n<HomeSponsors />\n"
  },
  {
    "path": "docs/zh/api/README.md",
    "content": "---\nsidebar: auto\n---\n\n# API 参考\n\n## `<router-link>`\n\n`<router-link>` 组件支持用户在具有路由功能的应用中 (点击) 导航。\n通过 `to` 属性指定目标地址，默认渲染成带有正确链接的 `<a>` 标签，可以通过配置 `tag` 属性生成别的标签.。另外，当目标路由成功激活时，链接元素自动设置一个表示激活的 CSS 类名。\n\n`<router-link>` 比起写死的 `<a href=\"...\">` 会好一些，理由如下：\n\n- 无论是 HTML5 history 模式还是 hash 模式，它的表现行为一致，所以，当你要切换路由模式，或者在 IE9 降级使用 hash 模式，无须作任何变动。\n- 在 HTML5 history 模式下，`router-link` 会守卫点击事件，让浏览器不再重新加载页面。\n- 当你在 HTML5 history 模式下使用 `base` 选项之后，所有的 `to` 属性都不需要写 (基路径) 了。\n\n### `v-slot` API (3.1.0 新增)\n\n`router-link` 通过一个[作用域插槽](https://cn.vuejs.org/v2/guide/components-slots.html#作用域插槽)暴露底层的定制能力。这是一个更高阶的 API，主要面向库作者，但也可以为开发者提供便利，多数情况用在一个类似 _NavLink_ 这样的自定义组件里。\n\n**在使用 `v-slot` API 时，需要向 `router-link` 传入一个单独的子元素**。否则 `router-link` 将会把子元素包裹在一个 `span` 元素内。\n\n```html\n<router-link\n  to=\"/about\"\n  custom\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n>\n  <NavLink :active=\"isActive\" :href=\"href\" @click=\"navigate\"\n    >{{ route.fullPath }}</NavLink\n  >\n</router-link>\n```\n\n- `href`：解析后的 URL。将会作为一个 `a` 元素的 `href` attribute。\n- `route`：解析后的规范化的地址。\n- `navigate`：触发导航的函数。**会在必要时自动阻止事件**，和 `router-link` 同理。\n- `isActive`：如果需要应用[激活的 class](#active-class) 则为 `true`。允许应用一个任意的 class。\n- `isExactActive`：如果需要应用[精确激活的 class](#exact-active-class) 则为 `true`。允许应用一个任意的 class。\n\n### 示例：将激活的 class 应用在外层元素\n\n有的时候我们可能想把激活的 class 应用到一个外部元素而不是 `<a>` 标签本身，这时你可以在一个 `router-link` 中包裹该元素并使用 `v-slot` property 来创建链接：\n\n```html\n<router-link\n  to=\"/foo\"\n  v-slot=\"{ href, route, navigate, isActive, isExactActive }\"\n  custom\n>\n  <li\n    :class=\"[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']\"\n  >\n    <a :href=\"href\" @click=\"navigate\">{{ route.fullPath }}</a>\n  </li>\n</router-link>\n```\n\n:::tip 提示\n如果你在 `<a>` 元素上添加一个 `target=\"_blank\"`，则 `@click=\"navigate\"` 处理器会被忽略。\n:::\n\n## `<router-link>` Props\n\n### to\n\n- 类型: `string | Location`\n- required\n\n  表示目标路由的链接。当被点击后，内部会立刻把 `to` 的值传到 `router.push()`，所以这个值可以是一个字符串或者是描述目标位置的对象。\n\n  ```html\n  <!-- 字符串 -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- 渲染结果 -->\n  <a href=\"home\">Home</a>\n\n  <!-- 使用 v-bind 的 JS 表达式 -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- 不写 v-bind 也可以，就像绑定别的属性一样 -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- 同上 -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- 命名的路由 -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- 带查询参数，下面的结果为 /register?plan=private -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\"\n    >Register</router-link\n  >\n  ```\n\n### replace\n\n- 类型: `boolean`\n- 默认值: `false`\n\n  设置 `replace` 属性的话，当点击时，会调用 `router.replace()` 而不是 `router.push()`，于是导航后不会留下 history 记录。\n\n  ```html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n### append\n\n- 类型: `boolean`\n- 默认值: `false`\n\n  设置 `append` 属性后，则在当前 (相对) 路径前添加基路径。例如，我们从 `/a` 导航到一个相对路径 `b`，如果没有配置 `append`，则路径为 `/b`，如果配了，则为 `/a/b`\n\n  ```html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n### tag\n\n- 类型: `string`\n- 默认值: `\"a\"`\n\n  有时候想要 `<router-link>` 渲染成某种标签，例如 `<li>`。\n  于是我们使用 `tag` prop 类指定何种标签，同样它还是会监听点击，触发导航。\n\n  ```html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- 渲染结果 -->\n  <li>foo</li>\n  ```\n\n### active-class\n\n- 类型: `string`\n- 默认值: `\"router-link-active\"`\n\n  设置链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 `linkActiveClass` 来全局配置。\n\n### exact\n\n- 类型: `boolean`\n- 默认值: `false`\n\n  “是否激活”默认类名的依据是**包含匹配**。\n  举个例子，如果当前的路径是 `/a` 开头的，那么 `<router-link to=\"/a\">` 也会被设置 CSS 类名。\n\n  按照这个规则，每个路由都会激活 `<router-link to=\"/\">`！想要链接使用“精确匹配模式”，则使用 `exact` 属性：\n\n  ```html\n  <!-- 这个链接只会在地址为 / 的时候被激活 -->\n  <router-link to=\"/\" exact></router-link>\n  ```\n\n  查看更多关于激活链接类名的例子[可运行](https://jsfiddle.net/8xrk1n9f/)\n\n### event\n\n- 类型: `string | Array<string>`\n- 默认值: `'click'`\n\n  声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。\n\n### exact-active-class\n\n- 类型: `string`\n- 默认值: `\"router-link-exact-active\"`\n\n  配置当链接被精确匹配的时候应该激活的 class。注意默认值也是可以通过路由构造函数选项 `linkExactActiveClass` 进行全局配置的。\n\n### aria-current-value\n\n- 类型: `'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false'`\n- 默认值: `\"page\"`\n\n  当链接根据精确匹配规则激活时配置的 `aria-current` 的值。这个值应该是 ARIA 规范中[允许的 aria-current 的值](https://www.w3.org/TR/wai-aria-1.2/#aria-current)。在绝大多数场景下，默认值 `page` 应该是最合适的。\n\n## `<router-view>`\n\n`<router-view>` 组件是一个 functional 组件，渲染路径匹配到的视图组件。`<router-view>` 渲染的组件还可以内嵌自己的 `<router-view>`，根据嵌套路径，渲染嵌套组件。\n\n其他属性 (非 router-view 使用的属性) 都直接传给渲染的组件，\n很多时候，每个路由的数据都是包含在路由参数中。\n\n因为它也是个组件，所以可以配合 `<transition>` 和 `<keep-alive>` 使用。如果两个结合一起用，要确保在内层使用 `<keep-alive>`：\n\n```html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n\n## `<router-view>` Props\n\n### name\n\n- 类型: `string`\n- 默认值: `\"default\"`\n\n  如果 `<router-view>`设置了名称，则会渲染对应的路由配置中 `components` 下的相应组件。查看 [命名视图](../guide/essentials/named-views.md) 中的例子。\n\n## Router 构建选项\n\n### routes\n\n- 类型: `Array<RouteConfig>`\n\n  `RouteConfig` 的类型定义：\n\n  ```ts\n  interface RouteConfig = {\n    path: string,\n    component?: Component,\n    name?: string, // 命名路由\n    components?: { [name: string]: Component }, // 命名视图组件\n    redirect?: string | Location | Function,\n    props?: boolean | Object | Function,\n    alias?: string | Array<string>,\n    children?: Array<RouteConfig>, // 嵌套路由\n    beforeEnter?: (to: Route, from: Route, next: Function) => void,\n    meta?: any,\n\n    // 2.6.0+\n    caseSensitive?: boolean, // 匹配规则是否大小写敏感？(默认值：false)\n    pathToRegexpOptions?: Object // 编译正则的选项\n  }\n  ```\n\n### mode\n\n- 类型: `string`\n- 默认值: `\"hash\" (浏览器环境) | \"abstract\" (Node.js 环境)`\n- 可选值: `\"hash\" | \"history\" | \"abstract\"`\n\n  配置路由模式:\n\n  - `hash`: 使用 URL hash 值来作路由。支持所有浏览器，包括不支持 HTML5 History Api 的浏览器。\n\n  - `history`: 依赖 HTML5 History API 和服务器配置。查看 [HTML5 History 模式](../guide/essentials/history-mode.md)。\n\n  - `abstract`: 支持所有 JavaScript 运行环境，如 Node.js 服务器端。**如果发现没有浏览器的 API，路由会自动强制进入这个模式。**\n\n### base\n\n- 类型: `string`\n\n- 默认值: `\"/\"`\n\n  应用的基路径。例如，如果整个单页应用服务在 `/app/` 下，然后 `base` 就应该设为 `\"/app/\"`。\n\n### linkActiveClass\n\n- 类型: `string`\n\n- 默认值: `\"router-link-active\"`\n\n  全局配置 `<router-link>` 默认的激活的 class。参考 [router-link](#router-link)。\n\n### linkExactActiveClass\n\n- 类型: `string`\n\n- 默认值: `\"router-link-exact-active\"`\n\n  全局配置 `<router-link>` 默认的精确激活的 class。可同时翻阅 [router-link](#router-link)。\n\n### scrollBehavior\n\n- 类型: `Function`\n\n  签名:\n\n  ```ts\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    void\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  更多详情参考[滚动行为](../guide/advanced/scroll-behavior.md)。\n\n### parseQuery / stringifyQuery\n\n- 类型: `Function`\n\n  提供自定义查询字符串的解析/反解析函数。覆盖默认行为。\n\n### fallback\n\n- 类型: `boolean`\n\n- 默认值: `true`\n\n  当浏览器不支持 `history.pushState` 控制路由是否应该回退到 `hash` 模式。默认值为 `true`。\n\n  在 IE9 中，设置为 `false` 会使得每个 `router-link` 导航都触发整页刷新。它可用于工作在 IE9 下的服务端渲染应用，因为一个 hash 模式的 URL 并不支持服务端渲染。\n\n## Router 实例属性\n\n### router.app\n\n- 类型: `Vue instance`\n\n  配置了 `router` 的 Vue 根实例。\n\n### router.mode\n\n- 类型: `string`\n\n  路由使用的[模式](#mode)。\n\n### router.currentRoute\n\n- 类型: `Route`\n\n  当前路由对应的[路由信息对象](#路由对象)。\n\n### router.START_LOCATION\n\n- 类型：`Route`\n\n  以[路由对象](#路由对象)的格式展示初始路由地址，即路由开始的地方。可用在导航守卫中以区分初始导航。\n\n  ```js\n  import VueRouter from 'vue-router'\n\n  const router = new VueRouter({\n    // ...\n  })\n\n  router.beforeEach((to, from) => {\n    if (from === VueRouter.START_LOCATION) {\n      // 初始导航\n    }\n  })\n  ```\n\n## Router 实例方法\n\n### router.beforeEach\n\n### router.beforeResolve\n\n### router.afterEach\n\n函数签名：\n\n```js\nrouter.beforeEach((to, from, next) => {\n  /* 必须调用 `next` */\n})\n\nrouter.beforeResolve((to, from, next) => {\n  /* 必须调用 `next` */\n})\n\nrouter.afterEach((to, from) => {})\n```\n\n增加全局的导航守卫。参考[导航守卫](../guide/advanced/navigation-guards.md)。\n\n在 2.5.0+ 这三个方法都返回一个移除已注册的守卫/钩子的函数。\n\n### router.push\n\n### router.replace\n\n### router.go\n\n### router.back\n\n### router.forward\n\n函数签名：\n\n```js\nrouter.push(location, onComplete?, onAbort?)\nrouter.push(location).then(onComplete).catch(onAbort)\nrouter.replace(location, onComplete?, onAbort?)\nrouter.replace(location).then(onComplete).catch(onAbort)\nrouter.go(n)\nrouter.back()\nrouter.forward()\n```\n\n动态的导航到一个新 URL。参考[编程式导航](../guide/essentials/navigation.md)。\n\n这些函数仅在安装路由插件并将其传递给 Vue 根实例后调用，如[起步](../guide/README.md)所示。\n\n### router.getMatchedComponents\n\n函数签名：\n\n```js\nconst matchedComponents: Array<Component> = router.getMatchedComponents(location?)\n```\n\n返回目标位置或是当前路由匹配的组件数组 (是数组的定义/构造类，不是实例)。通常在服务端渲染的数据预加载时使用。\n\n### router.resolve\n\n函数签名：\n\n```js\nconst resolved: {\n  location: Location;\n  route: Route;\n  href: string;\n} = router.resolve(location, current?, append?)\n```\n\n解析目标位置 (格式和 `<router-link>` 的 `to` prop 一样)。\n\n- `current` 是当前默认的路由 (通常你不需要改变它)\n- `append` 允许你在 `current` 路由上附加路径 (如同 [`router-link`](#router-link.md-props))\n\n### router.addRoutes\n\n*已废弃*：使用 [`router.addRoute()`](#router-addroute) 代替。\n\n函数签名：\n\n```js\nrouter.addRoutes(routes: Array<RouteConfig>)\n```\n\n动态添加更多的路由规则。参数必须是一个符合 `routes` 选项要求的数组。\n\n### router.addRoute\n\n添加一条新路由规则。如果该路由规则有 `name`，并且已经存在一个与之相同的名字，则会覆盖它。\n\n函数签名:\n\n```ts\naddRoute(route: RouteConfig): () => void\n```\n\n### router.addRoute\n\n添加一条新的路由规则记录作为现有路由的子路由。如果该路由规则有 `name`，并且已经存在一个与之相同的名字，则会覆盖它。\n\n函数签名:\n\n```ts\naddRoute(parentName: string, route: RouteConfig): () => void\n```\n\n### router.getRoutes\n\n获取所有活跃的路由记录列表。**注意只有文档中记录下来的 property 才被视为公共 API**，避免使用任何其它 property，例如 `regex`，因为它在 Vue Router 4 中不存在。\n\n函数签名:\n\n```ts\ngetRoutes(): RouteRecord[]\n```\n\n### router.onReady\n\n函数签名：\n\n```js\nrouter.onReady(callback, [errorCallback])\n```\n\n该方法把一个回调排队，在路由完成初始导航时调用，这意味着它可以解析所有的异步进入钩子和路由初始化相关联的异步组件。\n\n这可以有效确保服务端渲染时服务端和客户端输出的一致。\n\n第二个参数 `errorCallback` 只在 2.4+ 支持。它会在初始化路由解析运行出错 (比如解析一个异步组件失败) 时被调用。\n\n### router.onError\n\n函数签名：\n\n```js\nrouter.onError(callback)\n```\n\n注册一个回调，该回调会在路由导航过程中出错时被调用。注意被调用的错误必须是下列情形中的一种：\n\n- 错误在一个路由守卫函数中被同步抛出；\n\n- 错误在一个路由守卫函数中通过调用 `next(err)` 的方式异步捕获并处理；\n\n- 渲染一个路由的过程中，需要尝试解析一个异步组件时发生错误。\n\n## 路由对象\n\n一个**路由对象 (route object)** 表示当前激活的路由的状态信息，包含了当前 URL 解析得到的信息，还有 URL 匹配到的**路由记录 (route records)**。\n\n路由对象是不可变 (immutable) 的，每次成功的导航后都会产生一个新的对象。\n\n路由对象出现在多个地方:\n\n- 在组件内，即 `this.$route`\n\n- 在 `$route` 观察者回调内\n\n- `router.match(location)` 的返回值\n\n- 导航守卫的参数：\n\n  ```js\n  router.beforeEach((to, from, next) => {\n    // `to` 和 `from` 都是路由对象\n  })\n  ```\n\n- `scrollBehavior` 方法的参数:\n\n  ```js\n  const router = new VueRouter({\n    scrollBehavior(to, from, savedPosition) {\n      // `to` 和 `from` 都是路由对象\n    }\n  })\n  ```\n\n### 路由对象属性\n\n- **\\$route.path**\n\n  - 类型: `string`\n\n    字符串，对应当前路由的路径，总是解析为绝对路径，如 `\"/foo/bar\"`。\n\n- **\\$route.params**\n\n  - 类型: `Object`\n\n    一个 key/value 对象，包含了动态片段和全匹配片段，如果没有路由参数，就是一个空对象。\n\n- **\\$route.query**\n\n  - 类型: `Object`\n\n    一个 key/value 对象，表示 URL 查询参数。例如，对于路径 `/foo?user=1`，则有 `$route.query.user == 1`，如果没有查询参数，则是个空对象。\n\n- **\\$route.hash**\n\n  - 类型: `string`\n\n    当前路由的 hash 值 (带 `#`) ，如果没有 hash 值，则为空字符串。\n\n- **\\$route.fullPath**\n\n  - 类型: `string`\n\n    完成解析后的 URL，包含查询参数和 hash 的完整路径。\n\n- **\\$route.matched**\n\n  - 类型: `Array<RouteRecord>`\n\n  一个数组，包含当前路由的所有嵌套路径片段的**路由记录** 。路由记录就是 `routes` 配置数组中的对象副本 (还有在 `children` 数组)。\n\n  ```js\n  const router = new VueRouter({\n    routes: [\n      // 下面的对象就是路由记录\n      {\n        path: '/foo',\n        component: Foo,\n        children: [\n          // 这也是个路由记录\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  当 URL 为 `/foo/bar`，`$route.matched` 将会是一个包含从上到下的所有对象 (副本)。\n\n- **\\$route.name**\n\n  当前路由的名称，如果有的话。(查看[命名路由](../guide/essentials/named-routes.md))\n\n- **\\$route.redirectedFrom**\n\n  如果存在重定向，即为重定向来源的路由的名字。(参阅[重定向和别名](../guide/essentials/redirect-and-alias.md))\n\n## 组件注入\n\n### 注入的属性\n\n通过在 Vue 根实例的 `router` 配置传入 router 实例，下面这些属性成员会被注入到每个子组件。\n\n- **this.\\$router**\n\n  router 实例。\n\n- **this.\\$route**\n\n  当前激活的[路由信息对象](#路由对象)。这个属性是只读的，里面的属性是 immutable (不可变) 的，不过你可以 watch (监测变化) 它。\n\n### 增加的组件配置选项\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate**\n- **beforeRouteLeave**\n\n  查看[组件内的守卫](../guide/advanced/navigation-guards.md#组件内的守卫)。\n"
  },
  {
    "path": "docs/zh/guide/README.md",
    "content": "# 起步\n\n::: tip 注意\n教程中的案例代码将使用 [ES2015](https://github.com/lukehoban/es6features) 来编写。\n\n同时，所有的例子都将使用完整版的 Vue 以解析模板。更多细节请[移步这里](https://cn.vuejs.org/v2/guide/installation.html#运行时-编译器-vs-只包含运行时)。\n:::\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to build powerful Single Page Applications with the Vue Router on Vue School\">观看 Vue School 的关于 Vue Router 的免费视频课程 (英文)</a></div>\n\n用 Vue.js + Vue Router 创建单页应用，感觉很自然：使用 Vue.js ，我们已经可以通过组合组件来组成应用程序，当你要把 Vue Router 添加进来，我们需要做的是，将组件 (components) 映射到路由 (routes)，然后告诉 Vue Router 在哪里渲染它们。下面是个基本例子：\n\n## HTML\n\n```html\n<script src=\"https://unpkg.com/vue@2/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router@3/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- 使用 router-link 组件来导航. -->\n    <!-- 通过传入 `to` 属性指定链接. -->\n    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- 路由出口 -->\n  <!-- 路由匹配到的组件将渲染在这里 -->\n  <router-view></router-view>\n</div>\n```\n\n## JavaScript\n\n```js\n// 0. 如果使用模块化机制编程，导入Vue和VueRouter，要调用 Vue.use(VueRouter)\n\n// 1. 定义 (路由) 组件。\n// 可以从其他文件 import 进来\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. 定义路由\n// 每个路由应该映射一个组件。 其中\"component\" 可以是\n// 通过 Vue.extend() 创建的组件构造器，\n// 或者，只是一个组件配置对象。\n// 我们晚点再讨论嵌套路由。\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. 创建 router 实例，然后传 `routes` 配置\n// 你还可以传别的配置参数, 不过先这么简单着吧。\nconst router = new VueRouter({\n  routes // (缩写) 相当于 routes: routes\n})\n\n// 4. 创建和挂载根实例。\n// 记得要通过 router 配置参数注入路由，\n// 从而让整个应用都有路由功能\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// 现在，应用已经启动了！\n```\n\n通过注入路由器，我们可以在任何组件内通过 `this.$router` 访问路由器，也可以通过 `this.$route` 访问当前路由：\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username() {\n      // 我们很快就会看到 `params` 是什么\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack() {\n      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')\n    }\n  }\n}\n```\n\n该文档通篇都常使用 `router` 实例。留意一下 `this.$router` 和 `router` 使用起来完全一样。我们使用 `this.$router` 的原因是我们并不想在每个独立需要封装路由的组件中都导入路由。\n\n你可以看看这个[在线的](https://jsfiddle.net/yyx990803/xgrjzsup/)例子。\n\n要注意，当 `<router-link>` 对应的路由匹配成功，将自动设置 class 属性值 `.router-link-active`。查看 [API 文档](../api/#router-link) 学习更多相关内容。\n"
  },
  {
    "path": "docs/zh/guide/advanced/data-fetching.md",
    "content": "# 数据获取\n\n有时候，进入某个路由后，需要从服务器获取数据。例如，在渲染用户信息时，你需要从服务器获取用户的数据。我们可以通过两种方式来实现：\n\n- **导航完成之后获取**：先完成导航，然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。\n\n- **导航完成之前获取**：导航完成前，在路由进入的守卫中获取数据，在数据获取成功后执行导航。\n\n从技术角度讲，两种方式都不错 —— 就看你想要的用户体验是哪种。\n\n## 导航完成后获取数据\n\n当你使用这种方式时，我们会马上导航和渲染组件，然后在组件的 `created` 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态，还可以在不同视图间展示不同的 loading 状态。\n\n假设我们有一个 `Post` 组件，需要基于 `$route.params.id` 获取文章数据：\n\n``` html\n<template>\n  <div class=\"post\">\n    <div v-if=\"loading\" class=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // 组件创建完后获取数据，\n    // 此时 data 已经被 observed 了\n    this.fetchData()\n  },\n  watch: {\n    // 如果路由有变化，会再次执行该方法\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // replace getPost with your data fetching util / API wrapper\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## 在导航完成前获取数据\n\n通过这种方式，我们在导航转入新的路由前获取数据。我们可以在接下来的组件的  `beforeRouteEnter` 守卫中获取数据，当数据获取成功后只调用 `next` 方法。\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // 路由改变前，组件就已经渲染完了\n  // 逻辑稍稍不同\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\n在为后面的视图获取数据时，用户会停留在当前的界面，因此建议在数据获取期间，显示一些进度条或者别的指示。如果数据获取失败，同样有必要展示一些全局的错误提醒。\n"
  },
  {
    "path": "docs/zh/guide/advanced/lazy-loading.md",
    "content": "# 路由懒加载\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-lazy-load-routes-with-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to increase performance by lazy loading routes on Vue School\">观看 Vue School 的如何路由懒加载的免费视频课程 (英文)</a></div>\n\n当打包构建应用时，JavaScript 包会变得非常大，影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块，然后当路由被访问的时候才加载对应组件，这样就更加高效了。\n\n结合 Vue 的[异步组件](https://cn.vuejs.org/v2/guide/components-dynamic-async.html#异步组件)和 Webpack 的[代码分割功能](https://doc.webpack-china.org/guides/code-splitting-async/#require-ensure-/)，轻松实现路由组件的懒加载。\n\n首先，可以将异步组件定义为返回一个 Promise 的工厂函数 (该函数返回的 Promise 应该 resolve 组件本身)：\n\n```js\nconst Foo = () =>\n  Promise.resolve({\n    /* 组件定义对象 */\n  })\n```\n\n第二，在 Webpack 2 中，我们可以使用[动态 import](https://github.com/tc39/proposal-dynamic-import)语法来定义代码分块点 (split point)：\n\n```js\nimport('./Foo.vue') // 返回 Promise\n```\n\n::: tip 注意\n如果您使用的是 Babel，你将需要添加 [`syntax-dynamic-import`](https://babeljs.io/docs/plugins/syntax-dynamic-import/) 插件，才能使 Babel 可以正确地解析语法。\n:::\n\n结合这两者，这就是如何定义一个能够被 Webpack 自动代码分割的异步组件。\n\n```js\nconst Foo = () => import('./Foo.vue')\n```\n\n在路由配置中什么都不需要改变，只需要像往常一样使用 `Foo`：\n\n```js\nconst router = new VueRouter({\n  routes: [{ path: '/foo', component: Foo }]\n})\n```\n\n## 把组件按组分块\n\n有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 [命名 chunk](https://webpack.js.org/guides/code-splitting-require/#chunkname)，一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。\n\n```js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nWebpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。\n"
  },
  {
    "path": "docs/zh/guide/advanced/meta.md",
    "content": "# 路由元信息\n\n定义路由的时候可以配置 `meta` 字段：\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // a meta field\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\n那么如何访问这个 `meta` 字段呢？\n\n首先，我们称呼 `routes` 配置中的每个路由对象为 **路由记录**。路由记录可以是嵌套的，因此，当一个路由匹配成功后，他可能匹配多个路由记录\n\n例如，根据上面的路由配置，`/foo/bar` 这个 URL 将会匹配父路由记录以及子路由记录。\n\n一个路由匹配到的所有路由记录会暴露为 `$route` 对象 (还有在导航守卫中的路由对象) 的 `$route.matched` 数组。因此，我们需要遍历 `$route.matched` 来检查路由记录中的 `meta` 字段。\n\n下面例子展示在全局导航守卫中检查元字段：\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // this route requires auth, check if logged in\n    // if not, redirect to login page.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // 确保一定要调用 next()\n  }\n})\n```\n"
  },
  {
    "path": "docs/zh/guide/advanced/navigation-failures.md",
    "content": "# 导航故障\n\n> 3.4.0中新增\n\n::: tip 译者注\n*导航故障*，或者叫*导航失败*，表示一次失败的导航，原文叫 navigation failures，本文统一采用*导航故障*。\n:::\n\n当使用 `router-link` 组件时，Vue Router 会自动调用 `router.push` 来触发一次导航。 虽然大多数链接的预期行为是将用户导航到一个新页面，但也有少数情况下用户将留在同一页面上：\n\n- 用户已经位于他们正在尝试导航到的页面\n- 一个[导航守卫](./navigation-guards.md)通过调用 `next(false)` 中断了这次导航\n- 一个[导航守卫](./navigation-guards.md)抛出了一个错误，或者调用了 `next(new Error())`\n\n当使用 `router-link` 组件时，**这些失败都不会打印出错误**。然而，如果你使用 `router.push` 或者 `router.replace` 的话，可能会在控制台看到一条 _\"Uncaught (in promise) Error\"_ 这样的错误，后面跟着一条更具体的消息。让我们来了解一下如何区分*导航故障*。\n\n::: tip 背景故事\n在 v3.2.0 中，可以通过使用 `router.push` 的两个可选的回调函数：`onComplete` 和 `onAbort` 来暴露*导航故障*。从版本 3.1.0 开始，`router.push` 和 `router.replace` 在没有提供 `onComplete`/`onAbort` 回调的情况下会返回一个 *Promise*。这个 *Promise* 的 resolve 和 reject 将分别用来代替 `onComplete` 和 `onAbort` 的调用。\n:::\n\n\n## 检测导航故障\n\n*导航故障*是一个 `Error` 实例，附带了一些额外的属性。要检查一个错误是否来自于路由器，可以使用 `isNavigationFailure` 函数：\n\n```js\nimport VueRouter from 'vue-router'\nconst { isNavigationFailure, NavigationFailureType } = VueRouter\n\n// 正在尝试访问 admin 页面\nrouter.push('/admin').catch(failure => {\n  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n    // 向用户显示一个小通知\n    showToast('Login in order to access the admin panel')\n  }\n})\n```\n\n::: tip\n如果你忽略第二个参数：`isNavigationFailure(failure)`，那么就只会检查这个错误是不是一个*导航故障*。\n:::\n\n## `NavigationFailureType`\n\n`NavigationFailureType` 可以帮助开发者来区分不同类型的*导航故障*。有四种不同的类型：\n\n- `redirected`：在导航守卫中调用了 `next(newLocation)` 重定向到了其他地方。\n- `aborted`：在导航守卫中调用了 `next(false)` 中断了本次导航。\n- `cancelled`：在当前导航还没有完成之前又有了一个新的导航。比如，在等待导航守卫的过程中又调用了 `router.push`。\n- `duplicated`：导航被阻止，因为我们已经在目标位置了。\n\n## *导航故障*的属性\n\n所有的导航故障都会有 `to` 和 `from` 属性，分别用来表达这次失败的导航的目标位置和当前位置。\n\n```js\n// 正在尝试访问 admin 页面\nrouter.push('/admin').catch(failure => {\n  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {\n    failure.to.path // '/admin'\n    failure.from.path // '/'\n  }\n})\n```\n\n在所有情况下，`to` 和 `from` 都是规范化的路由位置。\n"
  },
  {
    "path": "docs/zh/guide/advanced/navigation-guards.md",
    "content": "# 导航守卫\n\n::: tip 译者注\n“导航”表示路由正在发生改变。\n:::\n\n正如其名，`vue-router` 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中：全局的, 单个路由独享的, 或者组件级的。\n\n记住**参数或查询的改变并不会触发进入/离开的导航守卫**。你可以通过[观察 `$route` 对象](../essentials/dynamic-matching.md#响应路由参数的变化)来应对这些变化，或使用 `beforeRouteUpdate` 的组件内守卫。\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-configure-an-authentication-middleware-route-guard-with-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to create an authentication middleware with a global route guard on Vue School\">观看 Vue School 的导航守卫如何工作的免费视频课程 (英文)</a></div>\n\n## 全局前置守卫\n\n你可以使用 `router.beforeEach` 注册一个全局前置守卫：\n\n```js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\n当一个导航触发时，全局前置守卫按照创建顺序调用。守卫是异步解析执行，此时导航在所有守卫 resolve 完之前一直处于 **等待中**。\n\n每个守卫方法接收三个参数：\n\n- **`to: Route`**: 即将要进入的目标 [路由对象](../../api/#路由对象)\n\n- **`from: Route`**: 当前导航正要离开的路由\n\n- **`next: Function`**: 一定要调用该方法来 **resolve** 这个钩子。执行效果依赖 `next` 方法的调用参数。\n\n  - **`next()`**: 进行管道中的下一个钩子。如果全部钩子执行完了，则导航的状态就是 **confirmed** (确认的)。\n\n  - **`next(false)`**: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮)，那么 URL 地址会重置到 `from` 路由对应的地址。\n\n  - **`next('/')` 或者 `next({ path: '/' })`**: 跳转到一个不同的地址。当前的导航被中断，然后进行一个新的导航。你可以向 `next` 传递任意位置对象，且允许设置诸如 `replace: true`、`name: 'home'` 之类的选项以及任何用在 [`router-link` 的 `to` prop](../../api/#to) 或 [`router.push`](../../api/#router-push) 中的选项。\n\n  - **`next(error)`**: (2.4.0+) 如果传入 `next` 的参数是一个 `Error` 实例，则导航会被终止且该错误会被传递给 [`router.onError()`](../../api/#router-onerror) 注册过的回调。\n\n**确保 `next` 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次，但是只能在所有的逻辑路径都不重叠的情况下，否则钩子永远都不会被解析或报错**。这里有一个在用户未能验证身份时重定向到 `/login` 的示例：\n\n```js\n// BAD\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  // 如果用户未能验证身份，则 `next` 会被调用两次\n  next()\n})\n```\n\n```js\n// GOOD\nrouter.beforeEach((to, from, next) => {\n  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })\n  else next()\n})\n```\n\n## 全局解析守卫\n\n> 2.5.0 新增\n\n在 2.5.0+ 你可以用 `router.beforeResolve` 注册一个全局守卫。这和 `router.beforeEach` 类似，区别是在导航被确认之前，**同时在所有组件内守卫和异步路由组件被解析之后**，解析守卫就被调用。\n\n## 全局后置钩子\n\n你也可以注册全局后置钩子，然而和守卫不同的是，这些钩子不会接受 `next` 函数也不会改变导航本身：\n\n```js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n## 路由独享的守卫\n\n你可以在路由配置上直接定义 `beforeEnter` 守卫：\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\n这些守卫与全局前置守卫的方法参数是一样的。\n\n## 组件内的守卫\n\n最后，你可以在路由组件内直接定义以下路由导航守卫：\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (2.2 新增)\n- `beforeRouteLeave`\n\n```js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter(to, from, next) {\n    // 在渲染该组件的对应路由被 confirm 前调用\n    // 不！能！获取组件实例 `this`\n    // 因为当守卫执行前，组件实例还没被创建\n  },\n  beforeRouteUpdate(to, from, next) {\n    // 在当前路由改变，但是该组件被复用时调用\n    // 举例来说，对于一个带有动态参数的路径 /foo/:id，在 /foo/1 和 /foo/2 之间跳转的时候，\n    // 由于会渲染同样的 Foo 组件，因此组件实例会被复用。而这个钩子就会在这个情况下被调用。\n    // 可以访问组件实例 `this`\n  },\n  beforeRouteLeave(to, from, next) {\n    // 导航离开该组件的对应路由时调用\n    // 可以访问组件实例 `this`\n  }\n}\n```\n\n`beforeRouteEnter` 守卫 **不能** 访问 `this`，因为守卫在导航确认前被调用，因此即将登场的新组件还没被创建。\n\n不过，你可以通过传一个回调给 `next`来访问组件实例。在导航被确认的时候执行回调，并且把组件实例作为回调方法的参数。\n\n```js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // 通过 `vm` 访问组件实例\n  })\n}\n```\n\n注意 `beforeRouteEnter` 是支持给 `next` 传递回调的唯一守卫。对于 `beforeRouteUpdate` 和 `beforeRouteLeave` 来说，`this` 已经可用了，所以**不支持**传递回调，因为没有必要了。\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // just use `this`\n  this.name = to.params.name\n  next()\n}\n```\n\n这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 `next(false)` 来取消。\n\n```js\nbeforeRouteLeave (to, from, next) {\n  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\n## 完整的导航解析流程\n\n1. 导航被触发。\n2. 在失活的组件里调用 `beforeRouteLeave` 守卫。\n3. 调用全局的 `beforeEach` 守卫。\n4. 在重用的组件里调用 `beforeRouteUpdate` 守卫 (2.2+)。\n5. 在路由配置里调用 `beforeEnter`。\n6. 解析异步路由组件。\n7. 在被激活的组件里调用 `beforeRouteEnter`。\n8. 调用全局的 `beforeResolve` 守卫 (2.5+)。\n9. 导航被确认。\n10. 调用全局的 `afterEach` 钩子。\n11. 触发 DOM 更新。\n12. 调用 `beforeRouteEnter` 守卫中传给 `next` 的回调函数，创建好的组件实例会作为回调函数的参数传入。\n"
  },
  {
    "path": "docs/zh/guide/advanced/scroll-behavior.md",
    "content": "# 滚动行为\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-control-the-scroll-behavior-of-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to control the scroll behavior on Vue School\">观看 Vue School 的如何控制滚动行为的免费视频课程 (英文)</a></div>\n\n使用前端路由，当切换到新路由时，想要页面滚到顶部，或者是保持原先的滚动位置，就像重新加载页面那样。 `vue-router` 能做到，而且更好，它让你可以自定义路由切换时页面如何滚动。\n\n**注意: 这个功能只在支持 `history.pushState` 的浏览器中可用。**\n\n当创建一个 Router 实例，你可以提供一个 `scrollBehavior` 方法：\n\n```js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // return 期望滚动到哪个的位置\n  }\n})\n```\n\n`scrollBehavior` 方法接收 `to` 和 `from` 路由对象。第三个参数 `savedPosition` 当且仅当 `popstate` 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。\n\n这个方法返回滚动位置的对象信息，长这样：\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset 只在 2.6.0+ 支持)\n\n如果返回一个 falsy (译者注：falsy 不是 `false`，[参考这里](https://developer.mozilla.org/zh-CN/docs/Glossary/Falsy))的值，或者是一个空对象，那么不会发生滚动。\n\n举例：\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\n对于所有路由导航，简单地让页面滚动到顶部。\n\n返回 `savedPosition`，在按下 后退/前进 按钮时，就会像浏览器的原生表现那样：\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\n如果你要模拟“滚动到锚点”的行为：\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n    }\n  }\n}\n```\n\n我们还可以利用[路由元信息](meta.md)更细颗粒度地控制滚动。查看完整例子请[移步这里](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js)。\n\n## 异步滚动\n\n> 2.8.0 新增\n\n你也可以返回一个 Promise 来得出预期的位置描述：\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\n将其挂载到从页面级别的过渡组件的事件上，令其滚动行为和页面过渡一起良好运行是可能的。但是考虑到用例的多样性和复杂性，我们仅提供这个原始的接口，以支持不同用户场景的具体实现。\n\n## 平滑滚动\n\n只需将 `behavior` 选项添加到 `scrollBehavior` 内部返回的对象中，就可以为[支持它的浏览器](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior)启用原生平滑滚动：\n\n```js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash,\n      behavior: 'smooth',\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/zh/guide/advanced/transitions.md",
    "content": "# 过渡动效\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-create-route-transitions-with-vue-router?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to create route transitions on Vue School\">观看 Vue School 的如何创建路由过渡动效的免费视频课程 (英文)</a></div>\n\n`<router-view>` 是基本的动态组件，所以我们可以用 `<transition>` 组件给它添加一些过渡效果：\n\n```html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[Transition 的所有功能](https://v2.cn.vuejs.org/v2/guide/transitions.html) 在这里同样适用。\n\n## 单个路由的过渡\n\n上面的用法会给所有路由设置一样的过渡效果，如果你想让每个路由组件有各自的过渡效果，可以在各路由组件内使用 `<transition>` 并设置不同的 name。\n\n```js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n## 基于路由的动态过渡\n\n还可以基于当前路由与目标路由的变化关系，动态设置过渡效果：\n\n```html\n<!-- 使用动态的 transition name -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n```js\n// 接着在父组件内\n// watch $route 决定使用哪种过渡\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\n查看完整例子请[移步这里](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js)。\n"
  },
  {
    "path": "docs/zh/guide/essentials/dynamic-matching.md",
    "content": "# 动态路由匹配\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/vue-router-dynamic-routes?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to match dynamic routes with Vue School\">观看 Vue School 的如何匹配动态路由的免费视频课程 (英文)</a></div>\n\n我们经常需要把某种模式匹配到的所有路由，全都映射到同个组件。例如，我们有一个 `User` 组件，对于所有 ID 各不相同的用户，都要使用这个组件来渲染。那么，我们可以在 `vue-router` 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果：\n\n```js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // 动态路径参数 以冒号开头\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n现在呢，像 `/user/foo` 和 `/user/bar` 都将映射到相同的路由。\n\n一个“路径参数”使用冒号 `:` 标记。当匹配到一个路由时，参数值会被设置到\n`this.$route.params`，可以在每个组件内使用。于是，我们可以更新 `User` 的模板，输出当前用户的 ID：\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\n你可以看看这个[在线例子](https://jsfiddle.net/yyx990803/4xfa2f19/)。\n\n你可以在一个路由中设置多段“路径参数”，对应的值都会设置到 `$route.params` 中。例如：\n\n| 模式                          | 匹配路径            | \\$route.params                         |\n| ----------------------------- | ------------------- | -------------------------------------- |\n| /user/:username               | /user/evan          | `{ username: 'evan' }`                 |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\n除了 `$route.params` 外，`$route` 对象还提供了其它有用的信息，例如，`$route.query` (如果 URL 中有查询参数)、`$route.hash` 等等。你可以查看 [API 文档](../../api/#路由对象) 的详细说明。\n\n## 响应路由参数的变化\n\n提醒一下，当使用路由参数时，例如从 `/user/foo` 导航到 `/user/bar`，**原来的组件实例会被复用**。因为两个路由都渲染同个组件，比起销毁再创建，复用则显得更加高效。**不过，这也意味着组件的生命周期钩子不会再被调用**。\n\n复用组件时，想对路由参数的变化作出响应的话，你可以简单地 watch (监测变化) `$route` 对象：\n\n```js\nconst User = {\n  template: '...',\n  watch: {\n    $route(to, from) {\n      // 对路由变化作出响应...\n    }\n  }\n}\n```\n\n或者使用 2.2 中引入的 `beforeRouteUpdate` [导航守卫](../advanced/navigation-guards.html)：\n\n```js\nconst User = {\n  template: '...',\n  beforeRouteUpdate(to, from, next) {\n    // react to route changes...\n    // don't forget to call next()\n  }\n}\n```\n\n## 捕获所有路由或 404 Not found 路由\n\n常规参数只会匹配被 `/` 分隔的 URL 片段中的字符。如果想匹配**任意路径**，我们可以使用通配符 (`*`)：\n\n```js\n{\n  // 会匹配所有路径\n  path: '*'\n}\n{\n  // 会匹配以 `/user-` 开头的任意路径\n  path: '/user-*'\n}\n```\n\n当使用*通配符*路由时，请确保路由的顺序是正确的，也就是说含有*通配符*的路由应该放在最后。路由 `{ path: '*' }` 通常用于客户端 404 错误。如果你使用了*History 模式*，请确保[正确配置你的服务器](./history-mode.md)。\n\n当使用一个*通配符*时，`$route.params` 内会自动添加一个名为 `pathMatch` 参数。它包含了 URL 通过*通配符*被匹配的部分：\n\n```js\n// 给出一个路由 { path: '/user-*' }\nthis.$router.push('/user-admin')\nthis.$route.params.pathMatch // 'admin'\n// 给出一个路由 { path: '*' }\nthis.$router.push('/non-existing')\nthis.$route.params.pathMatch // '/non-existing'\n```\n\n## 高级匹配模式\n\n`vue-router` 使用 [path-to-regexp](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0) 作为路径匹配引擎，所以支持很多高级的匹配模式，例如：可选的动态路径参数、匹配零个或多个、一个或多个，甚至是自定义正则匹配。查看它的[文档](https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters)学习高阶的路径匹配，还有[这个例子 ](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js)展示 `vue-router` 怎么使用这类匹配。\n\n## 匹配优先级\n\n有时候，同一个路径可以匹配多个路由，此时，匹配的优先级就按照路由的定义顺序：路由定义得越早，优先级就越高。\n"
  },
  {
    "path": "docs/zh/guide/essentials/history-mode.md",
    "content": "# HTML5 History 模式\n\n`vue-router` 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL，于是当 URL 改变时，页面不会重新加载。\n\n如果不想要很丑的 hash，我们可以用路由的 **history 模式**，这种模式充分利用 `history.pushState` API 来完成 URL 跳转而无须重新加载页面。\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\n当你使用 history 模式时，URL 就像正常的 url，例如 `http://yoursite.com/user/id`，也好看！\n\n不过这种模式要玩好，还需要后台配置支持。因为我们的应用是个单页客户端应用，如果后台没有正确的配置，当用户在浏览器直接访问 `http://oursite.com/user/id` 就会返回 404，这就不好看了。\n\n所以呢，你要在服务端增加一个覆盖所有情况的候选资源：如果 URL 匹配不到任何静态资源，则应该返回同一个 `index.html` 页面，这个页面就是你 app 依赖的页面。\n\n## 后端配置例子\n\n**注意**：下列示例假设你在根目录服务这个应用。如果想部署到一个子目录，你需要使用 [Vue CLI 的 `publicPath` 选项](https://cli.vuejs.org/zh/config/#publicpath) 和相关的 [router `base` property](https://router.vuejs.org/zh/api/#base)。你还需要把下列示例中的根目录调整成为子目录 (例如用 `RewriteBase /name-of-your-subfolder/` 替换掉 `RewriteBase /`)。\n\n#### Apache\n\n```apache\n<IfModule mod_negotiation.c>\n  Options -MultiViews\n</IfModule>\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n除了 `mod_rewrite`，你也可以使用 [`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource)。\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### 原生 Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile('index.html', 'utf-8', (err, content) => {\n    if (err) {\n      console.log('We cannot open \"index.html\" file.')\n    }\n\n    res.writeHead(200, {\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log('Server listening on: http://localhost:%s', httpPort)\n})\n```\n\n#### 基于 Node.js 的 Express\n\n对于 Node.js/Express，请考虑使用 [connect-history-api-fallback 中间件](https://github.com/bripkens/connect-history-api-fallback)。\n\n#### Internet Information Services (IIS)\n\n1. 安装 [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite)\n2. 在你的网站根目录中创建一个 `web.config` 文件，内容如下：\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Firebase 主机\n\n在你的 `firebase.json` 中加入：\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## 警告\n\n给个警告，因为这么做以后，你的服务器就不再返回 404 错误页面，因为对于所有路径都会返回 `index.html` 文件。为了避免这种情况，你应该在 Vue 应用里面覆盖所有的路由情况，然后再给出一个 404 页面。\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\n或者，如果你使用 Node.js 服务器，你可以用服务端路由匹配到来的 URL，并在没有匹配到路由的时候返回 404，以实现回退。更多详情请查阅 [Vue 服务端渲染文档](https://ssr.vuejs.org/zh/)。\n"
  },
  {
    "path": "docs/zh/guide/essentials/named-routes.md",
    "content": "# 命名路由\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/vue-router-named-routes-and-params?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to work with named routes and params with Vue School\">观看 Vue School 的如何使用命名路由及其参数的免费视频课程 (英文)</a></div>\n\n有时候，通过一个名称来标识一个路由显得更方便一些，特别是在链接一个路由，或者是执行一些跳转的时候。你可以在创建 Router 实例的时候，在 `routes` 配置中给某个路由设置名称。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\n要链接到一个命名路由，可以给 `router-link` 的 `to` 属性传一个对象：\n\n```html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\n这跟代码调用 `router.push()` 是一回事：\n\n```js\nrouter.push({ name: 'user', params: { userId: 123 } })\n```\n\n这两种方式都会把路由导航到 `/user/123` 路径。\n\n完整的例子请[移步这里](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js)。\n"
  },
  {
    "path": "docs/zh/guide/essentials/named-views.md",
    "content": "# 命名视图\n\n有时候想同时 (同级) 展示多个视图，而不是嵌套展示，例如创建一个布局，有 `sidebar` (侧导航) 和 `main` (主内容) 两个视图，这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图，而不是只有一个单独的出口。如果 `router-view` 没有设置名字，那么默认为 `default`。\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\n一个视图使用一个组件渲染，因此对于同个路由，多个视图就需要多个组件。确保正确使用 `components` 配置 (带上 s)：\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\n以上案例相关的可运行代码请[移步这里](https://jsfiddle.net/posva/6du90epg/)。\n\n## 嵌套命名视图\n\n我们也有可能使用命名视图创建嵌套视图的复杂布局。这时你也需要命名用到的嵌套 `router-view` 组件。我们以一个设置面板为例：\n\n```\n/settings/emails                                       /settings/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` 只是一个常规组件。\n- `UserSettings` 是一个视图组件。\n- `UserEmailsSubscriptions`、`UserProfile`、`UserProfilePreview` 是嵌套的视图组件。\n\n**注意**：_我们先忘记 HTML/CSS 具体的布局的样子，只专注在用到的组件上。_\n\n`UserSettings` 组件的 `<template>` 部分应该是类似下面的这段代码：\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>User Settings</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_嵌套的视图组件在此已经被忽略了，但是你可以在[这里](https://jsfiddle.net/posva/22wgksa3/)找到完整的源代码。_\n\n然后你可以用这个路由配置完成该布局：\n\n```js\n{\n  path: '/settings',\n  // 你也可以在顶级路由就配置命名视图\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\n一个可以工作的示例的 demo 在[这里](https://jsfiddle.net/posva/22wgksa3/)。\n"
  },
  {
    "path": "docs/zh/guide/essentials/navigation.md",
    "content": "---\nsidebarDepth: 0\n---\n\n# 编程式的导航\n\n除了使用 `<router-link>` 创建 a 标签来定义导航链接，我们还可以借助 router 的实例方法，通过编写代码来实现。\n\n## `router.push(location, onComplete?, onAbort?)`\n\n**注意：在 Vue 实例内部，你可以通过 `$router` 访问路由实例。因此你可以调用 `this.$router.push`。**\n\n想要导航到不同的 URL，则使用 `router.push` 方法。这个方法会向 history 栈添加一个新的记录，所以，当用户点击浏览器后退按钮时，则回到之前的 URL。\n\n当你点击 `<router-link>` 时，这个方法会在内部调用，所以说，点击 `<router-link :to=\"...\">` 等同于调用 `router.push(...)`。\n\n| 声明式                    | 编程式             |\n| ------------------------- | ------------------ |\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\n该方法的参数可以是一个字符串路径，或者一个描述地址的对象。例如：\n\n``` js\n// 字符串\nrouter.push('home')\n\n// 对象\nrouter.push({ path: 'home' })\n\n// 命名的路由\nrouter.push({ name: 'user', params: { userId: '123' }})\n\n// 带查询参数，变成 /register?plan=private\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n**注意：如果提供了 `path`，`params` 会被忽略，上述例子中的 `query` 并不属于这种情况。取而代之的是下面例子的做法，你需要提供路由的 `name` 或手写完整的带有参数的 `path`：**\n\n```js\nconst userId = '123'\nrouter.push({ name: 'user', params: { userId }}) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// 这里的 params 不生效\nrouter.push({ path: '/user', params: { userId }}) // -> /user\n```\n\n同样的规则也适用于 `router-link` 组件的 `to` 属性。\n\n在 2.2.0+，可选的在 `router.push` 或 `router.replace` 中提供 `onComplete` 和 `onAbort` 回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。在 3.1.0+，可以省略第二个和第三个参数，此时如果支持 Promise，`router.push` 或 `router.replace` 将返回一个 Promise。\n\n**注意**： 如果目的地和当前路由相同，只有参数发生了改变 (比如从一个用户资料到另一个 `/users/1` -> `/users/2`)，你需要使用 [`beforeRouteUpdate`](./dynamic-matching.md#响应路由参数的变化) 来响应这个变化 (比如抓取用户信息)。\n\n## `router.replace(location, onComplete?, onAbort?)`\n\n跟 `router.push` 很像，唯一的不同就是，它不会向 history 添加新记录，而是跟它的方法名一样 —— 替换掉当前的 history 记录。\n\n| 声明式                            | 编程式                |\n| --------------------------------- | --------------------- |\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n## `router.go(n)`\n\n这个方法的参数是一个整数，意思是在 history 记录中向前或者后退多少步，类似 `window.history.go(n)`。\n\n例子\n\n``` js\n// 在浏览器记录中前进一步，等同于 history.forward()\nrouter.go(1)\n\n// 后退一步记录，等同于 history.back()\nrouter.go(-1)\n\n// 前进 3 步记录\nrouter.go(3)\n\n// 如果 history 记录不够用，那就默默地失败呗\nrouter.go(-100)\nrouter.go(100)\n```\n\n## 操作 History\n\n你也许注意到 `router.push`、 `router.replace` 和 `router.go` 跟 [`window.history.pushState`、 `window.history.replaceState` 和 `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History)好像， 实际上它们确实是效仿 `window.history` API 的。\n\n因此，如果你已经熟悉 [Browser History APIs](https://developer.mozilla.org/en-US/docs/Web/API/History_API)，那么在 Vue Router 中操作 history 就是超级简单的。\n\n还有值得提及的，Vue Router 的导航方法 (`push`、 `replace`、 `go`) 在各类路由模式 (`history`、 `hash` 和 `abstract`) 下表现一致。\n"
  },
  {
    "path": "docs/zh/guide/essentials/nested-routes.md",
    "content": "# 嵌套路由\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/vue-router-nested-routes?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to work with nested routes with Vue School\">观看 Vue School 的如何使用嵌套路由的免费视频课程 (英文)</a></div>\n\n实际生活中的应用界面，通常由多层嵌套的组件组合而成。同样地，URL 中各段动态路径也按某种结构对应嵌套的各层组件，例如：\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\n借助 `vue-router`，使用嵌套路由配置，就可以很简单地表达这种关系。\n\n接着上节创建的 app：\n\n```html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [{ path: '/user/:id', component: User }]\n})\n```\n\n这里的 `<router-view>` 是最顶层的出口，渲染最高级路由匹配到的组件。同样地，一个被渲染组件同样可以包含自己的嵌套 `<router-view>`。例如，在 `User` 组件的模板添加一个 `<router-view>`：\n\n```js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\n要在嵌套的出口中渲染组件，需要在 `VueRouter` 的参数中使用 `children` 配置：\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        {\n          // 当 /user/:id/profile 匹配成功，\n          // UserProfile 会被渲染在 User 的 <router-view> 中\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // 当 /user/:id/posts 匹配成功\n          // UserPosts 会被渲染在 User 的 <router-view> 中\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**要注意，以 `/` 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。**\n\n你会发现，`children` 配置就是像 `routes` 配置一样的路由配置数组，所以呢，你可以嵌套多层路由。\n\n此时，基于上面的配置，当你访问 `/user/foo` 时，`User` 的出口是不会渲染任何东西，这是因为没有匹配到合适的子路由。如果你想要渲染点什么，可以提供一个 空的 子路由：\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id',\n      component: User,\n      children: [\n        // 当 /user/:id 匹配成功，\n        // UserHome 会被渲染在 User 的 <router-view> 中\n        { path: '', component: UserHome }\n\n        // ...其他子路由\n      ]\n    }\n  ]\n})\n```\n\n提供以上案例的可运行代码请[移步这里](https://jsfiddle.net/yyx990803/L7hscd8h/)。\n"
  },
  {
    "path": "docs/zh/guide/essentials/passing-props.md",
    "content": "# 路由组件传参\n\n<div class=\"vueschool\"><a href=\"https://vueschool.io/lessons/how-to-pass-vue-router-params-as-props-to-components?friend=vuerouter\" target=\"_blank\" rel=\"sponsored noopener\" title=\"Learn how to pass props to route components with Vue School\">观看 Vue School 的如何向路由组件传递 prop 的免费视频课程 (英文)</a></div>\n\n在组件中使用 `$route` 会使之与其对应路由形成高度耦合，从而使组件只能在某些特定的 URL 上使用，限制了其灵活性。\n\n使用 `props` 将组件和路由解耦：\n\n**取代与 `$route` 的耦合**\n\n```js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [{ path: '/user/:id', component: User }]\n})\n```\n\n**通过 `props` 解耦**\n\n```js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // 对于包含命名视图的路由，你必须分别为每个命名视图添加 `props` 选项：\n    {\n      path: '/user/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\n这样你便可以在任何地方使用该组件，使得该组件更易于重用和测试。\n\n## 布尔模式\n\n如果 `props` 被设置为 `true`，`route.params` 将会被设置为组件属性。\n\n## 对象模式\n\n如果 `props` 是一个对象，它会被按原样设置为组件属性。当 `props` 是静态的时候有用。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/promotion/from-newsletter',\n      component: Promotion,\n      props: { newsletterPopup: false }\n    }\n  ]\n})\n```\n\n## 函数模式\n\n你可以创建一个函数返回 `props`。这样你便可以将参数转换成另一种类型，将静态值与基于路由的值结合等等。\n\n```js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/search',\n      component: SearchUser,\n      props: route => ({ query: route.query.q })\n    }\n  ]\n})\n```\n\nURL `/search?q=vue` 会将 `{query: 'vue'}` 作为属性传递给 `SearchUser` 组件。\n\n请尽可能保持 `props` 函数为无状态的，因为它只会在路由发生变化时起作用。如果你需要状态来定义 `props`，请使用包装组件，这样 Vue 才可以对状态变化做出反应。\n\n更多高级用法，请查看[例子](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js)。\n"
  },
  {
    "path": "docs/zh/guide/essentials/redirect-and-alias.md",
    "content": "# 重定向和别名\n\n## 重定向\n\n重定向也是通过 `routes` 配置来完成，下面例子是从 `/a` 重定向到 `/b`：\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\n重定向的目标也可以是一个命名的路由：\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\n甚至是一个方法，动态返回重定向目标：\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // 方法接收 目标路由 作为参数\n      // return 重定向的 字符串路径/路径对象\n    }}\n  ]\n})\n```\n\n注意[导航守卫](../advanced/navigation-guards.md)并没有应用在跳转路由上，而仅仅应用在其目标上。在下面这个例子中，为 `/a` 路由添加一个 `beforeEnter` 守卫并不会有任何效果。\n\n其它高级用法，请参考[例子](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js)。\n\n## 别名\n\n“重定向”的意思是，当用户访问 `/a`时，URL 将会被替换成 `/b`，然后匹配路由为 `/b`，那么“别名”又是什么呢？\n\n**`/a` 的别名是 `/b`，意味着，当用户访问 `/b` 时，URL 会保持为 `/b`，但是路由匹配则为 `/a`，就像用户访问 `/a` 一样。**\n\n上面对应的路由配置为：\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\n“别名”的功能让你可以自由地将 UI 结构映射到任意的 URL，而不是受限于配置的嵌套路由结构。\n\n更多高级用法，请查看[例子](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js)。\n"
  },
  {
    "path": "docs/zh/installation.md",
    "content": "# 安装\n\n### 直接下载 / CDN\n\n[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) 提供了基于 NPM 的 CDN 链接。上面的链接会一直指向在 NPM 发布的最新版本。你也可以像  `https://unpkg.com/vue-router@3.0.0/dist/vue-router.js` 这样指定 版本号 或者 Tag。\n<!--/email_off-->\n\n在 Vue 后面加载 `vue-router`，它会自动安装的：\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### NPM\n\n``` bash\nnpm install vue-router\n```\n\n如果在一个模块化工程中使用它，必须要通过 `Vue.use()` 明确地安装路由功能：\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\n如果使用全局的 script 标签，则无须如此 (手动安装)。\n\n### Vue CLI\n\n如果你有一个正在使用 [Vue CLI](https://cli.vuejs.org/zh/) 的项目，你可以以项目插件的形式添加 Vue Router。CLI 可以生成上述代码及两个示例路由。**它也会覆盖你的 `App.vue`**，因此请确保在项目中运行以下命令之前备份这个文件：\n\n```sh\nvue add router\n```\n\n### 构建开发版\n\n如果你想使用最新的开发版，就得从 GitHub 上直接 clone，然后自己 build 一个 `vue-router`。\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs-gitbook/LANGS.md",
    "content": "* [English](en/)\n* [French](fr/)\n* [Japanese](ja/)\n* [中文](zh-cn/)\n* [German](de/)\n* [Русский](ru/)\n* [한국어(Korean)](kr/)\n* [Español](es/)\n* [0.7 Docs](old/)\n"
  },
  {
    "path": "docs-gitbook/assets/CNAME",
    "content": "router.vuejs.org\n"
  },
  {
    "path": "docs-gitbook/assets/circle.yml",
    "content": "general:\n  branches:\n    ignore:\n      - gh-pages\n"
  },
  {
    "path": "docs-gitbook/book.json",
    "content": "{\n  \"title\": \"vue-router\",\n  \"gitbook\": \">3.0.0\",\n  \"plugins\": [\"edit-link\", \"theme-vuejs\", \"-fontsettings\", \"github\"],\n  \"pluginsConfig\": {\n    \"edit-link\": {\n      \"base\": \"https://github.com/vuejs/vue-router/edit/dev/docs\",\n      \"label\": \"Edit This Page\"\n    },\n    \"github\": {\n      \"url\": \"https://github.com/vuejs/vue-router/\"\n    }\n  },\n  \"links\": {\n    \"sharing\": {\n      \"facebook\": false,\n      \"twitter\": false\n    }\n  }\n}\n"
  },
  {
    "path": "docs-gitbook/de/SUMMARY.md",
    "content": "# vue-router\n\n<!--email_off-->\n> Merke: vue-router@2.x ist nur mit Vue 2.x kompatibel. Dokumentation für 0.7.x ist [hier (englisch)](https://github.com/vuejs/vue-router/tree/1.0/docs/en)\n<!--/email_off-->\n\n**[Versionshinweise (englisch)](https://github.com/vuejs/vue-router/releases)**\n\n- [Installation](installation.md)\n- Grundlegendes\n  - [Erste Schritte](essentials/getting-started.md)\n  - [Dynamisches Route-Matching](essentials/dynamic-matching.md)\n  - [Verschachtelte Routes](essentials/nested-routes.md)\n  - [Programmatische Navigation](essentials/navigation.md)\n  - [Benannte Routes](essentials/named-routes.md)\n  - [Benannte Views](essentials/named-views.md)\n  - [Redirect und Alias](essentials/redirect-and-alias.md)\n  - [HTML5-Verlaufsmodus](essentials/history-mode.md)\n- Fortgeschritten\n  - [Navigations-Guards](advanced/navigation-guards.md)\n  - [Route Meta-Felder](advanced/meta.md)\n  - [Transitions (Übergänge)](advanced/transitions.md)\n  - [Daten laden](advanced/data-fetching.md)\n  - [Scroll-Verhalten](advanced/scroll-behavior.md)\n  - [Lazy Loading](advanced/lazy-loading.md)\n- API-Referenz\n  - [router-link](api/router-link.md)\n  - [router-view](api/router-view.md)\n  - [Das Route-Objekt](api/route-object.md)\n  - [Router-Option](api/options.md)\n  - [Router-Instanz](api/router-instance.md)\n  - [Injection von Komponenten](api/component-injections.md)\n"
  },
  {
    "path": "docs-gitbook/de/advanced/data-fetching.md",
    "content": "# Daten laden\n\nOftmals müssen wir Daten von einem Server laden, sobald eine Route aktiviert wird. Zum Beispiel müssen die Daten des Users vom Server geladen werden, bevor das Userprofil angezeigt werden kann. Dies kann auf zwei Arten erreicht werden:\n\n- **Laden nach der Navigation**: Der Router schließt zuerst die Navigation ab und wir laden die Daten anschließend in der neuen Komponente. Während der Übertragung kann ein Ladebalken oder ähnliches in der Komponente angezeigt werden.\n\n- **Laden der Navigation**: Wir laden Daten bevor die Navigation der Route durchgeführt wird und navigieren danach erst zur neuen Route.\n\nTechnisch gesehen sind beide Optionen gleich \"gut\" - letztendlich hängt es davon ab, welche Benutzererfahrung man erreichen möchte.\n\n## Laden nach der Navigation\n\nIn diesem Fall navigieren und rendern wir die neue Komponente direkt und laden die Daten im `created`-Hook der Komponente. Das ermöglicht es uns dem Nutzer in der neuen Komponente einen Ladebalken oder ähnliches anzuzeigen während der Content vom Server geladen wird. Außerdem können wir so den Ladevorgang in jeder Komponente individuell gestalten.\n\nIm folgenden Beispiel haben wir eine `Post`-Komponente, welche Daten für einen Blog-Post basierend auf `$route.params.id` einholt:\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Lade..\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // Lade die Daten, wenn die Komponente erstellt wurde und die\n    // Daten bereits observed (\"beobachtet\") werden.\n    this.fetchData()\n  },\n  watch: {\n    // Rufe die Methode erneut auf, wenn sich die Route ändert.\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // Ersetze 'getPost' mit einem beliebigen AJAX-tool / API-Wrapper\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Laden vor der Navigation\n\nIn diesem Fall werden die Daten geladen, bevor wir in die neue Route navigieren. Die Inhalte werden in dem `beforeRouteEnter`-Guard der neuen Komponente geladen. Die `next`-Funktion wird erst aufgerufen, wenn der Vorgang abgeschlossen ist:\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      if (err) {\n        // Zeige eine globale Fehlermeldung.\n        next(false)\n      } else {\n        next(vm => {\n          vm.post = post\n        })\n      }\n    })\n  },\n  // Wenn die Route geändert und die Komponente bereits gerendert wurde,\n  // ist der Aufbau etwas anders:\n  watch: {\n    $route () {\n      this.post = null\n      getPost(this.$route.params.id, (err, post) => {\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\nDer Nutzer bleibt im aktuellen View, während die Daten für den neuen View geladen werden. Daher ist es während des Ladevorgangs empfehlenswert, innerhalb der App einen Ladebalken oder ähnliches anzuzeigen. Wenn der Ladevorgang fehlschlägt, ist es außerdem wichtig, eine Fehlermeldung auszugeben.\n"
  },
  {
    "path": "docs-gitbook/de/advanced/lazy-loading.md",
    "content": "# Lazy Loading\n\nWenn Apps mit einem Bundler erstellt werden, kann das erzeugte \"Bundle\" recht groß werden und so die Seitenladezeit beeinträchtigen. Es wäre effizienter, wenn man das Bundle in die einzelnen  Router-Komponenten aufteilen könnte und sie nur dann lädt, wenn die Route besucht wird.\n\nMit der Kombination von Vue's Feature für [asynchrone Komponenten](http://vuejs.org/guide/components.html#Async-Components) und Webpack's Feature [\"Code-Splitting\"](https://webpack.js.org/guides/code-splitting-require/) (engl. _to split_: _teilen_) ist es einfach, dieses \"Lazy Loading\" genannte Verhalten für Route-Komponenten zu erreichen.\n\nDazu müssen wir nur unsere Route-Komponenten als asynchrone Komponente definieren:\n\n``` js\nconst Foo = resolve => {\n  // require.ensure ist Webpacks speziale Syntax für Code-Splitting.\n  require.ensure(['./Foo.vue'], () => {\n    resolve(require('./Foo.vue'))\n  })\n}\n```\n\nEs gibt auch eine alternative Code-Splitting Syntax mit `require` im AMD-Stil, mit der das ganze folgendermaßen vereinfacht werden kann:\n\n``` js\nconst Foo = resolve => require(['./Foo.vue'], resolve)\n```\n\nIn der Route-Konfiguration muss nichts genändert werden - wir nutzen `Foo` wie gewohnt:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/foo', component: Foo }\n  ]\n})\n```\n\n### Gruppierung von Komponenten im selben Chunk\n\nManchmal wollen wir alle Komponenten unter derselben Route in den selben ansynchronen Chunk gruppieren. Dafür benutzern wir das [\"named Chunks\" (englisch)](https://webpack.js.org/guides/code-splitting-require/#chunkname) Feature, indem wir einen Chunk-Namen als drittes Argument für `require.ensure` hinzufügen.\n\n``` js\nconst Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo')\nconst Bar = r => require.ensure([], () => r(require('./Bar.vue')), 'group-foo')\nconst Baz = r => require.ensure([], () => r(require('./Baz.vue')), 'group-foo')\n```\n\nWebpack bündelt alle asynchronen Module mit dem gleichen Chunk-Namen in denselben asynchronen Chunk. Das bedeutet auch, dass keine Dependencies mehr für `require.ensure` explizit aufgelistet werden müssen - daher das leere Array als Argument.\n"
  },
  {
    "path": "docs-gitbook/de/advanced/meta.md",
    "content": "# Route Meta-Felder\n\nIn der Route-Definition kann man ein Meta-Feld definieren:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // ein Metafeld\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nUnd wie greifen wir auf das `meta`-Feld zu?\n\nZunächst einmal: Wir nennen jedes Route-Objekt in der `routes`-Konfiguration **Route-Record**. Route-Records können verschachtelt sein, weshalb eine URL potentiell zu mehreren Route-Records passen kann.\n\nZum Beispiel werden mit der obigen Konfiguration und der URL `/foo/bar` beide - Parent-Record und Child-Record - gematched.\n\nAlle Route-Records, die auf eine URL zutreffen, sind im `$route`-Objekt und in den Route-Objekten in Navigation-Guards im `$route.matched`-Array zu finden. Deswegen müssen wir mit einer Schleife das `$route.matched` Array durchlaufen, um alle Route-Records auf Metafelder zu prüfen.\n\nEin Anwendungsfall ist die Prüfung nach einem Metafeld im globalen Before-Guard:\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // Diese Route benötigt Authentifizierung und prüft,\n    // ob man eingeloggt ist.\n    // Wenn nicht, Redirect zur Login-Seite.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // Rufe immer next() auf.\n  }\n})\n```\n"
  },
  {
    "path": "docs-gitbook/de/advanced/navigation-guards.md",
    "content": "# Navigation Guards (\"Navigations-Wächter\")\n\nWie der Name schon andeutet, werden \"navigation guards\" `vue-router` primär genutzt, um Navigationen zu \"bewachen\", indem diese bei Bedarf redirected oder abgebrochen werden. Es gibt dabei verschiedene Möglichkeiten, sich in den Navigationsprozess einzuklinken: global, in der Route Definition oder direkt in der Komponente.\n\nHinweis: Guards werden nicht ausgelöst, wenn Params oder Querys geändert werden. Beobachte in diesen Fällen einfach [das `$route`-Objekt](../essentials/dynamic-matching.md#reacting-to-params-changes), um auf Änderungen zu reagieren.\n\n### Globale Guards\n\nMan kann globale Before-Guards (\"davor-guards\") mit `router.beforeEach` registrieren:\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nGlobale Before-Guards werden in der Reihenfolge aufgerufen, in der sie registriert wurden, wann immer eine Navigation ausgelöst wird. Der guard kann auch auch asynchron beendet werden - die Navigation ist solange im Status **pending**, bis alle bearbeitet wurden.\n\nJede Guard Funktion erhält drei Argumente:\n\n- **`to: Route`**: das [Route-Objekt](../api/route-object.md), zu dem navigiert wird\n\n- **`from: Route`**: die aktuelle Route, von der wegnavigiert wird\n\n- **`next: Function`**: Diese Funktion muss aufgerufen werden, um den guard zu beenden. Die daraus resultierende Aktion hängt von den Argumenten in `next` ab:\n\n  - **`next()`**: Gehe zum nächsten guard in der Reihe. Wenn keine mehr vorhanden sind, ist die Navigation **bestätigt**.\n\n  - **`next(false)`**: Brich die aktuelle Navigation ab. Wurde die URL geändert (entweder manuell durch den Nutzer oder über den Zurück-Button), wird sie zurückgesetzt auf die der `from`-Route.\n\n  - **`next('/')` or `next({ path: '/' })`**: Umleitung zu einer anderen Route. Die aktuelle Navigation wird abgebrochen und eine neue gestartet.\n\n**Die `next`-Funktion muss immer aufgerufen werden, sonst kann der Guard nicht aufgelöst werden.**\n\nMan kann auch globale After-Guards (\"Danach-Guards\") registrieren, allerdings erhalten diese keine `next`-Funktion wie der Navigationsschutz und beeinflussen nicht die Navigation selbst:\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### Guards in der Route\n\nMan kann den `beforeEnter`-Guard direkt in der Router-Konfiguration definieren:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nDiese Guards haben die exakt gleiche Signatur wie globale Before-Guards.\n\n### Guards in Komponenten\n\nZu guter Letzt kann man Guards auch direkt in den Route-Komponenten (die, die der Router-Konfiguration hinzugefügt werden) mit `beforeRouteEnter` und `beforeRouteLeave` definieren:\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // Wird aufgerufen bevor die Route bestätigt wird, die diese Komponenten rendert.\n    // Hat keinen Zugriff auf den `this`-Kontext der Komponenteninstanz,\n    // da diese noch nicht erstellt wurde, wenn die Guard-Funktion aufgerufen wird.\n  },\n  beforeRouteLeave (to, from, next) {\n    // Wird aufgerufen, wenn von der Route, die diese Komponente rendert, wegnavigiert wird.\n    // Hat Zugriff zum `this`-Kontext.\n  }\n}\n```\n\nDer `beforeRouteEnter`-Guard hat keinen Zugriff auf den `this`-Kontext, weil der Guard aufgerufen wird, bevor die Navigation bestätigt wurde, weshalb die Komponente noch gar nicht erzeugt wurde.\n\nAllerdings bekommt man Zugriff auf die Instanz, indem man einen Callback an `next` übergibt. Der Callback wird ausgeführt wenn die Navigation bestätigt wurde. Die Komponente wird im Callback als Argument übergeben:\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // Zugriff auf Komponenteninstanz via 'vm'\n  })\n}\n```\n\nIn `beforeRouteLeave`-Guards kann man den `this`-Kontext aufrufen. Dieser Guard wird normalerweise verwendet um zu verhindern, dass ein Benutzer die Route versehentlich verlässt ohne ungesicherten Arbeit zu speichern. Die Navigation kann mit `next(false)` abgebrochen werden.\n"
  },
  {
    "path": "docs-gitbook/de/advanced/scroll-behavior.md",
    "content": "# Scroll-Verhalten\n\nOft wollen wir, dass die Seite nach oben scrollt, wenn zu einer neuen Route navigiert wird, oder dass die Scroll-Position von Verlaufseinträgen wie beim Neuladen einer Seite beibehalten wird. `vue-router` ermöglichst das und noch mehr - wir können das Scroll-Verhalten komplett individualisieren.\n\n> Merke: Dies funktioniert nur im HTML5-Verlaufsmodus (\"history mode\").\n\nBeim Erzeugen der Router-Instanz fügt man die `scrollBehavior`-Funktion hinzu:\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // zurückgeben der gewünschten Position\n  }\n})\n```\n\nDie `scrollBehavior`-Funktion erhält die Route-Objeke `to` und `from` als Argumente. Das dritte Argument `savedPosition` steht nur zur Verfügung, wenn es sich um eine `popstate`-Navigation handelt (d.h. der Vor-/Zurück-Button des Browsers hat die Navigation ausgelöst).\n\nDie Funktion sollte ein Objekt zurückgeben, dass die Scroll-Position beschreibt. Das Objekt kann folgendermaßen aussehen:\n\n- `{ x: number, y: number }`\n- `{ selector: string }`\n\nWenn ein falscher (falsy) Wert oder ein leeres Objekt zurückgegeben wird, wird nicht gescrollt.\n\nIm folgenden Beispiel scrollt die Seite komplett nach oben:\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\n\nWenn die Funktion das `savedPosition`-Object zurückgibt, verhält sich die Seite wie ein Browser, innerhalb dessen mit den Vor-/Zurück Buttons navigiert wird.\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nSimulation des \"Scrolle zum Anchor\"-Verhaltens:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n    }\n  }\n}\n```\n\nDu kannst außerdem die [Route Meta-Felder](meta.md) für eine noch genauere Kontrolle des Scroll-Verhaltens nutzen.  [Hier](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js) findest du ein Beispiel.\n"
  },
  {
    "path": "docs-gitbook/de/advanced/transitions.md",
    "content": "# Transitions (Übergänge)\n\nDa `<router-view>` im Grunde eine dynamische Komponente ist, kann man Übergangs-Effekte mit der `<transition>`-Komponente hinzufügen:\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[Alle Features von `<transition>`](http://vuejs.org/guide/transitions.html) funktionieren hier genauso.\n\n### Übergang für einzelne Routes\n\nDas obige Beispiel nutzt den gleichen Übergangseffekt für alle Routes. Wenn unterschiedliche Übergänge je Route gewollt sind, kann man `<transition>` stattdessen *in* der Route-Komponente mit jeweils anderen Namen verwenden:\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n### Route-basierter dynamischer Übergang\n\nEs ist auch möglich, den Übergang dynamisch anhand der Beziehung zwischen Ziel- und aktueller Route festzulegen:\n\n``` html\n<!-- nutze einen dynamischen Übergangsnamen -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// überwache $route in der Parent-Komponente,\n// um den Übergang festzulegen\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nKomplettes Beispiel [hier](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js) ansehen.\n"
  },
  {
    "path": "docs-gitbook/de/api/component-injections.md",
    "content": "# Injektion von Komponenten\n\n### Injizierte Eigenschaften\n\nDie folgenden Eigenschaften werden in jede Child-Komponente injiziert, wenn man die Router-Instanz in die Root-Instanz der App als `router:`-Option übergibt.\n\n- #### $router\n\n  Die Router-Instanz.\n\n- #### $route\n\n  Die aktuell aktive [Route](route-object.md). Diese Eigenschaft ist schreibgeschützt und ihre Eigenschaften sind unveränderbar - aber sie kann überwacht werden.\n\n### Aktivierte Optionen\n\n- **beforeRouteEnter**\n- **beforeRouteLeave**\n\n  Siehe [Guards in Komponenten Komponentenschutz](../advanced/navigation-guards.md#guards-in-komponenten).\n"
  },
  {
    "path": "docs-gitbook/de/api/options.md",
    "content": "# Optionen des Router-Konstruktors\n\n### routes\n\n- Typ: `Array<RouteConfig>`\n\n  Typendeklaration für `RouteConfig`:\n\n  ``` js\n  declare type RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // für benannte Routes\n    components?: { [name: string]: Component }; // für benannte Views\n    redirect?: string | Location | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // für Verschachtelte Routes\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n  }\n  ```\n\n### mode\n\n- Typ: `string`\n\n- Default: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- verfügbare Werte: `\"hash\" | \"history\" | \"abstract\"`\n\n  Bestimmt den Router-Mode.\n\n  - `hash`: Nutzt den URL-Hash für das Routing. Funktioniert in allen Vue-unterstützten Browsern, inklusive derer, die die HTML5 Verlaufs-API nicht unterstützen.\n\n  - `history`: Benötigt die HTML5 Verlaufs-API und Serverkonfiguration. Siehe [HTML5 Verlaufsmodus](../essentials/history-mode.md).\n\n  - `abstract`: Funktioniert in jeder JavaScript-Umgebung, zB. serverseitig mit Node.js. **Der Router wird automatisch in diesen Modus gezwungen, wenn keine Browser-API vorhanden ist.**\n\n### base\n\n- Typ: `string`\n\n- Default: `\"/\"`\n\n  Die Basis-URL der App. Läuft zum Beispiel die gesamte Single-Page-Applikation unter `/app`, sollte `base` den Wert `\"/app\"` haben.\n\n### linkActiveClass\n\n- Typ: `string`\n\n- Default: `\"router-link-active\"`\n\n  Definiert global den Namen der \"active\" Klasse für `<router-link>`. Siehe auch [router-link](router-link.md).\n\n### scrollBehavior\n\n- Typ: `Function`\n\n  Signatur:\n\n  ```\n  (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => { x: number, y: number } | { selector: string } | ?{}\n  ```\n\n  Für mehr Details siehe [Scroll-Verhalten](../advanced/scroll-behavior.md).\n"
  },
  {
    "path": "docs-gitbook/de/api/route-object.md",
    "content": "# Das Route-Objekt\n\nDas **Route-Objekt** repräsentiert den Zustand der aktuell aktiven Route. Es enthält geparste Informationen zur aktuellen URL und den Route-Einträgen, die mit der URL gematched wurden.\n\nDas Route-Objekt ist 'immutable' (unveränderbar). Jede erfolgreiche Navigation resultiert in einem neuen Route-Objekt.\n\nDas Route-Objekt kann an mehreren Orten gefunden werden:\n\n- in Komponenten als `this.$route`\n\n- in `$route`-Watcher-Callbacks.\n\n- als Rückgabewert von `router.match(location)`\n\n- in Navigation-Guards als die ersten beiden Argumente:\n\n  ``` js\n  router.beforeEach((to, from, next) => {\n    // 'to' und 'from' sind Router-Objekte\n  })\n  ```\n\n- in der `scrollBehavior`-Funktion als die ersten beiden Argumente:\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n        // 'to' und 'from' sind Router-Objekte\n    }\n  })\n  ```\n\n### Eigenschaften des Router-Objekts\n\n- **$route.path**\n\n  - Typ: `string`\n\n    Ein String, der gleich dem Pfad der aktuellen Route ist immer als absoluter Pfad ausgegeben wird, zB. `\"/foo/bar\"`.\n\n- **$route.params**\n\n  - Typ: `Object`\n\n    Ein Objekt, welches Schlüssel/Wert-Paare von Stern- und dynamischen Segmenten enthält. Gibt es keine Parameter, ist der Wert ein leeres Objekt.\n\n- **$route.query**\n\n  - Typ: `Object`\n\n    Ein Objekt, welches Schlüssel/Wert-Paare des Query-Strings enthält. Für den Pfad `/foo?user=1` erhält man zum Beispiel `$route.query.user == 1`. Gibt es kein Query, ist der Wert ein leeres Objekt.\n\n- **$route.hash**\n\n  - Typ: `string`\n\n    Der Hash der aktuellen Route (mit `#`). Gibt es keinen Hash, ist dessen Wert ein leerer String.\n\n- **$route.fullPath**\n\n  - Typ: `string`\n\n    Die voll umgewandelte URL inklusive Abfrage und Hash.\n\n- **$route.matched**\n\n  - Typ: `Array<RouteRecord>`\n\n  Ein Array von **Route-Einträgen** für alle verschachtelten Pfadsegmente der aktuellen Route. Route-Einträge sind Kopien der Objekte im Array der `routes`-Konfiguration (und deren `children`-Arrays):\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // das folgende Objekt in ein Route-Eintrag\n      { path: '/foo', component: Foo,\n        children: [\n          // das ist auch ein Route-Eintrag\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  Wenn die URL `/foo/bar` ist, ist `$route.matched` ein Array, welches beide geklonten Objekte von Parent nach Child sortiert enthält.\n\n- **$route.name**\n\n  Der Name der aktuellen Route, sofern vorhanden. Siehe [Benannte Routes](../essentials/named-routes.md).\n"
  },
  {
    "path": "docs-gitbook/de/api/router-instance.md",
    "content": "# Router-Instanz\n\n### Eigenschaften\n\n#### router.app\n\n- Typ: `Vue instance`\n\n  Die grundlegende Vue-Instanz, in die `router` injiziert wurde.\n\n#### router.mode\n\n- Typ: `string`\n\n  Der [Modus](options.md#mode), den der Router nutzt.\n\n\n#### router.currentRoute\n\n- Typ: `Route`\n\n  Die akuelle Route, widergespiegelt als [Route-Objekt](route-object.md).\n\n### Methoden\n\n- **router.beforeEach(guard)**\n- **router.afterEach(hook)**\n\n  Füge globalen Navigationsschutz hinzu. Siehe [Navigations-Guards](../advanced/navigation-guards.md).\n\n\n- **router.push(location)**\n- **router.replace(location)**\n- **router.go(n)**\n- **router.back()**\n- **router.forward()**\n\n  Navigiere programmatisch zu einer neuen URL. Siehe [Programmatische Navigation](../essentials/navigation.md).\n\n- **router.getMatchedComponents(location?)**\n\n  Gibt ein Array von Komponenten (Definition/Konstruktor, nicht Instanz) zurück, die für den gegebenen Ort oder die aktuelle Route gematched wurden. Wird meist bei serverseitigem Rendern genutzt, um ein Vorladen von Daten zu ermöglichen.\n\n- **router.resolve(location, current?, append?)**\n\n  Umgekehrte URL-Erkennung. Wenn man ein Ziel in gleicher Form wie in `<router-link>` übergibt, gibt die Funktion ein Objekt mit den folgenden Eigenschaften zurück:\n\n``` js\n{\n  location: Location;\n  route: Route;\n  href: string;\n}\n```\n\n- **router.addRoutes(routes)**\n\n  > 2.2.0+\n\n  Füge dynamisch weitere Routen zum Router hinzu. Das Argument muss ein Array mit demselben Format wie die `routes` Konstruktor-Option sein.\n\n- **router.onReady(callback)**\n\n  > 2.2.0+\n\n  Diese Methode queued eine Callback-Funktion, welche aufgerufen wird, sobald der Router die initiale Navigation beendet hat - das heißt, dass alle asynchronen Komponenten und enter-hooks, die zu der aktuellen Route gehören, geladen und ausgeführt wurden.\n\n  Damit lässt sich im serverseitigen Rendern sicherstellen, dass auf dem Server und im Client der gleiche Output gerendert wird.\n"
  },
  {
    "path": "docs-gitbook/de/api/router-link.md",
    "content": "# `<router-link>`\n\n`<router-link>` ist eine Komponente zum Auslösen von Nutzernavigationen. Die Ziel-Route wird mit der `to`-Prop angegeben. Sie wird standardmäßig als `<a>` mit korrektem `href` Attribut gerendert, das Element kann jedoch mit dem `tag`-Prop geändert werden. Darüber hinaus erhält der Link automatisch die \"active\" CSS-Klasse, wenn die Ziel-Route gerade aktiv ist.\n\n`<router-link>` ist aus folgenden Gründen gegenüber fest definierten `<a href=\"\">` links zu bevorzugen:\n\n- Funktioniert in allen Router-Modi (history, hash, abstract) gleich. Daher muss man nichts ändern, wenn man den Modus jemals wechslen sollte oder er automatisch in den Hash-Modus für IE9 zurückfällt.\n\n- Im HTML5-Verlaufsmodus fängt `router-link` das `click`-Event ab, sodass der Browser nicht versucht, das Fenster neu zu laden.\n\n- Wenn die `base`-Option im HTML5-Verlaufsmodus genutzt wird, muss man die Base-URL nicht immer wieder in `to` mit angeben.\n\n### Props\n\n- **to**\n\n  - Typ: `string | Location`\n\n  - Pflichtfeld\n\n  Kennzeichnet die Ziel-Route des Links. Wenn die Komponente geklickt wird, wird der Wert von `to` intern an `router.push()` übergeben - der Wert kann also entweder ein String oder ein Objekt sein kann.\n\n\n  ``` html\n  <!-- literaler String -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- gerendert zu -->\n  <a href=\"home\">Home</a>\n\n  <!-- JavaScript-Expression mit v-bind -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- Auslassen von v-bind ist okay wie bei jedem anderen Prop -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- entspricht dem obigen Link -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- benannte Route -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- mit Query, resultiert in /register?plan=private -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n- **replace**\n\n  - Typ: `boolean`\n\n  - Default: `false`\n\n  Das Setzen von `replace` aktiviert `router.replace()` anstelle von `router.push()`. Die Navigation hinterlässt also keinen Verlaufseintrag.\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n- **append**\n\n  - Typ: `boolean`\n\n  - Default: `false`\n\n  Das Setzen von `append` hängt immer den relativen Pfad an den aktuellen an. Angenommen, man navigiert von `/a` zu einem relativen Pfad `b` - ohne `append` gelangt man zu `/b`, mit `append` jedoch wird daraus `/a/b`.\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n- **tag**\n\n  - Typ: `string`\n\n  - Default: `\"a\"`\n\n  Manchmal soll `<router-link>` einen anderen Tag rendern, zB. `<li>`. Mit Hilfe des `tag`-Props kann man definieren, welcher Tag gerendert werden soll. Der Tag reagiert nach wie vor auf Klick-Events für die Navigation.\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- gerendert als -->\n  <li>foo</li>\n  ```\n\n- **active-class**\n\n  - Typ: `string`\n\n  - Default: `\"router-link-active\"`\n\n  Festlegen der aktiven CSS-Klasse die zugewiesen wird, wenn der Link aktiv ist.\n  Der Standardwert kann ebenfalls mit der `linkActiveClass`-Option des Router-Konstruktors global konfiguriert werden.\n\n- **exact**\n\n  - Typ: `boolean`\n\n  - Default: `false`\n\n  Das standardmäßige Matching-Verfahren der aktiven Klasse ist ein **inklusives Match**. Zum Beispiel erhält `<router-link to=\"/a\">` die Klasse, solange der aktuelle Pfad mit `/a` beginnt.\n\n  Eine Konsequenz daraus ist, dass `<router-link to=/>` für jede Route aktiv ist! Um den \"exakten Match-Modus\" zu aktivieren, nutzt man die `exact`-Prop:\n\n  ``` html\n  <!-- dieser Link wird nur bei '/' aktiv -->\n  <router-link to=\"/\" exact>\n  ```\n\n  Siehe weitere Beispiele zur aktiven Linkklasse [hier](http://jsfiddle.net/fnlCtrl/dokbyypq/).\n\n- **event**\n\n  > 2.1.0+\n\n  - Typ: `string | Array<string>`\n\n  - Default: `'click'`\n\n  Lege das Event fest, das die Navigation auslöst.\n\n\n### \"active\" Klasse auf ein äußeres Element anwenden\n\nMachmal soll die aktive Klasse an einem äußeren Element anstelle das `<a>` gesetzt werden. In diesem Fall kann man das äußere Element als `<router-link>` rendern und damit den `<a>`-Tag umschließen:\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\nIn diesem Fall ist `<a>` der eigentliche Link und erhält das korrekte `href` attribut, aber die aktive Klasse wird auf das äußere `<li>` gesetzt.\n"
  },
  {
    "path": "docs-gitbook/de/api/router-view.md",
    "content": "# `<router-view>`\n\nDie `<router-view>`-Komponente ist eine 'functional' Komponente, die die gematchte Komponente zum gegebenen Pfad rendert. Komponenten, die in `router-view` gerendert werden, können auch eigene `<router-view>`s enthalten, welche dann Komponenten für verschachtelte Pfade rendern.\n\n### Props\n\n- **name**\n\n  - Typ: `string`\n\n  - Default: `\"default\"`\n\n  Wenn `<router-view>` einen Namen trägt, rendert es die Komponente mit dem zugehörigen Namen in der `components`-Option in dem gematchten Route-Eintrag. Siehe [Benannte Views](../essentials/named-views.md).\n\n### Verhalten\n\nAlle anderen Props werden an die gerenderte Komponente weitergeleitet, allerdings sind die relevanten Daten je Route meistens in den Route-Parametern vorhanden.\n\nDa `<router-view>` auch nur eine normale Komponente ist, funktioniert sie mit `<transition>` und `<keep-alive>`. Wenn zusammen genutzt, achte darauf dass `<keep-alive>` innerhalb der `<transition>` ist:\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n"
  },
  {
    "path": "docs-gitbook/de/essentials/dynamic-matching.md",
    "content": "# Dynamisches Route-Matching\n\nHäufig müssen wir URLs, die einem bestimmten Muster entsprechen, einer Route bzw. Komponente zuordnen. Zum Beispiel haben wir eine `User`-Komponente, welche für alle User mit unterschiedlichen IDs gerendert werden soll. In `vue-router` können wir hierfür ein dynamisches Segment im Pfad nutzen:\n\n``` js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // dynamische Segmente beginnen mit Doppelpunkt\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nNun werden URLs wie `/user/foo` und `/user/bar` der gleichen Route und damit der gleichen Komponente zugeordnet.\n\nEin dynamisches Segment wird mit einem Doppelpunkt `:` gekennzeichnet. Wenn eine Route mit einem dynamischen Segment erkannt wird, kann man über `this.$route.params`  in jeder Komponente auf die Werte der dynamischen Segmente zugreifen. So können wir zum Beispiel die aktuelle User-ID rendern, indem wir das `User`-Template folgendermaßen erweitern:\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\nEin interactives Beispiel ist [hier](http://jsfiddle.net/yyx990803/4xfa2f19/) zu finden.\n\nMehrere dynamische Segmente in der gleichen Route sind möglich und werden den entsprechenden Feldern in `$route.params` zugeordnet. Beispiele:\n\n| Muster | passender Pfad | $route.params |\n|---------|------|--------|\n| /user/:username | /user/evan | `{ username: 'evan' }` |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\nNeben `$route.params` bietet das `$route`-Objekt Zugriff auf weitere nützliche Informationen wie `$route.query` (sofern eine Query in der URL vorhanden ist). Du findest alle Details dazu in der [API Referenz](../api/route-object.md).\n\n\n### Reagieren auf Änderungen von \"Params\"\n\nBei der Nutzung von Parametern in Routes ist zu beachten, dass **die selbe Komponenteninstanz genutzt wird,** wenn der Nutzer von `/user/foo` nach `/user/bar` navigiert. Da beide Routes die gleiche Komponente rendern, ist das effizienter als die alte zu zerstören und eine neue zu erstellen. **Allerdings bedeutet das auch, dass die \"lifecycle hooks\" der Komponente nicht aufgerufen werden.**\n\nUm nun auf Änderungen der Params in der gleichen Komponente zu reagieren, kann man einfach das `$route`-Objekt mit einer watch-function beobachten:\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // reagiere auf @Route-Änderungen\n    }\n  }\n}\n```\n\n### Erweiterte Matchingsmuster\n\n`vue-router` nutzt [path-to-regexp](https://github.com/pillarjs/path-to-regexp) für das Matching der URL-Pfade, und unterstützt damit viele erweiterte Matching-Muster wie optionale dynamische Segmente, \"null oder mehr\" / \"ein oder mehr\" Bedingungen und sogar benutzerdefinierte RegEx-Muster.\nAn dieser Stelle sei für weitere Informationen zur Nutzung dieser Features auf die [Dokumentation für erweiterte Muster](https://github.com/pillarjs/path-to-regexp#parameters) und [dieses Beispiel](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) verwiesen.\n\n### Matching Priorität\n\nManchmal passt die URL zu mehr als einer Route. In diesem Fall ist die Priorität durch die Anordnung der Routes definiert: **Je früher eine Route definiert ist, desto höher ihre Priorität.**\n"
  },
  {
    "path": "docs-gitbook/de/essentials/getting-started.md",
    "content": "# Erste Schritte\n\n> Hinweis: Wir benutzen [ES2015](https://github.com/lukehoban/es6features) in den Code-Beispielen.\n\nEine Single-Page-Applikation mit Vue.js und vue-router zu erstellen ist wirklich simpel. Mit Vue.js stellen wir unsere App ja bereits aus Komponenten zusammen. Wenn wir nun vue-router ins Spiel bringen, müssen wir lediglich unsere Komponenten den \"Routes\" zuordnen und vue-router mitteilen, wo diese Komponenten gerendert werden sollen. Hier ein einfaches Beispiel:\n\n> Alle Beispiele nutzen die Standalone-Version von Vue, um Template-Parsing nutzen zu können. Mehr Details [hier (englisch)](http://vuejs.org/guide/installation.html#Standalone-vs-Runtime-only-Build)\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- nutze <router-link> zur Navigation -->\n    <!-- gib den Link mit der `to`-Prop an -->\n    <!-- <router-link> wird standardmäßig als <a> gerendert-->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- Route-Outlet (zu deutsch soviel wie: \"Ausgang\") -->\n  <!-- die der Route zugeordnete Komponente wird hier gerendert-->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. Wenn du ein Modul-System wie Webpack oder Browserify benutzt (z. B. via vue-cli), importiere Vue sowie VueRouter und rufe Vue.use(VueRouter) auf.\n\n// 1. Definiere die Route-Komponenten\n// Diese können auch aus anderen Dateien importiert werden.\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Definiere ein paar Routes\n// Jede Route sollte mit einer Komponente verbunden sein.\n// Die Komponenente kann entweder eine tatsächliche Komponente sein, die via Vue.extend() erstellt wird\n// oder lediglich ein Optionsobjekt der Komponenente.\n// Hinweis: Verschachtelte (engl: \"nested\") Routes werden später in dieser Anleitung behandelt.\n\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Erstelle die Router-Instanz und füge ihr die `routes`-Option hinzu.\n// Es gibt ntürlich noch mehr Optionen, aber hier halten wir es erstmal einfach.\n\nconst router = new VueRouter({\n  routes // kurz für 'routes: routes'\n})\n\n// 4. Erstelle und mounte die Root-Instanz.\n// Stelle sicher, dass der Router mit der `router` option an die Root Instanz übergeben wird, damit er später überall in deiner App zur Verfügung steht.\n\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// Die App ist nun gestartet.\n```\nDas ganze gibt es natürlich auch als [Live-Beispiel](http://jsfiddle.net/yyx990803/xgrjzsup/).\n\nHinweis: `<router-link>` erhält automatisch die CSS-Klasse `.router-link-active`, wenn die aktuelle Route im Browser der des router-link entspricht. Mehr Infos dazu in der [API-Referenz](../api/router-link.md).\n"
  },
  {
    "path": "docs-gitbook/de/essentials/history-mode.md",
    "content": "# HTML5-Verlaufsmodus (\"History Mode\")\n\nDer Standardmodus für `vue-router` ist der _Hash-Modus_. Er nutzt den URL-Hash, um eine komplette URL zu simulieren, damit die Seite nicht neu geladen wird, wenn sich die URL ändert.\n\nUm ohne Hash zu arbeiten, nutzt man den **Verlaufsmodus**, welcher die `history.pushState`-API von HTML5 nutzt, um URL-Navigation ohne Reload zu erreichen:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nBei Nutzung des Verlaufsmodus sieht die URL \"normal\" aus, zB. `http://meine-seite.de/benutzer/id` - Wunderschön!\n\nEs gibt jedoch ein Problem: Da unsere App eine so genannte \"Single Page Application (SPA)\" ist, die komplett im Browser läuft, erhält der Nutzer einen 404-Fehler, wenn er `http://meine-seite.de/benutzer/id` direkt aufruft - denn unter diesem Pfad wird dein Webserver nichts finden.\n\nAber keine Sorge: Um dieses Problem zu beheben, musst du nur eine einzige \"catch-all\"-Route in deiner Serverkonfiguration ergänzen. Wenn die URL zu keiner statischen Datei gehört, sollte diese Route immer die `index.html` an den Browser senden, in der deine App läuft ist.\n\n## Beispiel einer Serverkonfiguration\n\n#### Apache\n\n```apache\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Node.js (Express)\n\nFür Node.js/Express benutz du am besten [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback).\n\n## Warnung\n\nEs gibt einen kleinen Nachteil: Der Server wird  keine 404-Fehler mehr melden, da alle nicht gefundenen Pfade zur `index.html` führen. Um das zu beheben, solltest du eine Sammel-Route in der Vue-App für die 404-Seite definieren.\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\nAlternativ kann man bei einem Node.js-Server den Fallback nutzen, indem man das serverseitige Router-System den 404-Fehler ausgeben lässt, sollte die URL auf keine Route treffen, die deine Vue-App kennt.\n"
  },
  {
    "path": "docs-gitbook/de/essentials/named-routes.md",
    "content": "# Benannte Routes\n\nManchmal ist es einfacher, eine Route mit einem Namen anzusprechen. Besonders bei Links zu einer Route oder dem Ausführen von Navigationen. Den Namen vergibt man beim Erzeugen der Router-Instanz in den `routes`-Optionen:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nUm mit `router-link` zu einer benannten Route zu verlinken, gibt man ein Objekt in die `to`-Prop ein:\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\nDas exakt gleiche Objekt kann auch programmatisch in `router.push()` genutzt werden.\n\n\n``` js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nIn beiden Fällen wird der Router zum Pfad `/user/123` navigieren.\n\nVollständiges Beispiel [hier](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs-gitbook/de/essentials/named-views.md",
    "content": "# Benannte Views\n\nManchmal muss man mehrere Views zur selben Zeit darstellen, anstatt sie zu verschachteln. Zum Beispiel bei einem Layout mit Hauptteil und Seitenleiste. Hier sind benannte Views nützlich. Anstelle eines einzigen Outlets für die View-Darstellung gibt es mehrere, die Namen tragen können. Ein `router-view` ohne Namen heißt standardmäßig `default`.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nEin View wird durch eine Komponente gerendert, deswegen benötigen mehrere Views auch mehrere Komponenten für dieselbe Route. Dabei ist es wichtig, `components` (Plural) in den Optionen zu verwenden:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nEine Demo zu diesem Beispiel ist\n[hier](https://jsfiddle.net/posva/6du90epg/) zu finden.\n"
  },
  {
    "path": "docs-gitbook/de/essentials/navigation.md",
    "content": "# Programmatische Navigation\n\nNeben `router-link` für deklarative Links in Templates, können wir mit Hilfe der Methoden der Router-Instanz programmatisch navigieren.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\nUm zu einer anderen URL zu navigieren, nutzt man `router.push`. Diese Methode \"pusht\" einen neuen Eintrag in den Browser-Verlauf, sodass der Nutzer, wenn er die Zurück-Schaltfläche des Browsers betätigt, zur vorherigen URL zurückkehrt.\n\nDas ist dieselbe Methode, die intern aufgerufen wird, wenn wir auf einen `<router-link>` klicken. Das Anlicken von `<router-link :to=\"...\">` ist also das Äquivalent zu `router.push(...)`.\n\n| Deklarativ | Programmatisch |\n|-------------|--------------|\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\nDas Argument kann ein Pfad als String oder eine Beschreibung des Ziels (der \"location\") als Objekt sein.\n\n``` js\n// String\nrouter.push('home')\n\n// Objekt\nrouter.push({ path: 'home' })\n\n// benannte (\"named\") Route\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// mit Query, resultiert in /register?plan=private\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\nIn Version 2.2.0 können wir optional `onComplete` und `onAbort` Callbacks als zweites und drittes Argument angeben. Diese Callbacks werden jeweilse aufgerufen, wenn die Navigation entweder erfolgreich abgeschlossen wurde (nachdem alle asynchronen hooks durchlaufen wurden), oder wenn sie abgerochen wurde (weil eine neue Navigation zu derselben oder einer anderen Route gestartet wurde, z.B. durch einen Klick, bevor die aktuelle Navigation beendet werden konnte).\n\n#### `router.replace(location, onComplete?, onAbort?)`\n\nDise methode verhält sich wie `router.push`, allerdings erstellt sie keinen neuen Eintrag im Browser-Verlauf. Sie ersetzt lediglich den aktuellen Eintrag.\n\n| Deklarativ | Programmatisch |\n|-------------|--------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n#### `router.go(n)`\n\nDiese Methode akzeptiert einen einfachen Integer als Parameter, der angibt, wie viele Schritte im Browser-Verlauf vor- oder rückwärts zu gehen sind - ähnlich wie `window.history.go(n)`.\n\nBeispiele\n\n``` js\n// gehe einen Eintrag vorwärts - wie history.forward()\nrouter.go(1)\n\n// gehe einen Eintrag zurück - wie history.back()\nrouter.go(-1)\n\n// gehe drei Einträge vor\nrouter.go(3)\n\n// scheitert ohne Nachricht, wenn nicht genügend Einträge vorhanden sind\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### Manipulation des Verlaufs\n\nVielleicht ist dir aufgefallen, dass `router.push`, `router.replace` und `router.go` Gegenstücke von [`window.history.pushState`, `window.history.replaceState` und `window.history.go`](https://developer.mozilla.org/de/docs/Web/API/History) sind und sie die `window.history`-API imitieren.\n\nDas macht es einfach, den Verlauf zu manipulieren, wenn man sich mit den [Browser-Verlauf-APIs](https://developer.mozilla.org/de/docs/Web/Guide/DOM/Manipulating_the_browser_history)\nauskennt.\n\nErwähnenswert ist, dass Navigationsmethoden von `vue-router` (`push`, `replace`, `go`) in allen router modes (`history`, `hash`, `abstract`) genau gleich funktionieren.\n"
  },
  {
    "path": "docs-gitbook/de/essentials/nested-routes.md",
    "content": "# Verschachtelte Routes\n\nEchte App-UIs bestehen normalerweise aus Komponenten, die mehrere Ebenen tief verschachtelt sind. Und es ist durchaus üblich, dass die Segmente der URL die Struktur der Verschachtelung wiederspiegeln, zum Beispiel so:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\nMit `vue-router` können wir derartige Beziehungen sehr leicht mit einer verschachtelten (englisch: \"nested\") Route-Konfiguration abbilden.\n\nWir bauen auf der App auf, die im letzten Kapitel erstellt wurde:\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nDie `router-view` Komponente ist das Outlet der obersten Ebene. Sie rendert die Komponenten, welche zu Routes der obersten Ebene gehören. Eine dort gerenderte Komponente kann selbst wiederum eine `router-view` Komponente enthalten. Wenn wir zum Beispiel eine `router-view` Komponente im Template der User-Komponente platzieren, sieht das so aus:\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nUm Komponenten in diesem verschachtelten Outlet zu rendern, müssen wir die `children`-Option in der Konfiguration des `VueRouter`-Konstruktors verwenden.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User,\n      children: [\n        {\n          // UserProfile wird innerhalb der\n          // <router-view> von User gerendert,\n          // wenn '/user/:id/profile' gematched wird.\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // UserPosts wird innerhalb der\n          // <router-view> von User gerendert,\n          // wenn '/user/:id/posts' gematched wird.\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Hinweis: Verschachtelte Pfade, die mit `/` starten, werden als \"root-path\" (zu deutsch: \"Wurzel-Pfad\") behandelt. Damit kann man eine verschachtelte Route mit einem direkten Pfad erreichen, ohne dass die verschachtelten Pfadsegmente der übergeordneten Routes enthalten sein müssen.**\n\nWie du sieht, ist die `children`-Option nur eine weiteres Array mit Route-Konfigurationsobjekten - wie das `routes`-Array selbst. Daher können wir Views so oft ineinander verschachteln, wie wir möchten.\n\nWenn du nun aber mit mit der aktuellen Konfiguration `/user/foo` aufrufst, wird nichts im `router-view` Outlet von `User` gerendert, da keine Sub-Route gematched wurde. Wollen wir in dem Fall dennoch eine Komponente rendern, erreichen wir das ganz einfach mit einer Route im `children`-Array, die einen leeren String als Pfad hat:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id', component: User,\n      children: [\n        // UserHome wird in <router-view>\n        // von User gerendert,\n        // wenn /user/:id zutrifft.\n        { path: '', component: UserHome },\n\n        // ...weitere Sub-Routes\n      ]\n    }\n  ]\n})\n```\n\nEine Demo dazu findest du [hier](http://jsfiddle.net/yyx990803/L7hscd8h/)\n"
  },
  {
    "path": "docs-gitbook/de/essentials/redirect-and-alias.md",
    "content": "# Redirect und Alias\n\n### Redirect (Umleitung)\n\nEin Redirect bedeutet, dass, wenn der Nutzer `/a` besucht, die URL mit `/b` ersetzt wird und auch die Komponente der Route zu `/b` rendert. Das kann in der `routes`-Konfiguration folgendermaßen eingestellt werden:\n\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nDer Redirect kann auch auf eine benannten Route angewandt werden:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nOder auch mit einer Funktion für dynamische Redirects:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // Die Funktion erhält die Ziel-Route als Argument\n      // und gibt den Umleitungsort/-pfad hier aus.\n    }}\n  ]\n})\n```\n\nFür erweiterte Anwendungsmöglichkeiten siehe auch dieses [Beispiel](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n### Alias\n\nEin Redirect bedeutet: Wenn wir die URL `/a` besuchen, wird die URL mit `/b` ersetzt und dann mit der Route für `/b` gematched. Aber was ist dann ein *Alias*?\n\nEin Alias von `/a` als `/b` bedeutet, dass die URL `/b` bleibt, wenn diese besucht wird, jedoch die Komponente von `/a` gerendert wird.\n\nDieses kann man in der Router-Konfiguration folgendermaßen definieren:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nEin Alias biete die Möglichkeit, eine bestimmte UI-Struktur einer beliebigen URL zuzuordnen, anstatt von der verschachtelten Struktur der Konfiguration eingeschränkt zu werden.\n\nFür die erweiterte Anwendung siehe folgendes [Beispiel](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js).\n"
  },
  {
    "path": "docs-gitbook/de/installation.md",
    "content": "# Installation\n\n### Direkter Download / CDN\n\n[https://unpkg.com/vue-router](https://unpkg.com/vue-router)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) bietet NPM-basierte CDN-Links an. Der obige Link führt immer zur aktuellsten Version auf NPM. Eine genaue Version kann via URL genutzt werden: `https://unpkg.com/vue-router@2.0.0`.\n<!--/email_off-->\n\nFüge `vue-router` nach Vue ein und es installiert sich automatisch selbst:\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### NPM\n\n``` bash\nnpm install vue-router\n```\n\nWenn ein Module-System genutzt wird (z.B. Webpack, Browserify), muss der Router explizit via `Vue.use()` installiert werden:\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nWenn globale Skript-Tags genutzt werden ist das nicht notwendig.\n\n### Dev Build (Entwicklungs-Version)\n\nWenn die aktuelle Dev-Version genutzt werden soll, muss das Repository direkt von GitHub geklont und die aktuelle `vue-router`-Build selbst erstellt werden, .\n\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs-gitbook/es/README.md",
    "content": "{% include \"./SUMMARY.md\" %}\n"
  },
  {
    "path": "docs-gitbook/es/SUMMARY.md",
    "content": "# vue-router\n<!--email_off-->\n> Notas: vue-router@2.x funciona solamente con Vue 2.x. La documentación para la versión 0.7.x está [aquí (en inglés)](https://github.com/vuejs/vue-router/tree/1.0/docs/en).\n<!--/email_off-->\n**[Notas de lanzamiento](https://github.com/vuejs/vue-router/releases)**\n\n- [Instalación](installation.md)\n- Esenciales\n  - [Primeros pasos](essentials/getting-started.md)\n  - [Matching dinámico de rutas](essentials/dynamic-matching.md)\n  - [Sub-rutas](essentials/nested-routes.md)\n  - [Navegación mediante código](essentials/navigation.md)\n  - [Rutas con nombre](essentials/named-routes.md)\n  - [Vistas con nombre](essentials/named-views.md)\n  - [Redireccionamiento y alias](essentials/redirect-and-alias.md)\n  - [Pasando propiedades a componentes de ruteo](essentials/passing-props.md)\n  - [Modo historial HTML5](essentials/history-mode.md)\n- Avanzado\n  - [Guardias de navegación](advanced/navigation-guards.md)\n  - [Campos Meta en las rutas](advanced/meta.md)\n  - [Transiciones](advanced/transitions.md)\n  - [Obtención de datos](advanced/data-fetching.md)\n  - [Comportamiento del scroll](advanced/scroll-behavior.md)\n  - [Lazy loading](advanced/lazy-loading.md)\n- API\n  - [Opciones del constructor de Router](api/options.md)\n    - [rutas](api/options.md#routes)\n    - [modo](api/options.md#mode)\n    - [base](api/options.md#base)\n    - [linkActiveClass](api/options.md#linkactiveclass)\n    - [linkExactActiveClass](api/options.md#linkexactactiveclass)\n    - [scrollBehavior](api/options.md#scrollbehavior)\n    - [parseQuery / stringifyQuery](api/options.md#parsequery--stringifyquery)\n    - [fallback](api/options.md#fallback)\n  - [La instancia de Router](api/router-instance.md)\n    - [Propiedades](api/router-instance.md#properties)\n    - [Métodos](api/router-instance.md#methods)\n  - [El objeto Route](api/route-object.md)\n  - [Inyección en componentes](api/component-injections.md)\n  - [router-link](api/router-link.md)\n  - [router-view](api/router-view.md)\n"
  },
  {
    "path": "docs-gitbook/es/advanced/data-fetching.md",
    "content": "# Obtención de datos\n\nA veces es necesario obtener datos del servidor cuando una ruta es activada. Por ejemplo, antes de renderizar un perfil de usuario, puedes obtener la información de ese usuario desde el servidor. Podemos lograr esto de dos maneras diferentes:\n\n- **Obtener la información después de la navegación**: realiza la navegación primero y luego obtén los datos en un _hook_ del ciclo de vida del componente entrante. Puedes mostrar un indicador de carga mientras se obtienen los datos.\n\n- **Obtener la información antes de la navegación**: Obtén los datos antes de la navegación en la guardia de entrada de la ruta, y realiza la navegación una vez estos obtenidos.\n\nTécnicamente, ambas opciones son válidas - todo depende de la experiencia de usuario a la que apuntes.\n\n## Obtener la información después de la navegación\n\nCuando utilizamos este enfoque, navegamos y renderizamos el componente entrante inmediatamente, y obtenemos los datos en el _hook_ `created` del componente. Esto nos permite mostrar un indicador de estado de carga mientras se obtiene la información desde un servidor remoto, y también manejar la carga de datos según la ruta.\n\nAsumamos que tenemos un componente `Post` que necesita obtener datos de un _post_ basándose en `$route.params.id`:\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // obtén los datos cuando la vista es creada y _data_ ya\n    // está siendo observada\n    this.fetchData()\n  },\n  watch: {\n    // ejecuta nuevamente el método si la ruta cambia\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // reemplaza getPost con lo que corresponda\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Obtener la información antes de la navegación\n\nCon este enfoque, obtenemos la información antes de navegar a la nueva ruta. Podemos obtener los datos en el guardia `beforeRouteEnter` del componente entrante, y solo ejecutar `next` cuando se haya completado:\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // cuando la ruta cambie y este componente ya haya sido renderizado,\n  // la lógica será ligeramente diferente\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\nEl usuario permanecerá en la vista anterior mientras se esté obteniendo el recurso para la vista entrante. Por lo tanto, es recomendable mostrar algún tipo de indicador o barra de progreso. Si la obtención de datos falla, es necesario mostrar algún tipo de advertencia global.\n"
  },
  {
    "path": "docs-gitbook/es/advanced/lazy-loading.md",
    "content": "# Lazy loading\n\nCuando se construyen aplicaciones con un sistema de empaquetamiento de módulos, el archivo JavaScript resultante puede terminar siendo muy grande, afectando los tiempos de carga de la página. Sería más eficiente si pudiesemos dividir los componentes de cada ruta en porciones separadas y cargarlas solo cuando esa ruta es visitada.\n\nCombinando [las características asíncronas de componentes de Vue](http://vuejs.org/guide/components.html#Async-Components) y las características de división de código de [Webpack](https://webpack.js.org/guides/code-splitting-require/), es trivial el _lazy loading_ de componentes de ruta.\n\nTodo lo que necesitamos es definir nuestros componentes de rutas como asíncronos:\n\n``` js\nconst Foo = resolve => {\n  // require.ensure es la sintaxis especial de Webpack para indicar un punto de división de código.\n  require.ensure(['./Foo.vue'], () => {\n    resolve(require('./Foo.vue'))\n  })\n}\n```\n\nHay una alternativa a la sintaxis de división de código utilizando _require_ como lo hace AMD, por lo que puede simplificarse como:\n\n``` js\nconst Foo = resolve => require(['./Foo.vue'], resolve)\n```\n\nNada debe cambiarse en la configuración del _router_, solo utiliza `Foo` como lo harías normalmente:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/foo', component: Foo }\n  ]\n})\n```\n\n### Agrupando componentes en la misma porción\n\nA veces deseamos agrupar todos los componentes bajo la misma ruta en la misma porción asíncrona. Para lograr esto, necesitamos usar [porciones con nombre](https://webpack.js.org/guides/code-splitting-require/#chunkname) proveyendo un nombre de porción a `require.ensure` como el tercer argumento:\n\n``` js\nconst Foo = r => require.ensure([], () => r(require('./Foo.vue')), 'group-foo')\nconst Bar = r => require.ensure([], () => r(require('./Bar.vue')), 'group-foo')\nconst Baz = r => require.ensure([], () => r(require('./Baz.vue')), 'group-foo')\n```\n\nWebpack agrupará los módulos asíncronos con el mismo nombre dentro de la misma porción asíncrona - esto también significa que no necesitamos más listar explícitamente las dependencias de `require.ensure` (por lo tanto pasamos un array vacío).\n"
  },
  {
    "path": "docs-gitbook/es/advanced/meta.md",
    "content": "# Campos Meta en las rutas\n\nPuedes incluir un campo `meta` cuando definas una ruta:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // campo meta\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nEntonces, ¿como accedemos al campo `meta`?\n\nPrimero, cada objeto route en la configuración de `routes` se llama **registro de ruta**. Los registros de ruta pueden estar anidados. Por lo tanto, cuando una ruta coincida, existe la posibilidad que lo haga con más de un registro de ruta.\n\nPor ejemplo, con la configuración anterior, la URL `/foo/bar` coincidirá tanto con el registro de ruta padre como con el hijo.\n\nTodos los registros de rutas que hayan coincidido son expuestos en el objeto `$route` (y también a los objetos route en las guardias de navegación) como el array `$route.matched`. Por ende, necesitaremos iterar sobre `$route.matched` para verificar campos meta en los registros de rutas.\n\nUn caso de uso de ejemplo es verificar la existencia de campos metas en los guardias de navegación global:\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // esta ruta requiere autenticación, verificamos que haya iniciado sesión\n    // sino, redirigimos a la página de inicio de sesión.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // ¡Asegúrate de ejecutar next siempre!\n  }\n})\n```\n"
  },
  {
    "path": "docs-gitbook/es/advanced/navigation-guards.md",
    "content": "# Guardias de navegación\n\nComo el nombre sugiere, las guardias de navegación provistas por `vue-router` son básicamente utilizadas para proteger rutas de navegación ya sea redireccionando o cancelándolas. Hay varias maneras de engancharse en el proceso de navegación de rutas: globalmente, por ruta o dentro de los componentes.\n\nRecuerda: **Los cambios en los parámetros o las _queries_ no harán que se ejecuten los guardias de navegación**. Simplemente [observa el objeto `$route`](../essentials/dynamic-matching.md#reacting-to-params-changes) para poder reaccionar frente a esos cambios o utiliza el guardia `beforeRouteUpdate` en el componente.\n\n### Guardias globales\n\nPuedes registrar guardias _before_ globales utilizando `router.beforeEach`:\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nLas guardias _before_ globales son llamadas por orden de creación, cuando una navegación comienza. Las guardias pueden ejecutarse asincrónicamente, y la navegación se considera **pendiente** hasta que todos los _hooks_ sean resueltos. \n\nCada función guardia recibe tres argumentos:\n\n- **`to: Route`**: el [Objeto Route](../api/route-object.md) hacia donde se navega.\n\n- **`from: Route`**: la ruta actual desde la cual se navega.\n\n- **`next: Function`**: esta función debe ser ejecutada para **resolver** el _hook_. La acción a realizar depende de los argumentos provistos a `next`:\n\n  - **`next()`**: moverse al siguiente _hook_ en la cadena. Si no queda ninguno, la navegación se **confirma**.\n\n  - **`next(false)`**: cancelar la navegación actual. Si la URL en el navegador cambió (ya sea manualmente o a través del botón _atrás_), será reseteada al valor de la ruta `from`.\n\n  - **`next('/')` o `next({ path: '/' })`**: redirecciona a una ruta diferente. La navegación actual será abortada y una nueva será iniciada.\n\n  - **`next(error)`**: (2.4.0+) si el argumento pasado a `next` es una instancia de `Error`, la navegación se abortará y el error será pasado a las _funciones callback_ registradas a través de `router.onError()`.\n\n**Asegúrese de llamar siempre a la función `next`, sino el _hook_ nunca será resuelto.**\n\n### Guardias de resolución globales\n\n> Nuevo en 2.5.0\n\nA partir de la versión 2.5.0 puedes registrar un guardia global con `router.beforeResolve`. Esto es similar a `router.beforeEach`, con la diferencia que los guardias de resolución serán llamados justo antes de que la navegación sea confirmada, **después que todos los guardias en el componente y los componentes de rutas asíncronos sean resueltos**.\n\n### Post _hooks_ globales\n\nTambién puedes registrar _hooks_ globales que se ejecutarán después de que la navegación sea confirmada. Sin embargo, a diferencia de los guardias, estos _hooks_ no reciben una función `next` y no pueden afectar la navegación:\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### Guardias por ruta\n\nPuedes definir guardias `beforeEnter` directamente en el objeto de configuración de una ruta:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nEstos guardias tienen exactamente la misma firma que los guardias _before_ globales.\n\n### Guardias en componentes\n\nPor último, puedes directamente definir guardias de navegación dentro de los componentes de ruta (los que son pasados a la configuración del `router`) con las siguientes opciones:\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (agregado en la versión 2.2)\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // se llama antes que la ruta que renderiza este componente sea confirmada.\n    // NO tiene acceso a la instancia del componente `this`,\n    // ¡porque no ha sido creada todavía cuando este guardia es ejecutado!\n  },\n  beforeRouteUpdate (to, from, next) {\n    // se llama cuando la ruta que renderiza este componente ha cambiado,\n    // pero este componente es reusado en la nueva ruta.\n    // Por ejemplo, para una ruta con parámetros dinámicos /foo/:id, cuando\n    // navegamos desde /foo/1 havia /foo/2, la misma instancia del componente Foo\n    // será reusada, y este _hook_ será llamado cuando eso suceda.\n    // Tiene acceso a la instancia del componente `this`\n  },\n  beforeRouteLeave (to, from, next) {\n    // se llama cuando la ruta que renderiza el componente está por ser\n    // abandonada.\n    // Tiene acceso a la instancia del componente `this`\n  }\n}\n```\n\nLa guardia `beforeRouteEnter` **NO** tiene acceso a `this`, porque es ejecutada antes que la navegación sea confirmada, por lo tanto el componente destino todavía no ha sido creado.\n\nSin embargo, puedes acceder a la instancia pasando una _función callback_ a `next`. La _función callback_ se ejecutará cuando la navegación sea confirmada, y la instancia del componente será pasada como argumento:\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // accede a la instancia del componente a través de `vm`\n  })\n}\n```\n\nPuedes acceder directamente a `this` dentro de `beforeRouteLeave`. La guardia _leave_ se utiliza normalmente para prevenir al usuario cuando intenta abandonar la ruta accidentalmente sin guardar cambios. La navegación puede ser cancelada ejecutando `next(false)`.\n\n### El flujo de resolución de navegación completo\n\n1. Se dispara la navegación.\n2. Se llaman a los guardias _leave_ en los componentes desactivados.\n3. Se llaman a los guardias `beforeEach` globales.\n4. Se llaman a los guardias `beforeRouteUpdate` en los componentes reutilizados (2.2+).\n5. Se llama a `beforeEnter` en las configuraciones de rutas.\n6. Se resuelven componentes de rutas asíncronos.\n7. Se llama a `beforeRouteEnter` en los componentes activados.\n8. Se llama a los guardias globales `beforeResolve` (2.5+).\n9. Se confirma la navegación.\n10. Se llaman a los _hook_ globales`afterEach`.\n11. Se disparan las actualizaciones del DOM.\n12. Se llaman a las _funciones callback_ pasadas a `next` en los guardias `beforeRouteEnter` con las instancias creadas.\n"
  },
  {
    "path": "docs-gitbook/es/advanced/scroll-behavior.md",
    "content": "# Comportamiento del scroll\n\nCuando se utiliza enrutamiento del lado cliente, podemos querer hacer `scroll` hacia el inicio de la página cuando naveguemos a una nueva ruta, o preservar la posición actual, tal cual lo hace una recarga de la página. `vue-router` te permite lograr esto e incluso más: permite personalizar completamente el comportamiento del `scroll` durante la navegación.\n\n**Nota: esta característica solo funciona en el modo historial de HTML5.**\n\nCuando crees una instancia del `router`, puedes incluir la función `scrollBehavior`:\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // devolver la posición deseada\n  }\n})\n```\n\nLa función `scrollBehavior` recibe los objetos de ruta `to` y `from`. El tercer parámetro, `savedPosition`, solo está disponible si estamos en una navegación `popstate` (cuando se utilizan los botones _atrás_ o _adelante_ en el navegador).\n\nLa función puede devolver un objeto de posición de `scroll`. El objeto puede ser de la forma:\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset solo soportado a partir de la versión 2.6.0+)\n\nSi se devuelve un valor *falso* o un objeto vacio, no ocurrirá ningún desplazamiento.\n\nPor ejemplo:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nEsto hará que la página se desplace hacia el inicio para todas las navegaciones a la ruta.\n\nDevolver `savedPosition` hará que el comportamiento cuando se utilicen los botones _atrás_ o _adelante_ sea el nativo:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nSi deseas simular el `scroll` hacia anclas:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nTambién podemos utilizar [campos meta](meta.md) para implementar un control de `scroll` fino. Un ejemplo completo [aquí](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js).\n"
  },
  {
    "path": "docs-gitbook/es/advanced/transitions.md",
    "content": "# Transiciones\n\nDado que `<router-view>` es esencialmente un componente dinámico, podemos aplicarle efectos de transición utilizando el componente `<transition>`:\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[Todo acerca de `<transition>`](http://vuejs.org/guide/transitions.html) también funciona aquí.\n\n### Transiciones por ruta\n\nEl ejemplo anterior aplicará la misma transición a todas las rutas. Si deseas que cada componente de ruta tenga diferentes transiciones, puedes utilizar `<transition>` con diferentes nombres dentro de cada componente de ruta:\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n### Transiciones dinámicas basadas en componentes\n\nTambién es posible determinar dinámicamente la transición a utilizar basado en las relaciones entre la ruta destino y la ruta actual:\n\n``` html\n<!-- utiliza un nombre de transición dinámico -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// luego, en el componente padre,\n// observa $route para determinar que transición utilizar\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nTienes un ejemplo completo [aquí](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).\n"
  },
  {
    "path": "docs-gitbook/es/api/component-injections.md",
    "content": "# Inyección en componentes\n\n### Propiedades inyectadas\n\nEstas propiedades son inyectadas dentro de cada componente hijo pasando la instancia del `router` a la instancia principal como la opción `router`.\n\n- #### $router\n\n  La instancia del `router`.\n\n- #### $route\n\n  El objeto [Route activo](route-object.md). Esta propiedad es de solo lectura y sus propiedades son inmutables, pero puede ser observada.\n\n### Opciones habilitadas\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate** (agregado en 2.2)\n- **beforeRouteLeave**\n\n  Más información en [guardias en componentes](../advanced/navigation-guards.md#incomponent-guards).\n"
  },
  {
    "path": "docs-gitbook/es/api/options.md",
    "content": "# Opciones del constructor de Router\n\n### routes\n\n- tipo: `Array<RouteConfig>`\n\n  Declaración de tipos para `RouteConfig`:\n\n  ``` js\n  declare type RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // para rutas con nombre\n    components?: { [name: string]: Component }; // para vistas con nombre\n    redirect?: string | Location | Function;\n    props?: boolean | string | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // para sub-rutas\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n\n    // 2.6.0+\n    caseSensitive?: boolean; // utilizar o no matcheo case sensitive (valor por defecto: false)\n    pathToRegexpOptions?: Object; // Opciones path-to-regexp para compilar expresiones regulares\n  }\n  ```\n\n### mode\n\n- tipo: `string`\n\n- valor por defecto: `\"hash\" (en navegadores) | \"abstract\" (en Node.js)`\n\n- valores disponibles: `\"hash\" | \"history\" | \"abstract\"`\n\n  Configura el modo del `router`.\n\n  - `hash`: utiliza el _hash_ en la URL para el enrutamiento. Funciona en todos los navegadores que soportan Vue, incluidos aquellos que no soportan la API de historial de HTML5 .\n\n  - `history`: requiere la API de historial de HTML y configuración del lado servidor. [Modo historial HTML5](../essentials/history-mode.md).\n\n  - `abstract`: funciona en todos los ambientes de JavaScript, por ejemplo, del lado servidor con Node.js. **Se forzará este modo de trabajo en el router si no se detecta la API de navegador.**\n\n### base\n\n- tipo: `string`\n\n- valor por defecto: `\"/\"`\n\n  La URL base para la aplicación. Por ejemplo, si toda la aplicación se encuentra dentro de `/app/`, entonces `base` debería llevar ese valor.\n\n### linkActiveClass\n\n- tipo: `string`\n\n- valor por defecto: `\"router-link-active\"`\n\n  Configura globalmente la clase activa por defecto de `<router-link>`. Más información en [router-link](router-link.md).\n\n### linkExactActiveClass\n\n> 2.5.0+\n\n- tipo: `string`\n\n- valor por defecto: `\"router-link-exact-active\"`\n\n  Configura globalmente la clase activa de `<router-link>` para coincidencias de rutas exactas. Más información en [router-link](router-link.md).\n\n### scrollBehavior\n\n- tipo: `Function`\n\n  Firma:\n\n  ```\n  (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => { x: number, y: number } | { selector: string } | ?{}\n  ```\n\n  Para más detalles, [comportamiento del scroll](../advanced/scroll-behavior.md).\n\n### parseQuery / stringifyQuery\n\n> 2.4.0+\n\n- tipo: `Function`\n\n  Provee funciones parse / stringify para _query string_ personalizadas. Sobreescribe la función por defecto.\n\n### fallback\n\n> 2.6.0+\n\n- tipo: `boolean`\n\n  Controla si el router debe o no utilizar el modo `hash` cuando el navegador no soporte `history.pushState`. El valor por defecto es `true`.\n\n  Configurar esto como `false` hace que cada navegación a través de `router-link` sea una recarga completa de la página en IE9. Esto es útil cuando la aplicación es renderizada en el servidor y necesita funcionar en IE9, porque las URL en modo hash no funcionan con SSR.\n"
  },
  {
    "path": "docs-gitbook/es/api/route-object.md",
    "content": "# El objeto Route\n\nUn **objeto Route** representa el estado de la ruta activa actualmente. Contiene información analizada de la URL actual y los **registros de rutas** que coinciden con ella.\n\nEl objeto `Route` es inmutable. Cada navegación exitosa resultará en un nuevo objeto `Route`.\n\nEl objeto `Route` puede encontrarse en diferentes lugares.\n\n- Dentro de los componentes, como `this.$route`\n\n- Dentro de las _funciones callbacks_ de observación de `$route`\n\n- Como valor de retorno de la función `router.match(location)`\n\n- Dentro de las guardias de navegación como los primeros dos argumentos:\n\n  ``` js\n  router.beforeEach((to, from, next) => {\n    // to y from son objetos de ruta\n  })\n  ```\n\n- Dentro de la función `scrollBehavior`como los primeros dos argumentos:\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n      // to y from son objetos de ruta\n    }\n  })\n  ```\n\n### Propiedades del objeto Route\n\n- **$route.path**\n\n  - tipo: `string`\n\n    Una cadena de texto equivalente a la ruta actual, siempre resuelta como una ruta absoluta. Por ejemplo`\"/foo/bar\"`.\n\n- **$route.params**\n\n  - tipo: `Object`\n\n    Un objeto que contiene pares llave/valor de segmentos dinámicos y segmentos estrella. Si no hay parametros, el valor será un objeto vacio.\n\n- **$route.query**\n\n  - tipo: `Object`\n\n    Un objeto que contiene pares llave/valor del _query string_. Por ejemplo, para la ruta `/foo?user=1`, obtendremos `$route.query.user == 1`. Si no hay _query string_ el valor será un objeto vacio.\n\n- **$route.hash**\n\n  - tipo: `string`\n\n    El _hash_ de la ruta actual (con la `#`), si posee. Si no hay un _hash_ el valor será una cadena de texto vacia.\n\n- **$route.fullPath**\n\n  - tipo: `string`\n\n    La URL completa incluyendo _query_ y _hash_.\n\n- **$route.matched**\n\n  - tipo: `Array<RouteRecord>`\n\n  Un array que contiene **registros de ruta** para todos los segmentos anidados de la ruta actual. Los registros de ruta son copias de los objetos en el array de configuración `routes` (y en los arrays `children`):\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // el siguiente objeto es un registro de ruta\n      { path: '/foo', component: Foo,\n        children: [\n          // este también es un registro de ruta\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  Cuando la URL es `/foo/bar`, `$route.matched` será un array que contendrá ambos objetos (clonados), en orden descendente de padre a hijo.\n\n- **$route.name**\n\n  El nombre de la ruta acutal, si tiene. (Más información en [rutas con nombre](../essentials/named-routes.md))\n"
  },
  {
    "path": "docs-gitbook/es/api/router-instance.md",
    "content": "# La instancia de Router\n\n### Propiedades\n\n#### router.app\n\n- tipo: `Vue instance`\n\n  La instancia principal de Vue donde `router` fue inyectado.\n\n#### router.mode\n\n- tipo: `string`\n\n  El [modo](options.md#mode) que `router` está utilizando.\n\n#### router.currentRoute\n\n- tipo: `Route`\n\n  La ruta actual representada como un [objeto Route](route-object.md).\n\n### Métodos\n\n- **router.beforeEach(guard)**\n- **router.beforeResolve(guard)** (2.5.0+)\n- **router.afterEach(hook)**\n\n  Agrega guardias de navegación globales. Info: [guardias de navegación](../advanced/navigation-guards.md).\n\n  A partir de la versión 2.5.0 los tres métodos devuelven una función que elimina el guardia/hook registrado.\n\n- **router.push(location, onComplete?, onAbort?)**\n- **router.replace(location, onComplete?, onAbort?)**\n- **router.go(n)**\n- **router.back()**\n- **router.forward()**\n\n  Navega mediante código a una nueva URL. Info: [navegación mediante código](../essentials/navigation.md).\n\n- **router.getMatchedComponents(location?)**\n\n  Devuelve un array de componentes (definiciones/constructores, no instancias) que coincidan con la ubicación provista o la ruta actual. Se utiliza principalmente durante el renderizado del lado servidor para realizar precarga de datos.\n\n- **router.resolve(location, current?, append?)**\n\n  > 2.1.0+\n\n  Resolución inversa de URL. Dada una ubicación de la misma forma que las usadas en `<router-link/>`, devuelve un objeto con las siguiente propiedades:\n\n  ``` js\n  {\n    location: Location;\n    route: Route;\n    href: string;\n  }\n  ```\n\n- **router.addRoutes(routes)**\n\n  > 2.2.0+\n\n  Agrega dinámicamente más rutas al `router`. El argumento debe ser un array utilizando el mismo formato de configuración que las opciones del constructor de `routes`.\n\n- **router.onReady(callback, [errorCallback])**\n\n  > 2.2.0+\n\n  Este método pone una _función callback_ en espera a ser llamada cuando el `router` haya completado la navegación inicial, lo cual significa que ya ha resuelto todos los _hooks_ de entrada asíncronos y los componentes asíncronos asociados con la ruta inicial.\n\n  Esto es útil en el renderizado del lado servidor para asegurar un resultado consistente tanto en el servidor como en el cliente.\n\n  El segundo argumento, `errorCallback`, solo es soportado a partir de la versión 2.4. Será llamado cuando la resolución de ruta inicial devuelva un error (por ejemplo, cuando falla la resolución de un componente asíncrono).\n\n- **router.onError(callback)**\n\n  > 2.4.0+\n\n  Registra una _función callback_ la cual será llamada cuando un error es capturado durante la navegación. Ten en cuenta que sucederá solo en las siguientes situaciones:\n\n  - El error es lanzado sincrónicamente dentro de una función de guardia de ruta;\n\n  - El error es capturado y manejado asíncronamente llamando a `next(err)` dentro de una función de guardia de ruta;\n\n  - El error ocurre cuando se intenta resolver un componente asíncrono que es necesario para renderizar una ruta.\n"
  },
  {
    "path": "docs-gitbook/es/api/router-link.md",
    "content": "# `<router-link>`\n\n`<router-link>` es el componente para posibilitar la navegación de los usuarios en una aplicación con el `router` habilitado. La ubicación destino se especifica con la propiedad `to`. Por defecto, renderiza una etiqueta `<a>` con el atributo `href` correspondiente, pero puede configurarse mediante la propiedad `tag`. Además, el enlace obtiene una clase CSS cuando la ruta a la que apunta es activada.\n\nEs preferible utilizar `<router-link>` en lugar de escribir directamente `<a href=\"...\">` por las siguientes razones:\n\n- Funciona de la misma manera tanto en el modo _hash_ como en el modo historial de HTML5, por lo que si decides intercambiar modos, o cuando el `router` utiliza el modo _hash_ en IE9, no deberás modificar nada.\n\n- En el modo historial de HTML5, `router-link` interceptará el evento _click_ para que el navegador no intente recargar la página.\n\n- Cuando estés utilizando la opción `base` en el modo historial de HTML5, no necesitas incluirla en la URL de la propiedad `to`.\n\n### Propiedades\n\n- **to**\n\n  - tipo: `string | Location`\n\n  - requerida\n\n  Identifica la ruta destino del enlace. Cuando es accedida, el valor de la propiedad `to` será pasado a `router.push()` internamente, por lo que el valor puede ser tanto una cadena de texto como un objeto descriptor de ubicación.\n\n  ``` html\n  <!-- cadena de texto -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- renders to -->\n  <a href=\"home\">Home</a>\n\n  <!-- expresión javascript utilizando v-bind -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- omitir v-bind es correcto, tal cual se hace con cualquier otra propiedad -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- lo mismo que el ejemplo anterior -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- rutas con nombre -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- con query, resultando en /register?plan=private -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n- **replace**\n\n  - tipo: `boolean`\n\n  - valor por defecto: `false`\n\n  Establecer la propiedad `replace` ejecutará `router.replace()` en lugar de `router.push()` cuando se acceda, por lo que la navegación no dejará un registro en el historial.\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n- **append**\n\n  - tipo: `boolean`\n\n  - valor por defecto: `false`\n\n  Establecer la propiedad `append` hará que se agregue la ruta relativa a la ruta actual. Por ejemplo, asumiendo que estamos navegando desde `/a` a un enlace relativo `b`, sin `append` accederemos a `/b`, pero con `append` accederemos a `/a/b`.\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n- **tag**\n\n  - tipo: `string`\n\n  - valor por defecto: `\"a\"`\n\n  A veces puede que quieras que `<router-link>` se renderice como otra etiqueta, por ejemplo `<li>`. Puedes utilizar la propiedad `tag` para especificar que etiqueta renderizar, y seguirá escuchando eventos _click_ para la navegación.\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- se renderiza como -->\n  <li>foo</li>\n  ```\n\n- **active-class**\n\n  - tipo: `string`\n\n  - valor por defecto: `\"router-link-active\"`\n\n  Configura la clase CSS que se aplicará al enlace cuando este activo. Nota que el valor por defecto puede ser configurado de manera global a través de la opción `linkActiveClass`  del constructor del `router`.\n\n- **exact**\n\n  - tipo: `boolean`\n\n  - valor por defecto: `false`\n\n  El comportamiento por defecto para la aplicación de la clase CSS activa en matching dinámico de rutas es **inclusivo**. Por ejemplo, `<router-link to=\"/a\">` obtendrá la clase CSS mientras la ruta actual comience con `/a/` o sea `/a`.\n\n  Una consecuencia de esto es que `<router-link to=\"/\">` ¡permanecerá activa para todas las rutas! Para forzar un matching exacto, utiliza la propiedad `exact`:\n\n  ``` html\n  <!-- este enlace estará activo solamente para la ruta / -->\n  <router-link to=\"/\" exact>\n  ```\n\n  Más ejemplos explicando la clase activa [aquí](https://jsfiddle.net/8xrk1n9f/).\n\n- **event**\n\n  > 2.1.0+\n\n  - tipo: `string | Array<string>`\n\n  - valor por defecto: `'click'`\n\n  Son los eventos que permiten lanzar la navegacion.\n\n- **exact-active-class**\n\n  > 2.5.0+\n\n  - tipo: `string`\n\n  - valor por defecto: `\"router-link-exact-active\"`\n\n  Configura la clase CSS activa que será aplicada cuando el enlace esté activo con una coincidencia de ruta exacta. Ten en cuenta que el valor por defecto también puede configurarse globalmente a través de la opción `linkExactActiveClass` del constructor del router.\n\n### Aplicar la clase activa al elemento envolvente.\n\nA veces puede que queramos que la clase activa se aplique al elemento envolvente en lugar de aplicarla directamente a la etiqueta `<a>`. En ese caso, puedes renderizar el elemento envolvente utilizando `<router-link>` y luego una etiqueta `<a>` dentro:\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\nEn este caso, la etiqueta `<a>` será el enlace (y obtendrá el atributo `href` correcto), pero la clase activa será aplicada al elemento envolvente `<li>`.\n"
  },
  {
    "path": "docs-gitbook/es/api/router-view.md",
    "content": "# `<router-view>`\n\nEl componente `<router-view>` es un componente funcional que renderiza a otro en base a la ruta seleccionada. Los componentes renderizados en `<router-view>` pueden contener su propio `<router-view>`, el cual renderizará componentes para sub-rutas.\n\n### Propiedades\n\n- **name**\n\n  - tipo: `string`\n\n  - valor por defecto: `\"default\"`\n\n  Cuando un componente `<router-view>` tiene un nombre, renderizará el componente con el nombre correspondiente en la opción `components` del registro de ruta que coincida. Accede a [vistas con nombre](../essentials/named-views.md) para más información.\n\n### Comportamiento\n\nCualquier propiedad diferente a `name` será pasada al componente renderizado. De cualquier manera, la mayor parte del tiempo los datos de la ruta están contenidos dentro de los parámetros de la ruta.\n\nDado que es simplemente un componente, funciona con `<transition>` y `<keep-alive>`. Cuando utilices ambos en conjunto, asegúrate de usar `<keep-alive>` dentro de `<transition>`:\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n"
  },
  {
    "path": "docs-gitbook/es/essentials/dynamic-matching.md",
    "content": "# Matching dinámico de rutas\n\nEs bastante común tener que mapear rutas con un patrón determinado al mismo componente. Por ejemplo, puede que tengamos un componente `User` el cual debería ser renderizado para todos los usuarios, pero con diferente ID. En `vue-router` podemos usar un segmento dinámico en el _path_ para lograrlo:\n\n``` js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // los segmentos dinámicos comienzan con dos puntos\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nAhora, las URL como `/user/foo` y `/user/bar` mapearán a la misma ruta.\n\nUn segmento dinámico se representa mediante dos puntos `:`. Cuando se encuentra una coincidencia en la ruta, el valor del segmento dinámico se expondrá como `this.$route.params` en cada componente. Por lo tanto, podremos renderizar el ID del usuario actual modificando el template de `User`de la siguiente manera:\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\nPuedes consultar el siguiente [ejemplo](http://jsfiddle.net/yyx990803/4xfa2f19/).\n\nSe pueden tener múltiples segmentos dinámicos en la misma ruta, y todos serán mapeados a los correspondientes campos en `$route.params`. Por ejemplo:\n\n| patrón | matching de ruta | $route.params |\n|---------|------|--------|\n| /user/:username | /user/evan | `{ username: 'evan' }` |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\nAdemás de `$route.params`, el objeto `$route` expone más información útil, como `$route.query` (si hay alguna _query_ en la URL), `$route.hash`, etc. Puedes verificar todos los detalles en la documentación de la [API](../api/route-object.md).\n\n### Reaccionando ante cambios de los parámetros\n\nUna cosa a tener en cuenta cuando se usan rutas con parámetros es que cuando el usuario navega de `/user/foo` a `/user/bar`, **la misma instancia del componente será reutilizada**. Dado que ambas rutas renderizan el mismo componente, esto es más eficiente que destruir la instancia anterior y crear una nueva. **Sin embargo, esto significa que los hooks del ciclo de vida del componentes no serán emitidos**.\n\nPara detectar cambios en los parámetros en el mismo componente, puedes observar el objeto `$route`:\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // Código que responde al cambio\n    }\n  }\n}\n```\n\nO utiliza el guardia de navegación `beforeRouteUpdate` introducido en la versión 2.2:\n\n``` js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // Código que responde al cambio\n    // no olvides ejecutar next()\n  }\n}\n```\n\n### Patrones de matching avanzados\n\n`vue-router` usa [path-to-regexp](https://github.com/pillarjs/path-to-regexp) como su motor de búsqueda de patrones, por lo que soporta varios patrones de matching avanzados tales como segmentos dinámicos opcionales, requerimientos del tipo cero o más / uno o más, e incluso patrones _regex_ personalizados. Verifica la  [documentación](https://github.com/pillarjs/path-to-regexp#parameters) para estos patrones avanzados, y [este ejemplo](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) de como usarlos con `vue-router`.\n\n### Prioridad en el matching de patrones\n\nA veces la misma URL puede coincidir con múltiples rutas. En ese caso, la prioridad se determina por el orden de la definición de las rutas: la primera ruta definida será la que tenga mayor prioridad.\n"
  },
  {
    "path": "docs-gitbook/es/essentials/getting-started.md",
    "content": "# Primeros pasos\n\n> Utilizaremos [ES2015](https://github.com/lukehoban/es6features) en el código de los ejemplos en esta guía.\n\nCrear una aplicación de una sola página (SPA por sus siglas en inglés) con Vue.js + vue-router es muy sencillo. Con Vue.js, ya estamos estructurando nuestra aplicación con componentes. Cuando agregamos vue-router, todo lo que debemos hacer es mapear nuestros componentes a las rutas e informar a vue-router donde renderizarlas. Aquí hay un ejemplo básico:\n\n> Todos los ejemplos utilizarán la versión independiente de Vue para hacer posible el análisis de plantillas. Más detalles [aquí](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only).\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- Utiliza el componente router-link para la navegación. -->\n    <!-- especifica el enlace pasando la propiedad `to`. -->\n    <!-- <router-link> será renderizado por defecto como una etiqueta `<a>` -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- El componente que coincida con la ruta será renderizado aquí -->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. Si utilizas un sistema de empaquetamiento de módulos (por ejemplo, a través de vue-cli), importa Vue y VueRouter y luego ejecuta Vue.use(VueRouter).\n\n// 1. Define componentes de enrutamiento.\n// Estos pueden ser importados desde otros archivos\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Define algunas rutas\n// Cada ruta debe mapear a un componente. El \"componente\" puede\n// ser un constructor de componente creado a través de\n// Vue.extend(), o simplemente un objeto de opciones de componente.\n// Más tarde hablaremos acerca de las sub-rutas.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Crea una instancia del _router_ y pasa la opción `routes`\n// Puedes pasar opciones adicionales aquí,\n// pero mantengámoslo simple por el momento.\nconst router = new VueRouter({\n  routes // forma corta para routes: routes\n})\n\n// 4. Crea y monta la instancia principal.\n// Asegúrate de inyectar el _router_ con la opcion router para\n// garantizar que toda la aplicación tenga acceso al mismo.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// ¡Ahora la aplicación está ejecutándose!\n```\n\nPuedes consultar este [ejemplo](http://jsfiddle.net/yyx990803/xgrjzsup/).\n\nNota que `<router-link>` obtiene automáticamente la clase `.router-link-active` cuando la ruta a la que apunta es accedida. Puedes leer más acerca de eso en la documentación de la [API](../api/router-link.md).\n"
  },
  {
    "path": "docs-gitbook/es/essentials/history-mode.md",
    "content": "# Modo historia HTML5\n\nEl modo por defecto para `vue-router` es _hash mode_ - el cual utiliza una almohadilla para simular la URL completa para que la página no sea recargada cuando la URL cambia.\n\nPara eliminar la almohadilla, podemos seleccionar el **modo historia** del `router`, el cual utiliza el método `history.pushState` de la API para conseguir una navegación sin recarga de página:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nCuando utilices el modo historial, la URL lucirá \"normal\", por ejemplo: `http://oursite.com/user/id`. ¡Hermoso!\n\nSin embargo, hay un problema: dado que nuestra aplicación es de una sola página del lado cliente, sin una configuración apropiada del lado servidor los usuarios van a obtener errores 404 si intentan acceder directamente a `http://oursite.com/user/id` en sus navegadores. Eso es horrible.\n\nNo hay problema: para solucionar el error, todo lo que debes hacer es agregar un redireccionamiento en tu servidor. Si la URL no coincide con ningún recurso estático, debes apuntar a la misma página `index.html` donde se encuentra tu aplicación. De nuevo, ¡Hermoso! \n\n## Ejemplos de configuraciones de servidores\n\n#### Apache\n\n```apache\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Node.js (Express)\n\nPara Node.js/Express, considera utilizar el middleware [connect-history-api-fallback](https://github.com/bripkens/connect-history-api-fallback).\n\n## Deventajas\n\nHay una deventaja para esto: tu servidor ya no reportará errores 404 dado que todas las rutas no encontradas serán redireccionadas al archivo `index.html`. Para solucionar este problema debes implementar dentro de la aplicación Vue una ruta por defecto para mostrar una página de error 404:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\nOtra solución, si utilizas un servidor Node.js, es utilizar el `router` del lado del servidor para analizar las URL ingresadas y responder con un error 404 si ninguna ruta coincide.\n"
  },
  {
    "path": "docs-gitbook/es/essentials/named-routes.md",
    "content": "# Rutas con nombre\n\n A veces es conveniente identificar una ruta con un nombre, especialmente cuando enlazamos a esa ruta o navegamos mediante código. Puedes darle un nombre a una ruta en las opciones de `routes` cuando se crea la instancia de Router:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nPara enlazar a una ruta con nombre, puedes pasar un objeto a la propiedad `to` del componente `router-link`:\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\nEste es exactamente el mismo objeto utilizado mediante código con `router.push()`:\n\n``` js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nEn ambos casos, el _router_ navegará a la ruta `/user/123`.\n\nRevisa un ejemplo completo [aquí](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs-gitbook/es/essentials/named-views.md",
    "content": "# Vistas con nombre\n\nA veces es necesario mostrar múltiples vistas al mismo tiempo en lugar de anidarlas. Por ejemplo, cuando se crea una plantilla con una vista `sidebar` y una vista `main`. Aquí es cuando las vistas con nombre se vuelven útiles. En lugar de tener un solo _outlet_ en tu vista, puedes tener varios y darle a cada uno un nombre diferente. Por defecto, un `router-view` sin nombre se llamará `default`.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nUna vista se renderiza utilizando un componente, por lo tanto, múltiples vistas requerirán múltiples componentes para la misma ruta. Asegúrate de utilizar la opción `components` (con una _s_ al final):\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nPuedes ver una demostración de este ejemplo [aquí](https://jsfiddle.net/posva/6du90epg/).\n"
  },
  {
    "path": "docs-gitbook/es/essentials/navigation.md",
    "content": "# Navegación mediante código\n\nAdemás de utilizar `<router-link>` para crear etiquetas `a` para una navegación declarativa, podemos hacer lo mismo a través de código usando los métodos de la instancia del enrutador.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**Nota: Dentro de una instancia de Vue, tienes acceso a la instancia del router a través de `$router`. Por lo tanto puedes llamar a `this.$router.push`.**\n\nPara navegar a una URL diferente, utiliza `router.push`. Este método agrega una nueva entrada a la pila del historial, por lo que cuando el usuario presione el botón _volver_ del navegador, será llevado a la URL anterior.\n\nEste método es el que se llama internamente cuando se hace clic en un componente `<router-link>`, por lo que`<router-link :to=\"...\">` es el equivalente a ejecutar `router.push(...)`.\n\n| Declarativo | Mediante código |\n|-------------|--------------|\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\nEl argumento puede ser una cadena de texto o un objeto descriptor. Por ejemplo:\n\n``` js\n// cadena de texto literal\nrouter.push('home')\n\n// Objeto\nrouter.push({ path: 'home' })\n\n// Ruta con nombre\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// Con _query_, con lo que se obtiene /register?plan=private\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\nA partir de la version 2.2.0+, puedes opcionalmente pasar _funciones callbacks_ `onComplete` y `onAbort` a `router.push` o `router.replace` como segundo y tercer argumento. Estas _funciones callbacks_ serán ejecutadas cuando la navegación sea completada exitosamente (luego que todos los _hooks_ asíncronos sean resueltos), o abortada (navegando a la misma ruta, o a una ruta diferente antes que la navegación actual haya finalizado), respectivamente.\n\n#### `router.replace(location, onComplete?, onAbort?)`\n\nActúa como `router.push`, la única diferencia es que navega sin agregar una nueva entrada al historial, como su nombre sugiere - reemplaza la entrada actual.\n\n| Declarativo | Mediante código |\n|-------------|--------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n#### `router.go(n)`\n\nEste método toma un entero como parámetro que indica cuantos pasos avanzar o retroceder en el historial, similar a `window.history.go(n)`.\n\nEjemplos\n\n``` js\n// Ir hacia adelante un paso, similar a history.forward()\nrouter.go(1)\n\n// Ir hacia atrás un paso, similar a history.back()\nrouter.go(-1)\n\n// Ir 3 pasos hacia adelante\nrouter.go(3)\n\n// Falla silenciosamente si no existe esa cantidad de registros en el historial\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### Manipulación del historial\n\nSeguramente notaste que `router.push`, `router.replace` y `router.go` son contra partes de [`window.history.pushState`, `window.history.replaceState` y `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History), y que imitan a las API de `window.history`.\n\nPor lo tanto, si estás familiarizado con las [API del historial del navegador](https://developer.mozilla.org/en-US/docs/Web/API/History_API), manipularlo será muy sencillo con vue-router.\n\nVale la pena mencionar que los métodos de navegacion de vue-router (`push`, `replace`, `go`) funcionan consistentemente en todos los modos de trabajo del `router` (`history`, `hash` y `abstract`).\n"
  },
  {
    "path": "docs-gitbook/es/essentials/nested-routes.md",
    "content": "# Sub-rutas\n\nLas interfaces de usuario (UI por sus siglas en inglés) de aplicaciones reales normalmente están compuestas por componentes que están anidados varios niveles. Es también muy común que los segmentos de una URL correspondan a cierta estructura de componentes anidados, por ejemplo:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\nCon `vue-router` es muy sencillo expresar esta relación usando configuraciones de sub-rutas.\n\nDada la aplicación que creamos en el capítulo anterior:\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nAquí, `<router-view>` es un contenedor de nivel superior. Renderiza el componente que coincida con una ruta de nivel superior. Así, un componente renderizado puede contener su propio `<router-view>` anidado. Por ejemplo, si agregamos uno dentro de la plantilla del componente `User`:\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nPara renderizar componentes dentro de este contenedor anidado, necesitamos usar la opción `children` en la configuración del constructor de `VueRouter`:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User,\n      children: [\n        {\n          // UserProfile será renderizado en el <router-view> dentro de User\n          // cuando /user/:id/profile coincida\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // UserPosts será renderizado en el <router-view> dentro de User\n          // cuando /user/:id/posts coincida\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Nota que las sub-rutas que empiecen con `/` serán tratadas como absolutas. Esto permite aprovechar el anidamiento de componentes sin tener que usar URL anidadas.**\n\nComo puedes ver, la opción `children` es simplemente otro array de objetos de configuración de rutas, como `routes`. Por lo tanto, puedes anidar tantas vistas como necesites.\n\nEn este punto, con la configuración anterior, cuando visites `/user/foo`, nada será renderizado dentro del contenedor de  `User` porque ninguna sub ruta coincidió. Tal vez quieras renderizar algo ahí. En ese caso, puedes pasar una sub ruta vacía:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id', component: User,\n      children: [\n        // UserHome será renderizado en el <router-view> dentro de User\n        // cuando /user/:id coincida\n        { path: '', component: UserHome },\n\n        // ...otras sub rutas\n      ]\n    }\n  ]\n})\n```\n\nPuedes encontrar una demostración de este ejemplo [aquí](http://jsfiddle.net/yyx990803/L7hscd8h/).\n"
  },
  {
    "path": "docs-gitbook/es/essentials/passing-props.md",
    "content": "# Pasando propiedades a componentes de ruteo\n\nUsar `$route` en tu componente genera un acoplamiento estrecho con la ruta, lo cual limita la flexibilidad del componente dado que solo puede utilizarse en ciertas URL.\n\nPara desacoplar el componente del enrutador utiliza _props_:\n\n** Acoplado a $route**\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n** Desacoplado con props**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // utilizando vistas con nombre, tienes que definir la opción prop para cada una de ellas:\n    {\n      path: '/user/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nEsto te permite utilizar el componente en cualquier lugar, lo cual hace al mismo reutilizable y más sencillo de testear.\n\n### Modo boolean\n\nCuando _props_ tiene asignado el valor true, `route.params` serán asignados como las _props_ del componente.\n\n### Modo objeto\n\nCuando _props_ es un objeto, este será asignado tal cual como las _props_ del componente.\nÚtil para cuando las _props_ son estáticas.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n### Modo función\n\nPuedes crear una función que retorne _props_.\nEsto te permite convertir los parámetros a otro tipo, combinar valores estáticos con valores basados en rutas, etc.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\nLa URL: `/search?q=vue` pasaría `{query: \"vue\"}` como _props_ al componente SearchUser.\n\nIntenta crear funciones _props_ sin estado, dado que solo se evalúan cuando ocurren cambios de ruta.\nUtiliza un componente envolvente si necesitas estado para definir las _props_, de esa manera Vue puede reaccionar a cambios de estado.\n\n\nPara un uso avanzado, aquí hay un [ejemplo](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).\n"
  },
  {
    "path": "docs-gitbook/es/essentials/redirect-and-alias.md",
    "content": "# Redireccionamiento y alias\n\n### Redireccionamiento\n\nEl redireccionamiento también se realiza en la configuración de `routes`. Para redireccionar desde `/a` hasta `/b`:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nEL redireccionamiento también puede apuntar a una ruta con nombre:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nO incluso puedes utilizar una función para un redireccionamiento dinámico:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // la función recibe la ruta destino como argumento\n      // retorna aquí la ruta de redirección.\n    }}\n  ]\n})\n```\n\nPara otros usos avanzados, tienes el siguiente [ejemplo](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n### Alias\n\nUna redirección significa que el usuario visita `/a`, y la URL será reemplazada por `/b`, para luego ejecutar el código correspondiente a `/b`. Pero, ¿qué es un alias?\n\n**Un alias de `/a` como `/b` significa que cuando el usuario visita `/b`, la URL se mantiene como `/b`, pero el código ejecutado corresponderá al mismo que si el usuario visitase `/a`.**\n\nLo anterior puede ser expresado en la configuración de enrutamiento como:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nUn alias te da la libertad de mapear una estructura de _UI_ a una URL arbitraria, en lugar de estar restringido por la estructura anidada de la configuración.\n\nPara otros usos avanzados, aquí tienes un [ejemplo](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js).\n"
  },
  {
    "path": "docs-gitbook/es/installation.md",
    "content": "# Instalación\n\n### Descarga directa / CDN\n\n[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) provee enlaces a CDN basadas en NPM. El enlace anterior siempre apuntará a la última versión en NPM. También puedes usar una versión/etiqueta específica a través de URLs como`https://unpkg.com/vue-router@2.0.0/dist/vue-router.js`.\n<!--/email_off-->\n\nIncluye `vue-router` luego de Vue y se instalará automáticamente:\n\n``` html\n<script src=\"/ruta/a/vue.js\"></script>\n<script src=\"/ruta/a/vue-router.js\"></script>\n```\n\n### NPM\n\n``` bash\nnpm install vue-router\n```\n\nCuando lo utilices con un sistema de empaquetamiento de módulos, debes instalarlo explícitamente a través de `Vue.use()`:\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nNo necesitas hacer esto cuando utilices etiquetas _script_ globales.\n\n### Versión de desarrollo\n\nDebes clonar el repositorio directamente desde GitHub y construir `vue-router` tu mismo si quieres utilizar la última versión de desarrollo.\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs-gitbook/fr/README.md",
    "content": "{% include \"./SUMMARY.md\" %}\n"
  },
  {
    "path": "docs-gitbook/fr/SUMMARY.md",
    "content": "# vue-router\n\n> Note aux utilisateurs de TypeScript : vue-router@3.0+ nécessite vue@2.5+, et inverssement.\n\n**[Notes de version](https://github.com/vuejs/vue-router/releases)**\n\n- [Installation](installation.md)\n- Essentiel\n  - [Pour commencer](essentials/getting-started.md)\n  - [Concordance dynamique de route](essentials/dynamic-matching.md)\n  - [Navigation programmatique](essentials/navigation.md)\n  - [Routes imbriquées](essentials/nested-routes.md)\n  - [Routes nommées](essentials/named-routes.md)\n  - [Vues nommées](essentials/named-views.md)\n  - [Redirection et alias](essentials/redirect-and-alias.md)\n  - [Passage de props aux composants de route](essentials/passing-props.md)\n  - [Mode historique de HTML5](essentials/history-mode.md)\n- Avancé\n  - [Intercepteurs de navigation](advanced/navigation-guards.md)\n  - [Champs meta de route](advanced/meta.md)\n  - [Transitions](advanced/transitions.md)\n  - [Récupération de données](advanced/data-fetching.md)\n  - [Comportement du défilement](advanced/scroll-behavior.md)\n  - [Chargement à la volée](advanced/lazy-loading.md)\n- Référence de l'API\n  - [Options de construction du routeur](api/options.md)\n    - [routes](api/options.md#routes)\n    - [mode](api/options.md#mode)\n    - [base](api/options.md#base)\n    - [linkActiveClass](api/options.md#linkactiveclass)\n    - [linkExactActiveClass](api/options.md#linkexactactiveclass)\n    - [scrollBehavior](api/options.md#scrollbehavior)\n    - [parseQuery / stringifyQuery](api/options.md#parsequery--stringifyquery)\n    - [fallback](api/options.md#fallback)\n  - [L'instance du routeur](api/router-instance.md)\n    - [Propriétés](api/router-instance.md#propriétés)\n    - [Méthodes](api/router-instance.md#méthodes)\n  - [L'objet Route](api/route-object.md)\n  - [Injections de composant](api/component-injections.md)\n  - [router-link](api/router-link.md)\n  - [router-view](api/router-view.md)\n"
  },
  {
    "path": "docs-gitbook/fr/advanced/data-fetching.md",
    "content": "# Récupération de données\n\nParfois vous avez besoin de récupérer des données depuis le serveur lorsqu'une route est activée. Par exemple, avant de faire le rendu d'un profil utilisateur, vous avez besoin de récupérer les données de l'utilisateur depuis le serveur. Nous pouvons y parvenir de deux façons différentes :\n\n- **Récupération de données après la navigation** : effectue la navigation en premier, et récupère les données dans le hook entrant du cycle de vie d'un composant. Affiche un état de chargement pendant que les données sont en train d'être récupérées.\n\n- **Récupération de données avant la navigation** : récupère les données avant la navigation dans la fonction d'interception d'entrée de la route, et effectue la navigation après que les données aient été récupérées.\n\nTechniquement, les deux choix sont valides. Cela dépend de l'expérience utilisateur que vous souhaitez apporter.\n\n## Récupération de données après la navigation\n\nEn utilisant cette approche, nous naviguons et faisons immédiatement le rendu du composant et récupérons les données via le hook `created` du composant. Cela nous donne l'opportunité d'afficher un état de chargement pendant que les données sont récupérées à travers le réseau, et nous pouvons aussi gérer le chargement différemment pour chaque vue.\n\nAssumons que nous ayons un composant `Post` qui a besoin de récupérer des données pour un billet identifié par `$route.params.id` :\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Chargement...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // récupérer les données lorsque la vue est créée et\n    // que les données sont déjà observées\n    this.fetchData()\n  },\n  watch: {\n    // appeler encore la méthode si la route change\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // remplacer `getPost` par une fonction de récupération de données\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Récupération de données avant la navigation\n\nAvec cette approche, nous récupèrerons les données avant de naviguer vers la nouvelle route. Nous pouvons effectuer la récupération de données dans la fonction d'interception `beforeRouteEnter` du composant à venir, et seulement appeler `next` lorsque la récupération est terminée :\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // quand la route change et que ce composant est déjà rendu,\n  // la logique est un peu différente\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\nL'utilisateur va rester sur la vue précédente pendant que la ressource est en train d'être récupérée pour la vue à venir. Il est cependant recommandé d'afficher une barre de progression ou un autre type d'indicateur pendant que les données sont en train d'être récupérées. Si la récupération échoue, il est aussi recommandé d'afficher une sorte de message d'erreur global.\n"
  },
  {
    "path": "docs-gitbook/fr/advanced/lazy-loading.md",
    "content": "# Chargement à la volée\n\nPendant la construction d'applications avec un empaqueteur (« bundler »), le paquetage JavaScript peut devenir un peu lourd, et donc cela peut affecter le temps de chargement de la page. Il serait plus efficace si l'on pouvait séparer chaque composant de route dans des fragments séparés, et de les charger uniquement lorsque la route est visitée.\n\nEn combinant la [fonctionnalité de composant asynchrone](https://fr.vuejs.org/v2/guide/components.html#Composants-asynchrones) de Vue et la [fonctionnalité de scission de code](https://webpack.js.org/guides/code-splitting-async/) de webpack, il est très facile de charger à la volée les composants de route.\n\nPremièrement, un composant asynchrone peut définir une fonction fabrique qui retourne une Promesse (qui devrait résoudre le composant lui-même) :\n\n``` js\nconst Foo = () => Promise.resolve({ /* définition du composant */ })\n```\n\nDeuxièmement, avec webpack 2, nous pouvons utiliser la syntaxe d'[import dynamique](https://github.com/tc39/proposal-dynamic-import) pour indiquer un point de scission de code :\n\n``` js\nimport('./Foo.vue') // returns a Promise\n```\n\n> Note: si vous utilisez Babel, vous aurez besoin d'ajouter le plugin [syntax-dynamic-import](http://babeljs.io/docs/plugins/syntax-dynamic-import/) de façon à ce que Babel puisse analyser correctement la syntaxe.\n\nEn combinant les deux, on définit un composant asynchrone qui sera automatiquement scindé par webpack :\n\n``` js\nconst Foo = () => import('./Foo.vue')\n```\n\nRien n'a besoin d'être modifié dans la configuration de la route, utilisez `Foo` comme d'habitude.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/foo', component: Foo }\n  ]\n})\n```\n\n### Grouper des composants dans le même fragment\n\nParfois on aimerait grouper tous les composants imbriqués sous la même route, dans un seul et même fragment asynchrone. Pour arriver à cela, nous avons besoin d'utiliser les [fragments nommés](https://webpack.js.org/guides/code-splitting-async/#chunk-names) en donnant un nom au fragment en utilisant une syntaxe de commentaire spéciale (requires webpack > 2.4) :\n\n``` js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nwebpack groupera tous les modules asynchrones avec le même nom de fragment dans le même fragment asynchrone.\n"
  },
  {
    "path": "docs-gitbook/fr/advanced/meta.md",
    "content": "# Champs meta de route\n\nVous pouvez inclure un champ `meta` quand vous définissez une route :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // un champ `meta`\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nComment maintenant accéder à ce champ `meta` ?\n\nTout d'abord, chaque objet route dans la configuration de `routes` est appelé un **registre de route**. Les registres de route peuvent être imbriqués. Par conséquent, quand une route concorde, elle peut potentiellement concorder avec plus d'un registre de route.\n\nPar exemple, avec la configuration de route ci-dessous, l'URL `/foo/bar` va concorder avec le registre parent et le registre enfant.\n\nTous les registres concordants avec une route sont exposés dans l'objet `$route` (ainsi que les objets de route dans les sécurisations de navigation) dans le tableau `$route.matched`. Donc, nous devons itérer à travers `$route.matched` pour vérifier les champs meta dans les registres de route.\n\nUn exemple concret est la vérification d'un champ meta dans une interception de navigation globale :\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // cette route demande une autorisation, vérifions si l'utilisateur est logué.\n    // sinon, redirigeons le sur la page de login.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // assurez vous de toujours appeler `next()` !\n  }\n})\n```\n"
  },
  {
    "path": "docs-gitbook/fr/advanced/navigation-guards.md",
    "content": "# Intercepteurs de navigation\n\nComme le nom le suggère, l'interception de navigation fournie par `vue-router` est principalement utilisée pour intercepter la navigation avec des redirections ou des annulations d'accès. Il y a plusieurs hooks disponibles lors du processus de navigation : globaux, par route ou par composant.\n\nSouvenez-vous de cela : **le changement de paramètre ou de query ne va pas lancer d'interception d'entrée ou de sortie de navigation**. Vous pouvez toujours [observer l'objet `$route`](../essentials/dynamic-matching.md#reacting-to-params-changes) pour réagir à ces changements, ou utiliser la fonction `beforeRouteUpdate` d'une interception par composant.\n\n### Interception globale\n\nVous pouvez abonner une interception d'entrée en utilisant `router.beforeEach` :\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nLes interceptions d'entrées globales sont appelées lors de l'ordre de création, chaque fois qu'une navigation est déclenchée. Les interceptions peuvent être résolues de manière asynchrone, et la navigation est considérée comme **en attente** avant que tous les hooks ne soient résolus.\n\nChaque fonction d'interception reçoit trois arguments :\n\n- **`to: Route`**: L'[objet `Route`](../api/route-object.md) cible vers lequel on navigue.\n\n- **`from: Route`**: la route courante depuis laquelle nous venons de naviguer.\n\n- **`next: Function`**: cette fonction doit être appelée pour **résoudre** le hook. L'action dépend des arguments fournis à `next`:\n\n  - **`next()`**: se déplacer jusqu'au prochain hook du workflow. S'il ne reste aucun hook, la navigation est **confirmée**.\n\n  - **`next(false)`**: annuler la navigation courante. Si l'URL du navigateur avait changé (manuellement par l'utilisateur ou via le bouton retour du navigateur), il sera remis à sa valeur de route de `from`.\n\n  - **`next('/')` ou `next({ path: '/' })`**: redirige vers le nouvel URL. La navigation courante va être arrêtée et une nouvelle va se lancer. Vous pouvez passer n'importe quel objet à `next`, vous permettant ainsi de spécifier des options comme `replace: true`, `name: 'home'` et n'importe quelles options dans [la prop `to` du `router-link`](../api/router-link.md) ou [`router.push`](../api/router-instance#méthodes).\n\n  - **`next(error)`**: (2.4.0+) si l'argument passé à `next` est une instance de `Error`, la navigation va s'arrêter et l'erreur sera passée aux fonctions de rappel enregistrées via [`router.onError()`](../api/router-instance.html#methods).\n\n**Assurez-vous de toujours appeler la fonction `next`, sinon le hook ne sera jamais résolu.**\n\n### Résolutions des interceptions globales\n\n> Nouveau dans la 2.5.0\n\nDans la 2.5.0+ vous pouvez abonner une interception globale avec `router.beforeResolve`. Ceci est similaire a `router.beforeEach`, mais la différence est qu'elle sera appelée juste après que la navigation soit confirmée, **après que toutes les interceptions par composants et les composants de route asynchrone ait été résolu**.\n\n### Hooks de sortie globaux\n\nVous pouvez également abonner des hooks de sortie, cependant, à la différence des interceptions, ces hooks ne fournissent pas de fonction `next` et n'affecte pas la navigation :\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### Interception par route\n\nVous pouvez définir l'interception `beforeEnter` directement sur l'objet de configuration d'une route :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nCes interceptions ont exactement le même effet que les interceptions globales d'entrée.\n\n### Interception par composant\n\nEnfin, vous pouvez directement définir une interception de navigation a l'intérieur du composant lui-même (celui passer à la configuration du routeur) avec les options suivantes :\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (ajouté dans la 2.2+)\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // appelée avant que la route vers le composant soit confirmée.\n    // cette fonction n'a pas accès à l'instance du composant avec `this`,\n    // car le composant n'a pas encore été créé quand cette interception est appelée !\n  },\n  beforeRouteUpdate (to, from, next) {\n    // appelée quand la route qui fait le rendu de ce composant change,\n    // mais que ce composant est utilisé de nouveau dans la nouvelle route.\n    // Par exemple, pour une route avec le paramètre dynamique `/foo/:id`, quand nous\n    // naviguons entre `/foo/1` et `/foo/2`, la même instance du composant `Foo`\n    // va être réutilisée, et ce hook va être appelé quand cela arrivera.\n    // ce hook a accès à l'instance de ce composant via `this`.\n  },\n  beforeRouteLeave (to, from, next) {\n    // appelée quand la route qui fait le rendu de ce composant est sur le point\n    // d'être laissée en faveur de la prochaine route.\n    // elle a accès à l'instance de ce composant via `this`.\n  }\n}\n```\n\nL'interception `beforeRouteEnter` **n'**a **PAS** accès à `this`, car l'interception est appelée avant que la navigation soit confirmée, et le nouveau composant entrant n'a même pas encore été créé.\n\nCependant, vous pouvez accéder à l'instance en passant dans la fonction de rappel `next`. Cette fonction de rappel va être appelée quand la navigation sera confirmée, et l'instance du composant sera passée à la fonction de rappel en tant qu'argument :\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // accès à l'instance du composant via `vm`\n  })\n}\n```\n\nNotez que `beforeRouteEnter` est la seule interception qui supporte une fonction de rappelle dans `next`. Pour `beforeRouteUpdate` et `beforeRouteLeave`, `this` est déjà disponible. Le passage d'une fonction de rappel n'étant pas nécessaire, il n'est donc pas *supporté* :\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // utiliser juste `this`\n  this.name = to.params.name\n  next()\n}\n```\n\nL'**interception de sortie** est habituellement utilisée pour empécher l'utilisateur de quitter la route sans avoir sauvegardé ses changements. La navigation peut être annulée en appelant `next(false)`.\n\n```js\nbeforeRouteLeave (to, from , next) {\n  const answer = window.confirm('Voulez-vous vraiment quitter cette page ? Vos changements seront perdus.')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\n### Le flux de résolution de navigation complet\n\n1. La navigation est demandée.\n2. Appel de l'interception de sortie des composants désactivés (ceux que l'on va quitter).\n3. Appel des interceptions globales `beforeEach`.\n4. Appel des interceptions `beforeRouteUpdate` pour les composants réutilisés (2.2+).\n5. Appel de `beforeEnter` dans la configuration de route.\n6. Résolution des composants de route asynchrones.\n7. Appel de `beforeRouteEnter` dans les composants activés (ceux où l'on va arriver).\n8. Appel des interceptions `beforeResolve` (2.5+).\n9. Confirmation de la navigation.\n10. Appel des hooks globaux `afterEach`.\n11. Modification du DOM demandée.\n12. Appel des fonctions de rappel passées à `next` dans l'interception `beforeRouteEnter` avec l'instance instanciée.\n"
  },
  {
    "path": "docs-gitbook/fr/advanced/scroll-behavior.md",
    "content": "# Comportement du défilement\n\nEn utilisant le routage côté client, nous pourrions vouloir faire défiler la page jusqu'en haut lorsqu'on navigue vers une nouvelle route, ou alors préserver la position du défilement des entrées de l'historique comme le ferait une page réelle. `vue-router` vous permet de faire cela et, encore mieux, vous permet de changer le comportement du défilement pendant la navigation.\n\n**Note : cette fonctionnalité ne fonctionne que si le navigateur supporte `history.pushState`.**\n\nPendant la création de l'instance du routeur, vous pouvez renseigner la fonction `scrollBehavior` :\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // retourner la position désirée\n  }\n})\n```\n\nLa fonction `scrollBehavior` reçoit les objets de route `to` et `from`. Le troisième argument, `savedPosition`, est disponible uniquement si c'est une navigation `popstate` (déclenchée par les boutons précédent/suivant du navigateur).\n\nLa fonction peut retourner un objet décrivant la position du défilement. L'objet peut être de la forme :\n\n-  `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset seulement supporté pour les versions 2.6.0+)\n\nSi une valeur équivalente à `false` ou un objet vide est retourné, aucun défilement ne sera produit.\n\nPar exemple :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nCela permettra de défiler au haut de page à chaque navigation à travers les routes.\n\nRetourner l'objet `savedPosition` résultera en un comportement quasi natif en naviguant avec les boutons précédents/suivants :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nSi vous voulez simuler le comportement « aller à l'ancre » :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nOn peut aussi utiliser les [champs meta de route](meta.md) pour implémenter un contrôle bien précis pour le comportement du défilement. Allez voir un exemple complet [ici](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js).\n\n### Défilement asynchrone\n\n> Nouveau dans la 2.8.0+\n\nVous pouvez également retourner une promesse pour résoudre la description de position souhaitée :\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nIl est possible de relier les événements d'un composant de transition au niveau de la page pour que le comportement de défilement soit bien adapté à vos transitions de pages. Cependant, en raison de la variance et de la complexité des cas d'utilisation, nous fournissons simplement ce code primitif pour permettre aux utilisateurs de faire les implémentations spécifiques.\n"
  },
  {
    "path": "docs-gitbook/fr/advanced/transitions.md",
    "content": "# Transitions\n\nVu que `<router-view>` est essentiellement un composant dynamique, on peut lui appliquer certains effets de transitions en utilisant le composant `<transition>` :\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[Tout à propos de `<transition>`](https://fr.vuejs.org/v2/guide/transitions.html) fonctionne également ici de la même manière.\n\n### Transition par route\n\nL'utilisation du dessus applique la même transition pour chaque route. Si vous voulez que les composants de route aient des transitions différentes, vous pouvez utiliser à la place `<transition>` avec des noms différents à l'intérieur de chaque composant de route :\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n# Transition dynamique basée sur la route\n\nIl est aussi possible de déterminer la transition à utiliser en se basant sur la relation entre la route cible et la route actuelle :\n\n``` html\n<!-- utiliser un nom de transition dynamique -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// et dans le composant parent,\n// observer la `$route` pour déterminer la transition à utiliser\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nVoir un exemple complet [ici](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).\n"
  },
  {
    "path": "docs-gitbook/fr/api/component-injections.md",
    "content": "# Injections de composant\n\n### Propriétés injectées\n\nCes propriétés sont injectées dans chacun des composants enfants, en passant l'instance du routeur à l'application racine de Vue en tant qu'option `router`.\n\n- #### $router\n\n  L'instance du routeur.\n\n- #### $route\n\n La [Route](route-object.md) actuellement active. C'est une propriété en lecture seule et ses propriétés sont immutables, mais elles restent malgré tout observables.\n\n### Options activées\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate** (ajouté en 2.2)\n- **beforeRouteLeave**\n\n  Voir l'[interception par composant](../advanced/navigation-guards.md#securisation-par-composant).\n"
  },
  {
    "path": "docs-gitbook/fr/api/options.md",
    "content": "# Options de construction du routeur\n\n### routes\n\n- type: `Array<RouteConfig>`\n\n  Déclaration de type pour `RouteConfig` :\n\n  ``` js\n  declare type RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // pour les routes nommées\n    components?: { [name: string]: Component }; // pour les vues nommées\n    redirect?: string | Location | Function;\n    props?: boolean | string | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // pour les routes imbriquées\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n\n    // 2.6.0+\n    caseSensitive?: boolean; // use case sensitive match? (default: false)\n    pathToRegexpOptions?: Object; // path-to-regexp options for compiling regex\n  }\n  ```\n\n### mode\n\n- type : `string`\n\n- défaut : `\"hash\" (dans le navigateur) | \"abstract\" (en Node.js)`\n\n- valeurs disponibles : `\"hash\" | \"history\" | \"abstract\"`\n\n  Configure le mode du routeur.\n\n  - `hash` : utilise le hash de l'URL pour le routage. Fonctionne dans tous les navigateurs supportés par Vue, ainsi que ceux qui ne supportent pas l'API History d'HTML5.\n\n  - `history` : nécessite l'API History d'HTML 5 et la configuration du serveur. Voir [Mode historique de HTML5](../essentials/history-mode.md).\n\n  - `abstract` : fonctionne dans tous les environnements JavaScript, ex. côté serveur avec Node.js. **Le routeur sera automatiquement forcé d'utiliser ce mode si aucune API navigateur n'est présente.**\n\n### base\n\n- type : `string`\n\n- défaut : `\"/\"`\n\n  L'URL de base de l'application. Par exemple, si l'application monopage entière est distribuée sous `/app/`, alors `base` doit utiliser la valeur `\"/app/\"`.\n\n### linkActiveClass\n\n- type : `string`\n\n- défaut : `\"router-link-active\"`\n\n  Configure de manière globale la classe active par défaut de `<router-link>`. Voir aussi [router-link](router-link.md).\n\n### linkExactActiveClass\n\n> 2.5.0+\n\n- type : `string`\n\n- default : `\"router-link-exact-active\"`\n\n  Configure de manière globale la classe active par défaut de `<router-link>` lors d'une correspondance exacte. Voir aussi [router-link](router-link.md).\n\n### scrollBehavior\n\n- type : `Function`\n\n  Signature :\n\n  ```\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    ?{}\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  Pour plus de détails, voir [Comportement du Scroll](../advanced/scroll-behavior.md).\n\n### parseQuery / stringifyQuery\n\n> 2.4.0+\n\n- type : `Function`\n\n  Permettent de spécifier des fonctions personnalisées pour formater en objet ou en chaîne de caractères la requête. Surcharge les fonctions par défaut.\n\n### fallback\n\n> 2.6.0+\n\n- type : `boolean`\n\n  Contrôle comment le routeur devrait passer en mode `hash` quand le navigateur ne supporte pas `history.pushState`. Par défaut à `true`.\n\n  Passer cette valeur à `false` va essentiellement faire que la navigation via `router-link` va réclamer un rechargement de page dans IE9. Ceci est utile quand l'application est rendue côté serveur et à besoin de fonctionner dans IE9, car le mode hash ne fonctionne pas avec du SSR.\n"
  },
  {
    "path": "docs-gitbook/fr/api/route-object.md",
    "content": "# L'objet `Route`\n\nUn **objet `Route`** représente l'état actuel de la route active. Il contient des informations analysées à propos de l'URL courant et **les itinéraires de route** appariés par l'URL.\n\nL'objet `Route` est immutable. Chaque navigation qui se déroule avec succès résultera en un nouvel objet `Route`.\n\nL'objet `Route` peut être trouvé à plusieurs endroits :\n\n- À l'intérieur des composants en tant que `this.$route`\n\n- À l'intérieur des fonctions de rappel des observateurs de `$route`\n\n- Comme valeur de retour après l'appel de `router.match(location)`\n\n- À l'intérieur des fonctions d'interception de la navigation, dans les deux premiers paramètres de la fonction :\n\n  ``` js\n  router.beforeEach((to, from, next) => {\n    // `to` et `from` sont tous les deux des objets Route\n  })\n  ```\n\n- À l'intérieur de la fonction `scrollBehavior` dans les deux premiers arguments :\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n      // `to` et `from` sont tous les deux des objets Route\n    }\n  })\n  ```\n\n### Propriétés de l'objet `Route`\n\n- **$route.path**\n\n  - type : `string`\n\n    Une chaine de caractères représentant le chemin de la route en cours, toujours résolue en tant que chemin absolu, ex : `\"/foo/bar\"`.\n\n- **$route.params**\n\n  - type : `Object`\n\n    Un objet qui contient des pairs clé/valeur de segments dynamiques et segments *star*. S'il n'y a pas de paramètres, alors la valeur sera un objet vide.\n\n- **$route.query**\n\n  - type : `Object`\n\n    Un objet qui contient des pairs clé/valeur de la requête au format d'une chaine de caractères. Par exemple, pour un chemin `/foo?user=1`, on aura `$route.query.user == 1`. S'il n'y a pas de requête, alors la valeur sera un objet vide.\n\n- **$route.hash**\n\n  - type : `string`\n\n    Le hash de la route courante (avec le `#`), s'il y en a un. S'il n'y a pas de hash, alors la valeur sera une chaine de caractères vide.\n\n- **$route.fullPath**\n\n  - type : `string`\n\n    L'URL entièrement résolu, incluant la requête et le hash.\n\n- **$route.matched**\n\n  - type : `Array<RouteRecord>`\n\n    Un `Array` contenant les **les itinéraires de la route** pour chaque segment de chemin imbriqué de la route courante. Les itinéraires de la route sont des copies des objets dans le tableau de configuration `routes` (et dans les tableaux `children`).\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // l'objet qui suit est un itinéraire de route\n      { path: '/foo', component: Foo,\n        children: [\n          // c'est aussi un itinéraire\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  Lorsque l'URL sera `/foo/bar`, `$route.matched` sera un `Array` contenant les deux objets (clonés), dans l'ordre parent à l'enfant.\n\n- **$route.name**\n\n  Le nom de la route courante, si elle en a un. (Voir [Routes nommées](../essentials/named-routes.md)).\n\n- **$route.redirectedFrom**\n\n  Le nom de la route d'où la page a été redirigée, si elle en a un. (Voir [Redirection et alias](../essentials/redirect-and-alias.md)).\n"
  },
  {
    "path": "docs-gitbook/fr/api/router-instance.md",
    "content": "# L'instance du routeur\n\n### Propriétés\n\n#### router.app\n\n- type: `instance de Vue`\n\n L'instance racine de Vue dans laquelle l'instance de `routeur` a été injectée.\n\n#### router.mode\n\n- type: `string`\n\n  Le [mode](options.md#mode) que le routeur utilise.\n\n#### router.currentRoute\n\n- type: `Route`\n\n  La route actuelle représentée en tant qu'un [objet route](route-object.md).\n\n### Méthodes\n\n- **router.beforeEach(guard)**\n- **router.beforeResolve(guard)** (2.5.0+)\n- **router.afterEach(hook)**\n\n  Ajout des interceptions globales de navigation. Voir les [Intercepteurs de navigation](../advanced/navigation-guards.md).\n\n  Dans la version 2.5.0+, ces trois méthodes retournent une fonction qui enlève les fonctions d'interception et hooks enregistrés.\n\n- **router.push(location, onComplete?, onAbort?)**\n- **router.replace(location, onComplete?, onAbort?)**\n- **router.go(n)**\n- **router.back()**\n- **router.forward()**\n\n  Navigue à une nouvelle URL de façon programmée. Voir [Navigation de façon programmée](../essentials/navigation.md).\n\n- **router.getMatchedComponents(location?)**\n\n  Retourne un tableau de composants (définition/constructeur et non les instances) correspondant à la `location` passée en paramètre, ou alors de la route actuelle. Cette fonction est principalement utilisée pendant le rendu côté serveur afin d'effectuer une prérécupération des données.\n\n- **router.resolve(location, current?, append?)**\n\n  > 2.1.0+\n\n  Inverse la résolution d'URL. La `location` doit avoir la même forme qu'utilisée dans `<router-link>`, retourne un objet avec les propriétés suivantes :\n\n  ``` js\n  {\n    location: Location;\n    route: Route;\n    href: string;\n  }\n  ```\n\n  - `current` is the current Route by default (most of the time you don't need to change this)\n  - `append` allows you to append the path to the `current` route (as with [`router-link`](router-link.md#props))\n\n- **router.addRoutes(routes)**\n\n  > 2.2.0+\n\n  Permet d'ajouter dynamiquement des routes au routeur. L'argument doit être un tableau utilisant le même format de configuration que l'option `routes` du constructeur.\n\n- **router.onReady(callback, [errorCallback])**\n\n  > 2.2.0+\n\n  Cette méthode met en file d'attente une fonction de rappel qui sera appelée lorsque le routeur aura complété la navigation initiale, ce qui signifie qu'il a résolu tous les hooks d'entrées asynchrones et composants asynchrones qui sont associés à la route initiale.\n\n  C'est utile pendant un rendu côté serveur pour assurer une sortie consistance sur le serveur et le client.\n\n  Le deuxième argument `errorCallback` est uniquement supporté à partir de la version 2.4. Il sera appelé lorsque la résolution de la route initiale résultera en une erreur (ex. : la résolution d'un composant asynchrone qui a échoué).\n\n- **router.onError(callback)**\n\n  > 2.4.0+\n\n  Enregistre une fonction de rappel qui sera appelée lorsqu'une erreur sera capturée pendant la navigation vers une route. Notez que pour qu'une erreur soit appelée, cela doit correspondre à l'un des scénarios suivants :\n\n  - L'erreur est lancée de manière synchrone à l'intérieur d'une fonction d'interception de route ;\n\n  - L'erreur est capturée et traitée de manière asynchrone en appelant `next(err)` à l'intérieur d'une fonction d'interception de route ;\n\n  - Une erreur est survenue pendant la résolution d'un composant asynchrone qui est requis pour faire le rendu d'une route.\n"
  },
  {
    "path": "docs-gitbook/fr/api/router-link.md",
    "content": "# `<router-link>`\n\n`<router-link>` est le composant pour activer la navigation utilisateur dans une application où le routeur est activé. La localisation cible est spécifiée grâce à la prop `to`. Il est rendu en tant que balise `<a>` avec le `href` correct par défaut, mais peut être configuré grâce à la prop `tag`. De plus, le lien se verra attribuer une classe CSS active lorsque la route cible est active.\n\n`<router-link>` est préféré par rapport au `<a href=\"...\">` en dur dans le code pour les raisons suivantes :\n\n- Cela fonctionne de la même manière qu'on soit dans le mode historique HTML5 ou le mode hash, donc si vous avez décidé de changer de mode, ou alors que le routeur se replie sur le mode hash pour IE9, rien n'a besoin d'être changé.\n\n- Dans le mode historique HTML5, `router-link` interceptera l'évènement du clic, comme ça le navigateur n'essaiera pas de rafraichir la page.\n\n- En utilisant l'option `base` dans le mode historique HTML5, vous n'avez pas besoin de l'inclure dans les props `to` des URL.\n\n### Props\n\n- **to**\n\n  - type : `string | Location`\n\n  - requis\n\n   Désigne la route cible du lien. Lorsqu'il est cliqué, la valeur de la prop `to` va être passée de manière interne à `router.push`, donc la valeur peut soit être une chaine de caractères, ou alors un objet décrivant une localisation.\n\n  ``` html\n  <!--  chaine littérale  -->\n  <router-link to=\"home\">Accueil</router-link>\n  <!-- rend -->\n  <a href=\"home\">Accueil</a>\n\n  <!-- expression JavaScript en utilisant `v-bind` -->\n  <router-link v-bind:to=\"'home'\">Accueil</router-link>\n\n  <!-- Omettre `v-bind` est OK, tout comme une autre prop -->\n  <router-link :to=\"'home'\">Accueil</router-link>\n\n  <!-- pareil qu'au-dessus -->\n  <router-link :to=\"{ path: 'home' }\">Accueil</router-link>\n\n  <!-- route nommée -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">Utilisateur</router-link>\n\n  <!-- avec une requête, résulte en `/register?plan=private` -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">S'enregistrer</router-link>\n  ```\n\n\n- **replace**\n\n  - type : `boolean`\n\n  - défaut : `false`\n\n  Configurer la prop `replace` appellera `router.replace()` au lieu de `router.push()` lors du clic, comme ça, la navigation ne laissera pas un enregistrement dans l'historique.\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n\n- **append**\n\n  - type : `boolean`\n\n  - défaut : `false`\n\n  Configurer la propriété `append` suffixe toujours le chemin relatif au chemin courant. Par exemple, assumons que nous naviguons de `/a` à un lien relatif `b`, sans `append` on finira sur `/b`, mais avec `append` on finira sur `/a/b`.\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n\n- **tag**\n\n  - type : `string`\n\n  - défaut : `\"a\"`\n\n  Parfois, on veut que `<router-link>` soit rendu avec une balise différente, ex : `<li>`. On peut alors utiliser la prop `tag` pour modifier la balise qui sera rendue, et elle écoutera toujours les évènements de clic pour la navigation.\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- rend -->\n  <li>foo</li>\n  ```\n\n\n- **active-class**\n\n  - type : `string`\n\n  - défaut : `\"router-link-active\"`\n\n  Configure la classe CSS active qui sera appliquée lorsque le lien sera actif. Notez que la valeur par défaut peut aussi être configurée de manière globale via l'option `linkActiveClass` du constructeur du routeur.\n\n- **exact**\n\n  - type : `boolean`\n\n  - défaut : `false`\n\n  Le comportement par défaut de la correspondance de classe active est une **correspondance inclusive**. Par exemple, `<router-link to=\"/a\">` verra cette classe appliquée tant que le chemin courant commencera par `/a/` ou `/a`.\n\n  Une conséquence de cela est que `<router-link to=\"/\">` sera actif pour toutes les routes ! Pour forcer le lien dans un « mode correspondance exacte », utilisez la prop `exact`.\n\n  ``` html\n  <!-- ce lien sera uniquement actif à `/` -->\n  <router-link to=\"/\" exact>\n  ```\n\n  Allez voir les exemples expliquant la classe active pour les liens [ici](https://jsfiddle.net/8xrk1n9f/).\n\n- **event**\n\n  > 2.1.0+\n\n  - type : `string | Array<string>`\n\n  - défaut : `'click'`\n\n  Spécifie les évènement(s) que peu(ven)t lancer la navigation de lien.\n\n- **exact-active-class**\n\n  > 2.5.0+\n\n  - type : `string`\n\n  - défaut : `\"router-link-exact-active\"`\n\n  Configure la classe CSS active qui sera appliquée lorsqu'un lien sera actif avec une correspondance exacte. Notez que la valeur par défaut peut aussi être configurée de manière globale via l'option `linkExactActiveClass` du constructeur du routeur.\n\n### Appliquer la classe active à l'élément extérieur\n\nParfois, on voudrait que la classe active soit appliquée à un élément extérieur au lieu de l'élément `<a>` lui-même, dans ce cas, vous pouvez faire le rendu de cet élément extérieur en utilisant `<router-link>` et en entourant le tag `<a>` :\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\nDans ce cas, `<a>` sera le lien actuel (et récupèrera le bon `href`), mais la classe active sera appliquée à l'élément extérieur `<li>`.\n"
  },
  {
    "path": "docs-gitbook/fr/api/router-view.md",
    "content": "# `<router-view>`\n\nLe composant `<router-view>` est un composant fonctionnel qui fait le rendu du composant correspondant au chemin donné. Les composants rendus dans `<router-view>` peuvent aussi contenir leur propre `<router-view>`, qui fera le rendu des composants pour les chemins imbriqués.\n\n### Props\n\n- **name**\n\n  - type : `string`\n\n  - défaut : `\"default\"`\n\n  Lorsqu'un `<router-view>` a un nom, il fera le rendu du composant correspondant à ce nom dans les itinéraires de route correspondant à l'option `components`. Voir les [Routes nommées](../essentials/named-views.md) pour un exemple.\n\n### Comportement\n\nLes propriétés sans nom seront passées le long du composant rendu, toutefois la plupart du temps, les données par route seront contenues dans les paramètres de la route.\n\nCar c'est juste un composant, il fonctionne avec `<transition>` et `<keep-alive>`. Lorsque vous utilisez les deux ensemble, soyez sûr d'utiliser `<keep-alive> à l'intérieur :\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/dynamic-matching.md",
    "content": "# Concordance dynamique de route\n\nVous allez très souvent associer des routes avec un motif donné à un même composant. Par exemple nous pourrions avoir le composant `User` qui devrait être rendu pour tous les utilisateurs mais avec différents identifiants. Avec `vue-router` nous pouvons utiliser des segments dynamiques dans le chemin de la route pour réaliser cela :\n\n``` js\nconst User = {\n  template: '<div>Utilisateur</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // Les segments dynamiques commencent avec la ponctuation deux-points\n    { path: '/utilisateur/:id', component: User }\n  ]\n})\n```\n\nMaintenant des URL comme `/utilisateur/foo` et `/utilisateur/bar` seront chacun associé à la même route.\n\nUn segment dynamique se repère avec les deux-points `:`. Quand une route concorde, la valeur du segment dynamique est exposée via `this.$route.params` dans tous les composants. Et donc, nous pouvons faire le rendu de l'identifiant de l'utilisateur courant en mettant à jour le template de `User` ainsi :\n\n``` js\nconst User = {\n  template: '<div>Utilisateur {{ $route.params.id }}</div>'\n}\n```\n\nVous pouvez regarder un exemple en ligne [ici](https://jsfiddle.net/yyx990803/4xfa2f19/).\n\nVous pouvez avoir plusieurs segments dynamiques pour une même route, et ils seront associés aux champs associés dans `$route.params`. Des exemples :\n\n| motif | chemin concordant | $route.params |\n|---------|------|--------|\n| /utilisateur/:username | /utilisateur/evan | `{ username: 'evan' }` |\n| /utilisateur/:username/billet/:post_id | /utilisateur/evan/billet/123 | `{ username: 'evan', post_id: '123' }` |\n\nEn plus de `$route.params`, l'objet `$route` expose également d'autres informations utiles comme la `$route.query` (s'il y a une requête dans l'URL), `$route.hash`, etc. Vous pouvez accéder à tous les détails de cela dans la [référence de l'API](../api/route-object.md).\n\n### Réactivité aux changements de paramètres\n\nUne chose à noter quand vous utilisez des routes avec des paramètres (segments), c'est que lors de la navigation de l'utilisateur de `/utilisateur/foo` vers `/utilisateur/bar`, **la même instance de composant va être réutilisée**. Puisque les deux routes font le rendu du même composant, cela est plus performant que de détruire l'ancienne instance et d'en créer une nouvelle. **Cependant, cela signifie également que les hooks de cycle de vie ne seront pas appelés**.\n\nPour réagir aux changements de paramètres dans le même composant, vous pouvez simplement observer l'objet `$route` :\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // réagir au changement de route...\n    }\n  }\n}\n```\n\nOu utiliser la fonction d'interception `beforeRouteUpdate` introduite avec la 2.2 :\n\n``` js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // réagir au changement de route...\n    // n'oubliez pas d'appeler `next()`\n  }\n}\n```\n\n### Motifs de concordance avancés\n\n`vue-router` utilise [path-to-regexp](https://github.com/pillarjs/path-to-regexp) comme moteur de concordance de chemin, il supporte donc plusieurs motifs de concordance avancés tels que la présence optionnelle de segments dynamiques, aucun ou plusieurs motifs, plus d'options par motifs, et même des motifs d'expressions régulières personnalisés. Consultez cette [documentation](https://github.com/pillarjs/path-to-regexp#parameters) pour utiliser ces motifs avancés et [cet exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) pour les utiliser avec `vue-router`.\n\n### Priorité de concordance\n\nParfois la même URL peut être adressé par de multiples routes. Dans ce cas, la priorité de concordance est déterminée par l'ordre de la définition des routes : plus la route est définie tôt, plus sa priorité est élevée.\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/getting-started.md",
    "content": "# Pour commencer\n\n> Nous utiliserons [ES2015](https://github.com/lukehoban/es6features) dans les exemples de code dans ce guide.\n\nCréer une application monopage avec Vue + Vue Router est vraiment simple. Avec Vue.js, nous concevons déjà notre application avec des composants. En ajoutant vue-router dans notre application, tout ce qu'il nous reste à faire est de relier nos composants aux routes, et de laisser vue-router faire le rendu. Voici un exemple de base :\n\n> Tous les exemples utiliseront la version complète de Vue pour rendre l'analyse de template possible. Plus de détails [ici](https://fr.vuejs.org/guide/installation.html#Runtime-Compiler-vs-Runtime-seul).\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Bonjour l'application !</h1>\n  <p>\n    <!-- utilisez le composant router-link pour la navigation. -->\n    <!-- spécifiez le lien en le passant à la prop `to` -->\n    <!-- `<router-link>` sera rendu en tag `<a>` par défaut -->\n    <router-link to=\"/foo\">Aller à Foo</router-link>\n    <router-link to=\"/bar\">Aller à Bar</router-link>\n  </p>\n  <!-- balise pour le composant router-view -->\n  <!-- le composant correspondant à la route sera rendu ici -->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. Si vous utilisez un système de module (par ex. via vue-cli), il faut importer Vue et Vue Router et ensuite appeler `Vue.use(VueRouter)`.\n\n// 1. Définissez les composants de route.\n// Ces derniers peuvent être importés depuis d'autre fichier\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Définissez des routes.\n// Chaque route doit correspondre à un composant. Le « composant » peut\n// soit être un véritable composant créé via `Vue.extend()`, ou juste un\n// objet d'options.\n// Nous parlerons plus tard des routes imbriquées.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Créez l'instance du routeur et passez l'option `routes`.\n// Vous pouvez également passer des options supplémentaires,\n// mais nous allons faire simple pour l'instant.\nconst router = new VueRouter({\n  routes // raccourci pour `routes: routes`\n})\n\n// 5. Créez et montez l'instance de Vue.\n// Soyez sûr d'injecter le routeur avec l'option `router` pour\n// permettre à l'application tout entière d'être à l'écoute du routeur.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// L'application est maintenant en marche !\n```\n\nEn injectant le routeur, nous y avons accès à travers `this.$router`. Nous avons également accès à la route courante derrière `this.$route` depuis n'importe quel composant :\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username () {\n      // Nous verrons ce que représente `params` dans un instant.\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack () {\n      window.history.length > 1\n        ? this.$router.go(-1)\n        : this.$router.push('/')\n    }\n  }\n}\n```\n\nDans les documentations, nous allons souvent utiliser l'instance `router`. Gardez à l'esprit que l'utilisation de `this.$router` est exactement la même chose que celle de `router`. La raison pour laquelle nous utilisons `this.$router` est la possibilité ainsi offerte de ne pas avoir à importer le routeur dans chaque fichier de composant ayant besoin d'accéder au routage.\n\nVous pouvez aussi regarder cet [exemple](https://jsfiddle.net/yyx990803/xgrjzsup/).\n\nNotez qu'un `<router-link>` obtiendra automatiquement la classe `.router-link-active` lorsque sa route cible correspond à la route actuelle. Vous pouvez en apprendre plus à propos de cela dans sa [documentation d'API](../api/router-link.md).\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/history-mode.md",
    "content": "# Mode historique de HTML5\n\nLe mode par défaut de `vue-router` est le _mode hash_. Il utilise la partie hash de l'URL pour simuler un URL complet et ainsi ne pas recharger la page quand l'URL change.\n\nPour nous passer du hash, nous pouvons utiliser le **mode historique** qui utilisera l'API `history.pushState` afin de permettre une navigation sans rechargement de page :\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nQuand vous utilisez le mode historique, l'URL ressemblera à n'importe quel URL normal. Par ex. `http://oursite.com/user/id`. Magnifique !\n\nCependant, un problème apparait si votre application est une application monopage cliente. Sans une configuration serveur adaptée, les utilisateurs tomberont sur une page d'erreur 404 en tentant d'accéder à `http://oursite.com/user/id` directement dans leur navigateur. Maintenant ça craint.\n\nNe vous inquiétez pas. Pour résoudre ce problème, il vous suffit d'ajouter une route à votre serveur prenant en compte toutes les adresses demandées. Si l'URL demandée ne concorde avec aucun fichier statique, alors il doit toujours renvoyer la page `index.html` qui contient le code de votre application. De nouveau magnifique !\n\n## Exemple de configurations serveur\n\n#### Apache\n\n```apache\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Node.js natif\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile('index.htm', 'utf-8', (err, content) => {\n    if (err) {\n      console.log(`Impossible d'ouvrir le fichier \"index.htm\"`)\n    }\n\n    res.writeHead(200, {\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log('Le serveur écoute à : http://localhost:%s', httpPort)\n})\n```\n\n#### Node.js avec Express\n\nPour Node.js avec Express, vous pouvez utiliser le [middleware connect-history-api-fallback](https://github.com/bripkens/connect-history-api-fallback).\n\n#### Internet Information Services (IIS)\n\n1. Instaler [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite)\n2. Créer un fichier `web.config` dans le répertoire racine de votre site avec le contenu suivant :\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Hébergement Firebase\n\nAjouter ceci à votre fichier `firebase.json` :\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## Limitation\n\nIl y a une limitation a tout ceci. Votre serveur ne renverra plus les erreurs 404 des chemins qui ne sont pas trouvés puisqu'il va servir à présent le fichier `index.html`. Pour contourner ce problème, vous pouvez implémenter une route concordant avec toutes les adresses en 404 dans votre application Vue :\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\nUne alternative possible, si vous utilisez un serveur Node.js, est d'implémenter ce mécanisme de substitution en utilisant le routeur côté serveur pour vérifier la concordance des demandes d'URL entrant. Si la route ne concorde avec rien, la page est inexistante. Consultez l'[utilisation de Vue côté serveur](https://ssr.vuejs.org/fr/) pour plus d'informations.\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/named-routes.md",
    "content": "# Routes nommées\n\nParfois il est plus pratique d'identifier une route avec un nom, tout particulièrement quand on souhaite attacher cette route ou exécuter des actions de navigation. Vous pouvez donner un nom à une route dans les options `routes` pendant la création de l'instance du routeur :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/utilisateur/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nPour attacher une route nommée, vous pouvez passer un objet à la prop `to` du composant `router-link` :\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">Utilisateur</router-link>\n```\n\nC'est exactement le même objet à utiliser programmatiquement avec `router.push()` :\n\n``` js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nDans les deux cas, le routeur va naviguer vers le chemin `/utilisateur/123`.\n\nUn exemple complet se trouve [ici](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/named-views.md",
    "content": "# Vues nommées\n\nParfois vous avez besoin d'afficher différentes vues en même temps plutôt que de les imbriquer, c.-à-d. créer un affichage avec une vue `sidebar` et une vue `main` par exemple. C'est ici que les routes nommées entrent en jeu. Au lieu d'avoir une seule balise de vue, vous pouvez en avoir une multitude et donner à chacune d'entre elles un nom. Un `router-view` sans nom aura comme nom par défaut : `default`.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nUne vue est rendue en utilisant un composant, donc de multiples vues nécessitent de multiples composants pour une même route. Assurez-vous d'utiliser l'option `components` (avec un s) :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nUne démo de cet exemple peut-être trouvée [ici](https://jsfiddle.net/posva/6du90epg/).\n\n## Vues nommées imbriquées\n\nIl est possible de créer des dispositions complexes en utilisant les vues nommées avec les vues imbriquées. Quand vous le faites, vous devez nommer les composants imbriqués de `router-view` utilisés. Voyons cela avec un panneau de configuration exemple :\n\n```\n/parametres/emails                                     /parametres/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` est juste un composant standard.\n- `UserSettings` est un composant de vue.\n- `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` sont des composants de vue imbriqués.\n\n**Note** : _mettons de côté la partie HTML / CSS de cette disposition et concentrons nous sur le composant utilisé en lui-même._\n\nLa section `<template>` pour le composant `UserSettings` de la disposition ci-dessus devrait ressembler à quelque chose comme cela :\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>Paramètres utilisateurs</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_Le composant de vue imbriqué est omis ici mais vous pouvez le trouver dans le code source complet de l'exemple ci-dessus [ici](https://jsfiddle.net/posva/22wgksa3/)._\n\nPuis vous pouvez achever la disposition ci-dessus avec la configuration de route :\n\n```js\n{\n  path: '/parametres',\n  // Vous pouvez également avoir des vues nommées à la racine\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nUne démo de cet exemple peut-être trouvée [ici](https://jsfiddle.net/posva/22wgksa3/).\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/navigation.md",
    "content": "# Navigation programmatique\n\nEn complément du l'utilisation de `<router-link>` pour créer des balises ancres pour la navigation déclarative, nous pouvons le faire de manière programmatique en utilisant les méthodes de l'instance du routeur.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n** Note : Dans une instance Vue, vous pouvez accéder à l'instance du routeur via `$router`. Vous pouvez donc appeler `this.$router.push`.**\n\nPour naviguer vers un URL différent, utilisez `router.push`. Cette méthode ajoute une nouvelle entrée dans la pile de l'historique. Ainsi quand un utilisateur clique sur le bouton retour de son navigateur, il retournera à l'URL précédent.\n\nCette méthode est appelée en interne quand vous cliquez sur `<router-link>`, donc cliquer sur `<router-link :to=\"...\">` est équivalent à appeler `router.push(...)`.\n\n| Déclarative | Programmatique |\n|-------------|--------------|\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\nL'argument peut être une chaine de caractère représentant un chemin, ou un objet de description de destination. Des exemples :\n\n``` js\n// chaine de caractère représentant un chemin\nrouter.push('home')\n\n// objet\nrouter.push({ path: 'home' })\n\n// route nommée\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// avec une requête « query » résultant de `/register?plan=private`\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n**Note :** `params` est ignoré si `path` est fourni, ce qui n'est pas le cas pour `query`, comme démontré dans l'exemple ci-dessous. À la place, vous devez fournir le `name` de la route ou manuellement spécifier le `path` complet avec tous les paramètres :\n\n```js\nconst userId = 123\nrouter.push({ name: 'user', params: { userId }}) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// Ceci ne va PAS fonctionner\nrouter.push({ path: '/user', params: { userId }}) // -> /user\n```\n\nLes mêmes règles s'appliquent pour la propriété `to` du composant `router-link`.\n\nDans la version 2.2.0+, vous pouvez optionnellement fournir les fonctions de rappel `onComplete` et `onAbort` à `router.push` ou `router.replace` en tant que deuxième et troisième arguments. Ces fonctions de rappel seront appelées quand la navigation sera respectivement ; complétée avec succès (après la résolution de tous les hooks asynchrones), ou arrêtée (navigation vers la même route ou vers une route différente avant que la navigation courante ne soit achevée).\n\n**Note :** si la destination est la même que la route courante et que seuls les paramètres ont changés (par ex. naviguer d'un profil à l'autre `/utilisateurs/1` -> `/utilisateurs/2`), vous devrez utiliser [`beforeRouteUpdate`](./dynamic-matching.html#réactivité-aux-changements-de-paramètres) pour réagir aux changements (par ex. récupérer les informations de l'utilisateur).\n\n#### `router.replace(location, onComplete?, onAbort?)`\n\nIl agit comme `router.push`. La seule différence est que la navigation se fait sans ajouter de nouvelle entrée dans la pile de l'historique. Comme son nom l'indique, il remplace l'entrée courante.\n\n| Déclarative | Programmatique |\n|-------------|--------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n#### `router.go(n)`\n\nCette méthode prend un seul nombre en tant que paramètre. Celui-ci indique de combien d'entrées vers l'avant ou vers l'arrière il faut naviguer dans la pile de l'historique, de la même manière qu'avec `window.history.go(n)`.\n\nDes exemples\n\n``` js\n// avancer d'une entrée, identique à `history.forward()`\nrouter.go(1)\n\n// retourner d'une entrée en arrière, identique à `history.back()`\nrouter.go(-1)\n\n// avancer de trois entrées\nrouter.go(3)\n\n// échoue silencieusement s'il n'y a pas assez d'entrées.\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### Manipulation de l'historique\n\nVous avez peut être remarqué que `router.push`, `router.replace` et `router.go` sont des équivalents de [`window.history.pushState`, `window.history.replaceState` et `window.history.go`](https://developer.mozilla.org/fr-FR/docs/Web/API/History), et qu'ils imitent les APIs de `window.history`.\n\nDonc, si vous utilisez déjà l'[API History des navigateurs](https://developer.mozilla.org/fr-FR/docs/Web/API/History_API), manipuler l'historique sera très simple avec vue-router.\n\nIl n'est pas nécessaire de préciser que les méthodes de navigation (`push`, `replace`, `go`) fonctionnent de la même manière dans tous les modes de routage (`history`, `hash` and `abstract`).\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/nested-routes.md",
    "content": "# Routes imbriquées\n\nLes vraies interfaces utilisateurs d'application sont faites de composants imbriqués à de multiples niveaux de profondeur. Il est aussi très commun que les segments d'URL correspondent à une certaine structure de composants imbriqués, par exemple :\n\n```\n/utilisateur/foo/profil                  /utilisateur/foo/billets\n+---------------------+                  +--------------------+\n| User                |                  | User               |\n| +-----------------+ |                  | +----------------+ |\n| | Profile         | |  +------------>  | | Posts          | |\n| |                 | |                  | |                | |\n| +-----------------+ |                  | +----------------+ |\n+---------------------+                  +--------------------+\n```\n\nAvec `vue-router`, il est vraiment très simple d'exprimer cette relation en utilisant des configurations de route imbriquées.\n\nReprenons l'application créée au chapitre précédent :\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>Utilisateur {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User }\n  ]\n})\n```\n\nIci le `<router-view>` est une balise de premier niveau. Il fait le rendu des composants qui concordent avec une route de premier niveau. De la même façon, un composant de rendu peut contenir également sa propre balise `<router-view>` imbriquée. Par exemple, ajoutons en une à l'intérieur du template du composant `User` :\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>Utilisateur {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nPour faire le rendu de composants à l'intérieur des balises imbriquées, nous avons besoin d'utiliser l'option `children` dans la configuration du constructeur de `VueRouter` :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User,\n      children: [\n        {\n          // `UserProfile` va être rendu à l'intérieur du `<router-view>` de `User`\n          // quand `/utilisateur/:id/profil` concorde\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // `UserPosts` va être rendu à l'intérieur du `<router-view>` de `User`\n          // quand `/utilisateur/:id/billets` concorde\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Notez que les chemins imbriqués commençants par `/` vont être traités comme des chemins partant de la racine. Cela vous permet d'adresser des composants imbriqués sans avoir à utiliser un URL imbriqué.**\n\nComme vous pouvez le voir, l'option `children` n'est qu'un autre tableau d'objet de configuration de route comme dans `routes`. Et donc, vous pouvez garder les vues imbriquées au plus près de vos besoins.\n\nÀ ce niveau, avec la configuration ci-dessus, quand vous visitez `/utilisateur/foo`, rien ne sera rendu dans la partie `User`, car aucune sous route ne concorde. Peut-être voudriez-vous afficher quelque chose ici. Dans ce cas, vous pouvez fournir une sous route vide :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/utilisateur/:id', component: User,\n      children: [\n        // `UserProfile` va être rendu à l'intérieur du `<router-view>` de `User`\n        // quand `/utilisateur/:id` concorde\n        { path: '', component: UserHome },\n\n        // ...autres sous routes\n      ]\n    }\n  ]\n})\n```\n\nUne démo de fonctionnement de cet exemple peut-être trouvée [ici](https://jsfiddle.net/yyx990803/L7hscd8h/).\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/passing-props.md",
    "content": "# Passage de props aux composants de route\n\nUtiliser `$route` dans vos composants crée un couplage fort à la route qui va limiter la flexibilité du composant qui ne pourra être utilisé que par certains URL.\n\nPour découpler un composant de son routeur, utilisez les props :\n\n**Plutôt que de coupler avec `$route`**\n\n``` js\nconst User = {\n  template: '<div>Utilisateur {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User }\n  ]\n})\n```\n\n**Découplez avec les `props`**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>Utilisateur {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/utilisateur/:id', component: User, props: true },\n\n    // pour les routes avec vues nommées, vous devez définir l'option `props` pour chaque vue nommée :\n    {\n      path: '/utilisateur/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nCela vous permet d'utiliser le composant n'importe où, ce qui le rend plus facile à réutiliser et à tester.\n\n### Mode booléen\n\nQuand `props` est mis à `true`, le `route.params` est remplis en tant que props du composant.\n\n### Mode objet\n\nQuand `props` est un objet, cela alimente les props de celui-ci. Utile quand les props sont statiques.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n### Mode fonction\n\nVous pouvez créer une fonction qui va retourner les props. Cela vous permet de caster des paramètres dans un autre type, de combiner les valeurs statiques avec les valeurs des routes, etc.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\nL'URL `/search?q=vue` passerait `{query: 'vue'}` comme `props` au composant `SearchUser`.\n\nEssayez de garder la fonction de `props` sans état, car il n'est évalué que sur les changements de route. Utilisez un composant englobant si vous avez besoin d'état pour définir les props, ainsi la vue pourra réagir au changement d'état.\n\nPour une utilisation avancée, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).\n"
  },
  {
    "path": "docs-gitbook/fr/essentials/redirect-and-alias.md",
    "content": "# Redirection et alias\n\n### Redirection\n\nLes redirections peuvent aussi être faites depuis la configuration de `routes`. Pour rediriger `/a` vers `/b` :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nLa redirection peut également être effectuée en ciblant une route nommée :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nOu on peut même utiliser une fonction pour les redirections dynamiques :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // la fonction reçoit la route cible en tant qu'argument\n      // retournez le chemin vers la nouvelle route ici.\n    }}\n  ]\n})\n```\n\nNotez que les [intercepteurs de navigation](../advanced/navigation-guards.md) ne sont pas appliqués sur les routes d'où à lieu la redirection mais uniquement sur les routes cibles. Dans l'exemple ci-dessous, ajouter une interception `beforeEnter` ou `beforeLeave` à la route `/a` n'aura aucun effet.\n\nPour d'autres utilisations avancées, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n### Alias\n\nUne redirection signifie que si l'utilisateur visite `/a`, l'URL va être remplacé par `/b` et concordé avec `/b`. Mais qu'est-ce qu'un alias ?\n\n** Un alias de `/a` en tant que `/b` signifie que lorsque l'utilisateur va visiter `/b`, l'URL va rester `/b`, mais la concordance va se faire comme si l'utilisateur visitait `/a`.**\n\nLa phase du dessus peut être exprimée dans la configuration de la route de la manière suivante :\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nUn alias vous donne la liberté d'associer une structure d'interface utilisateur à un URL arbitraire, au lieu d'être contraint par une configuration de structure.\n\nPour d'autres utilisations avancées, jetez un œil à cet [exemple](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js).\n"
  },
  {
    "path": "docs-gitbook/fr/installation.md",
    "content": "# Installation\n\n### Téléchargement direct / CDN\n\n[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) fournit des liens CDN basés sur npm. Le lien ci-dessus pointera toujours vers la dernière version sur npm. Vous pouvez aussi utiliser un tag ou une version spécifique via un URL comme `https://unpkg.com/vue-router@2.0.0/dist/vue-router.js`.\n<!--/email_off-->\n\nIncluez `vue-router` après Vue et l'installation sera automatique :\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### npm\n\n``` bash\nnpm install vue-router\n```\n\nLorsqu'il est utilisé avec un système de module, vous devez explicitement installer le router via `Vue.use()` :\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nVous n'avez pas besoin de faire cela lors de l'utilisation des balises de script globales (`<script>`).\n\n### Build de développement\n\nVous aurez besoin de cloner directement `vue-router` depuis GitHub et le compiler vous-même si vous souhaitez utiliser le dernier build de développement.\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs-gitbook/ja/README.md",
    "content": "{% include \"./SUMMARY.md\" %}\n"
  },
  {
    "path": "docs-gitbook/ja/SUMMARY.md",
    "content": "# vue-router\n\n> 注意: TypeScript ユーザ向けは、vue-router@3.0+ と vue@2.5+ が必須、逆もまた同様です。\n\n**[リリースノート](https://github.com/vuejs/vue-router/releases)**\n\n- [インストール](installation.md)\n- 基本的な使い方\n  - [はじめに](essentials/getting-started.md)\n  - [動的ルートマッチング](essentials/dynamic-matching.md)\n  - [ネストされたルート](essentials/nested-routes.md)\n  - [プログラムによるナビゲーション](essentials/navigation.md)\n  - [名前付きルート](essentials/named-routes.md)\n  - [名前付きビュー](essentials/named-views.md)\n  - [リダイレクトとエイリアス](essentials/redirect-and-alias.md)\n  - [ルートコンポーネントにプロパティを渡す](essentials/passing-props.md)\n  - [HTML5 History モード](essentials/history-mode.md)\n- 高度な使い方\n  - [ナビゲーションガード](advanced/navigation-guards.md)\n  - [ルートメタフィールド](advanced/meta.md)\n  - [トランジション](advanced/transitions.md)\n  - [データの取得](advanced/data-fetching.md)\n  - [スクロールの振る舞い](advanced/scroll-behavior.md)\n  - [遅延ローディング](advanced/lazy-loading.md)\n- API リファレンス\n  - [ルーターコンストラクタオプション](api/options.md)\n    - [routes](api/options.md#routes)\n    - [mode](api/options.md#mode)\n    - [base](api/options.md#base)\n    - [linkActiveClass](api/options.md#linkactiveclass)\n    - [linkExactActiveClass](api/options.md#linkexactactiveclass)\n    - [scrollBehavior](api/options.md#scrollbehavior)\n    - [parseQuery / stringifyQuery](api/options.md#parsequery--stringifyquery)\n    - [fallback](api/options.md#fallback)\n  - [ルーターインスタンス](api/router-instance.md)\n    - [Properties](api/router-instance.md#properties)\n    - [Methods](api/router-instance.md#methods)\n  - [ルートオブジェクト](api/route-object.md)\n  - [コンポーネント注入](api/component-injections.md)\n  - [router-link](api/router-link.md)\n  - [router-view](api/router-view.md)\n"
  },
  {
    "path": "docs-gitbook/ja/advanced/data-fetching.md",
    "content": "# データ取得\n\nルートが有効化された時にサーバーからデータを取得する必要がしばしばあります。例えば、ユーザープロフィールを描画する前に、サーバーからユーザーデータを取得する必要があります。これを実現するためには 2 種類の方法があります。\n\n- **ナビゲーション後の取得**: ナビゲーションを先に実行し、その後次に入ってくるコンポーネントのライフサイクルフック内でデータを取得します。データ取得中にローディングを表示します。\n\n- **ナビゲーション前の取得**: ルートに入るガード内でナビゲーション前にデータ取得をします。そして、データ取得後にナビゲーションを実行します。\n\n技術的にはどちらも正当な選択肢です。究極的にはあなたが目指しているユーザーエクスペリエンスに依存します。\n\n## ナビゲーション後の取得\n\nこのアプローチを取る時は次に来るコンポーネントが即座にナビゲーションされ、描画されます。そして、コンポーネントの `created` フックの中でデータを取得します。この方法ではネットワーク越しにデータを取得している間にローディング状態を表示する機会があります。また、各 view に対して、異なるローディングの対応をすることもできます。\n\n`$route.params.id` を元にポストのデータを取得する必要がある `Post` コンポーネントを想定してみましょう。\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // view が作られた時にデータを取得し、\n    // そのデータは既に監視されています\n    this.fetchData()\n  },\n  watch: {\n    // ルートが変更されたらこのメソッドを再び呼び出します\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // `getPost` をあなたのデータ取得用 util や API ラッパーに置き換えてください\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## ナビゲーション前の取得\n\nこちらのアプローチでは新しいルートへ実際にナビゲーションする前にデータを取得します。次に入ってくるコンポーネント内の  `beforeRouteEnter` ガードでデータ取得を実行できます。データ取得が完了したら `next` を呼ぶだけです。\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (route, redirect, next) {\n    getPost(route.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // コンポーネントが既に描画されている際のルート変更時は\n  // ロジックが少し異なります\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\n次に入ってくる view へのリソースを取得している間、ユーザーは前の view に滞在します。したがって、データ取得中にプログレスバーや何らかの指標を表示することをオススメします。また、もしデータ取得が失敗した場合、何かグローバルな警告メッセージのようなものを表示する必要があります。\n"
  },
  {
    "path": "docs-gitbook/ja/advanced/lazy-loading.md",
    "content": "# 遅延ローディングルート\n\nバンドラーを使ってアプリケーションを構築している時、バンドルされる JavaScript が非常に大きいものになり得ます。結果的にページのロード時間に影響を与えてしまいます。もし各ルートコンポーネントごとに別々のチャンクにして、訪れたルートの時だけロードできればより効率的でしょう。\n\nVue の [非同期コンポーネント機能](http://jp.vuejs.org/guide/components.html#非同期コンポーネント) と webpack の [コード分割機能](https://webpack.js.org/guides/code-splitting-async/) を組み合わせることでとても簡単に遅延ロードするルートコンポーネントができます。\n\n最初に、非同期コンポーネントは Promise (コンポーネント自身解決する必要がある) を返すファクトリ関数として定義できます:\n\n``` js\nconst Foo = () => Promise.resolve({ /* component definition */ })\n```\n\n次に、webpack 2 において [動的 import](https://github.com/tc39/proposal-dynamic-import) 構文を使用して、コード分割ポイントを示すことができます:\n\n``` js\nimport('./Foo.vue') // returns a Promise\n```\n\n> Note: Babel を使用している場合、Babel が構文を正しく解析するために [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/) プラグインを追加する必要があります。\n\n2 つを組み合わせることで、これは、webpack によって自動的にコード分割される非同期コンポーネントを定義する方法です:\n\n``` js\nconst Foo = () => import('./Foo.vue')\n```\n\n### 同じチャンク内でのコンポーネントグループ化\n\nしばしば同じ非同期のチャンクに、そのルート配下のネストされた全てのコンポーネントをグループ化したいと思うかもしれません。それを実現するためには、 特別なコメント構文 (webpack > 2.4 必須)を使用してチャンクの名前を提供する [名前付きチャンク](https://webpack.js.org/guides/code-splitting-async/#chunk-names) を使う必要があります。\n\n``` js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nwebpack は同じチャンク名のどんな非同期のモジュールも同じ非同期のチャンクにグループします。\n"
  },
  {
    "path": "docs-gitbook/ja/advanced/meta.md",
    "content": "# ルートメタフィールド\n\nルートの定義をする際に `meta` フィールドを含めることができます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // メタフィールド\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nではどのように `meta` フィールドにアクセスしましょう？\n\nまず、 `routes` 設定の中の各ルートオブジェクトは**ルートレコード**と呼ばれます。ルートレコードはネストされているかもしれません。したがって、ルートがマッチした時に、潜在的には 1 つ以上のルートレコードがマッチされる可能性があります。\n\n例えば上記のルート設定で、 `/foo/bar` という URL は親のルートレコードにも子のルートレコードにもマッチします。\n\nルートにマッチした全てのルートレコードは `$route.matched` 配列として `$route` オブジェクト上で (また、ナビゲーションガード上のルートオブジェクトでも) アクセス可能になります。\n\nメタフィールドをグローバルナビゲーションガードで確認するユースケースの例:\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // このルートはログインされているかどうか認証が必要です。\n    // もしされていないならば、ログインページにリダイレクトします。\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // next() を常に呼び出すようにしてください!\n  }\n})\n\n```\n"
  },
  {
    "path": "docs-gitbook/ja/advanced/navigation-guards.md",
    "content": "# ナビゲーションガード\n\nこの名前が示すように、 `vue-router` によって提供されるナビゲーションガードは、リダイレクトもしくはキャンセルによって遷移をガードするために主に使用されます。ルートナビゲーション処理 (グローバル、ルート単位、コンポーネント内) をフックする多くの方法があります。\n\n**パラメータまたはクエリの変更は enter/leave ナビゲーションガードをトリガーしない** ということを覚えておいてください。それらの変更に対応するために [`$route` オブジェクトを監視する](../essentials/dynamic-matching.md#reacting-to-params-changes)、またはコンポーネント内ガード `beforeRouteUpdate` を使用するかの、どちらかができます。\n\n### グローバルガード\n\n`router.beforeEach` を使ってグローバル before ガードを登録できます。\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nいつナビゲーションがトリガーされようとも、グローバル before ガードは作られた順番で呼び出されます。ガードは非同期に解決されるかもしれません。そしてそのナビゲーションは全てのフックが解決されるまで **未解決状態** として扱われます。\n\n全てのガード関数は 3 つの引数を受け取ります。\n\n  - **`to: Route`**: 次にナビゲーションされる対象の [ルートオブジェクト](../api/route-object.md)。\n  \n  - **`from: Route`**: ナビゲーションされる前の現在のルートです。\n  \n  - **`next: Function`**: フックを **解決** するためにこの関数を呼ぶ必要があります。この振る舞いは `next` に渡される引数に依存します:\n\n  - **`next()`**: パイプラインの次のフックに移動します。もしフックが残っていない場合は、このナビゲーションは **確立** されます。\n\n  - **`next(false)`**: 現在のナビゲーションを中止します。もしブラウザのURLが変化した場合は（ユーザーが手動で変更した場合でも、戻るボタンの場合でも）、 `from` ルートのURLにリセットされます。\n\n  - **`next('/')` または `next({ path: '/' })`**: 異なる場所へリダイレクトします。現在のナビゲーションは中止され、あたらしいナビゲーションが始まります。任意のロケーションオブジェクトを `next` に渡すことができます。この `next` には、`replace: true`、 `name: 'home'` のようなオプション、そして [`router-link`、`to` プロパティ](../api/router-link.md)または [`router.push`](../api/router-instance.md#methods)で使用される任意のオプションを指定することができます。\n\n  - **`next(error)`**: (2.4.0+) `next` に渡された引数が `Error` インスタンスである場合、ナビゲーションは中止され、エラーは `router.onError()` を介して登録されたコールバックに渡されます。\n\n  **常に `next` 関数を呼び出すようにしてください。そうでなければ、フックは決して解決されません。**\n\n### グローバル解決ガード\n\n> New in 2.5.0\n\n2.5.0 以降では、`router.beforeResolve` によってグローバルガードを登録できます。これは `router.beforeEach` に似ていますが、**すべてのコンポーネント内ガードと非同期ルートコンポーネントが解決された後**、ナビゲーションが解決される直前に解決ガードが呼び出されるという違いがあります。\n\n### グローバルな After フック\n\nグローバル after フックを登録することもできます。しかしながら、ガードとは異なり、これらのフックは `next` 関数を受け取らず、ナビゲーションに影響しません。\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### ルート単位ガード\n\n直接ルート設定オブジェクトの `beforeEnter` ガードを定義することができます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nこれらのガードはグローバル before ガードと全く同じシグネチャを持ちます。\n\n### コンポーネント内ガード\n\n最後に、 以下のオプションでルートコンポーネント(ルータ設定に渡されるもの)の内側でルートナビゲーションガードを直接定義することができます。\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (2.2 で追加)\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // このコンポーネントを描画するルートが確立する前に呼ばれます。\n    // `this` でのこのコンポーネントへのアクセスはできません。\n    // なぜならばこのガードが呼び出される時にまだ作られていないからです!\n  },\n  beforeRouteUpdate (to, from, next) {\n    // このコンポーネントを描画するルートが変更されたときに呼び出されますが、\n    // このコンポーネントは新しいルートで再利用されます。\n    // たとえば、動的な引数 `/foo/:id` を持つルートの場合、`/foo/1` と `/foo/2` の間を移動すると、\n    // 同じ `Foo` コンポーネントインスタンスが再利用され、そのときにこのフックが呼び出されます。\n    // `this` でコンポーネントインスタンスにアクセスできます。\n  },\n  beforeRouteLeave (to, from, next) {\n    // このコンポーネントを描画するルートが間もなく\n    // ナビゲーションから離れていく時に呼ばれます。\n    // `this` でのコンポーネントインスタンスへのアクセスができます。\n  }\n}\n```\n\nこの `beforeRouteEnter` ガードは `this` へのアクセスは**できない**です。なぜならば、ナビゲーションが確立する前にガードが呼び出されるからです。したがって、新しく入ってくるコンポーネントはまだ作られていないです。\n\nしかしながら、 `next` にコールバックを渡すことでインスタンスにアクセスすることができます。このコールバックはナビゲーションが確立した時に呼ばれ、コンポーネントインスタンスはそのコールバックの引数として渡されます。\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // `vm` を通じてコンポーネントインスタンスにアクセス\n  })\n}\n```\n\nコールバックを `next` に渡すことをサポートするのは、`beforeRouteEnter` ガードだけであるということに注意してください。`beforeRouteUpdate` と `beforeRouteLeave` の場合、 `this` は既に利用可能です。したがって、コールバックを渡す必要はないので、*サポートされません*:\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // `this` を使用\n  this.name = to.params.name\n  next()\n}\n```\n\n**leave ガード**は、通常、ユーザが保存されていない編集内容で誤って経路を離れるのを防ぐために使用されます。ナビゲーションは `next(false)` を呼び出すことで取り消すことができます。\n\n```js\nbeforeRouteLeave (to, from , next) {\n  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\n### 完全なナビゲーション解決フロー\n1. ナビゲーションがトリガされる\n2. 非アクティブ化されたコンポーネントで leave ガードを呼ぶ\n3. グローバル `beforeEach` ガードを呼ぶ\n4. 再利用されるコンポーネントで `beforeRouteUpdate` ガードを呼ぶ (2.2 以降)\n5. ルート設定内の `beforeEnter` を呼ぶ\n6. 非同期ルートコンポーネントを解決する\n7. アクティブ化されたコンポーネントで `beforeRouteEnter` を呼ぶ\n8. グローバル `beforeResolve` ガードを呼ぶ (2.5 以降)\n9. ナビゲーションが確定される\n10. グローバル `afterEach` フックを呼ぶ\n11. DOM 更新がトリガされる\n12. インスタンス化されたインスンタンスによって `beforeRouteEnter` ガードで `next` に渡されたコールバックを呼ぶ\n"
  },
  {
    "path": "docs-gitbook/ja/advanced/scroll-behavior.md",
    "content": "# スクロールの振る舞い\n\nクライアントサイドのルーティングを使っている時に、新しいルートに対してスクロールをトップへ移動させたいかもしれません、もしくは実際のページリロードがしているように history 要素のスクロールポジションを保持したいこともあるかもしれません。 `vue-router` ではこれらをさらによく実現できます。ルートナビゲーションにおけるスクロールの挙動を完全にカスタマイズすることができます。\n\n**注意: この機能は ブラウザが `history.pushState` をサポートしている場合のみ動作します。**\n\nルーターインスタンスを作る時に、 `scrollBehavior` 関数を提供できます。\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // 望みのポジションを返す\n  }\n})\n```\n\n`scrollBehavior` 関数は  `to` と `from` のルートオブジェクトを受け取ります。第 3 引数の `savedPosition` は `popstate` ナビゲーション (ブラウザの戻る/進むボタンがトリガーされた) 時のみ利用可能です。\n\nこの関数はスクロールポジションオブジェクトを返すことができます。そのオブジェクトは以下のような形式です。\n\n- `{ x: number, y: number }`\n- `{ selector: string }`\n- `{ selector: string, offset? : { x: number, y: number }}` (2.6.0 以降においてだけ offset はサポート)\n\nもし falsy な値や空のオブジェクトが返った場合、何もスクロールは起きません。\n\n例:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nこれは単純に全てのルートナビゲーションに対してページスクロールをトップにします。\n\n`savedPosition` を返すことは結果的に戻る/進むボタンを押してナビゲーションした時にネイティブのような挙動になります。\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nもし\"アンカーへスクロール\"の振る舞いをシミュレートしたい場合は以下のようにしてください。\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nきめの細かいスクロールの挙動コントロールを実装するために [ルートメタフィールド](meta.md) も利用可能です。詳細な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js) をご参照ください。\n\n### 非同期なスクローリング\n\n> 2.8.0 で新規\n\n期待する位置記述子 (position descriptor) に解決されるプロミスを返すこともできます:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nスクロールの振る舞いをページの遷移とうまく合わせるために、ページレベルのトランジションコンポーネントからのイベントにフックすることは可能ですが、ユースケースにおいて可能性のある食い違いと複雑さのために、単純に特定のユーザランド実装を可能にするために、このプリミティブな機能を提供します。\n"
  },
  {
    "path": "docs-gitbook/ja/advanced/transitions.md",
    "content": "# トランジション\n\n基本的に `<router-view>` は動的コンポーネントなので、 `<transition>` コンポーネントを使うのと同じ方法でトランジションを適用することができます。\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[`<transition>` についての全て](http://jp.vuejs.org/guide/transitions.html) はここでも動作します。\n\n### ルート単位のトランジション\n\n上記の使い方では全てのトランジションが全てのルートに対して適用されます。もし各ルートコンポーネントにそれぞれ違うトランジションを持たせたい場合は、代わりにルーターコンポーネント内で異なる名前で `<transition>` を使うことができます。\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n### ルートベースの動的トランジション\n\n対象のルートと現在のルートの関係を元に動的にトランジションを決定することも可能です。\n\n``` html\n<!-- 動的なトランジション名の使用 -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// そして親コンポーネントの中で、\n// `$route` を watch して使用するトランジションを決定します\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\n完全な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js) をご参照ください。\n"
  },
  {
    "path": "docs-gitbook/ja/api/component-injections.md",
    "content": "# コンポーネント注入\n\n### 注入されるプロパティ\n\nルーターインスタンスを root インスタンスに `router` オプションとして渡すことによって、全ての子コンポーネントに以下のプロパティが注入されます。\n\n- #### $router\n\n  ルーターインスタンス\n\n- #### $route\n\n  現在のアクティブな [ルート](route-object.md) 。このプロパティは読み出しのみ可能かつ変更不可ですが、watch は可能です。\n\n### 有効になるオプション\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate** (2.2 で追加)\n- **beforeRouteLeave**\n\n  [コンポーネント内ガード](../advanced/navigation-guards.md#incomponent-guards) をご参照ください。\n"
  },
  {
    "path": "docs-gitbook/ja/api/options.md",
    "content": "# ルーターコンストラクタオプション\n\n### routes\n\n- 型: `Array<RouteConfig>`\n\n  `RouteConfig` の型宣言:\n\n  ``` js\n  declare type RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // 名前付きルート用\n    components?: { [name: string]: Component }; // 名前付き view 用\n    redirect?: string | Location | Function;\n    props?: boolean | string | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // ネストされたルート用\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n\n    // 2.6.0+\n    caseSensitive?: boolean; // センシティブマッチをケースとして使用するかどうか? (デフォルト: false)\n    pathToRegexpOptions?: Object; // 正規表現のコンパイルとして path-to-regexp オプション\n  }\n  ```\n\n### mode\n\n- 型: `string`\n\n- デフォルト: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- 利用可能な値: `\"hash\" | \"history\" | \"abstract\"`\n\n  ルーターモードの設定。\n\n  - `hash`: ルーティングに URL hash を使います。HTML5 History API をサポートしていないブラウザ含めて、全ての Vue がサポートしているブラウザで動作します。\n\n  - `history`: HTML5 History API とサーバーの設定が必要です。[HTML5 History モード](../essentials/history-mode.md) を参照してください。\n\n  - `abstract`: 全ての JavaScript の環境で動作します。 e.g. Node.js を使ったサーバーサイド。 **もしブラウザの API が存在しない場合、ルーターは自動的にこのモードに強制されます。**\n\n### base\n\n- 型: `string`\n\n- デフォルト: `\"/\"`\n\n  アプリケーションのベース URL です。例えば、 `/app/` 配下で完全なシングルページアプリケーションを提供する場合、 `base` は `\"/app/\"` の値が使われるべきです。\n\n### linkActiveClass\n\n- 型: `string`\n\n- デフォルト: `\"router-link-active\"`\n\n  グローバルに設定される `<router-link>` のデフォルトのアクティブクラスです。こちらの [router-link](router-link.md) も参照してください。\n\n### linkExactActiveClass\n\n> 2.5.0+\n\n- 型: `string`\n\n- デフォルト: `\"router-link-exact-active\"`\n\n  完全一致に対してグローバルな `<router-link>` デフォルトアクティブクラスを設定します。[router-link](router-link.md) も参照してください。\n\n### scrollBehavior\n\n- 型: `Function`\n\n  シグネチャ:\n\n  ```\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    ?{}\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  より詳細については [スクロールの振る舞い](../advanced/scroll-behavior.md) を参照してください。\n\n### parseQuery / stringifyQuery\n\n> 2.4.0+\n\n- 型: `Function`\n\n  カスタムクエリ構文解析関数 / 文字列化関数を提供します。デフォルトを上書きします。\n\n### fallback\n\n> 2.6.0+\n\n- 型: `boolean`\n\n  ブラウザが `history.pushState` をサポートしないとき、 ルーターが `hash` モードにフォールバックかどうか制御します。デフォルトは `true`\n\n  これを `false` に設定すると、本質的に全ての `router-link` ナビゲーションが IE9 においてフルページリフレッシュになります。これは、サーバサイドレンダリングでハッシュモードの URL が機能しないため、IE9 で動作する必要がある場合に便利です。\n"
  },
  {
    "path": "docs-gitbook/ja/api/route-object.md",
    "content": "# ルートオブジェクト\n\n**ルートオブジェクト**は現在のアクティブなルートの状態を表現しています。現在の URL をパースした情報と、その URL とマッチした**ルートレコード**を保持しています。\n\nルートオブジェクトは変更不可です。成功した全てのナビゲーションは結果的に新たなルートオブジェクトになります。\n\nルートオブジェクトは複数の場所に存在します。\n\n- コンポーネント内での `this.$route`、また、 `$route` watcher コールバック内部。\n\n- `router.match(location)` を呼び出した時の返り値。\n\n- ナビゲーションガード内での第 1 引数、第 2 引数として:\n\n  ``` js\n  router.beforeEach((route, redirect, next) => {\n    // `to` と `from` は両方ともルートオブジェクト\n  })\n  ```\n\n- `scrollBehavior` 関数内の第 1 引数、第 2 引数として:\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n      // `to` と `from` は両方ともルートオブジェクト\n    }\n  })\n  ```\n\n### ルートオブジェクトプロパティ\n\n- **$route.path**\n\n  - 型: `string`\n\n    現在のルートのパスに等しい文字列。常に絶対パスとして解釈されます。e.g. `\"/foo/bar\"`\n\n- **$route.params**\n\n  - 型: `Object`\n\n    動的セグメントとスターセグメントの key/value ペアを保持するオブジェクト。もしパラメーターがない場合、この値は空オブジェクトになります。\n\n- **$route.query**\n\n  - 型: `Object`\n\n    クエリ文字列の key/value ペアを保持するオブジェクト。例えば `/foo?user=1` というパスの場合、`$route.query.user == 1` となります。もしクエリがない場合は、この値は空オブジェクトになります。\n\n- **$route.hash**\n\n  - 型: `string`\n\n    hash がある時の現在のルートの hash (# 有り) です。もし hash がない場合、この値は空オブジェクトになります。\n\n- **$route.fullPath**\n\n  - 型: `string`\n\n    クエリや hash を含む完全に解決された URL です。\n\n- **$route.matched**\n\n  - 型: `Array<RouteRecord>`\n\n  現在のルートのネストされた全パスセグメントに対しての**ルートレコード** を保持している配列です。ルートレコードは `routes` 設定の配列 (と `children` 配列) 内のオブジェクトのコピーです。\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // 以下のオブジェクトがルートレコード\n      { path: '/foo', component: Foo,\n        children: [\n          // こちらもルートレコード\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  URL が `/foo/bar` である時、 `$route.matched` は親から子の順番で両方の (クローンされた) オブジェクトを含む配列になります。\n\n- **$route.name**\n\n  名前がある場合の現在のルートの名前です。(詳しくは [名前付きルート](../essentials/named-routes.md) をご参照ください)\n\n- **$route.redirectedFrom**\n\n  もしあれば、リダイレクト元の名前。(参照[リダイレクトとエイリアス](../essentials/redirect-and-alias.md))\n"
  },
  {
    "path": "docs-gitbook/ja/api/router-instance.md",
    "content": "# ルーターインスタンス\n\n### プロパティ\n\n#### router.app\n\n- 型: `Vue インスタンス`\n\n  `router` が注入される root の Vue インスタンス\n\n#### router.mode\n\n- 型: `string`\n\n  ルーターが使う [モード](options.md#mode) 。\n\n#### router.currentRoute\n\n- 型: `Route`\n\n  [ルーターオブジェクト](route-object.md) として表される現在のルート。\n\n### メソッド\n\n- **router.beforeEach(guard)**\n- **router.beforeResolve(guard)** (2.5.0+)\n- **router.afterEach(hook)**\n\n  グローバルなナビゲーションガードの追加。[ナビゲーションガード](../advanced/navigation-guards.md) をご参照ください。\n\n  2.5.0 以降では、3 つのメソッドすべてが、登録されたガード/フックを削除する関数を返します。\n\n- **router.push(location, onComplete?, onAbort?)**\n- **router.replace(location, onComplete?, onAbort?)**\n- **router.go(n)**\n- **router.back()**\n- **router.forward()**\n\n  プログラムによる新しい URL へのナビゲーション。 [プログラムによるナビゲーション](../essentials/navigation.md) をご参照ください。\n\n- **router.getMatchedComponents(location?)**\n\n  現在のルートまたは提供されたロケーションにマッチしているコンポーネント (インスタンスではなく定義 / コンストラクタ) の配列を返します。これは大抵の場合データ取得を行うサーバーサイドレンダリングで使用されます。\n\n- **router.resolve(location, current?, append?)**\n\n  > 2.1.0+\n\n  逆 URL 解決します。`<router-link/>` で使われているものと同じ形式の location が与えられた場合は、以下の解決されたプロパティを返します。\n\n  ``` js\n  {\n    location: Location;\n    route: Route;\n    href: string;\n  }\n  ```\n\n - `current` はデフォルトによる現在のルートです(ほとんどの場合、これを変更する必要はありません)\n - `append` は `current` ルートにパスを追加できます([`router-link`](https://router.vuejs.org/en/api/router-link.html#props)と同様に)\n\n- **router.addRoutes(routes)**\n\n  > 2.2.0+\n\n  動的にルートをルーターに追加します。引数は `routes` コンストラクタオプションで同じルート設定形式を使用する配列でなければなりません。\n\n- **router.onReady(callback, [errorCallback])**\n\n  > 2.2.0+\n\n  このメソッドは、ルーターが初期ナビゲーションを完了したときに呼び出されるコールバックをキューに入れます。つまり、初期ルートに関連付けられているすべての非同期 enter フックと非同期コンポーネントを解決したことを意味します。\n\n  これは、サーバーとクライアントの両方で一貫した出力を保証するために、サーバーサイドレンダリングに役立ちます。\n\n  第 2 引数 `errorCallback` は 2.4 以降でのみサポートされます。初期ルート解決がエラーの時に、呼び出されます (例: 非同期コンポーネントの解決が失敗)。\n\n- **router.onError(callback)**\n\n  > 2.4.0+\n\n  ルートナビゲーション中にエラーが検出されたときに呼び出されるコールバックを登録します。エラーを呼び出すには、次のいずれかのシナリオが必要であることに注意してください:\n\n  - エラーがルートガード関数内で同期的に投げられる;\n\n  - エラーが補足され、ルートガード関数内で `next(err)` を呼び出すことによって非同期に処理される;\n\n  - ルートを描画するために必須な非同期コンポーネントを解決しようとする時に発生したエラー;\n"
  },
  {
    "path": "docs-gitbook/ja/api/router-link.md",
    "content": "# `<router-link>`\n\n`<router-link>` はルーターが使用可能になっているアプリケーションでユーザーのナビゲーションを有効にするためのコンポーネントです。対象とする location は `to` プロパティを使って指定します。デフォルトでは正しい `href` と共に `<a>` タグとして描画しますが、 `tag` プロパティを設定することも可能です。さらに、対象のルートがアクティブの時に、そのリンクは自動的にアクティブな CSS クラスが当てられます。\n\n下記の理由により `<router-link>` はハードコードする `<a href=\"...\">` よりも好ましいです。\n\n- HTML5 history モードでも hash モードでも同じ方法で動作します。もしあなたがモードを切り替えたりする場合や、IE9 で hash モードにフォールバックする場合に、何も変更する必要はありません。\n\n- HTML5 history モードにおいて、ブラウザがページのリロードをしないように `router-link` はクリックイベントに割り込みます。\n\n- HTML5 history モードで `base` オプションを使っている時に、 `to` プロパティの URL にそれを含める必要がありません。\n\n### プロパティ\n\n- **to**\n\n  - 型: `string | Location`\n\n  - 必須\n\n　リンクする対象のルートを表します。クリックされた時に `to` プロパティの値が内部的に `router.push()` に渡されます。つまり、この値は文字列でも location を記述するオブジェクトでも構いません。\n\n  ``` html\n  <!-- 文字列 -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- 次のように描画される -->\n  <a href=\"home\">Home</a>\n\n  <!-- `v-bind` を使った javascript 式-->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- 他のプロパティのバインディングのような `v-bind` の省略表現 -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- 上記と同じ -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- 名前付きルート -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- 結果的に `/register?plan=private` になるクエリ-->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n- **replace**\n\n  - 型: `boolean`\n\n  - デフォルト: `false`\n\n  `replace` プロパティを設定するとクリックされた時に `router.push()` の代わりに `router.replace()` が呼ばれます。したがって、ナビゲーションは history レコードに残りません。\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n- **append**\n\n  - 型: `boolean`\n\n  - デフォルト: `false`\n\n  `append` プロパティを設定すると現在のパスに対して常に相対パスを追加します。例えば、 `/a` から相対リンクの `b` へ遷移するのを想定した時に、 `append` がない場合は `/b` に、`append` がある場合は `/a/b` になります。\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n- **tag**\n\n  - 型: `string`\n\n  - デフォルト: `\"a\"`\n\n  しばしば `<router-link>` を `<li>` などの他のタグとして描画したい時があるでしょう。そこで、どのタグとして描画するかを指定するために `tag` プロパティを使うことができます。そして、依然ナビゲーションのためのクリックイベントを listen します。\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- 以下のように描画されます -->\n  <li>foo</li>\n  ```\n\n- **active-class**\n\n  - 型: `string`\n\n  - デフォルト: `\"router-link-active\"`\n\n  リンクがアクティブな時に適用されるアクティブ CSS クラスの設定です。デフォルト値はルーターコンストラクタオプションの `linkActiveClass` でグローバルに設定可能です。\n\n- **exact**\n\n  - 型: `boolean`\n\n  - デフォルト: `false`\n\n  デフォルトのアクティブクラスのマッチングの振る舞いは **包含的なマッチ** です。 例えば、現在のパスが `/a/` または `/a` から始まる限りは、`<router-link to=\"/a\">` にアクティブクラスが適用されます。\n\n  この結果として `<router-link to=\"/\">` は全てのルートに対してアクティブになります! リンクに対して \"正確なマッチモード\" を強制するために、 `exact` プロパティを使ってください。\n\n  ``` html\n  <!-- このリンクは `/` だけにアクティブになります -->\n  <router-link to=\"/\" exact>\n  ```\n\n  アクティブリンククラスをより説明している例としてこちらの [動作](https://jsfiddle.net/8xrk1n9f/) を確認してください。\n\n- **event**\n\n  > 2.1.0+\n\n  - 型: `string | Array<string>`\n\n  - デフォルト: `'click'`\n\n  リンクナビゲーションをトリガーできるイベントを指定します。\n\n- **exact-active-class**\n\n  > 2.5.0+\n\n  - 型 `string`\n\n  - デフォルト: `\"router-link-exact-active\"`\n\n  完全一致によってリンクがアクティブになっているときに適用されるアクティブな CSS クラスを設定します。デフォルト値は `linkExactActiveClass` ルーターコンストラクタのオプション経由でグローバルに設定することもできます。\n\n### 外側の要素へのアクティブクラスの適用\n\nアクティブクラスを `<a>` タグ自身よりも、外側の要素に対して適用したいことがあるでしょう。その場合、 `<router-link>` を使って外側の要素を描画して、その内側に生の `<a>` タグをラップすることができます。\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\nこの時、 `<a>` は実際のリンクになります (そして正しい `href` が得られます)。しかし、アクティブクラスは外側の `<li>` に適用されます。\n"
  },
  {
    "path": "docs-gitbook/ja/api/router-view.md",
    "content": "# `<router-view>`\n\n`<router-view>` コンポーネントは与えられたパスに対してマッチしたコンポーネントを描画する関数型コンポーネントです。`<router-view>` の中で描画されるコンポーネント自身もまた、ネストされたパスに対してコンポーネントを描画するための `<router-view>` を持つことができます。\n\n### プロパティ\n\n- **name**\n\n  - 型: `string`\n\n  - デフォルト: `\"default\"`\n\n  `<router-view>` が名前を持つ時、マッチしたルートレコードの `components` オプション内で対応する名前のコンポーネントを描画します。例は [名前付きビュー](../essentials/named-views.md) をご参照ください。\n\n### 振る舞い\n\nname ではないプロパティも描画されるコンポーネントに渡されますが、ほとんどの場合ルート単位のデータはルートのパラメーターに含まれています。\n\nこれは普通のコンポーネントなので、 `<transition>` と `<keep-alive>` と共に動作します。両方を同時に使用する場合は `<keep-alive>` を内側にするようにしてください。\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/dynamic-matching.md",
    "content": "# 動的ルートマッチング\n\nパターンを使って同じコンポーネントにルートをマップする必要がしばしばあるでしょう。例えば、 `User` コンポーネントは全てのユーザーに対して描画されるべきであるが、それぞれ異なるユーザー ID を持つ場合などです。`vue-router` ではパスの中の動的なセグメントを使用して実現できます。\n\n``` js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // コロンで始まる動的セグメント\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nこれで `/user/foo` や `/user/bar` などの URL 両方とも同じルートにマッチします。\n\n動的セグメントはコロン `:` を使って表されます。ルートがマッチした時、この動的セグメントの値は全てのコンポーネント内で `this.$route.params` として利用可能になります。したがって、現在の `User` のテンプレートを次のように更新することで現在のユーザー ID を表示することができます。\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\n[こちら](https://jsfiddle.net/yyx990803/4xfa2f19/) のデモの例も確認してみてください。\n\n1 つのルートが複数の動的なセグメントを持つこともできます。そして、それらは `$route.params` の一致したフィールドとマップされます。例:\n\n| パターン | マッチしたパス | $route.params |\n|---------|------|--------|\n| /user/:username | /user/evan | `{ username: 'evan' }` |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\n`$route.params` に加えて、`$route` オブジェクトでは `$route.query` (もし URL 上にクエリがあるなら) や `$route.hash` など便利な情報も利用可能です。それらの詳細については [API リファレンス](../api/route-object.md) でご確認ください。\n\n### パラメーター変更の検知\n\nルートのパラメーターを使う際に特筆すべき点は、ユーザーが `/user/foo` から `/user/bar` へ遷移するときに**同じコンポーネントインスタンスが再利用される**ということです。 両方のルートが同じコンポーネントを描画するため、古いインスタンスを破棄して新しいものを生成するよりも効率的です。**しかしながら、これはコンポーネントのライフサイクルフックが呼ばれないことを意味しています。**\n\n同じコンポーネントでパラメーター変更を検知するためには、 `$route` オブジェクトを watch するだけです。\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // ルートの変更の検知...\n    }\n  }\n}\n```\n\nまたは、2.2 で導入された `beforeRouteUpdate` ガードを使用します:\n\n``` js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // ルート変更に反応する...\n    // next() を呼び出すのを忘れないでください\n  }\n}\n```\n\n### 高度なマッチングパターン\n\n`vue-router` はパスのマッチングエンジンとして [path-to-regexp](https://github.com/pillarjs/path-to-regexp) を使っています。これは Optional による動的なセグメント、Zero or more / One or more に対する要求、また、カスタム正規表現パターンまでもサポートしています。 これらの高度なパターンについてはこちらの [ドキュメンテーション](https://github.com/pillarjs/path-to-regexp#parameters) または、 `vue-router` の中でそれらを使っている [こちらの例](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) をご参照ください。\n\n### マッチングの優先度\n\nしばしば同じURLで複数のルートがマッチすることがあります。そのようなケースではマッチングの優先度はルートの定義された順番によって決定されます。先に定義されたルートほど優先度が高くなります。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/getting-started.md",
    "content": "# はじめに\n\n> ガイド内のコードのサンプルは [ES2015](https://github.com/lukehoban/es6features) を使っています。\n\nVue.js と vue-router を使ったシングルページアプリケーションの構築は驚くほど簡単です。Vue.js のコンポーネントを使ってアプリケーションを既に構成しています。vue-router を混ぜ込むには、コンポーネントとルートをマッピングさせて vue-router にどこで描画するかを知らせるだけです。以下が基本的な例です。\n\n> すべての example では、vue の完全バージョンを使用してテンプレートを解析可能にしています。詳細は[こちら](https://jp.vuejs.org/v2/guide/installation.html#ランタイム-コンパイラとランタイム限定の違い)を参照してください。\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- ナビゲーションに router-link コンポーネントを使う -->\n    <!-- リンク先を `to` プロパティに指定します -->\n    <!-- デフォルトで `<router-link>` は `<a>` タグとして描画されます -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- ルートアウトレット -->\n  <!-- ルートとマッチしたコンポーネントがここへ描画されます -->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. モジュールシステムを使っている場合 (例: vue-cli 経由で)、Vue と VueRouter をインポートし、`Vue.use(VueRouter)` を呼び出します。\n\n// 1. ルートコンポーネントを定義します\n// 他のファイルからインポートすることもできます\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. ルートをいくつか定義します\n// 各ルートは 1 つのコンポーネントとマッピングされる必要があります。\n// このコンポーネントは実際の `Vue.extend()`、\n// またはコンポーネントオプションのオブジェクトでも構いません。\n// ネストされたルートに関しては後で説明します\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. ルーターインスタンスを作成して、ルートオプションを渡します\n// 追加のオプションをここで指定できますが、\n// この例ではシンプルにしましょう\nconst router = new VueRouter({\n  routes // `routes: routes` の短縮表記\n})\n\n// 4. root となるインスタンスを作成してマウントします\n// アプリケーション全体がルーターを認知できるように、\n// ルーターをインジェクトすることを忘れないでください。\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// これで開始です!\n```\n\nルーターを注入することによって、`this.$router` と同様、任意のコンポーネント内部で現在のルートを `this.$route` としてアクセスすることができます:\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username () {\n      // `params` が表示される\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack () {\n      window.history.length > 1\n        ? this.$router.go(-1)\n        : this.$router.push('/')\n    }\n  }\n}\n```\n\nドキュメントを通して、しばしば `router` インスタンスを使用することがよくあります。`this.$router` は `router` を使用するのと全く同じです。`this.$router` を使用する理由は、ルーティング操作する必要がある全てのコンポーネントにルーターをインポートしたくないからです。\n\n[動作](https://jsfiddle.net/yyx990803/xgrjzsup/) の例も確認してみてください.\n\n`<router-link>` は対象のルートがマッチした時に自動的に `.router-link-active` が付与されるのにお気づきでしょうか。\nより詳細については [API リファレンス](../api/router-link.md) をご参照ください。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/history-mode.md",
    "content": "# HTML5 History モード\n\n`vue-router` のデフォルトは _hash モード_ です - 完全な URL を hash を使ってシミュレートし、 URL が変更された時にページのリロードが起きません。\n\nその hash を取り除くために、ページのリロード無しに URL 遷移を実現する `history.pushState` API を利用したルーターの **history モード** を使うことができます。\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nhistory モードを使用する時は、URL は \"普通\" に見えます e.g. `http://oursite.com/user/id`。美しいですね!\n\nしかしながら一点問題があります。シングルページのクライアントサイドアプリケーションなので、適切なサーバーの設定をしないと、ユーザーがブラウザで直接 `http://oursite.com/user/id` にアクセスした場合に 404 エラーが発生します。\n\n心配する必要はありません。この問題を直すためには、単純な catch-all フォールバックのためのルートをサーバー側で追加するだけです。もし URL がどの静的なアセットにもマッチしなかった時はあなたのアプリケーションが動作しているのと同じ `index.html` ページで受け付けましょう。これも美しいですね!\n\n## サーバーの設定例\n\n#### Apache\n\n```apache\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n`mod_rewrite`の代わりに、[`FallbackResource`](https://httpd.apache.org/docs/2.2/mod/mod_dir.html#fallbackresource) も使用することができます。\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Native Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile('index.htm', 'utf-8', (err, content) => {\n    if (err) {\n      console.log('We cannot open \"index.htm\" file.')\n    }\n\n    res.writeHead(200, {\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log('Server listening on: http://localhost:%s', httpPort)\n})\n```\n\n#### Node.js (Express)\n\nNode.js/Express では [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback) の利用を検討してください。\n\n#### Internet Information Services (IIS)\n\n1. [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite) をインストール\n2. 以下によるサイトのルートディレクトリに `web.config` ファイルを作成\n\n``` xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Firebase のホスティング\n\n以下を `firebase.json` に追加します:\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## 注意\n\nこの点に関して注意があります。全ての not-found パスが `index.html` を提供するため、もはや 404 エラーをサーバーがレポートしなくなります。回避策として、Vue アプリケーション内で 404 ページを表示するために catch-all ルートを実装すべきです。\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\n他の方法として、もしあなたが Node.js サーバーを使っている場合、入ってきた URL とマッチさせて、マッチしなかった場合に 404 を返答するサーバーサイドのルーターを使って fallback を実装することもできます。詳細については [Vue サーバサイドレンダリングのドキュメント](https://ssr.vuejs.org/ja/) を参照してください。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/named-routes.md",
    "content": "# 名前付きルート\n\nしばしば、名前を使ってルートを特定できるとより便利です。特にルートにリンクするときやナビゲーションを実行するときなどです。Router インスタンスを作成するときに `routes` オプションの中でルートに名前を付けることができます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\n名前を付けたルートにリンクするには、 `router-link` コンポーネントの `to` プロパティにオブジェクトを渡します。\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\nこれはプログラムで `router.push()` を呼び出すときに使われるオブジェクトと全く同じです。\n\n``` js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nどちらのケースもルーターは `/user/123` のパスにナビゲーションします。\n\n完全な例は [こちら](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js) です。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/named-views.md",
    "content": "# 名前付きビュー\n\nしばしば、ネストをさせずに同時に複数の view を表示する必要があるでしょう。例えば、`sidebar` view と `main` view を使ったレイアウトを作成する時です。そんな時に名前付きビューは便利です。あなたの view に 1 つのアウトレットを持つのではなく、複数のそれぞれが名前付きの view を持つことができます。名前を持たない `router-view` はその名前として `default` が付与されます。\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\n1 つの view は 1 つのコンポーネントを使って描画されます。したがって、同じルートに対する複数の view には複数のコンポーネントが必須になります。この `components` (s が付いている) オプションに注意してください。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nこの例の動作しているデモは \n[こちら](https://jsfiddle.net/posva/6du90epg/) です。\n\n## ネストされた名前付きビュー\n\nネストされたビューを持つ名前付きビューを使用して複雑なレイアウトを作成することができます。そうする際に、ネストされた `router-view` コンポーネントを使用するために名前をつける必要があります。設定パネルの例を見てみましょう:\n\n```\n/settings/emails                                       /settings/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` は普通のコンポーネントです\n- `UserSettings` はビューコンポーネントです\n- `UserEmailsSubscriptions` 、`UserProfile` 、`UserProfilePreview` はネストされたビューコンポーネントです\n\n**Note**: _そのようなレイアウトに HTML/CSS がどのように表示されるのか、そして使用されるコンポーネントに焦点を当てる方法については、ここでは忘れましょう_\n\n上記レイアウトでの `UserSettings` コンポーネントの `<template>` セクションは次のようになります:\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>User Settings</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_ここではネストされたビューコンポーネントは省略されていますが、上記例の完全なソースコードを[ここ](https://jsfiddle.net/posva/22wgksa3/)で見ることができます_\n\nそれから、以下のルート設定で上記のレイアウトを表現することができます:\n\n```js\n{ path: '/settings',\n  // トップで名前付きビューを持つこともできます\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nこの例の動作するデモは、[ここ](https://jsfiddle.net/posva/22wgksa3/)に見ることができます。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/navigation.md",
    "content": "# プログラムによるナビゲーション\n\n宣言的なナビゲーションとしてアンカータグを作成する `<router-link>` がありますが、ルーターのインスタンスメソッドを使ったプログラムによる方法でもそれは可能です。\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**注意: Vue インスタンスの内部では、`$router` としてルーターインスタンスにアクセスできます。従って、`this.$router.push` で呼ぶことができます。**\n\n異なる URL へ遷移するときに `router.push` が使えます。このメソッドは history スタックに新しいエントリを追加します。それによってユーザーがブラウザの戻るボタンをクリックした時に前の URL に戻れるようになります。\n\n\nこのメソッドは `<router-link>` をクリックした時に内部的に呼ばれています。つまり `<router-link :to=\"...\">` をクリックすることは `router.push(...)` を呼ぶことと等価です。\n\n| 宣言的 | プログラム的 |\n|-------------|--------------|\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\n引数は文字列のパス、もしくは、location を記述するオブジェクトが使えます。例:\n\n``` js\n// 文字列パス\nrouter.push('home')\n\n// オブジェクト\nrouter.push({ path: 'home' })\n\n// 名前付きルート\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// 結果的に /register?plan=private になる query\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n**注意**: `params` は、上記例に示すように、`path` が提供されている場合は無視されます。これは `query` に対するケースとは異なります。\n代わりに、ルートの `name` か任意のパラメータを付与した `path` 全体を手動で指定する必要があります:\n\n```js\nconst userId = 123\nrouter.push({ name: 'user', params: { userId }}) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// これは動作\"しません\"\nrouter.push({ path: '/user', params: { userId }}) // -> /user\n```\n\n同じルールが、`router-link` コンポーネントの `to` プロパティに対して適用されます。\n\n2.2.0 以降では、必要に応じて、第 2 引数と第 3 引数として `router.push` または `router.replace` に `onComplete` と `onAbort` コールバックを指定します。これらのコールバックは、ナビゲーションが正常に完了したとき(すべての非同期フックが解決された後)に呼び出されるか、またはそれぞれ中止されます(現在のナビゲーションが終了する前に同じルートまたは別のルートにナビゲートされた)\n\n**注意:** ルートの行き先が現在のルートと同じで、かつパラメータのみが変更されている場合(例: `/users/1` -> `/users/2` のようにあるプロファイルから他へ)、変更(例: ユーザー情報の取得など)に反応するために[beforeRouteUpdate](./dynamic-matching.html#パラメーター変更の検知) を使用しなければなりません。\n\n#### `router.replace(location, onComplete?, onAbort?)`\n\nこれは `router.push` のように動作しますが、異なる点は新しい history エントリを追加しないで遷移することです。この名前から推定されるように、現在のエントリを置換します。\n\n| 宣言的 | プログラム的 |\n|-------------|--------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n#### `router.go(n)`\n\nこのメソッドは、history スタックの中でどのくらいステップを進めるか、もしくは戻るのか、を表す 1 つの integer をパラメーターとして受け取ります。`window.history.go(n)` と類似しています。\n\n例\n\n``` js\n// 1 つレコードを進める。history.forward() と同じ\nrouter.go(1)\n\n// 1 つレコードを戻す。history.back() と同じ\nrouter.go(-1)\n\n// 3 つレコードを進める\nrouter.go(3)\n\n// もし多くのレコードが存在しない場合、サイレントに失敗します\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### History 操作\n\nもしかすると `router.push`、`router.replace`、`router.go` は [`window.history.pushState`、`window.history.replaceState`、`window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History) と対応することにお気づきかもしれません。これらは `window.history` API を模倣しています。\n\nしたがって、もしあなたが既に [Browser History APIs](https://developer.mozilla.org/en-US/docs/Web/API/History_API) について詳しい場合は、vue-router による History 操作はとても簡単です。\n\nvue-router のナビゲーションメソッド (`push`、`replace`、`go`) は全てのモード (`history`、`hash`、`abstract`) で一貫して動作することは特筆すべき点です。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/nested-routes.md",
    "content": "# ネストされたルート\n\n実際のアプリケーションの UI では通常複数のレベルの階層的にネストしたコンポーネントで構成されます。ネストされたコンポーネントの特定の構造に対して URL のセグメントを対応させることはよくあります。例:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\n`vue-router` を使えば、これらのネストされたルートの設定を使って関連付けをシンプルに表現することができます。\n\n前の章で作ったアプリケーションを考えてみましょう。\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nここでの `<router-view>` はトップレベルのアウトレットです。トップレベルのルートによってマッチしたコンポーネントが描画されます。同様に描画されたコンポーネントもまた自身のネストされた `<router-view>` を持つことができます。`User` コンポーネントのテンプレート内部に 1 つ追加する例です。\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nこのネストされたアウトレットに対してコンポーネントを描画するためには、 `VueRouter` のコンストラクタの設定で `children` オプションを使用する必要があります。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User,\n      children: [\n        {\n          // /user/:id/profile がマッチした時に\n          // UserProfile は User の <router-view> 内部で描画されます\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // /user/:id/posts がマッチした時に\n          // UserPosts は User の <router-view> 内部で描画されます\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n**`/` から始まるネストされたパスは root パスとして扱われることに注意してください。これによってネストされた URL を指定しなくてもコンポーネントをネストすることができます。**\n\n`children` オプションを見るとわかる通り、これは `routes` 自身と同じようなルート設定オブジェクトの配列です。したがって、ネストしている view を必要なだけ保持することができます。\n\nここまでの点では、上記の設定で `/user/foo` に訪れた時に `User` アウトレット内部で何も描画されません。なぜならば、サブルートにマッチしていないからです。そこに何か描画したい場合は、空のサブルートパスを設定できます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id', component: User,\n      children: [\n        // /user/:id がマッチした時に\n        // UserHome は User の <router-view> 内部で描画されます\n        { path: '', component: UserHome },\n\n        // 他のサブルートも同様に...\n      ]\n    }\n  ]\n})\n```\n\nこの例の動作デモは [こちら](https://jsfiddle.net/yyx990803/L7hscd8h/) です。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/passing-props.md",
    "content": "# ルートコンポーネントにプロパティを渡す\n\nコンポーネントで `$route` を使うとコンポーネントとルートの間に密結合が生まれ、コンポーネントが特定のURLでしか使用できないなど柔軟性が制限されます。\n\nコンポーネントをルーターから分離するために `props` オプションを使います:\n\n**  `$route` に結合**\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n**  `props` による分離**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // 名前付きビューによるルートに対しては、名前付きビューごとに `props` オプションを定義しなければなりません:\n    {\n      path: '/user/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nこれにより、コンポーネントをどこからでも使用できるようになり、コンポーネントの再利用とテストが容易になります。\n\n### Boolean モード\n\n`props` を `true` に設定すると、`route.params` がコンポーネントのプロパティとして設定されます。\n\n### Object モード\n\n`props` がオブジェクトの場合、これはコンポーネントプロパティとしてそのまま設定されます。プロパティが静的なときに便利です。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n### Function モード\n\nプロパティを返す関数を作成することができます。これにより、パラメータを他のタイプにキャストし、静的な値をルートベースの値などと組み合わせることができます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\nURL `/search?q=vue` は `{query: 'vue'}` をプロパティとして `SearchUser` コンポーネントに渡します。\n\nルート変更時にのみ評価されるため、`props` 関数はステートレスにしてください。プロパティを定義するために状態を必要とする場合はラッパーコンポーネントを使用してください。その方法で vue は状態変更に対応することができます。\n\n高度な使い方については、[example](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js)を参照してください。\n"
  },
  {
    "path": "docs-gitbook/ja/essentials/redirect-and-alias.md",
    "content": "# リダイレクトとエイリアス\n\n### リダイレクト\n\n`routes` 設定でリダイレクトが可能です。`/a` から `/b` へリダイレクトする例:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\n名前付きルートに対してリダイレクトすることもできます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nまた、function を使った動的なリダイレクトもできます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // この function は対象のルートを引数として受け取ります\n      // ここではリダイレクト先の path もしくは location を返します\n    }}\n  ]\n})\n```\n\n[ナビゲーションガード](../advanced/navigation-guards.md)はリダイレクトするルートに提供されず、ターゲット上のみに適用されるということに注意してください。例では、`beforeEnter` または `beforeLeave` ガードを `/a` ルートに追加しても効果がありません。\n\nその他の高度な使い方として、[例](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js) をご参照ください。\n\n### エイリアス\n\nリダイレクトが意図するところは、ユーザーが `/a` に訪問した時に URL を `/b` に置換し、そして `/b` にマッチさせます。ではエイリアスは何でしょうか?\n\n**`/b` として扱う `/a` のエイリアスは、ユーザーが `/b` に訪問した時に URL は `/b` のままになります。しかし、それはまるでユーザーが `/a` に訪問したかのようにマッチされます。**\n\n上記はルートの設定で以下のように表現されます。\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\n設定のネスト構造による制約とは異なり、エイリアスは UI 構造に任意の URL をマップするための自由さがあります。\n\n高度な使い方に関しては、 [例](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js) をご参照ください。\n"
  },
  {
    "path": "docs-gitbook/ja/installation.md",
    "content": "# インストール\n\n### 直接ダウンロード / CDN\n\n[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) は npm ベースの CDN リンクです。 上記のリンクは常に NPM 上の最新のリリースを指します。 `https://unpkg.com/vue-router@2.0.0/dist/vue-router.js` のような URL を利用することで特定のバージョンやタグを指定することもできます。\n<!--/email_off-->\n\nVue の後に `vue-router` を含めると自動的にインストールされます。\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### npm\n\n``` bash\nnpm install vue-router\n```\n\nモジュールシステムを使う場合、`Vue.use()` を使って明示的にルーターをインストールする必要があります。\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nグローバルな script タグを使っている場合は必要ありません。\n\n### 開発用ビルド\n\nもし最新の開発用ビルドを使用したい場合は、GitHub から直接クローンして `vue-router` をご自身でビルドしてください。\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs-gitbook/kr/README.md",
    "content": "{% include \"./SUMMARY.md\" %}\n"
  },
  {
    "path": "docs-gitbook/kr/SUMMARY.md",
    "content": "# vue-router\n<!--email_off-->\n> 참고 : vue-router@2.x는 Vue 2.x에서만 작동합니다. 0.7.x용 문서는 [이 곳](https://github.com/vuejs/vue-router/tree/1.0/docs/en)입니다.\n<!--/email_off-->\n**[릴리즈 노트](https://github.com/vuejs/vue-router/releases)**\n\n- [설치](installation.md)\n- 필수 사항\n  - [시작하기](essentials/getting-started.md)\n  - [동적 라우트 매칭](essentials/dynamic-matching.md)\n  - [중첩된 라우트](essentials/nested-routes.md)\n  - [프로그래밍 방식 네비게이션](essentials/navigation.md)\n  - [이름을 가진 라우트](essentials/named-routes.md)\n  - [이름을 가진 뷰](essentials/named-views.md)\n  - [리다이렉트와 별칭](essentials/redirect-and-alias.md)\n  - [라우트 컴포넌트에 속성 전달](essentials/passing-props.md)\n  - [HTML5 History 모드](essentials/history-mode.md)\n- 고급\n  - [네비게이션 가드](advanced/navigation-guards.md)\n  - [라우트 메타 필드](advanced/meta.md)\n  - [전환](advanced/transitions.md)\n  - [데이터 가져오기](advanced/data-fetching.md)\n  - [스크롤 동작](advanced/scroll-behavior.md)\n  - [지연된 로딩](advanced/lazy-loading.md)\n- API 레퍼런스\n  - [라우터 생성자 옵션](api/options.md)\n    - [routes](api/options.md#routes)\n    - [mode](api/options.md#mode)\n    - [base](api/options.md#base)\n    - [linkActiveClass](api/options.md#linkactiveclass)\n    - [linkExactActiveClass](api/options.md#linkexactactiveclass)\n    - [scrollBehavior](api/options.md#scrollbehavior)\n    - [parseQuery / stringifyQuery](api/options.md#parsequery--stringifyquery)\n    - [fallback](api/options.md#fallback)\n  - [라우터 인스턴스](api/router-instance.md)\n    - [Properties](api/router-instance.md#properties)\n    - [Methods](api/router-instance.md#methods)\n  - [라우트 객체](api/route-object.md)\n  - [컴포넌트 주입](api/component-injections.md)\n  - [router-link](api/router-link.md)\n  - [router-view](api/router-view.md)\n"
  },
  {
    "path": "docs-gitbook/kr/advanced/data-fetching.md",
    "content": "# 데이터 가져오기\n\n때로는 라우트가 활성화될 때 서버에서 데이터를 가져와야 합니다. 예를 들어, 사용자 프로필을 렌더링하기 전에 서버에서 사용자의 데이터를 가져와야 합니다. 우리는 두 가지 방법을 사용할 수 있습니다.\n\n- **탐색 후 가져오기**: 먼저 탐색하고 들어오는 컴포넌트의 라이프 사이클 훅에서 데이터를 가져옵니다. 데이터를 가져오는 동안 로드 상태를 표시합니다.\n\n- **탐색하기 전에 가져오기**: 라우트 가드에서 경로를 탐색하기 전에 데이터를 가져오고 그 후에 탐색을 수행합니다.\n\n엄밀히 말하면 두 가지 모두 유효한 선택입니다. 궁극적인 목표는 사용자 경험에 달려 있습니다.\n\n## 탐색 후 가져오기\n\n이 방법을 사용하면 들어오는 컴포넌트를 즉시 탐색하고 렌더링하며 컴포넌트의 `created` 훅에서 데이터를 가져옵니다. 네트워크를 통해 데이터를 가져 오는 동안 로드 상태를 표시 할 수 있는 기회를 제공하며 각 뷰 마다 로드를 다르게 처리 할 수도 있습니다.\n\n`$route.params.id`를 기반으로 한 게시물의 데이터를 가져와야하는 `Post` 컴포넌트가 있다고 가정 해 봅시다 :\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Loading...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // 뷰가 생성되고 데이터가 이미 감시 되고 있을 때 데이터를 가져온다.\n    this.fetchData()\n  },\n  watch: {\n    // 라우트가 변경되면 메소드를 다시 호출됩니다.\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // `getPost`를 데이터 가져오기 위한 유틸리티/API 래퍼로 변경합니다.\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## 탐색하기 전에 가져오기\n\n이 접근 방식을 사용하면 실제로 새 경로로 이동하기 전에 데이터를 가져옵니다.\n들어오는 컴포넌트에서 `beforeRouteEnter` 가드에서 데이터를 가져올 수 있으며 페치가 완료되면 `next`만 호출 할 수 있습니다.\n\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  watch: {\n    // 라우트가 변경되면 메소드를 다시 호출합니다\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // `getPost`를 데이터 페치 유틸리티/API 래퍼로 바꿉니다.\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n다음 뷰에 대한 리소스를 가져 오는 동안 사용자는 현재 뷰를 유지합니다. 따라서 데이터를 가져 오는 동안 진행률 표시줄이나 일종의 표시기를 표시하는 것을 추천합니다. 데이터 가져오기가 실패하면 일종의 전역 경고 메시지를 표시해야합니다.\n"
  },
  {
    "path": "docs-gitbook/kr/advanced/lazy-loading.md",
    "content": "# 지연된 로딩\n\n번들러를 이용하여 앱을 제작할 때 JavaScript 번들이 상당히 커져 페이지로드 시간에 영향을 줄 수 있습니다. 각 라우트의 컴포넌트를 별도의 단위로 분할하고 경로를 방문할 때 로드하는 것이 효율적일 것입니다.\n\nVue의 [비동기 컴포넌트](http://vuejs.org/guide/components.html#Async-Components)와 Webpack의 [코드 분할](https://webpack.js.org/guides/code-splitting-async/)을 결합합니다. 라우트 컴포넌트를 쉽게 불러올 수 있습니다.\n\n첫째, 비동기 컴포넌트는 Promise를 반환하는 팩토리 함수로 정의할 수 있습니다 (컴포넌트가 resolve 되어야함).\n\n``` js\nconst Foo = () => Promise.resolve({ /* 컴포넌트 정의 */ })\n```\n\n둘째, Webpack 2에서 [dynamic import](https://github.com/tc39/proposal-dynamic-import)를 사용하여 코드 분할 포인트를 지정할 수 있습니다.\n\n``` js\nimport('./Foo.vue') // returns a Promise\n ```\n\n > 참고: Babel을 사용하고 있는 경우 올바른 구문 분석을 위해 [syntax-dynamic-import](http://babeljs.io/docs/plugins/syntax-dynamic-import/) 플러그인을 추가해야합니다.\n\n 이 두 가지를 결합하여 Webpack에 의해 자동으로 코드 분할될 비동기 컴포넌트를 정의하는 방법입니다.\n\n ``` js\n const Foo = () => import('./Foo.vue')\n```\n\n라우트 설정에서 아무것도 바꿀 필요가 없습니다. `Foo`만 사용하면 됩니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/foo', component: Foo }\n  ]\n})\n```\n\n### 같은 묶음으로 컴포넌트 그룹화하기\n\n때로는 동일한 라우트 아래에 중첩된 모든 컴포넌트를 동일한 비동기 묶음으로 그룹화 할 수 있습니다. 이를 위해 특수 주석 문법을 사용하는 이름(Webpack 2.4 이상 지원)을 제공하여 [이름을 가진 묶음](https://webpack.js.org/guides/code-splitting-async/#chunk-names)을 사용해야합니다.\n\n``` js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nWebpack은 동일한 이름의 묶음을 가진 비동기 모듈을 동일한 비동기 묶음으로 그룹화합니다.\n"
  },
  {
    "path": "docs-gitbook/kr/advanced/meta.md",
    "content": "# 라우트 메타 필드\n\n라우트를 정의 할 때 `meta` 필드를 포함시킬 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // 메타 필드\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\n그렇다면 이 `메타`필드에 어떻게 접근할까요?\n\n첫째,`routes` 설정의 각 라우트 객체를 **라우트 레코드** 라고합니다. 라우트 레코드는 중첩 될 수 있습니다. 따라서 라우트가 일치하면 둘 이상의 라우트 레코드와 잠재적으로 일치 할 수 있습니다.\n\n예를 들어, 위의 라우트 구성에서 URL `/foo/bar`는 상위 라우트 레코드와 하위 라우트 레코드 모두와 일치합니다.\n\n라우트와 일치하는 모든 라우트 레코드는 `$route` 객체(그리고 네비게이션 가드의 라우트 객체)에 `$route.matched` 배열로 노출됩니다. 그러므로 우리는 `$route.matched`를 반복하여 라우트 레코드의 메타 필드를 검사 할 필요가 있습니다.\n\n예제 사용 사례는 글로벌 네비게이션 가드에서 메타 필드를 확인하는 것입니다.\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // 이 라우트는 인증이 필요하며 로그인 한 경우 확인하십시오.\n    // 그렇지 않은 경우 로그인 페이지로 리디렉션하십시오.\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // 반드시 next()를 호출하십시오!\n  }\n})\n```\n"
  },
  {
    "path": "docs-gitbook/kr/advanced/navigation-guards.md",
    "content": "# 네비게이션 가드\n\n이름에서 알 수 있듯이 `vue-router`가 제공하는 네비게이션 가드는 주로 리디렉션하거나 취소하여 네비게이션을 보호하는 데 사용됩니다. 라우트 탐색 프로세스에 연결하는 방법에는 전역, 라우트별 또는 컴포넌트가 있습니다.\n\n**Params 또는 쿼리를 변경하면 네비게이션 가드가 실행되지 않습니다**. 단순히 [`$route` 객체를 감시](../essentials/dynamic-matching.md#reacting-to-params-changes)하고 그 변화에 반응하십시오. 또는 컴포넌트 가드의 `beforeRouteUpdate`를 사용하십시오\n\n### 전역 가드\n\n`router.beforeEach`를 사용하여 보호하기 이전에 전역 등록을 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\n네비게이션이 트리거될 때마다 가드가 작성 순서에 따라 호출되기 전의 모든 경우에 발생합니다. 가드는 비동기식으로 실행 될 수 있으며 네비게이션은 모든 훅이 해결되기 전까지 **보류 중** 으로 간주됩니다.\n\n모든 가드 기능은 세 가지 전달인자를 받습니다.\n\n- **`to: 라우트`**: 대상 [Route 객체](../api/route-object.md) 로 이동합니다.\n\n- **`from: 라우트`**: 현재 라우트로 오기전 라우트 입니다.\n\n- **`next: 함수`**: 이 함수는 **훅을 해결하기 위해** 호출 되어야 합니다. 액션은 `next`에 제공된 전달인자에 달려 있습니다.\n\n  - **`next()`**: 파이프라인의 다음 훅으로 이동하십시오. 훅이 없는 경우 네비게이션은 **승인**됩니다.\n\n  - **`next(false)`**: 현재 네비게이션을 중단합니다. 브라우저 URL이 변경되면(사용자 또는 뒤로 버튼을 통해 수동으로 변경됨) `from`경로의 URL로 재설정됩니다.\n\n  - **`next('/')` 또는 `next({ path: '/' })`**: 다른 위치로 리디렉션합니다. 현재 네비게이션이 중단되고 새 네비게이션이 시작됩니다.\n\n  - **`next(error)`**: (2.4.0 이후 추가) `next`에 전달된 인자가 `Error` 의 인스턴스이면 탐색이 중단되고 `router.onError()`를 이용해 등록 된 콜백에 에러가 전달됩니다.\n\n\n**항상 `next` 함수를 호출하십시오. 그렇지 않으면 훅이 절대 불러지지 않습니다.**\n\n### Global Resolve Guards\n\n> 2.5.0에서 추가됨\n\n2.5.0 이후로 `router.beforeResolve`를 사용하여 글로벌 가드를 등록 할 수 있습니다. 이는 `router.beforeEach`와 유사합니다. 모든 컴포넌트 가드와 비동기 라우트 컴포넌트를 불러온 후 네비게이션 가드를 확인하기 전에 호출된다는 차이가 있습니다\n\n### Global After Hooks\n\n전역 훅을 등록 할 수도 있지만, 가드와 달리 이 훅은 `next` 함수를 얻지 못하며 네비게이션에 영향을 줄 수 없습니다.\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### 라우트 별 가드\n\n`beforeEnter` 가드를 라우트의 설정 객체에 직접 정의 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\n이러한 가드는 전역 이전 가드와 동일한 서명을 가집니다.\n\n### 컴포넌트 내부 가드\n\n마지막으로 `beforeRouteEnter` 와 `beforeRouteLeave`를 사용하여 라우트 컴포넌트(라우터 설정으로 전달되는 컴포넌트) 안에 라우트 네비게이션 가드를 직접 정의 할 수 있습니다.\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (2.2 버전에 추가)\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // 이 컴포넌트를 렌더링하는 라우트 앞에 호출됩니다.\n    // 이 가드가 호출 될 때 아직 생성되지 않았기 때문에\n    // `this` 컴포넌트 인스턴스에 접근 할 수 없습니다!\n  },\n  beforeRouteLeave (to, from, next) {\n    // 이 컴포넌트를 렌더링하는 라우트가 이전으로 네비게이션 될 때 호출됩니다.\n    // `this` 컴포넌트 인스턴스에 접근 할 수 있습니다.\n  }\n}\n```\n\n`beforeRouteEnter` 가드는 네비게이션이 확인되기 전에 가드가 호출되어서 새로운 엔트리 컴포넌트가 아직 생성되지 않았기 때문에 `this`에 접근하지 **못합니다.**\n\n그러나 콜백을 `next`에 전달하여 인스턴스에 액세스 할 수 있습니다. 네비게이션이 확인되고 컴포넌트 인스턴스가 콜백에 전달인자로 전달 될 때 콜백이 호출됩니다.\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // `vm`을 통한 컴포넌트 인스턴스 접근\n  })\n}\n```\n\n`beforeRouteLeave` 안에서 `this`에 직접 접근 할 수 있습니다. leave 가드는 일반적으로 사용자가 저장하지 않은 편집 내용을 두고 실수로 라우트를 떠나는 것을 방지하는데 사용됩니다. 탐색은 `next(false)`를 호출하여 취소할 수 있습니다.\n\n### 전체 네비게이션 시나리오\n\n1. 네비게이션이 트리거됨.\n2. 비활성화될 컴포넌트에서 가드를 호출.\n3. 전역 `beforeEach` 가드 호출.\n4. 재사용되는 컴포넌트에서 `beforeRouteUpdate` 가드 호출. (2.2 이상)\n5. 라우트 설정에서 `beforeEnter` 호출.\n6. 비동기 라우트 컴포넌트 해결.\n7. 활성화된 컴포넌트에서 `beforeRouteEnter` 호출.\n8. 전역 `beforeResolve` 가드 호출. (2.5이상)\n9. 네비게이션 완료.\n10. 전역 `afterEach` 훅 호출.\n11. DOM 갱신 트리거 됨.\n12. 인스턴스화 된 인스턴스들의 `beforeRouteEnter`가드에서 `next`에 전달 된 콜백을 호출합니다.\n"
  },
  {
    "path": "docs-gitbook/kr/advanced/scroll-behavior.md",
    "content": "# 스크롤 동작\n\n클라이언트 측 라우팅을 사용할 때 새로운 경로로 이동할 때 맨 위로 스크롤하거나 실제 페이지를 다시 로드하는 것처럼 컨텐츠 항목의 스크롤 위치를 유지할 수 있습니다. `vue-router`는 이러한 것들을 할 수 있으며, 라우트 탐색에서 스크롤 동작을 완전히 사용자 정의할 수 있게합니다.\n\n**참고: 이 기능은 HTML5 히스토리 모드에서만 작동합니다.**\n\n라우터 인스턴스를 생성 할 때 `scrollBehavior` 함수를 제공 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // 원하는 위치로 돌아가기\n  }\n})\n```\n\n`scrollBehavior` 함수는 `to`와 `from` 라우트 객체를받습니다. 세 번째 전달인자인 `savedPosition`은 브라우저의 뒤로/앞으로 버튼으로 트리거되는 `popstate` 네비게이션인 경우에만 사용할 수 있습니다.\n\n이 함수는 스크롤 위치 객체를 반환 할 수 있습니다. 객체는 다음과 같은 형태 일 수 있습니다.\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset은 2.6.0 이상만 지원)\n\n잘못된 값이나 빈 객체가 반환되면 스크롤이 발생하지 않습니다.\n\n예제:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\n그러면 모든 라우트 네비게이션에 대해 페이지가 맨 위로 스크롤됩니다.\n\n`savedPosition`을 반환하면 뒤로/앞으로 버튼으로 탐색할 때 네이티브와 같은 동작이 발생합니다.\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\n\"anchor로 스크롤\" 동작을 시뮬레이트하려면 다음을 수행하십시오.\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\n또한 [라우트 메타 필드](meta.md)를 사용하여 세밀한 스크롤 동작 제어를 구현할 수 있습니다. 전체 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js)를 확인하십시오.\n"
  },
  {
    "path": "docs-gitbook/kr/advanced/transitions.md",
    "content": "# 전환\n\n`<router-view>`는 본질적으로 동적인 컴포넌트이기 때문에 `<transition>` 컴포넌트를 사용하는 것과 같은 방식으로 전환 효과를 적용할 수 있습니다.\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\n[`<transition>`에 대한 모든 것](http://vuejs.org/guide/transitions.html) 을 확인하십시오.\n\n### 라우트 별 전환\n\n위의 사용법은 모든 라우트에 대해 동일한 전환을 적용합니다. 각 라우트의 컴포넌트가 서로 다른 전환을 갖도록 하려면 각 라우트 컴포넌트 내에서 다른 이름으로 `<transition>`을 사용할 수 있습니다.\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n### 라우트 기반 동적 전환\n\n또한 대상 라우트와 현재 라우트 간의 관계를 기반으로 동적으로 사용할 전환을 결정할 수도 있습니다.\n\n``` html\n<!-- 동적 전환을 위한 name을 지정합니다. -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// 그런 다음 부모 구성 요소에서 `$route`를 보고 사용할 전환을 결정합니다\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\n전체 예제는 [여기](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js)에 있습니다.\n"
  },
  {
    "path": "docs-gitbook/kr/api/component-injections.md",
    "content": "# 컴포넌트 주입\n\n### 주입된 속성\n\n이러한 프로퍼티는 라우터 인스턴스를 루트 인스턴스에 `router` 옵션으로 전달함으로써 모든 자식 컴포넌트에 주입됩니다.\n\n- #### $router\n\n  라우터 인스턴스\n\n- #### $route\n\n  현재 활성화 된 [Route](route-object.md)입니다. 이 속성은 읽기 전용이며 해당 속성은 변경할 수는 없지만 감시 할 수 있습니다.\n\n### 활성화된 옵션\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate** (2.2에서 추가됨)\n- **beforeRouteLeave**\n\n  [컴포넌트 내부 가드](../advanced/navigation-guards.md#incomponent-guards)를 확인하세요.\n"
  },
  {
    "path": "docs-gitbook/kr/api/options.md",
    "content": "# 라우터 생성자 옵션\n\n### routes\n\n- 자료형: `Array<RouteConfig>`\n\n  `RouteConfig`에 대한 자료형 선언:\n\n  ``` js\n  declare type RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // 이름을 가진 라우트를 위함\n    components?: { [name: string]: Component }; // 이름을 가진 뷰를 위함\n    redirect?: string | Location | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // 중첩된 라우트를 위함 routes\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n  }\n\n  // 2.6.0+\n  caseSensitive?: boolean; // 대소문자를 구분합니까? (default: false)\n  pathToRegexpOptions?: Object; // path-to-regexp 옵션은 정규 표현식을 컴파일합니다.\n  ```\n\n### mode\n\n- 자료형: `string`\n\n- 기본값: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- 유효 값: `\"hash\" | \"history\" | \"abstract\"`\n\n  라우터 모드에 대한 설정입니다.\n\n  - `hash`: 라우팅에 URL 해시를 사용합니다. HTML5 기록 API를 지원하지 않는 브라우저를 포함하여 모든 Vue 지원 브라우저에서 작동합니다.\n\n  - `history`: HTML5 히스토리 API 및 서버 설정이 필요합니다. [HTML5 History 모드](../essentials/history-mode.md)를 확인하세요.\n\n  - `abstract`:   모든 자바 스크립트 환경에서 작동합니다 (예: Node.js가 있는 서버 측 **브라우저 API가없는 경우 라우터가 자동으로이 모드로 강제 전환됩니다.**\n\n### base\n\n- 자료형: `string`\n\n- 기본값: `\"/\"`\n\n  앱의 기본 URL입니다. 예를 들어, 전체 단일 페이지 응용 프로그램이 `/app/`하에 제공된다면`base`는 `\"/app/\"` 값을 사용해야합니다.\n\n### linkActiveClass\n\n- 자료형: `string`\n\n- 기본값: `\"router-link-active\"`\n\n  전역의 `<router-link>` 기본 active 클래스를 설정하십시오. [router-link](router-link.md)를 확인하세요.\n\n### linkExactActiveClass\n\n> 2.5.0+\n\n- 자료형: `string`\n\n- 기본값: `\"router-link-exact-active\"`\n\n 전역으로 `<router-link>`에서 사용할  정확하게 일치하는 경우의 클래스를 설정할 수 있습니다. [router-link](router-link.md)를 확인하세요.\n\n### scrollBehavior\n\n- 자료형: `Function`\n\n  서명:\n\n  ```\n  (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => { x: number, y: number } | { selector: string } | ?{}\n  ```\n\n  [Scroll 동작](../advanced/scroll-behavior.md)를 확인하세요.\n\n### parseQuery / stringifyQuery\n\n> 2.4.0+\n\n- 자료형: `Function`\n\n  사용자 지정 쿼리 문자열 구문 분석/문자열화 함수를 사용할 수 있습니다. 기본 값을 오버라이드합니다.\n\n### fallback\n\n  > 2.6.0+\n\n  - 자료형: `boolean`\n\n   브라우저가 `history.pushState`를 지원하지 않을 때 라우터가 `hash`모드로 변경되어야 할지 설정합니다. 기본값은 `true`입니다.\n\n   이를 `false`로 설정하면 IE9에서 모든 `router-link`를 탐색 할 수 있습니다. 이것은 해시모드 URL이 SSR에서 작동하지 않기 때문에 앱이 서버에서 렌더링되어 IE9에서 작동해야하는 경우에 유용합니다.\n"
  },
  {
    "path": "docs-gitbook/kr/api/route-object.md",
    "content": "# 라우트 객체\n\n**라우트 객체** 는 현재 활성 경로의 상태를 나타냅니다. 여기에는 현재 URL의 구문 분석 된 정보와 URL에서 일치하는 **라우트 기록** 이 포함됩니다.\n\nroute 객체는 변경할 수 없습니다. 모든 성공적인 네비게이션은 새로운 라우트 객체를 생성합니다.\n\n라우트 객체는 여러 위치에서 찾을 수 있습니다.\n\n- 컴포넌트 내부에서 `this.$route`를 사용합니다.\n\n- 감시자 콜백에서 `$route`를 사용합니다.\n\n- `router.match(location)` 호출의 반환 값으로 사용합니다.\n\n- 처음 두 개의 전달인자로 내비게이션 가드에서 사용할 수 있습니다.\n\n  ``` js\n  router.beforeEach((to, from, next) => {\n    // to와 from은 둘 다 라우트 객체입니다.\n  })\n  ```\n\n- `scrollBehavior`함수 안에서 처음 두 개의 전달인자로 사용합니다.\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n      // to와 from은 둘 다 라우트 객체입니다.\n    }\n  })\n  ```\n\n### 라우트 객체 속성\n\n- **$route.path**\n\n  - 자료형: `string`\n\n    현재 경로의 경로와 동일한 문자열로 항상 절대 경로로 해석됩니다. 예 : `\"/foo/bar\"`를 사용하십시오.\n\n- **$route.params**\n\n  - 자료형: `Object`\n\n    동적 세그먼트와 별 세그먼트의 키/값 쌍을 포함하는 객체입니다. 매개 변수가 없는 경우 값은 빈 객체가됩니다.\n\n- **$route.query**\n\n  - 자료형: `Object`\n\n    쿼리 문자열의 키/값 쌍을 포함하는 객체입니다. 예를 들어 `/foo?user=1` 경로의 경우 `$route.query.user == 1`을 얻습니다. 쿼리가 없으면 값은 빈 객체가됩니다.\n\n- **$route.hash**\n\n  - 자료형: `string`\n\n    현재 경로의 해시(`#`가 없는 경우).해시가 존재하지 않으면 값은 빈 문자열이됩니다.\n\n- **$route.fullPath**\n\n  - 자료형: `string`\n\n    쿼리 및 해시를 포함한 전체 URL입니다.\n\n- **$route.matched**\n\n  - 자료형: `Array<RouteRecord>`\n\n  현재 라우트의 모든 중첩 된 라우트 세그먼트에 대해 **라우트 레코드** 가 포함 된 배열입니다. 라우트 레코드는 `routes` 배열(그리고 `children` 배열)에 있는 객체의 복사본입니다.\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // 다음 객체는 라우트 레코드입니다.\n      { path: '/foo', component: Foo,\n        children: [\n          // 이 또한 라우트 레코드입니다.\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  URL이 `/foo/bar` 인 경우, `$route.matched`는 두 객체(복제 된 객체)를 자식 배열에 포함하는 배열입니다.\n\n- **$route.name**\n\n  현재 라우트의 이름입니다.(가지고 있는 경우). [이름을 가진](../essentials/named-routes.md)를 확인하세요\n"
  },
  {
    "path": "docs-gitbook/kr/api/router-instance.md",
    "content": "# 라우터 인스턴스\n\n### 속성\n\n#### router.app\n\n- 자료형: `Vue instance`\n\n  `router`가 주입 된 루트 Vue 인스턴스.\n\n#### router.mode\n\n- 자료형: `string`\n\n  라우터가 사용하는 [mode](options.md#mode).\n\n#### router.currentRoute\n\n- 자료형: `Route`\n\n  [라우트 객체](route-object.md)로 표시된 현재 라우트.\n\n### Methods\n\n- **router.beforeEach(guard)**\n- **router.beforeResolve(guard)** (2.5.0+)\n- **router.afterEach(hook)**\n\n전역 네비게이션 가드 추가. [네비게이션 가드](../advanced/navigation-guards.md)를 보십시오.\n\n2.5.0이상에서 세 가지 메소드 모두 등록된 guard / hook을 제거하는 함수를 반환합니다.\n\n- **router.push(location, onComplete?, onAbort?)**\n- **router.replace(location, onComplete?, onAbort?)**\n- **router.go(n)**\n- **router.back()**\n- **router.forward()**\n\n  프로그래밍 방식으로 새 URL로 이동합니다. [프로그래밍 방식 네비게이션](../essentials/navigation.md)을 참조하십시오.\n\n- **router.getMatchedComponents(location?)**\n\n  지정된 위치 또는 현재의 라우트에 일치하는 컴퍼넌트(인스턴스는 아니고 정의/생성자)의 배열을 반환합니다. 이는 주로 데이터를 프리페치(prefetching)하기 위해 서버 측 렌더링 동안 사용됩니다.\n\n- **router.resolve(location, current?, append?)**\n\n  > 2.1.0+\n\n  역방향 URL 해석. `<router-link/>`에서 사용된 것과 같은 형식의 위치가 주어지면 다음과 같이 처리된 속성을 가진 객체를 반환합니다.\n\n  ``` js\n  {\n    location: Location;\n    route: Route;\n    href: string;\n  }\n  ```\n\n- `current` 현재 라우트를 나타냅니다. (대부분의 경우에 변경할 일이 없습니다.)\n\n- `append`는 `current` 라우트에 추가할 수 있도록 합니다 ([`router-link`](router-link.md#props)처럼)\n\n- **router.addRoutes(routes)**\n\n  > 2.2.0+\n\n  라우터에 동적으로 더 많은 라우트를 추가할 수 있습니다. 전달인자는 `routes` 생성자 옵션과 동일한 경로 설정 포맷을 사용하는 배열이어야 합니다.\n\n- **router.onReady(callback, [errorCallback])**\n\n  > 2.2.0+\n\n  이 메소드는 라우터가 초기 탐색을 완료할 때 호출하는 콜백을 대기시킵니다. 즉, 초기 라우트와 연결된 모든 비동기 입력 훅 및 비동기 컴포넌트를 해결합니다.\n\n  이는 서버와 클라이언트 모두 일관된 출력을 보장하기 위해 서버측 렌더링을 사용할 때 유용합니다.\n\n- **router.onError(callback)**\n\n  > 2.4.0+\n\n라우트 탐색 중에 에러가 발견되면 호출 될 콜백을 등록하십시오. 호출 할 에러에 유의하십시오. 에러는 다음 시나리오 중 하나이어야합니다.\n\n  - 에러는 라우트 가드 기능 내에서 동기적으로 발생한 경우.\n  - 에러는 라우트 가드 함수 내에서 `next(err)`를 호출하여 캐치한 경우\n  - 라우트를 렌더링하는데 필요한 비동기 컴포넌트를 처리하려고 할 때 에러가 발생한 경우.\n"
  },
  {
    "path": "docs-gitbook/kr/api/router-link.md",
    "content": "# `<router-link>`\n\n`<router-link>`는 라우터 지원 앱에서 사용자 네비게이션을 가능하게하는 컴포넌트입니다. 목표 위치는 `to` prop로 지정됩니다. 기본적으로 올바른 `href`를 갖는 `<a>`태그로 렌더링 되지만 `tag` prop로 구성 될 수 있습니다. 또한 대상 라우트가 활성화되어 있으면 링크가 자동으로 active CSS 클래스를 가져옵니다.\n\n`<router-link>`는 다음과 같은 이유로 하드 코드 된 `<a href=\"...\">`보다 선호됩니다.\n\n- HTML5 히스토리 모드와 해시 모드에서 모두 동일한 방식으로 작동하므로 모드를 전환하기로 결정하거나 라우터가 IE9에서 해시 모드로 전환 한 경우 변경할 필요가 없습니다.\n\n- HTML5 히스토리 모드에서, `router-link`는 클릭 이벤트를 차단하여 브라우저가 페이지를 다시 로드하지 않도록합니다.\n\n- HTML5 히스토리 모드에서 `base` 옵션을 사용할 때 `to` prop의 URL에 이를 포함 할 필요가 없습니다.\n\n### Props\n\n- **to**\n\n  - 자료형: `string | Location`\n\n  - 필수\n\n  링크의 대상 라우트를 나타냅니다. 클릭하면, `to` prop의 값은 내부적으로 `router.push()`에 전달 될 것이므로 값은 문자열이나 위치 디스크립터 객체가 될 수 있습니다.\n\n  ``` html\n  <!-- 리터럴 string -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- 이렇게 렌더링 됩니다. -->\n  <a href=\"home\">Home</a>\n\n  <!-- `v-bind`를 이용한 표현식 -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- `v-bind`를 생략하면 다른 prop를 바인딩 하는 것과 같습니다. -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- 위와 같습니다. -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- 이름을 가지는 라우트 -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- 쿼리가 있으면, `/register?plan=private` 이 됩니다. -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n- **replace**\n\n  - 자료형: `boolean`\n\n  - 기본값: `false`\n\n  `replace` prop를 설정하면 클릭할 때 `router.push()` 대신 `router.replace()`를 호출할 것이므로 내비게이션은 히스토리 레코드를 남기지 않을 것입니다.\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n- **append**\n\n  - 자료형: `boolean`\n\n  - 기본값: `false`\n\n  `append` prop를 설정하면 항상 상대 경로가 현재 경로에 추가됩니다. 예를 들어`/a`에서 상대 링크 `b`로 이동한다고 가정하면 `append`없이 `/b`에서 끝나지만 `append`로 `/a/b`에서 끝납니다 .\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n- **tag**\n\n  - 자료형: `string`\n\n  - 기본값: `\"a\"`\n\n  때때로 우리는 `<router-link>`를 `<li>`과 같은 다른 태그로 렌더링되길 바랍니다. 그런 다음 `tag` prop를 사용하여 렌더링할 태그를 지정할 수 있으며 탐색을 위해 클릭 이벤트를 계속 수신합니다.\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- 이렇게 렌더링됩니다 -->\n  <li>foo</li>\n  ```\n\n- **active-class**\n\n  - 자료형: `string`\n\n  - 기본값: `\"router-link-active\"`\n\n  링크가 활성화 되어 있을 때 적용된 active CSS 클래스를 구성합니다. 기본값은 `linkActiveClass` 라우터 생성자 옵션을 통해 전역적으로 설정될 수 있습니다.\n\n- **exact**\n\n  - 자료형: `boolean`\n\n  - 기본값: `false`\n\n  기본 활성 클래스 매치 동작은 **포괄적인 매칭** 입니다. 예를 들어, `<router-link to=\"/a\">`는 현재 경로가 `/a` 또는 `/a/`로 시작하는 한 이 클래스를 적용합니다.\n\n  이것의 결과는 `<router-link to=\"/\">`가 모든 라우터에 대해 활성화 될 것입니다! 링크를 \"완전 일치 모드\"로 강제하려면 `exact` prop를 사용하십시오.\n\n  ``` html\n  <!-- 이 링크는 `/` 에서만 active 됩니다 -->\n  <router-link to=\"/\" exact>\n  ```\n\n  active 링크 클래스를 설명하는 추가 [예제](https://jsfiddle.net/8xrk1n9f/)를 확인 하십시오.\n\n- **event**\n\n  > 2.1.0+\n\n  - 자료형: `string | Array<string>`\n\n  - 기본값: `'click'`\n\n  링크 네비게이션을 트리거 할 수있는 이벤트를 지정합니다.\n\n- **exact-active-class**\n\n  > 2.5.0+\n  - 자료형: `string`\n  - 기본값: `\"router-link-exact-active\"`\n\n 정확하게 일치하는 링크가 활성된 상태일 때 적용되는 CSS 클래스를 지정합니다. 기본값은`linkExactActiveClass` 라우터 생성자 옵션을 통해 전역으로 설정 될 수 있습니다.\n\n\n### 외부 엘리먼트에 active 클래스 적용하기\n\n때로 우리는 active 클래스가 `<a>` 태그 자체가 아닌 외부 엘리먼트에 적용되는 것을 원할 수 있습니다. 이 경우 `<router-link>` 를 사용하여 외부 엘리먼트를 렌더링하고 원시 `<a>`는 내부에 작성합니다.\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\n이 경우 `<a>`는 실제 링크가 될 것이고(올바른 `href`를 얻습니다.), 활성 클래스는 바깥 쪽 `<li>`에 적용됩니다.\n"
  },
  {
    "path": "docs-gitbook/kr/api/router-view.md",
    "content": "# `<router-view>`\n\n`<router-view>` 컴포넌트는 주어진 라우트에 대해 일치하는 컴포넌트를 렌더링하는 함수형 컴포넌트입니다. `<router-view>`에서 렌더링된 컴포넌트는 자체 `<router-view>`를 포함 할 수 있으며, 이는 중첩 된 라우트를 위해 컴포넌트를 렌더링합니다.\n\n### Props\n\n- **name**\n\n  - 자료형: `string`\n\n  - 기본값: `\"default\"`\n\n  `<router-view>`가 이름을 가지고있을 때, 그것은 일치된 라우트 레코드의 `components` 옵션에서 해당 이름으로 컴포넌트를 렌더링 할 것입니다. 예제는 [이름을 가지는 뷰](../essentials/named-views.md)를 참조하십시오.\n\n### 동작\n\n이름이없는 모든 props는 렌더링된 컴포넌트로 전달되지만 대부분의 경우 라우트 별 데이터는 라우트 매개 변수에 포함됩니다.\n\n이것은 단지 컴포넌트이므로 `<transition>` 및 `<keep-alive>`와 함께 작동합니다. 양쪽 모두를 사용할 때는 `<keep-alive>`를 다음과 같이 사용하십시오.\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/dynamic-matching.md",
    "content": "# 동적 라우트 매칭\n\n주어진 패턴을 가진 라우트를 동일한 컴포넌트에 매핑해야하는 경우가 자주 있습니다. 예를 들어 모든 사용자에 대해 동일한 레이아웃을 가지지만 하지만 다른 사용자 ID로 렌더링되어야하는 `User` 컴포넌트가 있을 수 있습니다. `vue-router`에서 우리는 경로에서 동적 세그먼트를 사용하여 다음을 할 수 있습니다.\n\n``` js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // 동적 세그먼트는 콜론으로 시작합니다.\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n이제 `/user/foo`와 `/user/bar` 같은 URL은 모두 같은 경로에 매핑됩니다.\n\n동적 세그먼트는 콜론 `:`으로 표시됩니다. 라우트가 일치하면 동적 세그먼트의 값은 모든 컴포넌트에서 `this.$route.params`로 표시됩니다. 그러므로 `User`의 템플릿을 다음과 같이 갱신하여 현재 사용자 ID를 표현할 수 있습니다 :\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n```\n\n실제 예제는 [여기](http://jsfiddle.net/yyx990803/4xfa2f19/)에 있습니다.\n\n동일한 라우트에 여러 동적 세그먼트를 가질 수 있으며, `$route.params`의 해당 필드에 매핑됩니다.\n\n예:\n\n| 패턴 | 일치하는 패스 | $route.params |\n|---------|------|--------|\n| /user/:username | /user/evan | `{ username: 'evan' }` |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\n`$route.params` 외에도 `$route` 객체는 `$route.query` (URL에 쿼리가 있는 경우), `$route.hash` 등의 유용한 정보를 제공합니다. [API 레퍼런스](../api/route-object.md)에서 전체 세부 정보를 확인할 수 있습니다.\n\n### Params 변경 사항에 반응하기\n\n매개 변수와 함께 라우트를 사용할 때 주의 해야할 점은 사용자가 `/user/foo`에서 `/user/bar`로 이동할 때 **동일한 컴포넌트 인스턴스가 재사용된다는 것입니다.** 두 라우트 모두 동일한 컴포넌트를 렌더링하므로 이전 인스턴스를 삭제 한 다음 새 인스턴스를 만드는 것보다 효율적입니다. **그러나 이는 또한 컴포넌트의 라이프 사이클 훅이 호출되지 않음을 의미합니다.**\n\n동일한 컴포넌트의 params 변경 사항에 반응하려면 `$route` 객체를 보면됩니다.\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // 경로 변경에 반응하여...\n    }\n  }\n}\n```\n\n또는 2.2에서 소개된 `beforeRouteUpdate` 가드를 사용하십시오.\n```js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // react to route changes...\n    // don't forget to call next()\n  }\n}\n```\n\n### 고급 매칭 패턴\n\n`vue-router`는 라우트 매칭 엔진으로 [path-to-regexp](https://github.com/pillarjs/path-to-regexp)를 사용하기 때문에 선택적 동적 세그먼트, 0개 이상/하나 이상의 요구 사항, 심지어 커스텀 정규식 패턴과 같은 많은 고급 매칭 패턴을 지원합니다. 이 고급 패턴들과 `vue-router`에서 사용하는 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js)에 대한 [문서](https://github.com/pillarjs/path-to-regexp#parameters)를 확인하십시오.\n\n### 매칭 우선순위\n\n동일한 URL이 여러 라우트와 일치하는 경우가 있습니다. 이 경우 일치하는 우선 순위는 라우트 정의의 순서에 따라 결정됩니다. 즉, 경로가 더 먼저 정의 될수록 우선 순위가 높아집니다.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/getting-started.md",
    "content": "# 시작하기\n\n> 가이드의 샘플 코드는[ES2015](https://github.com/lukehoban/es6features)를 사용합니다.\n\nVue.js와 vue-router로 단일 페이지 애플리케이션을 만드는 것은 간단합니다. Vue.js를 통해 우리는 이미 컴포넌트로 애플리케이션을 구성하고 있습니다. vue-router를 추가 할 때, 우리가해야 할 일은 우리의 컴포넌트를 route에 매핑하고 vue-router가 어디서 렌더링할 지 지정하는 것입니다. 다음은 기본적인 예입니다.\n\n> 모든 예제는 Vue의 전체 버전을 사용하여 템플릿 구문 분석을 가능하게합니다. 자세한 내용은 [여기](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only) 있습니다.\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- 탐색을 위해 라우터 링크 구성 요소를 사용하십시오. -->\n    <!-- `to` prop를 전달하여 링크를 지정하십시오. -->\n    <!-- `<router-link>`는 기본적으로`<a>`태그로 렌더링 될 것입니다 -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- route outlet -->\n  <!-- 라우트와 일치하는 컴포넌트가 여기 렌더링됩니다. -->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. 모듈 시스템을 사용하는 경우 (예: vue-cli를 이용해서), Vue 및 VueRouter를 가져온 다음 `Vue.use(VueRouter)`를 호출하십시오.\n\n// 1. 라우트 컴포넌트를 정의하십시오.\n// 다른 파일에서 가져올 수 있습니다.\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. 라우트를 정의합니다.\n// 일부 라우트 정의 각 라우트는 컴포넌트에 맵핑되어야합니다.\n// \"컴포넌트\"는 `Vue.extend()`를 통해 생성된\n// 실제 컴포넌트 생성자이거나 컴포넌트 옵션 객체 일 수 있습니다.\n// 나중에 중첩 된 라우트에 대해 이야기하겠습니다.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. 라우터 인스턴스를 생성하고 `routes` 옵션을 전달하십시오.\n// 여기에 추가 옵션을 전달할 수 있지만, 지금은 간단하게 하겠습니다.\nconst router = new VueRouter({\n  routes // routes: routes 의 약어\n})\n\n// 4. 루트 인스턴스를 만들고 마운트하십시오.\n// 라우터 옵션을 라우터에 삽입하여\n// 전체 응용 프로그램을 라우터가 인식하도록 하십시오.\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// 이제 앱을 시작 해보세요!\n```\n\n이 [예제](http://jsfiddle.net/yyx990803/xgrjzsup/)를 확인하십시오.\n\n`<router-link>`는 가리키는 라우트가 일치 할 때 자동으로 `.router-link-active` 클래스를 얻습니다. API 레퍼런스에서 더 많은 것을 배울 수 있습니다.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/history-mode.md",
    "content": "# HTML5 히스토리 모드\n\n`vue-router`의 기본 모드는 _hash mode_ 입니다. URL 해시를 사용하여 전체 URL을 시뮬레이트하므로 URL이 변경될 때 페이지가 다시 로드 되지 않습니다.\n\n해시를 제거하기 위해 라우터의 **history 모드** 를 사용할 수 있습니다. `history.pushState` API를 활용하여 페이지를 다시 로드하지 않고도 URL 탐색을 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\n히스토리 모드를 사용하면 URL이 \"정상\"으로 보입니다. `http://oursite.com/user/id`. 멋집니다!\n\n그러나 문제는 다음과 같습니다. 우리의 앱이 적절한 서버 설정이 없는 단일 페이지 클라이언트 앱이기 때문에 사용자가 직접 `http://oursite.com/user/id` 에 접속하면 404 오류가 발생합니다.\n\n걱정하지 않아도됩니다. 문제를 해결하려면 서버에 간단하게 포괄적인 대체 경로를 추가하기만 하면됩니다. URL이 정적 에셋과 일치하지 않으면 앱이 있는 동일한 `index.html`페이지를 제공해야 합니다.\n\n## 서버 설정 예제\n\n#### Apache\n\n```apache\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Native Node.js\n\n```js\nconst http = require(\"http\")\nconst fs = require(\"fs\")\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile(\"index.htm\", \"utf-8\", (err, content) => {\n    if (err) {\n      console.log('We cannot open \"index.htm\" file.')\n    }\n\n    res.writeHead(200, {\n      \"Content-Type\": \"text/html; charset=utf-8\"\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log(\"Server listening on: http://localhost:%s\", httpPort)\n})\n```\n\n\n#### Express와 Node.js\n\nNode.js/Express의 경우 [connect-history-api-fallback 미들웨어](https://github.com/bripkens/connect-history-api-fallback)를 고려해보세요.\n\n#### Internet Information Services (IIS)\n\n```\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n <system.webServer>\n   <rewrite>\n     <rules>\n       <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n         <match url=\"(.*)\" />\n         <conditions logicalGrouping=\"MatchAll\">\n           <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n           <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n         </conditions>\n         <action type=\"Rewrite\" url=\"index.html\" />\n       </rule>\n     </rules>\n   </rewrite>\n     <httpErrors>     \n         <remove statusCode=\"404\" subStatusCode=\"-1\" />                \n         <remove statusCode=\"500\" subStatusCode=\"-1\" />\n         <error statusCode=\"404\" path=\"/survey/notfound\" responseMode=\"ExecuteURL\" />                \n         <error statusCode=\"500\" path=\"/survey/error\" responseMode=\"ExecuteURL\" />\n     </httpErrors>\n     <modules runAllManagedModulesForAllRequests=\"true\"/>\n </system.webServer>\n</configuration>\n```\n\n\n## 주의 사항\n\n주의 사항이 있습니다. 여러분의 서버는 404 에러를 보고하지 않을 것입니다. 왜냐하면 모든 발견되지 않은 경로가 이제 `index.html` 파일을 제공하기 때문입니다. 이 문제를 해결하려면 Vue 앱에서 catch-all 라우트를 구현하여 404 페이지를 표시해야합니다.\n\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\n또는 Node.js 서버를 사용하는 경우 서버 측의 라우터를 사용하여 들어오는 URL을 일치시키고 라우트가 일치하지 않으면 404로 응답하여 폴백을 구현할 수 있습니다. 더 자세한 설명은 [Vue 서버사이드 렌더링 문서](https://ssr.vuejs.org/en/)을 읽어보세요\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/named-routes.md",
    "content": "# 이름을 가지는 라우트\n\n때로는 라우트에 연결하거나 탐색을 수행 할 때 이름이 있는 라우트를 사용하는 것이 더 편리합니다. Router 인스턴스를 생성하는 동안 `routes` 옵션에 라우트를 지정할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\n이름을 가진 라우트에 링크하려면, 객체를 `router-link`, 컴포넌트의 `to` prop로 전달할 수 있습니다.\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n```\n\n이것은 `router.push()`와 프로그램적으로 사용되는 것과 정확히 같은 객체입니다.\n\n```js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\n두 경우 모두 라우터는 `/user/123` 경로로 이동합니다.\n\n전체 예제는 [여기](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js)에 있습니다.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/named-views.md",
    "content": "# 이름을 가지는 뷰\n\n때로는 여러 개의 뷰를 중첩하지 않고 동시에 표시해야 하는 경우가 있습니다. `sidebar` 뷰와 `main` 뷰로 레이아웃을 생성합니다. 이름이 지정된 뷰가 편리한 경우 입니다. 뷰에 하나의 outlet이 있는 대신 여러 개를 사용하여 각 outlet에 이름을 지정할 수 있습니다. 이름이 없는 `router-view`는 이름으로 `default`가 주어집니다.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\n뷰는 컴포넌트를 사용하여 렌더링 되므로 여러 뷰에는 동일한 라우트에 대해 여러 컴포넌트가 필요합니다. `components`(s를 붙입니다) 옵션을 사용해야합니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\n이 예제는 [여기](https://jsfiddle.net/posva/6du90epg/)에서 확인할 수 있습니다.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/navigation.md",
    "content": "# 프로그래밍 방식 네비게이션\n\n`<router-link>`를 사용하여 선언적 네비게이션용 anchor 태그를 만드는 것 외에도 라우터의 인스턴스 메소드를 사용하여 프로그래밍으로 이를 수행 할 수 있습니다.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**참고: Vue 인스턴스 내부에서 라우터 인스턴스에 `$router`로 액세스 할 수 있습니다. 그러므로`this.$router.push`를 사용 할 수 있습니다.**\n\n다른 URL로 이동하려면 `router.push`를 사용하십시오. 이 메소드는 새로운 항목을 히스토리 스택에 넣기 때문에 사용자가 브라우저의 뒤로 가기 버튼을 클릭하면 이전 URL로 이동하게된다.\n\n이것은 `<router-link>`를 클릭 할 때 내부적으로 호출되는 메소드이므로 `<router-link :to=\"...\">`를 클릭하면 `router.push(...)`를 호출하는 것과 같습니다.\n\n| 선언적 방식 | 프로그래밍 방식 |\n|-------------|--------------|\n| `<router-link :to=\"...\">` | `router.push(...)` |\n\n전달인자는 문자열 경로 또는 로케이션 디스크립터 객체가 될 수 있습니다.\n\n예:\n\n``` js\n// 리터럴 string\nrouter.push('home')\n\n// object\nrouter.push({ path: 'home' })\n\n// 이름을 가지는 라우트\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// 쿼리와 함께 사용, 결과는 /register?plan=private 입니다.\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n2.2.0 버전이후로 선택적으로 `router.push` 또는 `router.replace`에 두번째와 세번째 전달인자로 `onComplete`와 `onAbort` 콜백을 제공합니다.\n이 콜백은 탐색이 성공적으로 완료되거나(모든 비동기 훅이 해결된 후) 또는 중단(현재 탐색이 완료되기 전에 동일한 경로로 이동하거나 다른 경로 이동)될 때 호출 됩니다.\n\n#### `router.replace(location)`\n\n`router.push`와 같은 역할을 하지만 유일한 차이는 새로운 히스토리 항목에 추가하지 않고 탐색한다는 것입니다. 이름에서 알 수 있듯이 현재 항목을 대체합니다.\n\n| 선언적 방식   | 프로그래밍 방식 |\n|-------------|--------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n\n#### `router.go(n)`\n\n이 메소드는 `window.history.go(n)`와 비슷하게 히스토리 스택에서 앞으로 또는 뒤로 이동하는 단계를 나타내는 하나의 정수를 매개 변수로 사용합니다.\n\n예제\n\n``` js\n// 한 단계 앞으로 갑니다. history.forward()와 같습니다. history.forward()와 같습니다.\nrouter.go(1)\n\n// 한 단계 뒤로 갑니다. history.back()와 같습니다.\nrouter.go(-1)\n\n// 3 단계 앞으로 갑니다.\nrouter.go(3)\n\n// 지정한 만큼의 기록이 없으면 자동으로 실패 합니다.\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### History 조작\n\n`router.push`, `router.replace` 및 `router.go`는 [`window.history.pushState`,`window.history.replaceState` 및 `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History)와 상응합니다. 그들은 `window.history` API를 모방합니다.\n\n따라서 [브라우저 히스토리 API](https://developer.mozilla.org/en-US/docs/Web/API/History_API)에 이미 익숙하다면 vue-router를 사용하여 히스토리를 손쉽게 조작 할 수 있습니다.\n\nvue-router 네비게이션 메소드(`push`,`replace`,`go`)는 모든 라우터 모드(`history`,`hash` 및`abstract`)에서 일관되게 작동합니다.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/nested-routes.md",
    "content": "# 중첩된 라우트\n\n실제 앱 UI는 일반적으로 여러 단계로 중첩 된 컴포넌트로 이루어져 있습니다. URL의 세그먼트가 중첩 된 컴포넌트의 특정 구조와 일치한다는 것은 매우 일반적입니다. 예를 들면 다음과 같습니다.\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\n`vue-router`를 사용하면 중첩 된 라우트 구성을 사용하여 관계를 표현하는 것이 매우 간단합니다.\n\n이전 장에서 만든 앱을 생각해보십시오.\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n여기에있는 `<router-view>`는 최상위 outlet입니다. 최상위 경로와 일치하는 컴포넌트를 렌더링합니다. 비슷하게 렌더링 된 컴포넌트는 자신의 중첩 된 `<router-view>`를 포함 할 수도 있습니다. 다음은 `User` 컴포넌트의 템플릿 안에 하나를 추가하는 예 입니다.\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>User {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\n이 중첩 outlet에 컴포넌트를 렌더링하려면 `children`을 사용해야합니다.\n`VueRouter` 생성자의 옵션 config:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User,\n      children: [\n        {\n          // /user/:id/profile 과 일치 할 때\n          // UserProfile은 User의 <router-view> 내에 렌더링 됩니다.\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // /user/:id/posts 과 일치 할 때\n          // UserPosts가 User의 <router-view> 내에 렌더링 됩니다.\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**`/`로 시작하는 중첩 된 라우트는 루트 경로로 취급됩니다. 이렇게하면 중첩 된 URL을 사용하지 않고도 컴포넌트 중첩을 활용할 수 있습니다.**\n\n여러분이 볼 수 있듯이 `children` 옵션은 `routes`와 같은 라우트 설정 객체의 또 다른 배열입니다. 따라서 필요한만큼 중첩 된 뷰를 유지할 수 있습니다.\n\n이 시점에서, 위의 설정으로, `/user/foo`를 방문했을 때 하위 라우트가 매치되지 않았기 때문에 `User`의 outlet에 아무것도 출력되지 않습니다. 어쩌면 거기에 무언가를 렌더링하고 싶을지도 모릅니다. 이 경우 빈 서브 루트 경로를 제공 할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id', component: User,\n      children: [\n        // UserHome은 /user/:id 가 일치 할 때\n        // User의 <router-view> 안에 렌더링됩니다.\n        { path: '', component: UserHome },\n\n        // ...또 다른 서브 라우트\n      ]\n    }\n  ]\n})\n```\n\n이 예제의 작업 데모는 [이 곳](http://jsfiddle.net/yyx990803/L7hscd8h/)에서 찾을 수 있습니다.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/passing-props.md",
    "content": "# 라우트 컴포넌트에 속성 전달\n\n컴포넌트에서 `$route`를 사용하면 특정 URL에서만 사용할 수 있는 컴포넌트의 유연성을 제한하는 라우트와 강한 결합을 만듭니다.\n\n컴포넌트와 라우터 속성을 분리하려면 다음과 같이 하십시오.\n\n** $route에 의존성 추가**\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n** 속성에 의존성 해제**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n  ]\n})\n```\n\n이를 통해 어디서나 컴포넌트를 사용할 수 있으므로 컴포넌트 재사용 및 테스트하기가 더 쉽습니다.\n\n### Boolean 모드\n\n`props`를 `true`로 설정하면 `route.params`가 컴포넌트 `props`로 설정됩니다.\n\n### 객체 모드\n\n`props`가 객체일때 컴포넌트 `props`가 있는 그대로 설정됩니다.\n`props`가 정적일 때 유용합니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n### 함수 모드\n\n`props`를 반환하는 함수를 만들 수 있습니다. 이를 통해 전달인자를 다른 타입으로 캐스팅하고 적정인 값을 라우트 기반 값과 결합됩니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\n`/search?q=vue`는 `{query: \"vue\"}`를 `SearchUser` 컴포넌트에 전달합니다.\n\n라우트 변경시에만 평가되므로 `props` 함수는 상태를 저장하지 않도록 합니다.\n`props`를 정의할 상태가 필요한 경우 래퍼 컴포넌트를 사용하면 상태가 변경될 때마다 응답할 수 있습니다.\n\n고급 사용예를 보려면 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js)를 확인하세요.\n"
  },
  {
    "path": "docs-gitbook/kr/essentials/redirect-and-alias.md",
    "content": "# 리다이렉트와 별칭\n\n### 리다이렉트\n\n리디렉션은 `routes` 설정에서도 할 수 있습니다. `/a`에서 `/b`로 리디렉션하려면\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\n리디렉션은 이름이 지정된 라우트를 지정할 수도 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\n또는 동적 리디렉션을 위한 함수를 사용할 수도 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // 함수는 인수로 대상 라우트를 받습니다.\n      // 여기서 path/location 반환합니다.\n    }}\n  ]\n})\n```\n기타 고급 사용법은 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js)를 확인 하십시오.\n\n### 별칭\n\n리다이렉트는 사용자가 `/a`를 방문했을 때 URL이 `/b`로 대체 된 다음 `/b`로 매칭된다는 것을 의미합니다. 하지만 별칭이란 무엇입니까?\n\n**`/a`의 별칭은 `/b`는 사용자가 `/b`를 방문했을 때 URL은 `/b`을 유지하지만 사용자가 `/a`를 방문한 것처럼 매칭합니다.**\n\n위는 라우트 구성에서 다음과 같이 표현할 수 있습니다.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\n별칭을 사용하면 구성의 중첩 구조에 의해 제약을 받는 대신 UI 구조를 임의의 URL에 매핑 할 수 있습니다.\n\n기타 고급 사용법은 [예제](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js)를 확인 하십시오.\n"
  },
  {
    "path": "docs-gitbook/kr/installation.md",
    "content": "# 설치\n\n### 직접 다운로드 / CDN\n\n[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com)은 NPM 기반 CDN 링크를 제공합니다. 위의 링크는 항상 NPM의 최신 릴리스를 가리킵니다. `https://unpkg.com/vue-router@2.0.0/dist/vue-router.js`와 같이 URL을 통해 특정 버전 / 태그를 사용할 수도 있습니다.\n<!--/email_off-->\n\nVue 다음에 `vue-router`를 포함하면 자동으로 설치됩니다.\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### NPM\n\n``` bash\nnpm install vue-router\n```\n\n모듈 시스템에서 사용하면 `Vue.use()`를 통해 명시적으로 라우터를 추가해야합니다.\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\n전역 스크립트 태그를 사용할 때는 이 작업을 하지 않아도 됩니다.\n\n### 개발용 빌드\n\n최신 dev 빌드를 사용하고 싶은 경우 GitHub에서 직접 복제하고 `vue-router`를 직접 빌드 해야 합니다.\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "docs-gitbook/old/README.md",
    "content": "# 0.7 Docs\n\n- [English](https://github.com/vuejs/vue-router/tree/1.0/docs/en)\n- [Chinese](https://github.com/vuejs/vue-router/tree/1.0/docs/zh-cn)\n- [Japanese](https://github.com/vuejs/vue-router/tree/1.0/docs/ja)\n"
  },
  {
    "path": "docs-gitbook/old/SUMMARY.md",
    "content": ""
  },
  {
    "path": "docs-gitbook/ru/README.md",
    "content": "{% include \"./SUMMARY.md\" %}\n"
  },
  {
    "path": "docs-gitbook/ru/SUMMARY.md",
    "content": "# vue-router\n\n> Примечание: для пользователей TypeScript, vue-router@3.0+ требуется vue@2.5+, и наоборот.\n\n**[История изменений](https://github.com/vuejs/vue-router/releases)**\n\n- [Введение](README.md)\n- [Установка](installation.md)\n- Основы\n  - [Начало работы](essentials/getting-started.md)\n  - [Динамические пути](essentials/dynamic-matching.md)\n  - [Вложенные пути](essentials/nested-routes.md)\n  - [Императивная навигация](essentials/navigation.md)\n  - [Именованные пути](essentials/named-routes.md)\n  - [Именованные представления](essentials/named-views.md)\n  - [Редиректы и псевдонимы](essentials/redirect-and-alias.md)\n  - [Передача входных параметров в компоненты маршрутов](essentials/passing-props.md)\n  - [Режим HTML5 History](essentials/history-mode.md)\n- Продвинутые возможности\n  - [Сторожевые хуки](advanced/navigation-guards.md)\n  - [Метаданные путей](advanced/meta.md)\n  - [Анимация переходов](advanced/transitions.md)\n  - [Запросы данных](advanced/data-fetching.md)\n  - [Скроллинг](advanced/scroll-behavior.md)\n  - [Ленивая загрузка путей](advanced/lazy-loading.md)\n- Справочник API\n  - [Опции конструктора Router'а](api/options.md)\n    - [routes](api/options.md#routes)\n    - [mode](api/options.md#mode)\n    - [base](api/options.md#base)\n    - [linkActiveClass](api/options.md#linkactiveclass)\n    - [linkExactActiveClass](api/options.md#linkexactactiveclass)\n    - [scrollBehavior](api/options.md#scrollbehavior)\n    - [parseQuery / stringifyQuery](api/options.md#parsequery--stringifyquery)\n    - [fallback](api/options.md#fallback)\n  - [Экземпляр Router](api/router-instance.md)\n    - [Свойства](api/router-instance.md#свойства)\n    - [Методы](api/router-instance.md#методы)\n  - [Объект route](api/route-object.md)\n  - [Интеграция с компонентами Vue](api/component-injections.md)\n  - [router-link](api/router-link.md)\n  - [router-view](api/router-view.md)\n"
  },
  {
    "path": "docs-gitbook/ru/advanced/data-fetching.md",
    "content": "# Запросы данных\n\nНередко при переходе между путями требуется получить от сервера какие-либо данные. Например, перед отображением профиля пользователя нужно запросить данные о нём. Этой цели можно достичь двумя различными путями:\n\n- **Запросив данные после перехода**: сначала перейти к новому пути, затем запросить данные в хуке жизненного цикла целевого компонента. По мере загрузки данных отобразить индикатор состояния загрузки.\n\n- **Запросив данные перед переходом**: запросить данные в сторожевом хуке роутера, и завершить навигацию уже когда они будут получены.\n\nС технической точки зрения, оба способа годятся — выбор зависит от того, какой UX вы хотите получить.\n\n## Запрос данных после перехода\n\nПри использовании этого подхода, мы осуществляем переход и рендеринг целевого компонента сразу же, а данные запрашиваем в хуке `created` компонента. Это позволяет нам отобразить состояние загрузки, пока данные подтягиваются по сети, причём имея возможность сделать это различным образом для разных компонентов.\n\nПредположим, у нас есть компонент `Post`, которому требуется загрузить с сервера данные, соответствующие id поста из `$route.params.id`:\n\n``` html\n<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">\n      Загрузка...\n    </div>\n\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n\n    <div v-if=\"post\" class=\"content\">\n      <h2>{{ post.title }}</h2>\n      <p>{{ post.body }}</p>\n    </div>\n  </div>\n</template>\n```\n\n``` js\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    // запрашиваем данные когда реактивное представление уже создано\n    this.fetchData()\n  },\n  watch: {\n    // в случае изменения маршрута запрашиваем данные вновь\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      // замените здесь `getPost` используемым методом получения данных / доступа к API\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n```\n\n## Запрос данных перед переходом\n\nИспользуя этот подход, мы запрашиваем данные до завершения перехода к новому пути. Запрос данных выполняется в сторожевом хуке `beforeRouteEnter` компонента, который вызывает `next`, когда данные получены:\n\n``` js\nexport default {\n  data () {\n    return {\n      post: null,\n      error: null\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    getPost(to.params.id, (err, post) => {\n      next(vm => vm.setData(err, post))\n    })\n  },\n  // если путь изменяется, а компонент уже отображён,\n  // логика будет немного иной\n  beforeRouteUpdate (to, from, next) {\n    this.post = null\n    getPost(to.params.id, (err, post) => {\n      this.setData(err, post)\n      next()\n    })\n  },\n  methods: {\n    setData (err, post) {\n      if (err) {\n        this.error = err.toString()\n      } else {\n        this.post = post\n      }\n    }\n  }\n}\n```\n\nПользователь останется на предыдущей странице, пока не загрузятся данные новой. По этой причине мы советуем отображать какой-нибудь индикатор загрузки. Кроме того, если загрузка данных не удастся, следует отобразить глобальное сообщение об ошибке.\n"
  },
  {
    "path": "docs-gitbook/ru/advanced/lazy-loading.md",
    "content": "# Ленивая загрузка путей\n\nПри использовании модульного сборщика, результирующая JavaScript-сборка может оказаться довольно большой, что негативно сказывается на времени загрузки страницы. В некоторых случаях было бы эффективнее разделить компоненты каждого пути на отдельные минисборки, и загружать их только при переходе к соответствующему пути.\n\nСовместное использование [асинхронной загрузки компонентов](https://ru.vuejs.org/v2/guide/components.html#Асинхронные-компоненты) Vue и [разделения кода](https://webpack.js.org/guides/code-splitting-async/) Webpack делает реализацию ленивой загрузки компонентов в зависимости от путей тривиальной.\n\nВо-первых, асинхронный компонент можно определить как функцию-фабрику, которая возвращает Promise (который должен разрешиться самим компонентом):\n\n``` js\nconst Foo = () => Promise.resolve({ /* определение компонента */ })\n```\n\nВо-вторых, в Webpack 2 мы можем использовать синтаксис [динамических импортов](https://github.com/tc39/proposal-dynamic-import) для указания точек разделения кода:\n\n``` js\nimport('./Foo.vue') // возвращает Promise\n```\n\n> Примечание: если вы используете Babel, то нужно будет добавить плагин [syntax-dynamic-import](https://babeljs.io/docs/plugins/syntax-dynamic-import/), чтобы Babel смог корректно обработать синтаксис.\n\nЭти два пункта — всё необходимое, чтобы определить асинхронный компонент, который Webpack автоматически вынесет в отдельный чанк:\n\n``` js\nconst Foo = () => import('./Foo.vue')\n```\n\nВ конфигурации путей ничего менять не нужно, просто используйте `Foo` как обычно:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/foo', component: Foo }\n  ]\n})\n```\n\n### Объединение компонентов в единую минисборку\n\nИногда может понадобиться объединить в единую минисборку все компоненты, расположенные по определённому пути. Для достижения этой цели можно использовать [именованные минисборки Webpack](https://webpack.js.org/guides/code-splitting-async/#chunk-names), указывая имя используя специальный синтаксис комментариев (в версиях Webpack > 2.4):\n\n``` js\nconst Foo = () => import(/* webpackChunkName: \"group-foo\" */ './Foo.vue')\nconst Bar = () => import(/* webpackChunkName: \"group-foo\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"group-foo\" */ './Baz.vue')\n```\n\nWebpack сгруппирует все одноимённые асинхронные модули в единую минисборку.\n"
  },
  {
    "path": "docs-gitbook/ru/advanced/meta.md",
    "content": "# Метаданные путей\n\nПри определении пути можно указывать метаданные в поле `meta`:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      children: [\n        {\n          path: 'bar',\n          component: Bar,\n          // метаданные\n          meta: { requiresAuth: true }\n        }\n      ]\n    }\n  ]\n})\n```\n\nКак получить к нему доступ?\n\nПрежде всего, каждый объект пути в конфигурации `routes` называется **записью пути**. Записи путей могут быть вложенными. Поэтому, при совпадении пути, потенциально могут быть активированы несколько записей путей.\n\nНапример, для конфигурации выше, URL `/foo/bar` совпадёт как с родительской, так и с дочерней записями путей.\n\nВсе совпавшие записи путей оказываются доступны через объект `$route` (а также через объекты пути в сторожевых хуках), в виде массива `$route.matched`. Таким образом, для проверки метаданных в записях путей нам понадобится обойти `$route.matched` в цикле.\n\nВ качестве примера можно привести проверку метаданных в глобальном сторожевом хуке:\n\n``` js\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(record => record.meta.requiresAuth)) {\n    // этот путь требует авторизации, проверяем залогинен ли\n    // пользователь, и если нет, перенаправляем на страницу логина\n    if (!auth.loggedIn()) {\n      next({\n        path: '/login',\n        query: { redirect: to.fullPath }\n      })\n    } else {\n      next()\n    }\n  } else {\n    next() // всегда так или иначе нужно вызвать next()!\n  }\n})\n```\n"
  },
  {
    "path": "docs-gitbook/ru/advanced/navigation-guards.md",
    "content": "# Сторожевые хуки\n\nКак следует из названия, сторожевые хуки `Vue-router` используются для редиректов или отмены навигационных переходов. Есть несколько способов внедрить сторожевой хук: глобально, для конкретного пути, или для конкретного компонента.\n\nСледует помнить, что **изменение параметров маршрута не вызывает выполнения сторожевых хуков enter/leave**. Вы можете добавить [watch на объект `$route`](../essentials/dynamic-matching.md#отслеживание-изменений-параметров) для отслеживания этих изменений, или использовать хук `beforeRouteUpdate`.\n\n### Глобальные хуки\n\nГлобальный хук можно зарегистрировать через `router.beforeEach`:\n\n``` js\nconst router = new VueRouter({ ... })\n\nrouter.beforeEach((to, from, next) => {\n  // ...\n})\n```\n\nГлобальные сторожевые хуки вызываются в порядке создания при каждом навигационном переходе. Допускается асинхронное разрешение хуков — в этом случае переход считается **незавершённым** до тех пор, пока не будут разрешены все хуки.\n\nВ каждый сторожевой хук передаётся три параметра:\n\n- **`to: Route`**: целевой [объект Route](../api/route-object.md), к которому осуществляется переход.\n\n- **`from: Route`**: текущий путь, с которого осуществляется переход к новому.\n\n- **`next: Function`**: функция, вызов которой **разрешает** хук. В зависимости от переданных в `next` аргументов, результатом будет:\n\n  - **`next()`**: переход к следующему хуку в цепочке. Если хуков больше нет, переход считается **подтверждённым**.\n\n  - **`next(false)`**: отмена перехода. Если URL был изменён (вручную пользователем, или кнопкой \"назад\"), он будет сброшен на соответствующий пути `from`.\n\n  - **`next('/')` или `next({ path: '/' })`**: перенаправление на другой путь. Текущий переход будет отменён, и процесс начнётся заново для нового пути. Вы можете передать любой объект местоположения в `next`, который позволяет вам указывать опции такие как `replace: true`, `name: 'home'` и любой другой параметр используемый во [входном параметре `to` компонента `router-link`](../api/router-link.md) или [`router.push`](../api/router-instance.md#methods)\n\n  - **`next(error)`**: (добавлено в версии 2.4.0+) если аргумент, переданный `next` является экземпляром `Error`, навигация будет прервана и ошибка будет передана в коллбек, зарегистрированный через [`router.onError()`](../api/router-instance.html#методы).\n\n**Удостоверьтесь, что функция `next` так или иначе будет вызвана, иначе хук никогда не будет разрешён.**\n\n### Глобальные хуки разрешения перехода\n\n> Добавлено в версии 2.5.0\n\nВ 2.5.0+ вы можете зарегистрировать глобальный хук с помощью `router.beforeResolve`. Это похоже на `router.beforeEach`, с той разницей, что разрешающий хук будет вызван непосредственно перед подтверждением навигации, **после того, как будут разрешены все хуки компонента и асинхронные компоненты для маршрута**.\n\n### Глобальные хуки завершения перехода\n\nМожно также зарегистрировать глобальные хуки, вызываемые после завершения перехода. Однако, в отличие от сторожевых хуков, в них не передаётся функция `next`, и на ход перехода они повлиять не могут:\n\n``` js\nrouter.afterEach((to, from) => {\n  // ...\n})\n```\n\n### Указание хука для конкретного пути\n\nСторожевые хуки `beforeEnter` можно указать напрямую для конкретного пути в его конфигурации:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/foo',\n      component: Foo,\n      beforeEnter: (to, from, next) => {\n        // ...\n      }\n    }\n  ]\n})\n```\n\nЭти хуки ничем не отличаются от глобальных.\n\n### Указание хука для конкретного компонента\n\nНаконец, сторожевой хук можно указать и непосредственно в компоненте (том, что указан в конфигурации пути), используя следующие опции:\n\n- `beforeRouteEnter`\n- `beforeRouteUpdate` (добавлено в версии 2.2+)\n- `beforeRouteLeave`\n\n``` js\nconst Foo = {\n  template: `...`,\n  beforeRouteEnter (to, from, next) {\n    // вызывается до подтверждения пути, соответствующего этому компоненту.\n    // НЕ имеет доступа к контексту экземпляра компонента `this`,\n    // так как к моменту вызова экземпляр ещё не создан!\n  },\n  beforeRouteUpdate (to, from, next) {\n    // вызывается когда маршрут, что рендерит этот компонент изменился,\n    // но этот компонент будет повторно использован в новом маршруте.\n    // Например, для маршрута с динамическими параметрами `/foo/:id`, когда мы\n    // перемещаемся между `/foo/1` и `/foo/2`, экземпляр того же компонента `Foo`\n    // будет использован повторно, и этот хук будет вызван когда это случится.\n    // Также имеется доступ в `this` к экземпляру компонента.\n  },\n  beforeRouteLeave (to, from, next) {\n    // вызывается перед переходом от пути, соответствующего текущему компоненту;\n    // имеет доступ к контексту экземпляра компонента `this`.\n  }\n}\n```\n\nХук `beforeRouteEnter` **НЕ** имеет доступа к `this`, так как к моменту его вызова навигация ещё не подтверждена, а значит и экземпляр компонента ещё не создан.\n\nТем не менее, доступ к экземпляру можно получить, передав коллбэк в `next`. Эта функция будет вызвана после подтверждения навигации, а экземпляр компонента будет передан в неё в качестве параметра:\n\n``` js\nbeforeRouteEnter (to, from, next) {\n  next(vm => {\n    // экземпляр компонента доступен как `vm`\n  })\n}\n```\n\nОбратите внимание, что `beforeRouteEnter` — единственный хук, который поддерживает передачу коллбэка в `next`. Для `beforeRouteUpdate` и `beforeRouteLeave`, `this` уже доступен, поэтому передача коллбэка не требуется и поэтому *не поддерживается*:\n\n```js\nbeforeRouteUpdate (to, from, next) {\n  // просто используйте `this`\n  this.name = to.params.name\n  next()\n}\n```\n\n**Сторожевой хук ухода со страницы** обычно используется для предотвращения случайного ухода пользователя со страницы с несохранёнными изменениями. Навигацию можно отменить вызовом `next(false)`.\n\n```js\nbeforeRouteLeave (to, from , next) {\n  const answer = window.confirm('Вы действительно хотите уйти? У вас есть несохранённые изменения!')\n  if (answer) {\n    next()\n  } else {\n    next(false)\n  }\n}\n```\n\n### Полная цепочка обработки навигации\n\n1. Срабатывание навигации.\n2. Вызов leave-хуков в деактивируемых компонентах.\n3. Вызов глобальных `beforeEach` хуков.\n4. Вызов `beforeRouteUpdate` хука в переиспользуемых компонентах (2.2+).\n5. Вызов `beforeEnter` в конфигурации маршрута.\n6. Разрешение асинхронных компонентов для маршрута.\n7. Вызов `beforeRouteEnter` в активируемых компонентах.\n8. Вызов глобальных `beforeResolve` хуков (2.5+).\n9. Навигация подтверждена.\n10. Вызов глобальных `afterEach` хуков.\n11. Выполняется обновление DOM.\n12. Вызов коллбэков, переданных в `next` в `beforeRouteEnter` хуке с созданными экземплярами.\n"
  },
  {
    "path": "docs-gitbook/ru/advanced/scroll-behavior.md",
    "content": "# Скроллинг\n\nПри переходе между страницами в рамках клиентского роутинга, можно сохранять позицию скроллинга для каждой записи в истории (что обычно делают браузеры при работе с традиционными приложениями), или же проматывать страницу вверх. `Vue-router` позволяет использовать оба варианта, и даже более того — позволяет полностью настроить поведение скроллинга при навигации.\n\n**Замечание: эта возможность работает если браузер поддерживает `history.pushState`.**\n\nПри создании экземпляра роутера, вы можете указать функцию `scrollBehavior`:\n\n``` js\nconst router = new VueRouter({\n  routes: [...],\n  scrollBehavior (to, from, savedPosition) {\n    // здесь нужно вернуть требуемую позицию скролла\n  }\n})\n```\n\nФункция `scrollBehavior` получает объекты путей `to` и `from`. В третьем параметре, `savedPosition`, передаётся сохранённая в истории браузера позиция скролла (только в случае `popstate`-перехода, вызванного нажатием кнопок вперёд/назад в браузере).\n\nФункция возвращает объект позиции скролла. Он может иметь одну из двух форм:\n\n- `{ x: number, y: number }`\n- `{ selector: string, offset? : { x: number, y: number }}` (offset поддерживается только в 2.6.0+)\n\nЕсли возвращается пустой объект или приводимое к ложному значение, скроллинга не произойдёт.\n\nНапример:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return { x: 0, y: 0 }\n}\n```\n\nТаким образом мы просто заставим браузер проматывать скролл к началу каждой открытой страницы.\n\nВозврат `savedPosition` позволяет эмулировать нативное поведение браузера при использовании кнопок назад/вперёд:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (savedPosition) {\n    return savedPosition\n  } else {\n    return { x: 0, y: 0 }\n  }\n}\n```\n\nЭмулировать поведение \"прокрутки к якорю\" (\"scroll to anchor\") можно так:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  if (to.hash) {\n    return {\n      selector: to.hash\n      // , offset: { x: 0, y: 10 }\n    }\n  }\n}\n```\n\nМожно также использовать [метаданные путей](meta.md) для более сложного управления скроллингом. Полная реализация подхода содержится в [этом примере](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js).\n\n### Асинхронный скроллинг\n\n> Добавлено в версии 2.8.0\n\nВы также можете вернуть Promise, который разрешится дескриптором с желаемой позицией:\n\n``` js\nscrollBehavior (to, from, savedPosition) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      resolve({ x: 0, y: 0 })\n    }, 500)\n  })\n}\n```\n\nЭто возможно связать с событиями из сменяющегося компонента-страниц, чтобы сделать поведение прокрутки более сочетаемым с вашими анимациями перехода между страницами, но из-за множества возможных вариантов и комплексности примеров, мы просто предоставляем этот просто пример чтобы показать где можно разместить собственную реализацию.\n"
  },
  {
    "path": "docs-gitbook/ru/advanced/transitions.md",
    "content": "# Анимация переходов\n\nПоскольку `<router-view>` — это просто динамический компонент, к нему можно применить анимированные переходы, используя `<transition>`:\n\n``` html\n<transition>\n  <router-view></router-view>\n</transition>\n```\n\nВсё, [что сказано о `<transition>` в документации основной библиотеки](https://ru.vuejs.org/v2/guide/transitions.html), применимо и здесь.\n\n### Анимация переходов для конкретных путей\n\nСинтаксис выше применит одну и ту же анимацию перехода для всех путей. Если для различных путей хочется указать разные анимационные эффекты, можно использовать разноимённые `<transition>` непосредственно в шаблонах компонентов:\n\n``` js\nconst Foo = {\n  template: `\n    <transition name=\"slide\">\n      <div class=\"foo\">...</div>\n    </transition>\n  `\n}\n\nconst Bar = {\n  template: `\n    <transition name=\"fade\">\n      <div class=\"bar\">...</div>\n    </transition>\n  `\n}\n```\n\n### Динамические анимационные переходы для путей\n\nМожно также определить переходы для путей динамически, в зависимости от соотношения между старым и новым путём:\n\n``` html\n<!-- используем динамическое имя анимационного перехода -->\n<transition :name=\"transitionName\">\n  <router-view></router-view>\n</transition>\n```\n\n``` js\n// затем, в родительском компоненте, будем следить за переменной `$route`,\n// чтобы определить, какой анимационный переход применить\n\nwatch: {\n  '$route' (to, from) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n  }\n}\n```\n\nПолный пример можно посмотреть [здесь](https://github.com/vuejs/vue-router/blob/dev/examples/transitions/app.js).\n"
  },
  {
    "path": "docs-gitbook/ru/api/component-injections.md",
    "content": "# Интеграция с компонентами Vue\n\n### Добавляемые свойства\n\nПеречисленные ниже свойства становятся доступными в каждом дочернем компоненте при передаче роутера через опцию `router` корневого экземпляра приложения.\n\n- #### $router\n\n  Экземпляр роутера.\n\n- #### $route\n\n  Объект [Route](route-object.md), соответствующий текущему активному пути. Это свойство доступно только на чтение и его параметры иммутабельны, но над ними можно установить наблюдение.\n\n### Доступные опции\n\n- **beforeRouteEnter**\n- **beforeRouteUpdate** (добавлено в версии 2.2)\n- **beforeRouteLeave**\n\n  См. [раздел документации о сторожевых хуках](../advanced/navigation-guards.md#указание-хука-для-конкретного-компонента).\n"
  },
  {
    "path": "docs-gitbook/ru/api/options.md",
    "content": "# Опции конструктора Router'а\n\n### routes\n\n- тип: `Array<RouteConfig>`\n\n  Декларация типа для `RouteConfig`:\n\n  ``` js\n  declare type RouteConfig = {\n    path: string;\n    component?: Component;\n    name?: string; // для именованных путей\n    components?: { [name: string]: Component }; // для именованных представлений\n    redirect?: string | Location | Function;\n    props?: boolean | string | Function;\n    alias?: string | Array<string>;\n    children?: Array<RouteConfig>; // для вложенных путей\n    beforeEnter?: (to: Route, from: Route, next: Function) => void;\n    meta?: any;\n\n    // 2.6.0+\n    caseSensitive?: boolean; // учитывать ли регистр при сравнении? (по умолчанию: false)\n    pathToRegexpOptions?: Object; // настройки path-to-regexp для компиляции regex\n  }\n  ```\n\n### mode\n\n- тип: `string`\n\n- значение по умолчанию: `\"hash\" (in browser) | \"abstract\" (in Node.js)`\n\n- возможные значения: `\"hash\" | \"history\" | \"abstract\"`\n\n  Указывает режим работы роутера.\n\n  - `hash`: для роутинга будут использоваться URL-хэши. Работает во всех поддерживаемых браузерах, включая те, что не поддерживают HTML5 History API.\n\n  - `history`: требует для работы поддержку HTML5 History API в браузере с соответствующую конфигурацию сервера. См. [раздел документации об использовании режима HTML5 History](../essentials/history-mode.md).\n\n  - `abstract`: работает в любом JavaScript-окружении, включая серверный рендеринг с помощью Node.js. **Роутер переключается в этот режим автоматически, если не обнаруживает API браузера.**\n\n### base\n\n- тип: `string`\n\n- значение по умолчанию: `\"/\"`\n\n  Базовый URL приложения. Например, если SPA находится по пути `/app/`, значением `base` также должно быть `\"/app/\"`.\n\n### linkActiveClass\n\n- тип: `string`\n\n- значение по умолчанию: `\"router-link-active\"`\n\n  Глобальная конфигурация CSS-класса по умолчанию для активных ссылок `<router-link>`. См. также [router-link](router-link.md).\n\n### linkExactActiveClass\n\n> Добавлено в версии 2.5.0+\n\n- Тип: `string`\n\n- По умолчанию: `\"router-link-exact-active\"`\n\n  Глобально настраивает для `<router-link>` активный класс по умолчанию для точных совпадений маршрута. См. также [router-link](router-link.md).\n\n### scrollBehavior\n\n- тип: `Function`\n\n  Сигнатура:\n\n  ```\n  type PositionDescriptor =\n    { x: number, y: number } |\n    { selector: string } |\n    ?{}\n\n  type scrollBehaviorHandler = (\n    to: Route,\n    from: Route,\n    savedPosition?: { x: number, y: number }\n  ) => PositionDescriptor | Promise<PositionDescriptor>\n  ```\n\n  Для подробностей см. [Скроллинг](../advanced/scroll-behavior.md).\n\n### parseQuery / stringifyQuery\n\n> Добавлено в версии 2.4.0+\n\n- Тип: `Function`\n\n  Пользовательские функции для парсинга строки запроса / приведения к строке запроса (функции stringify). Переопределяют значения по умолчанию.\n\n### fallback\n\n> 2.6.0+\n\n- Тип: `boolean`\n\n  Контролирует, должен ли маршрутизатор возвращаться в режим `hash`, когда браузер не поддерживает `history.pushState`. По умолчанию значение `true`.\n\n  Установка этого параметра в `false` будет вызывать для каждой навигации через `router-link` полное обновление страницы в IE9. Это может быть полезным, когда приложение рендерится на стороне сервера и должно работать в IE9, потому что режим `hash` не работает с SSR.\n"
  },
  {
    "path": "docs-gitbook/ru/api/route-object.md",
    "content": "# Объект Route\n\n**Объект Route** содержит состояние текущего активного пути, а именно: структурированную информацию о текущем URL и **записи путей**, совпавшие с ним.\n\nОбъект пути иммутабелен: при каждом навигационном переходе он пересоздаётся заново.\n\nОбъекты пути могут быть обнаружены в нескольких местах:\n\n- В компонентах, в виде `this.$route`\n\n- В коллбэках при отслеживании `$route`\n\n- Как возвращаемое значение при вызове `router.match(location)`\n\n- В качестве первых двух параметров сторожевых хуков:\n\n  ``` js\n  router.beforeEach((to, from, next) => {\n    // как `to` так и `from` являются объектами пути\n  })\n  ```\n\n- В качестве первых двух параметров функции `scrollBehavior` :\n\n  ``` js\n  const router = new VueRouter({\n    scrollBehavior (to, from, savedPosition) {\n      // как `to` так и `from` являются объектами пути\n    }\n  })\n  ```\n\n### Свойства объекта Route\n\n- **$route.path**\n\n  - тип: `string`\n\n    Строковое значение path текущего пути, всегда в абсолютном формате, напр. `\"/foo/bar\"`.\n\n- **$route.params**\n\n  - тип: `Object`\n\n    Объект, содержащий пары ключ/значение для динамических сегментов (включая *-сегменты). Будет пустым, если параметров у пути нет.\n\n- **$route.query**\n\n  - тип: `Object`\n\n    Объект, содержащий пары ключ/значение для строки запроса (query string). Например, для пути `/foo?user=1` получится `$route.query.user == 1`. При отсутствии строки запроса, будет пустым объектом.\n\n- **$route.hash**\n\n  - тип: `string`\n\n    Хэш текущего пути (с символом `#`), если присутствует. В противном случае — пустая строка.\n\n- **$route.fullPath**\n\n  - тип: `string`\n\n    Полная запись URL, включая строку запроса и хэш.\n\n- **$route.matched**\n\n  - тип: `Array<RouteRecord>`\n\n  Массив, содержащий **записи путей** для всех вложенных сегментов текущего пути. Записи путей — это копии объектов конфигурации из массива `routes` (и вложенных массивов `children`):\n\n  ``` js\n  const router = new VueRouter({\n    routes: [\n      // объект ниже — это запись пути\n      { path: '/foo', component: Foo,\n        children: [\n          // это — тоже запись пути\n          { path: 'bar', component: Bar }\n        ]\n      }\n    ]\n  })\n  ```\n\n  Для URL, равного `/foo/bar`, `$route.matched` будет массивом, содержащим копии обоих объектов, в порядке сортировки от родителя к потомку.\n\n- **$route.name**\n\n  Имя текущего пути, если указано. (См. [Именованные пути](../essentials/named-routes.md))\n"
  },
  {
    "path": "docs-gitbook/ru/api/router-instance.md",
    "content": "# Экземпляр Router\n\n### Свойства\n\n#### router.app\n\n- тип: `Vue instance`\n\n  Корневой экземпляр Vue, в который был интегрирован `router`.\n\n#### router.mode\n\n- тип: `string`\n\n  [Режим](options.md#mode), используемый роутером.\n\n#### router.currentRoute\n\n- тип: `Route`\n\n  Текущий путь в виде [объекта Route](route-object.md).\n\n### Методы\n\n- **router.beforeEach(guard)**\n- **router.beforeResolve(guard)** (добавлено в версии 2.5.0+)\n- **router.afterEach(hook)**\n\n  См. [сторожевые хуки](../advanced/navigation-guards.md).\n\n  С версии 2.5.0+ все три метода возвращают функцию, которая удаляет зарегистрированный хук.\n\n- **router.push(location, onComplete?, onAbort?)**\n- **router.replace(location, onComplete?, onAbort?)**\n- **router.go(n)**\n- **router.back()**\n- **router.forward()**\n\n  Методы для императивного перехода к новому URL. См. [Императивная навигация](../essentials/navigation.md).\n\n- **router.getMatchedComponents(location?)**\n\n  Возвращает массив компонентов (определение/конструктор, не экземпляры), совпадающих с текущим путём. В основном используется во время рендеринга на сервере для получения необходимых данных.\n\n- **router.resolve(location, current?, append?)**\n\n  > 2.1.0+\n\n  Служит для обратного разрешения URL. Получая на вход путь в том же формате, что используется `<router-link/>`, возвращает объект со следующими свойствами:\n\n  ``` js\n  {\n    location: Location;\n    route: Route;\n    href: string;\n  }\n  ```\n\n  - `current` — текущий маршрут по умолчанию (в большинстве случаем вам не нужно это изменять)\n  - `append` — позволяет вам добавить путь к маршруту `current` (например, с помощью [`router-link`](router-link.md#props))\n\n- **router.addRoutes(routes)**\n\n  > 2.2.0+\n\n  Динамически добавить дополнительные маршруты в маршрутизатор. Аргументом должен быть массив маршрутов в таком же формате как и в опции `routes` конструктора.\n\n- **router.onReady(callback[, errorCallback])**\n\n  > 2.2.0+\n\n  Этот метод добавляет в очередь коллбек, который будет вызван когда маршрутизатор завершит начальную навигацию, что означает что будут завершены все асинхронные хуки и будут готовы асинхронные компоненты связанные с начальным маршрутом.\n\n  Это будет полезно при рендеринге на стороне сервера для обеспечения одинакового результата как на сервере, так и на клиенте.\n\n  Второй аргумент `errorCallback` поддерживается только в версиях 2.4+. Он вызывается, когда исходное разрешение маршрута заканчивается ошибкой (например, не удалось разрешить асинхронный компонент).\n\n- **router.onError(callback)**\n\n  > Добавлено в версии 2.4.0+\n\n  Регистрация коллбека, который будет вызываться при ошибках во время навигации по маршруту. Обратите внимание, что для вызова ошибки должен быть использован один из следующих сценариев:\n\n  - Ошибка произошла синхронно внутри функции маршрута;\n\n  - Ошибка фиксируется и асинхронно обрабатывается с помощью `next(err)` внутри функции сторожевого хука;\n\n  - Произошла ошибка при попытке разрешить асинхронный компонент, необходимый для отображения маршрута.\n"
  },
  {
    "path": "docs-gitbook/ru/api/router-link.md",
    "content": "# `<router-link>`\n\n`<router-link>` — это компонент, используемый для создания ссылок в приложениях, использующих клиентский роутинг. Целевой путь указывается во входном параметре `to`. По умолчанию используется тег `<a>` и параметр `href`, но это поведение можно изменить указанием входного параметра `tag`. Кроме того, для ссылки автоматически устанавливается CSS-класс при активации соответствующего пути.\n\nИспользование `<router-link>` предпочтительнее, чем создание ссылок `<a href=\"...\">` вручную, по следующим причинам:\n\n- Единообразие вне зависимости от используемого режима навигации (HTML history или хеши), из-за чего не потребуется вносить изменения в код, если вы захотите сменить режим (или если приложение окажется открыто в IE9, не поддерживающем HTML history mode).\n\n- В HTML5 history mode, `router-link` перехватывает клики, что предотвращает попытки браузера перезагрузить страницу.\n\n- При использовании опции `base` в HTML5 history mode нет необходимости включать префиксы URL при указании входных параметров `to`.\n\n\n### Входные параметры\n\n- **to**\n\n  - тип: `string | Location`\n\n  - обязательный\n\n  Указывает целевой путь ссылки. При клике, значение `to` будет передано в `router.push()` — поэтому им может быть как строка, так и описывающий путь объект.\n\n  ``` html\n  <!-- строка -->\n  <router-link to=\"home\">Home</router-link>\n  <!-- результат рендеринга -->\n  <a href=\"home\">Home</a>\n\n  <!-- javascript-выражение через `v-bind` -->\n  <router-link v-bind:to=\"'home'\">Home</router-link>\n\n  <!-- Можно использовать сокращенную запись `v-bind` -->\n  <router-link :to=\"'home'\">Home</router-link>\n\n  <!-- даст тот же результат -->\n  <router-link :to=\"{ path: 'home' }\">Home</router-link>\n\n  <!-- с использованием именованного пути -->\n  <router-link :to=\"{ name: 'user', params: { userId: 123 }}\">User</router-link>\n\n  <!-- с использованием строки запроса, получим `/register?plan=private` -->\n  <router-link :to=\"{ path: 'register', query: { plan: 'private' }}\">Register</router-link>\n  ```\n\n- **replace**\n\n  - тип: `boolean`\n\n  - значение по умолчанию: `false`\n\n  При указании параметра `replace` вместо `router.push()` при клике будет вызываться `router.replace()`, и переход не оставит следов в браузерной истории.\n\n  ``` html\n  <router-link :to=\"{ path: '/abc'}\" replace></router-link>\n  ```\n\n- **append**\n\n  - тип: `boolean`\n\n  - значение по умолчанию: `false`\n\n  Указание параметра `append` заставляет считать пути по умолчанию относительными. Например, при переходе с `/a` по относительной ссылке `b`, без указания `append` мы получим `/b`, а с указанием этого параметра — `/a/b`.\n\n  ``` html\n  <router-link :to=\"{ path: 'relative/path'}\" append></router-link>\n  ```\n\n- **tag**\n\n  - тип: `string`\n\n  - значение по умолчанию: `\"a\"`\n\n  Время от времени хотелось бы, чтобы `<router-link>` использовал иной тег, например `<li>`. Мы можем использовать входной параметр `tag` для этих целей, и получившийся элемент всё так же будет реагировать на клики для навигации.\n\n  ``` html\n  <router-link to=\"/foo\" tag=\"li\">foo</router-link>\n  <!-- отобразится как -->\n  <li>foo</li>\n  ```\n\n- **active-class**\n\n  - тип: `string`\n\n  - значение по умолчанию: `\"router-link-active\"`\n\n  В этом параметре можно изменить CSS-класс, применяемый к активным ссылкам. Обратите внимание, что значение по умолчанию тоже может быть изменено при помощи опции `linkActiveClass` конструктора роутера.\n\n- **exact**\n\n  - тип: `boolean`\n\n  - значение по умолчанию: `false`\n\n  По умолчанию активность ссылки устанавливается по стратегии **совпадения по включению**. Например, для `<router-link to=\"/a\">` класс активности будет применён для всех ссылок, начинающихся с `/a/` или `/a`.\n\n  Одним из следствий этого подхода является тот факт, что корневая ссылка `<router-link to=\"/\">` будет считаться активной всегда. Чтобы заставить ссылку считаться активной только при полном совпадении, используйте входной параметр `exact`:\n\n  ``` html\n  <!-- эта ссылка будет активной только для корневого пути `/` -->\n  <router-link to=\"/\" exact>\n  ```\n\n  Больше примеров с подробными объяснениями использования класса активности можно найти [здесь](https://jsfiddle.net/8xrk1n9f/).\n\n- **event**\n\n  > 2.1.0+\n\n  - тип: `string | Array<string>`\n\n  - значение по умолчанию: `'click'`\n\n  Указывает событие(я), способные вызвать переход по ссылке.\n\n- **exact-active-class**\n\n  > Добавлено в версии 2.5.0+\n\n  - Тип: `string`\n\n  - По умолчанию: `\"router-link-exact-active\"`\n\n  Укажите активный CSS-класс, применяемый когда ссылка активна с точным соответствием маршрута. Обратите внимание, что значение по умолчанию также может быть настроено глобально с помощью опции `linkExactActiveClass` в конструкторе VueRouter.\n\n### Применение класса активности ко внешнему элементу\n\nИногда хочется применить класс активности не к самому тегу `<a>`, а к другому элементу. Для этих целей можно использовать `<router-link>` для наружного элемента, а ссылку разместить внутри, вручную:\n\n``` html\n<router-link tag=\"li\" to=\"/foo\">\n  <a>/foo</a>\n</router-link>\n```\n\nVue-router поймёт, что в качестве ссылки нужно использовать вложенный элемент (и укажет правильное значение `href` для неё), но вот класс активности будет применяться ко внешнему элементу `<li>`.\n"
  },
  {
    "path": "docs-gitbook/ru/api/router-view.md",
    "content": "# `<router-view>`\n\n`<router-view>` — это функциональный компонент, отображающий соответствующее текущему пути представление. Компоненты, отображаемые на месте `<router-view>` могут сами содержать вложенные `<router-view>`, что позволяет организовать иерархию вложенных путей.\n\n\n### Входные параметры\n\n- **name**\n\n  - тип: `string`\n\n  - значение по умолчанию: `\"default\"`\n\n  Если для `<router-view>` указывается имя, на его месте отобразится компонент, для которого в записи пути указано соответствующее имя в опции `components`. Для подробностей и примера см. [именованные представления](../essentials/named-views.md).\n\n\n### Поведение\n\nВсе остальные входные параметры будут напрямую переданы отображаемому компоненту представления. Тем не менее, чаще всего данные уровня пути содержатся в параметрах пути (`$route.params`).\n\nПоскольку мы имеем дело всего лишь с обыкновенным компонентом, можно использовать обёртки `<transition>` и `<keep-alive>`. Если вы используете оба, удостоверьтесь, что `<keep-alive>` располагается внутри:\n\n``` html\n<transition>\n  <keep-alive>\n    <router-view></router-view>\n  </keep-alive>\n</transition>\n```\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/dynamic-matching.md",
    "content": "# Динамические пути\n\nОчень часто требуется сопоставить компонент с множеством путей по указанному шаблону. Например, мы можем использовать компонент `User` для всех пользователей в соответствии с их ID. Во `Vue-router` мы можем указать динамический сегмент в пути для этой цели:\n\n``` js\nconst User = {\n  template: '<div>User</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    // динамические сегменты начинаются с двоеточия\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nТеперь все URL вида `/user/foo` или `/user/bar` соответствуют одному пути.\n\nДинамический сегмент обозначается двоеточием `:`. При совпадении пути, значение динамического сегмента можно получить через `this.$route.params` для каждого компонента. Например, мы можем отобразить ID текущего пользователя, немного изменив шаблон:\n\n``` js\nconst User = {\n  template: '<div>Пользователь {{ $route.params.id }}</div>'\n}\n```\n\nПосмотреть на пример вживую можно [здесь](https://jsfiddle.net/yyx990803/4xfa2f19/).\n\nМожет быть несколько динамических сегментов в одном пути. Для каждого сегмента появится соответствующее свойство в `$route.params`. Например:\n\n| Шаблон | Совпадающий путь | $route.params |\n|---------|------|--------|\n| /user/:username | /user/evan | `{ username: 'evan' }` |\n| /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` |\n\nПомимо `$route.params`, объект `$route` также позволяет получить доступ к другой полезной информации, например `$route.query` (если URL содержит строку запроса), `$route.hash`, и т.д. Подробнее в [справочнике API](../api/route-object.md).\n\n### Отслеживание изменений параметров\n\nВажно отметить, что при переходе от `/user/foo` к `/user/bar` **будет повторно использован тот же самый экземпляр компонента**. Поскольку оба пути указывают на один и тот же компонент, этот подход эффективнее, чем уничтожение и повторное создание экземпляра. **Но это означает, что хуки жизненного цикла компонента при этом вызваны не будут**.\n\nЧтобы отследить изменения параметров пути в рамках компонента, нужно просто установить наблюдение за объектом `$route`:\n\n``` js\nconst User = {\n  template: '...',\n  watch: {\n    '$route' (to, from) {\n      // обработка изменений параметров пути...\n    }\n  }\n}\n```\n\nИли можно воспользоваться хуком `beforeRouteUpdate`, добавленным в версии 2.2:\n\n``` js\nconst User = {\n  template: '...',\n  beforeRouteUpdate (to, from, next) {\n    // обработка изменений параметров пути...\n    // не забудьте вызывать next()\n  }\n}\n```\n\n### Продвинутые возможности\n\n`Vue-router` использует [path-to-regexp](https://github.com/pillarjs/path-to-regexp) в качестве движка для проверки совпадения путей, что позволяет задействовать многие продвинутые возможности, включая опциональные динамические сегменты и регулярные выражения. [Документация библиотеки](https://github.com/pillarjs/path-to-regexp#parameters) содержит информацию об этих возможностях роутинга, а [этот пример](https://github.com/vuejs/vue-router/blob/dev/examples/route-matching/app.js) — о том, как использовать их совместно с `Vue-router`.\n\n### Приоритетность при совпадении путей\n\nИногда один и тот же URL может совпасть с несколькими путями. В таких случаях приоритет определяется порядком определения путей: чем раньше определён путь, тем выше у него приоритет.\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/getting-started.md",
    "content": "# Введение\n\n> В примерах используется синтаксис [ES2015](https://github.com/lukehoban/es6features).\n\nСоздать одностраничное приложение используя Vue.js и Vue-router очень просто. Используя Vue.js, мы уже компонуем своё приложение из компонентов. Добавляя Vue-router, мы просто сопоставляем компонентам пути, и указываем, где именно их отображать. Вот простой пример:\n\n> Все примеры используют полную сборку Vue, которая позволяет использовать парсинг шаблонов. Подробнее о разнице сборок можно почитать [в документации к Vue.js](https://ru.vuejs.org/v2/guide/installation.html#Объяснение-различных-сборок).\n\n### HTML\n\n``` html\n<script src=\"https://unpkg.com/vue/dist/vue.js\"></script>\n<script src=\"https://unpkg.com/vue-router/dist/vue-router.js\"></script>\n\n<div id=\"app\">\n  <h1>Hello App!</h1>\n  <p>\n    <!-- используйте компонент router-link для создания ссылок -->\n    <!-- входной параметр `to` определяет путь для перехода -->\n    <!-- `<router-link>` по умолчанию преобразуется в тег `<a>` -->\n    <router-link to=\"/foo\">Go to Foo</router-link>\n    <router-link to=\"/bar\">Go to Bar</router-link>\n  </p>\n  <!-- отображение компонента, для которого совпал путь -->\n  <router-view></router-view>\n</div>\n```\n\n### JavaScript\n\n``` js\n// 0. При использовании модульной системы (напр. vue-cli),\n// импортируйте Vue и VueRouter и затем вызовите `Vue.use(VueRouter)`\n\n// 1. Определение используемых компонентов\n// Они могут быть импортированы из внешних файлов\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n// 2. Определение путей\n// Каждый путь должен указывать на компонент\n// \"Компонентом\" может быть как созданный через `Vue.extend()`\n// полноценный конструктор, так и просто объект с настройками компонента\n// Вложенные пути будут рассмотрены далее.\nconst routes = [\n  { path: '/foo', component: Foo },\n  { path: '/bar', component: Bar }\n]\n\n// 3. Создаём экземпляр роутера с опцией `routes`\n// Можно передать и другие опции, но пока не будем усложнять\nconst router = new VueRouter({\n  routes // сокращение от `routes: routes`\n})\n\n// 4. Создаём и монтируем корневой экземпляр Vue нашего приложения.\n// Удостоверьтесь, что передали экземпляр роутера в опции `router`,\n// что позволит приложению знать о его наличии\nconst app = new Vue({\n  router\n}).$mount('#app')\n\n// Всё, приложение работает! ;)\n```\n\nУстановив маршрутизатор, мы можем получить к нему доступ через `this.$router`, а также к текущему маршруту через `this.$route` внутри любого компонента:\n\n```js\n// Home.vue\nexport default {\n  computed: {\n    username () {\n      // Мы скоро разберём что такое `params`\n      return this.$route.params.username\n    }\n  },\n  methods: {\n    goBack () {\n      window.history.length > 1\n        ? this.$router.go(-1)\n        : this.$router.push('/')\n    }\n  }\n}\n```\n\nВ документации мы будем часто использовать экземпляр `router` (маршрутизатора). Имейте ввиду, что `this.$router` в точности тоже самое, что и `router`. Причина, по которой мы используем `this.$router` заключается в том, что мы не хотим импортировать маршрутизатор в каждом компоненте, в котором потребуется управлять маршрутизацией.\n\nВживую этот пример доступен [здесь](https://jsfiddle.net/yyx990803/xgrjzsup/).\n\nОбратите внимание, что `<router-link>` автоматически получает класс `.router-link-active` при совпадении пути. Подробнее об этом можно узнать в [справочнике API](../api/router-link.md).\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/history-mode.md",
    "content": "# Режим HTML5 History\n\nРежимом по умолчанию для `Vue-router` является _hash mode_, использующий хэш URL'а для симуляции полного URL-адреса, что позволяет избежать перезагрузки страницы при изменении URL.\n\nМы можем обойтись без хэша, используя **history mode**, который работает с API `history.pushState` для достижения той же цели:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [...]\n})\n```\n\nПри использовании history mode URL выглядит естественно, например: `http://oursite.com/user/id`. Прекрасно!\n\nВозникает, однако, и проблема: поскольку наше приложение — одностраничное, не сконфигурировав соответствующим образом сервер мы заставим пользователей получать ошибку 404, если они перейдут по `http://oursite.com/user/id` напрямую. Вот это уже прекрасным не назвать.\n\nНе спешите расстраиваться: всё, что нужно — единственная \"резервная\" запись в конфигурации сервера. Если URL не совпадает ни с одним статическим файлом, сервер должен просто отдать `index.html`, в котором и живёт наше приложение. И снова, прекрасно!\n\n## Примеры конфигурации серверов\n\n#### Apache\n\n```apache\n<IfModule mod_rewrite.c>\n  RewriteEngine On\n  RewriteBase /\n  RewriteRule ^index\\.html$ - [L]\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteRule . /index.html [L]\n</IfModule>\n```\n\n#### nginx\n\n```nginx\nlocation / {\n  try_files $uri $uri/ /index.html;\n}\n```\n\n#### Node.js\n\n```js\nconst http = require('http')\nconst fs = require('fs')\nconst httpPort = 80\n\nhttp.createServer((req, res) => {\n  fs.readFile('index.htm', 'utf-8', (err, content) => {\n    if (err) {\n      console.log('Невозможно открыть файл \"index.htm\".')\n    }\n\n    res.writeHead(200, {\n      'Content-Type': 'text/html; charset=utf-8'\n    })\n\n    res.end(content)\n  })\n}).listen(httpPort, () => {\n  console.log('Сервер запущен на: http://localhost:%s', httpPort)\n})\n```\n\n#### Node.js c использованием Express\n\nПри использовании Node.js/Express, мы рекомендуем пользоваться [connect-history-api-fallback middleware](https://github.com/bripkens/connect-history-api-fallback).\n\n#### Internet Information Services (IIS)\n\n1. Установить [IIS UrlRewrite](https://www.iis.net/downloads/microsoft/url-rewrite)\n2. Создать файл `web.config` в корневом каталоге вашего сайта со следующим содержимым:\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <rewrite>\n      <rules>\n        <rule name=\"Handle History Mode and custom 404/500\" stopProcessing=\"true\">\n          <match url=\"(.*)\" />\n          <conditions logicalGrouping=\"MatchAll\">\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsFile\" negate=\"true\" />\n            <add input=\"{REQUEST_FILENAME}\" matchType=\"IsDirectory\" negate=\"true\" />\n          </conditions>\n          <action type=\"Rewrite\" url=\"/\" />\n        </rule>\n      </rules>\n    </rewrite>\n  </system.webServer>\n</configuration>\n```\n\n#### Caddy\n\n```\nrewrite {\n    regexp .*\n    to {path} /\n}\n```\n\n#### Хостинг Firebase\n\nДобавьте в файл `firebase.json`:\n\n```\n{\n  \"hosting\": {\n    \"public\": \"dist\",\n    \"rewrites\": [\n      {\n        \"source\": \"**\",\n        \"destination\": \"/index.html\"\n      }\n    ]\n  }\n}\n```\n\n## Предостережение\n\nПри таком подходе возникает одно неприятное последствие: сервер больше не будет выдавать ошибки 404, так как обслуживание всех путей отдаётся на откуп клиентскому роутингу. Частично эту проблему можно решить, указав путь по умолчанию во Vue-router:\n\n``` js\nconst router = new VueRouter({\n  mode: 'history',\n  routes: [\n    { path: '*', component: NotFoundComponent }\n  ]\n})\n```\n\nЕсли же вы используете на сервере Node.js, уже на стороне сервера можно задействовать конфигурацию роутера и решить таким образом проблему целиком. Ознакомьтесь с [руководством по серверному рендерингу Vue.js](https://ssr.vuejs.org/ru/) для получения дополнительной информации.\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/named-routes.md",
    "content": "# Именованные пути\n\nЗачастую, при создании ссылок и вызове навигационных методов, удобно ссылаться на путь по его имени. Установить имя пути можно в опциях `routes` при создании экземпляра Router'а:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:userId',\n      name: 'user',\n      component: User\n    }\n  ]\n})\n```\n\nЧтобы создать ссылку на именованный маршрут, вы можете передать объект в компонент `router-link` используя входной параметр `to`:\n\n``` html\n<router-link :to=\"{ name: 'user', params: { userId: 123 }}\">Пользователь</router-link>\n```\n\nТот же самый объект можно использовать и для императивного вызова `router.push()`:\n\n``` js\nrouter.push({ name: 'user', params: { userId: 123 }})\n```\n\nВ обоих случаях результатом будет навигационный переход на `/user/123`.\n\nПолный пример находится [здесь](https://github.com/vuejs/vue-router/blob/dev/examples/named-routes/app.js).\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/named-views.md",
    "content": "# Именованные представления\n\nИногда необходимо отобразить сразу несколько компонентов, не вкладывая их один в другой — например, при создании разметки с боковой панелью и основным контентом. В этой ситуации может быть удобно использовать именованные представления. Вместо указания единственного `<router-view>`, можно использовать несколько, присвоив каждому собственное имя. Безымянный `router-view` автоматически получает имя `default`.\n\n``` html\n<router-view class=\"view one\"></router-view>\n<router-view class=\"view two\" name=\"a\"></router-view>\n<router-view class=\"view three\" name=\"b\"></router-view>\n```\n\nПри использовании нескольких представлений, вместо единственного компонента при описании пути необходимо указывать объект. Удостоверьтесь, что используете окончание множественного числа (`s`) в ключе `components`:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    }\n  ]\n})\n```\n\nРабочее демо этого примера можно найти [здесь](https://jsfiddle.net/posva/6du90epg/).\n\n## Вложенные именованные маршруты\n\nВозможно и создание сложных шаблонов используя именованные представления с вложенными представлениями. При этом вам также нужно будет именовать используемые вложенные компоненты `router-view`. Разберём пример панели настроек:\n\n```\n/settings/emails                                       /settings/profile\n+-----------------------------------+                  +------------------------------+\n| UserSettings                      |                  | UserSettings                 |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |\n| |     +-------------------------+ |                  | |     +--------------------+ |\n| |     |                         | |                  | |     | UserProfilePreview | |\n| +-----+-------------------------+ |                  | +-----+--------------------+ |\n+-----------------------------------+                  +------------------------------+\n```\n\n- `Nav` это просто обычный компонент\n- `UserSettings` компонент представления\n- `UserEmailsSubscriptions`, `UserProfile`, `UserProfilePreview` вложенные компоненты представлений\n\n**Примечание**: _Давайте опустим как должен выглядеть HTML/CSS для реализации подобного шаблона и сосредоточимся на используемых компонентах_\n\nСекция `<template>` компонента `UserSettings` будет выглядеть примерно так:\n\n```html\n<!-- UserSettings.vue -->\n<div>\n  <h1>Настройки пользователя</h1>\n  <NavBar/>\n  <router-view/>\n  <router-view name=\"helper\"/>\n</div>\n```\n\n_Вложенные компоненты представлений опущены здесь, но вы можете найти полные исходные коды примера [здесь](https://jsfiddle.net/posva/22wgksa3/)_\n\nЗатем вы можете достичь компоновки шаблона выше с помощью конфигурации маршрута:\n\n```js\n{\n  path: '/settings',\n  // Вы могли также иметь именованные представления в верхней части\n  component: UserSettings,\n  children: [{\n    path: 'emails',\n    component: UserEmailsSubscriptions\n  }, {\n    path: 'profile',\n    components: {\n      default: UserProfile,\n      helper: UserProfilePreview\n    }\n  }]\n}\n```\n\nРабочее демо этого примера можно найти [здесь](https://jsfiddle.net/posva/22wgksa3/).\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/navigation.md",
    "content": "# Императивная навигация\n\nПомимо декларативного использования `<router-link>` для создания ссылок, можно использовать роутер и императивно, напрямую вызывая методы его экземпляра.\n\n#### `router.push(location, onComplete?, onAbort?)`\n\n**Примечание: Внутри экземпляра Vue у вас есть доступ к экземпляру маршрутизатора через `$router`. Поэтому вы можете вызвать `this.$router.push`.**\n\nДля перехода к новому URL, используйте `router.push`. Этот метод добавляет новую запись в стек истории навигации, что позволяет клику пользователя по кнопке \"назад\" в браузере сработать привычным образом.\n\nПри клике на `<router-link>` этот метод вызывается автоматически. Клик по `<router-link :to=\"...\">` эквивалентен императивному вызову `router.push(...)`.\n\n| Декларативная запись      | Императивная запись |\n|---------------------------|---------------------|\n| `<router-link :to=\"...\">` | `router.push(...)`  |\n\nВ качестве аргумента можно передать строку или объект, описывающий путь. Например:\n\n``` js\n// строка\nrouter.push('home')\n\n// объект\nrouter.push({ path: 'home' })\n\n// именованный путь\nrouter.push({ name: 'user', params: { userId: 123 }})\n\n// со строкой запроса, получится /register?plan=private\nrouter.push({ path: 'register', query: { plan: 'private' }})\n```\n\n**Примечание**: `params` игнорируются, если указан `path`, что не соответствует случаю с `query` показанному в примере выше.\nВместо этого, вам нужно указать `name` маршрута или вручную указать весь `path` с необходимыми параметрами:\n\n```js\nconst userId = 123\nrouter.push({ name: 'user', params: { userId }}) // -> /user/123\nrouter.push({ path: `/user/${userId}` }) // -> /user/123\n// Это НЕ БУДЕТ работать\nrouter.push({ path: '/user', params: { userId }}) // -> /user\n```\n\nТе же правила применяются и к свойству `to` компонента `router-link`.\n\nВ версии 2.2.0+, можно указать опциональные `onComplete` и `onAbort` коллбеки в `router.push` или `router.replace` в качестве 2-го и 3-го аргументов. Эти коллбеки будут вызываться когда навигация либо успешно завершена (после того как все асинхронные хуки будут завершены), или прервана (переходом на этот же маршрут, или на другой маршрут прежде чем текущая навигация будет завершена), соответственно.\n\n**Примечание:** Если путь назначения совпадает с текущим маршрутом и меняются только параметры (например, переход из одного профиля в другой `/users/1` -> `/users/2`), вам потребуется использовать [`beforeRouteUpdate`](./dynamic-matching.html#отслеживание-изменений-параметров) чтобы реагировать на изменения (например, получение информации о пользователе).\n\n#### `router.replace(location, onComplete?, onAbort?)`\n\nДействует подобно `router.push`, с той лишь разницей, что вместо добавления новой записи к стеку истории переходов, заменяет текущую запись в нём.\n\n| Декларативная запись              |  Императивная запись  |\n|-----------------------------------|-----------------------|\n| `<router-link :to=\"...\" replace>` | `router.replace(...)` |\n\n#### `router.go(n)`\n\nЕдинственным параметром этого метода является целое число, указывающее на сколько шагов необходимо перейти по стеку истории навигации (вперёд или назад, аналогично `window.history.go(n)`.\n\nПримеры\n\n``` js\n// перейти на одну запись вперёд, эквивалентно history.forward()\nrouter.go(1)\n\n// перейти на одну запись назад, эквивалентно history.back()\nrouter.go(-1)\n\n// перейти на 3 записи вперёд\nrouter.go(3)\n\n// если записей в истории недостаточно много, перехода просто не произойдёт\nrouter.go(-100)\nrouter.go(100)\n```\n\n#### Манипулирование историей переходов\n\nВы могли заметить, что `router.push`, `router.replace` и `router.go` соответствуют [`window.history.pushState`, `window.history.replaceState` и `window.history.go`](https://developer.mozilla.org/en-US/docs/Web/API/History), имитируя таким образом API `window.history`.\n\nПо этой причине, если вы уже знакомы с [API истории переходов браузера](https://developer.mozilla.org/en-US/docs/Web/API/History_API), то и со Vue-router неожиданностей не возникнет.\n\nСтоит отметить, что методы навигации Vue-router'а (`push`, `replace`, `go`) работают одинаково во всех режимах роутера (`history`, `hash` и `abstract`).\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/nested-routes.md",
    "content": "# Вложенные пути\n\nПользовательский интерфейс реальных приложений обычно представлен многоуровневой иерархией компонентов. Столь же обычно и соответствие сегментов URL некоторой структуре вложенности компонентов, например:\n\n```\n/user/foo/profile                     /user/foo/posts\n+------------------+                  +-----------------+\n| User             |                  | User            |\n| +--------------+ |                  | +-------------+ |\n| | Profile      | |  +------------>  | | Posts       | |\n| |              | |                  | |             | |\n| +--------------+ |                  | +-------------+ |\n+------------------+                  +-----------------+\n```\n\nИспользуя `Vue-router`, мы можем с лёгкостью выразить эти взаимоотношения при помощи вложенных путей.\n\nРассмотрим созданное в предыдущем разделе приложение:\n\n``` html\n<div id=\"app\">\n  <router-view></router-view>\n</div>\n```\n\n``` js\nconst User = {\n  template: '<div>Пользователь {{ $route.params.id }}</div>'\n}\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\nЗдесь `<router-view>` — это точка, в которой будет отображён компонент, соответствующий пути верхнего уровня. Аналогичным образом, отображаемый там компонент может и сам содержать вложенный `<router-view>`. Изменим немного шаблон компонента `User`:\n\n``` js\nconst User = {\n  template: `\n    <div class=\"user\">\n      <h2>Пользователь {{ $route.params.id }}</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n```\n\nДля отображения компонентов в этой вложенной точке, нам понадобится опция `children` в конфигурации конструктора `VueRouter`:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User,\n      children: [\n        {\n          // при совпадении пути с шаблоном /user/:id/profile\n          // в <router-view> компонента User будет отображён UserProfile\n          path: 'profile',\n          component: UserProfile\n        },\n        {\n          // при совпадении с шаблоном /user/:id/posts\n          // в <router-view> компонента User будет отображён UserPosts\n          path: 'posts',\n          component: UserPosts\n        }\n      ]\n    }\n  ]\n})\n```\n\n**Обратите внимание, что вложенные пути, начинающиеся с `/`, будут считаться корневыми. Это позволяет задействовать вложенную структуру компонентов независимо от структуры URL.**\n\nКак вы могли заметить, опция `children` принимает обыкновенный массив объектов конфигурации путей, такой же как и сам `routes`. Таким образом, вложенность путей в теории по глубине ничем не ограничена.\n\nС текущим кодом, если перейти по пути `/user/foo`, внутри компонента `User` ничего отображено не будет, так как не произойдёт совпадения по второй части пути. Может быть, что-то в таких случаях отобразить всё же захочется — тогда стоит указать пустой путь:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/user/:id', component: User,\n      children: [\n        // при совпадении пути с шаблоном /user/:id\n        // в <router-view> компонента User будет отображён UserHome\n        { path: '', component: UserHome },\n\n        // ...остальные вложенные пути\n      ]\n    }\n  ]\n})\n```\n\nДействующее демо этого примера можно найти [здесь](https://jsfiddle.net/yyx990803/L7hscd8h/).\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/passing-props.md",
    "content": "# Передача входных параметров в компоненты маршрутов\n\nИспользование `$route` в вашем компоненте создаёт жёсткую связь с маршрутом, что ограничивает гибкость компонента, потому что он может быть использован только для определённых URL-адресов.\n\nДля разделения компонента от маршрутизатора можно использовать входные параметры:\n\n** Вместо жёсткой связи с `$route`**\n\n``` js\nconst User = {\n  template: '<div>User {{ $route.params.id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User }\n  ]\n})\n```\n\n** Разделяем с помощью входных параметров**\n\n``` js\nconst User = {\n  props: ['id'],\n  template: '<div>User {{ id }}</div>'\n}\nconst router = new VueRouter({\n  routes: [\n    { path: '/user/:id', component: User, props: true },\n\n    // для маршрутов с именованными представлениями, необходимо указывать опцию `props` для каждого именованного представления:\n    {\n      path: '/user/:id',\n      components: { default: User, sidebar: Sidebar },\n      props: { default: true, sidebar: false }\n    }\n  ]\n})\n```\n\nЭто позволяет использовать компонент в любом месте, а также делает его проще для повторного использования и тестирования.\n\n### Булево значение\n\nКогда `props` установлены в `true`, значение `route.params` будут установлены входными параметрами компонента.\n\n### Объект\n\nКогда `props` объект, они будут установлены входными параметрами компонента как есть. Полезно когда входные параметры являются статическими данными.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }\n  ]\n})\n```\n\n### Функция\n\nВы можете создать функцию, которая вернёт объект с входными параметрами. Это позволяет вам приводить параметры к другим типам, комбинировать статические значения с значениями из маршрута, и т.д.\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }\n  ]\n})\n```\n\nСсылка: `/search?q=vue` также передаст `{query: 'vue'}` в качестве входных параметров в компонент `SearchUser`.\n\nСтарайтесь держать функции генерации входных параметров независимыми от состояния, потому что они вызываются только при изменениях маршрута. Используйте компонент обёртку, если вам нужно состояние для определения входных параметров, в таком случае Vue сможет реагировать на изменения состояния.\n\nДля более продвинутого использования, смотрите [пример](https://github.com/vuejs/vue-router/blob/dev/examples/route-props/app.js).\n"
  },
  {
    "path": "docs-gitbook/ru/essentials/redirect-and-alias.md",
    "content": "# Редиректы и псевдонимы\n\n### Редирект\n\nРедиректы также определяются в конфигурации путей `routes`. Для редиректа с `/a` на `/b`, укажите:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: '/b' }\n  ]\n})\n```\n\nВ качестве цели редиректа можно использовать и именованный путь:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: { name: 'foo' }}\n  ]\n})\n```\n\nМожно даже указать функцию для организации динамического редиректа:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', redirect: to => {\n      // в функцию в качестве аргумента передаётся путь\n      // возвращаемым значением должна быть строка или объект пути\n    }}\n  ]\n})\n```\n\nОбратите внимание, что [сторожевые хуки](../advanced/navigation-guards.md) не применяются на маршруте, который служит для перенаправления, только на его цель. В приведённом ниже примере добавление хуков `beforeEnter` или `beforeLeave` на маршрут `/a` не будет иметь никакого эффекта.\n\nДля демонстрации более сложных возможностей, обратите внимание на [этот пример](https://github.com/vuejs/vue-router/blob/dev/examples/redirect/app.js).\n\n### Псевдонимы\n\nПри редиректе, если пользователь переходит по пути `/a`, URL заменяется на `/b` и затем уже `/b` рассматривается как основной путь. В чём отличие псевдонима?\n\n**В случае, когда псевдонимом `/a` является `/b`, при посещении пользователем `/b` URL останется равным `/b`, но роутер выполнит все действия так, как если бы он был равен `/a`.**\n\nВ виде конфигурации роутера вышесказанное может быть выражено так:\n\n``` js\nconst router = new VueRouter({\n  routes: [\n    { path: '/a', component: A, alias: '/b' }\n  ]\n})\n```\n\nПсевдонимы позволяют не ограничиваться вложенными структурами при организации связи URL и UI.\n\nЭтот [пример](https://github.com/vuejs/vue-router/blob/dev/examples/route-alias/app.js) демонстрирует более продвинутое использование возможностей.\n"
  },
  {
    "path": "docs-gitbook/ru/installation.md",
    "content": "# Установка\n\n### Локальный файл / CDN\n\n[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)\n\n[Unpkg.com](https://unpkg.com) предоставляет CDN-ссылки для NPM-пакетов. Ссылка выше всегда указывает на самую последнюю версию Vue-router на NPM. Вы также можете использовать конкретную версию используя ссылки вида `https://unpkg.com/vue-router@2.0.0/dist/vue-router.js`.\n\nПодключите `Vue-router` после Vue, и установка произойдёт автоматически:\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vue-router.js\"></script>\n```\n\n### NPM\n\n``` bash\nnpm install vue-router\n```\n\nПри использовании модульной системы сборки, необходимо явно обозначить использование роутера при помощи `Vue.use()`:\n\n``` js\nimport Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n```\n\nЭто не требуется при подключении через глобальный тег `script`.\n\n### Сборка версии, находящейся в разработке\n\nЕсли вы хотите использовать версию `Vue-router` в разработке, склонируйте репозиторий с GitHub и выполните сборку вручную:\n\n``` bash\ngit clone https://github.com/vuejs/vue-router.git node_modules/vue-router\ncd node_modules/vue-router\nnpm install\nnpm run build\n```\n"
  },
  {
    "path": "examples/active-links/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div><h2>Home</h2></div>' }\nconst About = { template: '<div><h2>About</h2></div>' }\n\nconst Users = {\n  template: `\n    <div>\n      <h2>Users</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n\nconst User = { template: '<div>{{ $route.params.username }}</div>' }\n\nconst Gallery = {\n  template: `\n    <div>\n      <h2>Gallery</h2>\n      <router-view></router-view>\n    </div>\n  `\n}\n\nconst Image = { template: '<div>{{ $route.params.imageId }}</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    { path: '/about', component: About },\n    {\n      path: '/redirect-gallery',\n      name: 'redirect-gallery',\n      redirect: { name: 'gallery' }\n    },\n    {\n      path: '/redirect-image',\n      name: 'redirect-image',\n      redirect: { name: 'image', params: { imageId: 'image1' }}\n    },\n    {\n      path: '/users',\n      component: Users,\n      children: [{ path: ':username', name: 'user', component: User }]\n    },\n    {\n      path: '/gallery',\n      component: Gallery,\n      children: [\n        {\n          path: '',\n          name: 'gallery',\n          redirect: { name: 'image', params: { imageId: 'image1' }}\n        },\n        { path: ':imageId', component: Image, name: 'image' }\n      ]\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Active Links</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/\" exact>/ (exact match)</router-link></li>\n\n        <li><router-link to=\"/users\">/users</router-link></li>\n        <li><router-link to=\"/users\" exact>/users (exact match)</router-link></li>\n\n        <li><router-link to=\"/users/evan\">/users/evan</router-link></li>\n        <li><router-link to=\"/users/evan#foo\">/users/evan#foo</router-link></li>\n        <li>\n          <router-link :to=\"{ path: '/users/evan', query: { foo: 'bar' }}\">\n            /users/evan?foo=bar\n          </router-link>\n        </li>\n        <li><!-- #635 -->\n          <router-link :to=\"{ name: 'user', params: { username: 'evan' }, query: { foo: 'bar' }}\" exact>\n            /users/evan?foo=bar (named view + exact match)\n          </router-link>\n        </li>\n        <li>\n          <router-link :to=\"{ path: '/users/evan', query: { foo: 'bar', baz: 'qux' }}\">\n            /users/evan?foo=bar&baz=qux\n          </router-link>\n        </li>\n\n        <li><router-link to=\"/about\">/about</router-link></li>\n\n        <router-link tag=\"li\" to=\"/about\">\n          <a>/about (active class on outer element)</a>\n        </router-link>\n\n        <li><router-link to=\"/gallery\">/gallery (redirect to /gallery/image1)</router-link></li>\n        <li><router-link :to=\"{ name: 'gallery' }\">/gallery named link (redirect to /gallery/image1)</router-link></li>\n        <li><router-link :to=\"{ name: 'image', params: {imageId: 'image2'} }\">/gallery/image2</router-link></li>\n        <li><router-link :to=\"{ name: 'image', params: {imageId: 'image1'} }\">/gallery/image1</router-link></li>\n        <li><router-link to=\"/redirect-gallery\">/redirect-gallery (redirect to /gallery)</router-link></li>\n        <li><router-link :to=\"{ name: 'redirect-gallery' }\">/redirect-gallery named (redirect to /gallery)</router-link></li>\n        <li><router-link to=\"/redirect-image\">/redirect-image (redirect to /gallery/image1)</router-link></li>\n        <li><router-link :to=\"{ name: 'redirect-image' }\" >/redirect-image named (redirect to /gallery/image1)</router-link></li>\n\n        <li><router-link to=\"/users?one\" exact-path>/users?one</router-link></li>\n        <li><router-link to=\"/users?two\" exact-path>/users?two</router-link></li>\n        <li><router-link to=\"/users/nested?two\" exact-path>/users/nested?two</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/active-links/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<style>\na.router-link-active, li.router-link-active a {\n  color: #f66;\n}\na.router-link-exact-active, li.router-link-exact-active a {\n  border-bottom: 1px solid #f66;\n}\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/active-links.js\"></script>\n"
  },
  {
    "path": "examples/auth-flow/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nimport auth from './auth'\nimport App from './components/App.vue'\nimport About from './components/About.vue'\nimport Dashboard from './components/Dashboard.vue'\nimport Login from './components/Login.vue'\n\nfunction requireAuth (to, from, next) {\n  if (!auth.loggedIn()) {\n    next({\n      path: '/login',\n      query: { redirect: to.fullPath }\n    })\n  } else {\n    next()\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/about', component: About },\n    { path: '/dashboard', component: Dashboard, beforeEnter: requireAuth },\n    { path: '/login', component: Login },\n    { path: '/logout',\n      beforeEnter (to, from, next) {\n        auth.logout()\n        next('/')\n      }\n    }\n  ]\n})\n\n/* eslint-disable no-new */\nnew Vue({\n  el: '#app',\n  router,\n  // replace the content of <div id=\"app\"></div> with App\n  render: h => h(App)\n})\n"
  },
  {
    "path": "examples/auth-flow/auth.js",
    "content": "/* globals localStorage */\n\nexport default {\n  login (email, pass, cb) {\n    cb = arguments[arguments.length - 1]\n    if (localStorage.token) {\n      if (cb) cb(true)\n      this.onChange(true)\n      return\n    }\n    pretendRequest(email, pass, (res) => {\n      if (res.authenticated) {\n        localStorage.token = res.token\n        if (cb) cb(true)\n        this.onChange(true)\n      } else {\n        if (cb) cb(false)\n        this.onChange(false)\n      }\n    })\n  },\n\n  getToken () {\n    return localStorage.token\n  },\n\n  logout (cb) {\n    delete localStorage.token\n    if (cb) cb()\n    this.onChange(false)\n  },\n\n  loggedIn () {\n    return !!localStorage.token\n  },\n\n  onChange () {}\n}\n\nfunction pretendRequest (email, pass, cb) {\n  setTimeout(() => {\n    if (email === 'joe@example.com' && pass === 'password1') {\n      cb({\n        authenticated: true,\n        token: Math.random().toString(36).substring(7)\n      })\n    } else {\n      cb({ authenticated: false })\n    }\n  }, 0)\n}\n"
  },
  {
    "path": "examples/auth-flow/components/About.vue",
    "content": "<template>\n  <div>\n    <h2>About</h2>\n  </div>\n</template>\n"
  },
  {
    "path": "examples/auth-flow/components/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <h1>Auth Flow</h1>\n    <ul>\n      <li>\n        <router-link v-if=\"loggedIn\" to=\"/logout\">Log out</router-link>\n        <router-link v-if=\"!loggedIn\" to=\"/login\">Log in</router-link>\n      </li>\n      <li>\n        <router-link to=\"/about\">About</router-link>\n      </li>\n      <li>\n        <router-link to=\"/dashboard\">Dashboard</router-link>\n        (authenticated)\n      </li>\n    </ul>\n    <template v-if=\"$route.matched.length\">\n      <router-view></router-view>\n    </template>\n    <template v-else>\n      <p>You are logged {{ loggedIn ? 'in' : 'out' }}</p>\n    </template>\n  </div>\n</template>\n\n<script>\nimport auth from '../auth'\n\nexport default {\n  data () {\n    return {\n      loggedIn: auth.loggedIn()\n    }\n  },\n  created () {\n    auth.onChange = loggedIn => {\n      this.loggedIn = loggedIn\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/auth-flow/components/Dashboard.vue",
    "content": "<template>\n  <div>\n    <h2>Dashboard</h2>\n    <p>Yay you made it!</p>\n  </div>\n</template>\n"
  },
  {
    "path": "examples/auth-flow/components/Login.vue",
    "content": "<template>\n  <div>\n    <h2>Login</h2>\n    <p v-if=\"$route.query.redirect\">\n      You need to login first.\n    </p>\n    <form @submit.prevent=\"login\">\n      <label><input v-model=\"email\" placeholder=\"email\"></label>\n      <label><input v-model=\"pass\" placeholder=\"password\" type=\"password\"></label> (hint: password1)<br>\n      <button type=\"submit\">login</button>\n      <p v-if=\"error\" class=\"error\">Bad login information</p>\n    </form>\n  </div>\n</template>\n\n<script>\nimport auth from '../auth'\n\nexport default {\n  data () {\n    return {\n      email: 'joe@example.com',\n      pass: '',\n      error: false\n    }\n  },\n  methods: {\n    login () {\n      auth.login(this.email, this.pass, loggedIn => {\n        if (!loggedIn) {\n          this.error = true\n        } else {\n          this.$router.replace(this.$route.query.redirect || '/')\n        }\n      })\n    }\n  }\n}\n</script>\n\n<style>\n.error {\n  color: red;\n}\n</style>\n"
  },
  {
    "path": "examples/auth-flow/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/auth-flow.js\"></script>\n"
  },
  {
    "path": "examples/basic/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\n// track number of popstate listeners\nlet numPopstateListeners = 0\nconst listenerCountDiv = document.createElement('div')\nlistenerCountDiv.id = 'popstate-count'\nlistenerCountDiv.textContent = numPopstateListeners + ' popstate listeners'\ndocument.body.appendChild(listenerCountDiv)\n\nconst originalAddEventListener = window.addEventListener\nconst originalRemoveEventListener = window.removeEventListener\nwindow.addEventListener = function (name, handler) {\n  if (name === 'popstate') {\n    listenerCountDiv.textContent =\n      ++numPopstateListeners + ' popstate listeners'\n  }\n  return originalAddEventListener.apply(this, arguments)\n}\nwindow.removeEventListener = function (name, handler) {\n  if (name === 'popstate') {\n    listenerCountDiv.textContent =\n      --numPopstateListeners + ' popstate listeners'\n  }\n  return originalRemoveEventListener.apply(this, arguments)\n}\n\n// 1. Use plugin.\n// This installs <router-view> and <router-link>,\n// and injects $router and $route to all router-enabled child components\nVue.use(VueRouter)\n\n// 2. Define route components\nconst Home = { template: '<div>home</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Unicode = { template: '<div>unicode</div>' }\nconst Query = { template: '<div>query: \"{{ $route.params.q }}\"</div>' }\n\n// 3. Create the router\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar },\n    { path: encodeURI('/é'), component: Unicode },\n    { path: '/query/:q', component: Query }\n  ]\n})\n\nrouter.beforeEach((to, from, next) => {\n  if (to.query.delay) {\n    setTimeout(() => {\n      next()\n    }, Number(to.query.delay))\n  } else {\n    next()\n  }\n})\n\n// 4. Create and mount root instance.\n// Make sure to inject the router.\n// Route components will be rendered inside <router-view>.\nconst vueInstance = new Vue({\n  router,\n  data: () => ({ n: 0 }),\n  template: `\n    <div id=\"app\">\n      <h1>Basic</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n        <router-link tag=\"li\" to=\"/bar\" :event=\"['mousedown', 'touchstart']\">\n          <a>/bar</a>\n        </router-link>\n        <li><router-link :to=\"encodeURI('/é')\">/é</router-link></li>\n        <li><router-link :to=\"encodeURI('/é?t=%ñ')\">/é?t=%ñ</router-link></li>\n        <li><router-link :to=\"encodeURI('/é#%ñ')\">/é#%25ñ</router-link></li>\n        <router-link to=\"/foo\" v-slot=\"props\" custom>\n          <li :class=\"[props.isActive && 'active', props.isExactActive && 'exact-active']\">\n            <a :href=\"props.href\" @click=\"props.navigate\">{{ props.route.path }} (with v-slot).</a>\n          </li>\n        </router-link>\n        <li><router-link to=\"/foo\" replace>/foo (replace)</router-link></li>\n        <li><router-link to=\"/query/A%25\">/query/A%</router-link></li>\n        <li><router-link to=\"/?delay=200\">/ (delay of 500ms)</router-link></li>\n        <li><router-link to=\"/foo?delay=200\">/foo (delay of 500ms)</router-link></li>\n      </ul>\n      <button id=\"navigate-btn\" @click=\"navigateAndIncrement\">On Success</button>\n      <pre id=\"counter\">{{ n }}</pre>\n      <pre id=\"query-t\">{{ $route.query.t }}</pre>\n      <pre id=\"hash\">{{ $route.hash }}</pre>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `,\n\n  methods: {\n    navigateAndIncrement () {\n      const increment = () => this.n++\n      if (this.$route.path === '/') {\n        this.$router.push('/foo', increment)\n      } else {\n        this.$router.push('/', increment)\n      }\n    }\n  }\n}).$mount('#app')\n\ndocument.getElementById('unmount').addEventListener('click', () => {\n  vueInstance.$destroy()\n  vueInstance.$el.innerHTML = ''\n})\n"
  },
  {
    "path": "examples/basic/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<button id=\"unmount\">Unmount</button>\n<hr />\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/basic.js\"></script>\n"
  },
  {
    "path": "examples/composables/app.js",
    "content": "import Vue, { defineComponent, watch, ref } from 'vue'\nimport VueRouter from 'vue-router'\nimport {\n  useRoute,\n  useRouter,\n  onBeforeRouteLeave,\n  onBeforeRouteUpdate,\n  useLink\n} from 'vue-router/composables'\n\nVue.use(VueRouter)\n\nconst Foo = defineComponent({\n  setup () {\n    const route = useRoute()\n    onBeforeRouteUpdate((to, from, next) => {\n      console.log('Foo updating')\n      next()\n    })\n    onBeforeRouteLeave((to, from, next) => {\n      console.log('Foo leaving')\n      next()\n    })\n\n    return { route }\n  },\n  template: `\n<div>\n  <h3>Foo</h3>\n  {{ route.fullPath }}\n</div>\n  `\n})\n\nconst Home = defineComponent({\n  setup () {\n    const route = useRoute()\n    const router = useRouter()\n\n    // should be /\n    const startRoute = route.fullPath\n\n    onBeforeRouteUpdate((to, from, next) => {\n      console.log('Home updating')\n      next()\n    })\n\n    onBeforeRouteLeave((to, from, next) => {\n      console.log('Home leaving')\n      next()\n    })\n\n    const watchCount = ref(0)\n\n    watch(\n      () => route.query.n,\n      () => {\n        watchCount.value++\n      }\n    )\n\n    function navigate () {\n      router.push({ query: { n: 1 + (Number(route.query.n) || 0) }})\n    }\n    return { route, navigate, watchCount, startRoute }\n  },\n  template: `\n<div>\n  <h2>Home</h2>\n  <p id=\"start-route\">{{ startRoute }}</p>\n  <p id='watch-count'>{{ watchCount }}</p>\n  <p id=\"fullpath\">{{ route.fullPath }}</p>\n  <button id=\"nav\" @click=\"navigate\">Navigate</button>\n  <hr>\n  <Foo />\n</div>\n  `,\n  components: { Foo }\n})\n\nconst About = defineComponent({\n  setup () {\n    const route = useRoute()\n    return { route }\n  },\n  template: `\n<div>\n  <h2>About</h2>\n  <p id=\"fullpath\">{{ route.fullPath }}</p>\n</div>\n  `\n})\n\nconst Nested = defineComponent({\n  template: `<RouterView />`\n})\n\nconst NestedEmpty = defineComponent({\n  template: `<div>NestedEmpty</div>`\n})\n\nconst NestedA = defineComponent({\n  template: `<div>NestedA</div>`\n})\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    {\n      path: '/nested',\n      component: Nested,\n      children: [\n        { path: '', component: NestedEmpty },\n        { path: 'a', component: NestedA }\n      ]\n    },\n    { path: '/about', component: About }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Basic</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/about\">/about</router-link></li>\n        <li><router-link to=\"/nested\">/nested</router-link></li>\n        <li><router-link to=\"/nested/a\">/nested/a</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n\n      <pre id=\"nested-active\" @click=\"navigate\">{{ href }}: {{ isActive }}, {{ isExactActive }}</pre>\n    </div>\n  `,\n  setup () {\n    const { href, isActive, isExactActive, navigate, route } = useLink({\n      to: '/nested'\n    })\n\n    return { href, isActive, navigate, route, isExactActive }\n  }\n}).$mount('#app')\n"
  },
  {
    "path": "examples/composables/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<hr />\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/composables.js\"></script>\n"
  },
  {
    "path": "examples/data-fetching/Post.vue",
    "content": "<template>\n  <div class=\"post\">\n    <div class=\"loading\" v-if=\"loading\">Loading...</div>\n    <div v-if=\"error\" class=\"error\">\n      {{ error }}\n    </div>\n    <transition name=\"slide\">\n      <!--\n        giving the post container a unique key triggers transitions\n        when the post id changes.\n      -->\n      <div v-if=\"post\" class=\"content\" :key=\"post.id\">\n        <h2>{{ post.title }}</h2>\n        <p>{{ post.body }}</p>\n      </div>\n    </transition>\n  </div>\n</template>\n\n<script>\nimport { getPost } from './api'\n\nexport default {\n  data () {\n    return {\n      loading: false,\n      post: null,\n      error: null\n    }\n  },\n  created () {\n    this.fetchData()\n  },\n  watch: {\n    '$route': 'fetchData'\n  },\n  methods: {\n    fetchData () {\n      this.error = this.post = null\n      this.loading = true\n      getPost(this.$route.params.id, (err, post) => {\n        this.loading = false\n        if (err) {\n          this.error = err.toString()\n        } else {\n          this.post = post\n        }\n      })\n    }\n  }\n}\n</script>\n\n<style>\n.loading {\n  position: absolute;\n  top: 10px;\n  right: 10px;\n}\n.error {\n  color: red;\n}\n.content {\n  transition: all .35s ease;\n  position: absolute;\n}\n.slide-enter {\n  opacity: 0;\n  transform: translate(30px, 0);\n}\n.slide-leave-active {\n  opacity: 0;\n  transform: translate(-30px, 0);\n}\n</style>\n"
  },
  {
    "path": "examples/data-fetching/api.js",
    "content": "const posts = {\n  '1': {\n    id: 1,\n    title: 'sunt aut facere',\n    body: 'quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto'\n  },\n  '2': {\n    id: 2,\n    title: 'qui est esse',\n    body: 'est rerum tempore vitae sequi sint nihil reprehenderit dolor beatae ea dolores neque fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis qui aperiam non debitis possimus qui neque nisi nulla'\n  }\n}\n\nexport function getPost (id, cb) {\n  // fake an API request\n  setTimeout(() => {\n    if (posts[id]) {\n      cb(null, posts[id])\n    } else {\n      cb(new Error('Post not found.'))\n    }\n  }, 100)\n}\n"
  },
  {
    "path": "examples/data-fetching/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport Post from './Post.vue'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>home</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    { path: '/post/:id', component: Post }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Data Fetching</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/post/1\">/post/1</router-link></li>\n        <li><router-link to=\"/post/2\">/post/2</router-link></li>\n        <li><router-link to=\"/post/3\">/post/3</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/data-fetching/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/data-fetching.js\"></script>\n"
  },
  {
    "path": "examples/discrete-components/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\n// 1. Use plugin.\n// This installs <router-view> and <router-link>,\n// and injects $router and $route to all router-enabled child components\nVue.use(VueRouter)\n\n// 2. Define route components\nconst Home = { template: '<div>Component: home</div>' }\nconst Foo = { template: '<div>Component: foo</div>' }\nconst Bar = { template: '<div>Component: bar</div>' }\n\n// 3. Create the router\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar }\n  ]\n})\n\n// 4. Create extended base Vue with router injected here (all\n// children should inherit the same router).\nconst BaseVue = Vue.extend({ router })\n\n// Discrete components means that a new Vue instance will be created\n// and bound on multiple *independent* nodes (eg. one Vue instance\n// per node); but the router should act as a singleton and keep all\n// instances in sync.\nArray.prototype.forEach.call(document.querySelectorAll('.app'), (node) => {\n  new BaseVue({\n    el: node\n  })\n})\n"
  },
  {
    "path": "examples/discrete-components/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<style>\n  .inliner {font-size:0;line-height:0;}\n  .app {font-size:1rem;line-height:1;display:inline-block;padding:1rem;width:33%;border-left:1px solid #f1f1f1;box-sizing:border-box;vertical-align:top;}\n  .snippet {display:inline-block;padding:5px;background:#f1f1f1;font-size:90%;}\n  .app.component-view {display:block;width:100%;text-align:center;}\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div class=\"inliner\">\n  <div class=\"app\">\n    <ul>\n      <li><router-link to=\"/\">/</router-link></li>\n      <li><router-link to=\"/foo\">/foo</router-link></li>\n      <li><router-link to=\"/bar\">/bar</router-link></li>\n    </ul>\n    $route.path value: <span class=\"snippet\">{{ $route.path }}</span>\n  </div>\n  <div class=\"app\">\n    <ul>\n      <li><router-link to=\"/\">/</router-link></li>\n      <li><router-link to=\"/foo\">/foo</router-link></li>\n      <li><router-link to=\"/bar\">/bar</router-link></li>\n    </ul>\n    $route.path value: <span class=\"snippet\">{{ $route.path }}</span>\n  </div>\n  <div class=\"app\">\n    <ul>\n      <li><router-link to=\"/\">/</router-link></li>\n      <li><router-link to=\"/foo\">/foo</router-link></li>\n      <li><router-link to=\"/bar\">/bar</router-link></li>\n    </ul>\n    $route.path value: <span class=\"snippet\">{{ $route.path }}</span>\n  </div>\n</div>\n<div class=\"app component-view\">\n  <router-view class=\"view\"></router-view>\n  $route.path value: <span class=\"snippet\">{{ $route.path }}</span>\n</div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/discrete-components.js\"></script>\n"
  },
  {
    "path": "examples/global.css",
    "content": "html, body {\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  color: #2c3e50;\n}\n\n#app {\n  padding: 0 20px;\n}\n\nul {\n  line-height: 1.5em;\n  padding-left: 1.5em;\n}\n\na {\n  color: #7f8c8d;\n  text-decoration: none;\n}\n\na:hover {\n  color: #4fc08d;\n}\n"
  },
  {
    "path": "examples/hash-mode/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\n// track number of popstate listeners\nlet numPopstateListeners = 0\nconst listenerCountDiv = document.createElement('div')\nlistenerCountDiv.id = 'popstate-count'\nlistenerCountDiv.textContent = numPopstateListeners + ' popstate listeners'\ndocument.body.appendChild(listenerCountDiv)\n\nconst originalAddEventListener = window.addEventListener\nconst originalRemoveEventListener = window.removeEventListener\nwindow.addEventListener = function (name, handler) {\n  if (name === 'popstate') {\n    listenerCountDiv.textContent =\n      ++numPopstateListeners + ' popstate listeners'\n  }\n  return originalAddEventListener.apply(this, arguments)\n}\nwindow.removeEventListener = function (name, handler) {\n  if (name === 'popstate') {\n    listenerCountDiv.textContent =\n      --numPopstateListeners + ' popstate listeners'\n  }\n  return originalRemoveEventListener.apply(this, arguments)\n}\n\n// 1. Use plugin.\n// This installs <router-view> and <router-link>,\n// and injects $router and $route to all router-enabled child components\nVue.use(VueRouter)\n\n// 2. Define route components\nconst Home = { template: '<div>home</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Unicode = { template: '<div>unicode: {{ $route.params.unicode }}</div>' }\nconst Query = { template: '<div>query: \"{{ $route.params.q }}\"</div>' }\n\n// 3. Create the router\nconst router = new VueRouter({\n  mode: 'hash',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home }, // all paths are defined without the hash.\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar },\n    { path: encodeURI('/é'), component: Unicode },\n    { path: encodeURI('/é/:unicode'), component: Unicode },\n    { path: '/query/:q', component: Query, name: 'param' }\n  ]\n})\n\n// 4. Create and mount root instance.\n// Make sure to inject the router.\n// Route components will be rendered inside <router-view>.\nconst vueInstance = new Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Mode: 'hash'</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n        <router-link tag=\"li\" to=\"/bar\">/bar</router-link>\n        <li><router-link :to=\"encodeURI('/é')\">/é</router-link></li>\n        <li><router-link :to=\"encodeURI('/é/ñ')\">/é/ñ</router-link></li>\n        <li><router-link :to=\"encodeURI('/é/ñ?t=%ñ')\">/é/ñ?t=%ñ</router-link></li>\n        <li><router-link :to=\"encodeURI('/é/ñ#é')\">/é/ñ#é</router-link></li>\n        <li><router-link to=\"/query/A%25\">/query/A%</router-link></li>\n        <li><router-link :to=\"{ name: 'param', params: { q: 'A%' }}\">/query/A% (object)</router-link></li>\n        <li><router-link to=\"/query/A%2FE\">/query/A%2FE</router-link></li>\n        <li><router-link :to=\"{ name: 'param', params: { q: 'A/E' }}\">/query/A%2FE (object)</router-link></li>\n      </ul>\n      <pre id=\"query-t\">{{ $route.query.t }}</pre>\n      <pre id=\"hash\">{{ $route.hash }}</pre>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `,\n  methods: {}\n}).$mount('#app')\n\ndocument.getElementById('unmount').addEventListener('click', () => {\n  vueInstance.$destroy()\n  vueInstance.$el.innerHTML = ''\n})\n"
  },
  {
    "path": "examples/hash-mode/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<button id=\"unmount\">Unmount</button>\n<hr />\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/hash-mode.js\"></script>\n"
  },
  {
    "path": "examples/hash-scroll-behavior/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>home</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = {\n  template: `\n    <div>\n      bar\n      <div style=\"height:500px\"></div>\n      <p id=\"anchor\" style=\"height:500px\">Anchor</p>\n      <p id=\"anchor2\">Anchor2</p>\n    </div>\n  `\n}\n\n// scrollBehavior:\n// - only available in html5 history mode\n// - defaults to no scroll behavior\n// - return false to prevent scroll\nconst scrollBehavior = (to, from, savedPosition) => {\n  if (savedPosition) {\n    // savedPosition is only available for popstate navigations.\n    return savedPosition\n  } else {\n    const position = {}\n    // new navigation.\n    // scroll to anchor by returning the selector\n    if (to.hash) {\n      position.selector = to.hash\n      console.log(to)\n\n      // specify offset of the element\n      if (to.hash === '#anchor2') {\n        position.offset = { y: 100 }\n      }\n    }\n    // check if any matched route config has meta that requires scrolling to top\n    if (to.matched.some(m => m.meta.scrollToTop)) {\n      // cords will be used if no selector is provided,\n      // or if the selector didn't match any element.\n      position.x = 0\n      position.y = 0\n    }\n    // if the returned position is falsy or an empty object,\n    // will retain current scroll position.\n    return position\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'hash',\n  scrollBehavior,\n  routes: [\n    { path: '/', component: Home, meta: { scrollToTop: true }},\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar, meta: { scrollToTop: true }}\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Scroll Behavior</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n        <li><router-link to=\"/bar#anchor\">/bar#anchor</router-link></li>\n        <li><router-link to=\"/bar#anchor2\">/bar#anchor2</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/hash-scroll-behavior/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\" />\n<style>\n  .view {\n    border: 1px solid red;\n    height: 3000px;\n    position: relative;\n  }\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/hash-scroll-behavior.js\"></script>\n"
  },
  {
    "path": "examples/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <title>Vue Router Examples</title>\n  <link rel=\"stylesheet\" href=\"/global.css\">\n</head>\n<body style=\"padding: 0 20px\">\n  <h1>Vue Router Examples</h1>\n  <ul>\n    <li><a href=\"basic\">Basic</a></li>\n    <li><a href=\"hash-mode\">Mode: 'hash'</a></li>\n    <li><a href=\"nested-routes\">Nested Routes</a></li>\n    <li><a href=\"named-routes\">Named Routes</a></li>\n    <li><a href=\"named-views\">Named Views</a></li>\n    <li><a href=\"route-matching\">Route Matching</a></li>\n    <li><a href=\"active-links\">Active Links</a></li>\n    <li><a href=\"redirect\">Redirect</a></li>\n    <li><a href=\"route-props\">Route Props</a></li>\n    <li><a href=\"route-alias\">Route Alias</a></li>\n    <li><a href=\"route-params\">Route Params</a></li>\n    <li><a href=\"router-errors\">Router errors</a></li>\n    <li><a href=\"transitions\">Transitions</a></li>\n    <li><a href=\"data-fetching\">Data Fetching</a></li>\n    <li><a href=\"navigation-guards\">Navigation Guards</a></li>\n    <li><a href=\"scroll-behavior\">Scroll Behavior</a></li>\n    <li><a href=\"lazy-loading\">Lazy Loading</a></li>\n    <li><a href=\"auth-flow\">Auth Flow</a></li>\n    <li><a href=\"discrete-components\">Discrete Components</a></li>\n    <li><a href=\"nested-router\">Nested Routers</a></li>\n    <li><a href=\"keepalive-view\">Keepalive View</a></li>\n    <li><a href=\"multi-app\">Multiple Apps</a></li>\n    <li><a href=\"restart-app\">Restart App</a></li>\n    <li><a href=\"composables\">Composables</a></li>\n  </ul>\n</body>\n</html>\n"
  },
  {
    "path": "examples/keepalive-view/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Wrap = { template: '<div>child: <router-view></router-view></div>' }\n\nconst Index = {\n  template: '<wrap />',\n  components: {\n    Wrap\n  }\n}\n\nconst WithGuard = {\n  template: '<div>{{ $route.name }}: {{ n }}</div>',\n  data: () => ({ n: 0 }),\n  beforeRouteEnter (to, from, next) {\n    next(vm => {\n      vm.n++\n    })\n  }\n}\n\nconst IndexChild1 = { template: '<div>index child1</div>' }\nconst IndexChild2 = { template: '<div>index child2</div>' }\n\nconst Home = { template: '<div>home</div>' }\n\nconst ViewWithKeepalive = {\n  template: '<keep-alive><router-view></router-view></keep-alive>'\n}\n\nconst Parent = { template: '<div>msg: {{ msg }}<router-view /></div>', props: ['msg'] }\n\nconst RequiredProps = {\n  template: '<div>props from route config is: {{ msg }}</div>',\n  props: {\n    msg: {\n      type: String,\n      required: true\n    }\n  }\n}\n\n// keep original values to restore them later\nconst originalSilent = Vue.config.silent\nconst originalWarnHandler = Vue.config.warnHandler\n\nconst CatchWarn = {\n  template: `<div>{{ didWarn ? 'caught missing prop warn' : 'no missing prop warn' }}</div>`,\n  data () {\n    return {\n      didWarn: false\n    }\n  },\n  beforeRouteEnter (to, from, next) {\n    let missPropWarn = false\n    Vue.config.silent = false\n    Vue.config.warnHandler = function (msg, vm, trace) {\n      if (/Missing required prop/i.test(msg)) {\n        missPropWarn = true\n      }\n    }\n    next(vm => {\n      vm.didWarn = missPropWarn\n    })\n  },\n  beforeRouteLeave (to, from, next) {\n    // restore vue config\n    Vue.config.silent = originalSilent\n    Vue.config.warnHandler = originalWarnHandler\n    next()\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    {\n      path: '/index',\n      component: Index,\n      children: [\n        {\n          path: 'child1',\n          component: IndexChild1\n        },\n        {\n          path: 'child2',\n          component: IndexChild2\n        }\n      ]\n    },\n    {\n      path: '/home',\n      component: Home\n    },\n    {\n      path: '/with-guard1',\n      name: 'with-guard1',\n      component: WithGuard\n    },\n    {\n      path: '/with-guard2',\n      name: 'with-guard2',\n      component: WithGuard\n    },\n    {\n      path: '/one',\n      component: ViewWithKeepalive,\n      children: [\n        {\n          path: 'two',\n          component: ViewWithKeepalive,\n          children: [\n            {\n              path: 'child1',\n              component: IndexChild1\n            },\n            {\n              path: 'child2',\n              component: IndexChild2\n            }\n          ]\n        }\n      ]\n    },\n    {\n      path: '/config-required-props',\n      component: Parent,\n      props: { msg: 'from parent' },\n      children: [\n        {\n          path: 'child',\n          component: RequiredProps,\n          props: {\n            msg: 'from child'\n          }\n        }\n      ]\n    },\n    {\n      path: '/catch-warn',\n      component: CatchWarn\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <ul>\n        <li><router-link to=\"/index/child1\">/index/child1</router-link></li>\n        <li><router-link to=\"/index/child2\">/index/child2</router-link></li>\n        <li><router-link to=\"/home\">/home</router-link></li>\n        <li><router-link to=\"/with-guard1\">/with-guard1</router-link></li>\n        <li><router-link to=\"/with-guard2\">/with-guard2</router-link></li>\n        <li><router-link to=\"/one/two/child1\">/one/two/child1</router-link></li>\n        <li><router-link to=\"/one/two/child2\">/one/two/child2</router-link></li>\n        <li><router-link to=\"/config-required-props\">/config-required-props</router-link></li>\n        <li><router-link to=\"/config-required-props/child\">/config-required-props/child</router-link></li>\n        <li><router-link to=\"/catch-warn\">/catch-warn</router-link></li>\n      </ul>\n      <keep-alive>\n        <router-view class=\"view\"></router-view>\n      </keep-alive>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/keepalive-view/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/keepalive-view.js\"></script>\n"
  },
  {
    "path": "examples/lazy-loading/Bar.vue",
    "content": "<template>\n  <div>\n    <h2>{{ msg }}</h2>\n    <p>I am lazy-loaded. (check out the Networks tab in Chrome devtools)</p>\n    <router-view></router-view>\n  </div>\n</template>\n\n<script>\nexport default {\n  data () {\n    return { msg: 'This is Bar!' }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/lazy-loading/Baz.vue",
    "content": "<template>\n  <div>\n    <h3>Baz</h3>\n    <p>I'm loaded in the same chunk with Bar.</p>\n  </div>\n</template>\n"
  },
  {
    "path": "examples/lazy-loading/Foo.vue",
    "content": "<template>\n  <div>\n    <h2>This is Foo!</h2>\n    <p>I am lazy-loaded. (check out the Networks tab in Chrome devtools)</p>\n  </div>\n</template>\n"
  },
  {
    "path": "examples/lazy-loading/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>home</div>' }\n\n// In Webpack we can use special require syntax to signify a \"split point\"\n// Webpack will automatically split and lazy-load the split modules.\n// - https://webpack.js.org/guides/code-splitting-require/\n\n// Combine that with Vue's async components, we can easily make our route\n// components lazy-loaded only when the given route is matched.\n\n// async components are defined as:\n// - resolve => resolve(Component)\n// or\n// - () => Promise<Component>\n\n// For single component, we can simply use dynamic import which returns\n// a Promise.\nconst Foo = () => import('./Foo.vue')\n\n// The import() syntax is a replacement for the deprecated System.import() and\n// is specified at https://github.com/tc39/proposal-dynamic-import. Webpack 2\n// supports using it to indicate a code-splitting point.\n// Note: if using Babel you will need `babel-plugin-syntax-dynamic-import`.\n\n// If using Webpack 1, you will have to use AMD syntax or require.ensure:\n// const Foo = resolve => require(['./Foo.vue'], resolve)\n\n// If you want to group a number of components that belong to the same\n// nested route in the same async chunk, you can use a special comment\n// to indicate a chunk name for the imported module. (note this requires\n// webpack 2.4.0+)\nconst Bar = () => import(/* webpackChunkName: \"bar\" */ './Bar.vue')\nconst Baz = () => import(/* webpackChunkName: \"bar\" */ './Baz.vue')\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    // Just use them normally in the route config\n    { path: '/foo', component: Foo },\n    // multiple parameters, `/` should not be encoded. The name is also important\n    // https://github.com/vuejs/vue-router/issues/2719\n    { path: '/a/:tags*', name: 'tagged', component: () => new Promise(resolve => {\n      setTimeout(() => {\n        resolve({\n          template: `<div>\n            <h2>Lazy with params</h2>\n            <pre id=\"tagged-path\">{{ $route.path }}</pre>\n          </div>`\n        })\n      }, 200)\n    }) },\n    // Bar and Baz belong to the same root route\n    // and grouped in the same async chunk.\n    { path: '/bar', component: Bar,\n      children: [\n        { path: 'baz', component: Baz }\n      ]\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Lazy Loading</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n        <li><router-link to=\"/bar/baz\">/bar/baz</router-link></li>\n        <li><router-link to=\"/a/b/c\">/a/b/c</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/lazy-loading/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/lazy-loading.js\"></script>\n"
  },
  {
    "path": "examples/lazy-loading-before-mount/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>Home</div>' }\nconst Foo = () =>\n  new Promise(resolve => {\n    setTimeout(() =>\n      resolve({\n        template: `<div class=\"foo\">This is Foo</div>`\n      })\n      , 10)\n  })\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    // Just use them normally in the route config\n    { path: '/async', component: Foo }\n  ]\n})\n\nrouter.onReady(() => {\n  router.push('/async')\n})\n\ndocument.getElementById('load-button').addEventListener('click', (event) => {\n  new Vue({\n    router,\n    template: `\n    <div id=\"app\">\n      <h1>Async</h1>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n  }).$mount('#app')\n  event.target.remove()\n})\n"
  },
  {
    "path": "examples/lazy-loading-before-mount/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n\n<button id=\"load-button\">Load</button>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/lazy-loading-before-mount.js\"></script>\n"
  },
  {
    "path": "examples/multi-app/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\n// track number of popstate listeners\nlet numPopstateListeners = 0\nconst listenerCountDiv = document.getElementById('popcount')\nlistenerCountDiv.textContent = 0\n\nconst originalAddEventListener = window.addEventListener\nconst originalRemoveEventListener = window.removeEventListener\nwindow.addEventListener = function (name, handler) {\n  if (name === 'popstate') {\n    listenerCountDiv.textContent =\n      ++numPopstateListeners\n  }\n  return originalAddEventListener.apply(this, arguments)\n}\nwindow.removeEventListener = function (name, handler) {\n  if (name === 'popstate') {\n    listenerCountDiv.textContent =\n      --numPopstateListeners\n  }\n  return originalRemoveEventListener.apply(this, arguments)\n}\n\n// 1. Use plugin.\n// This installs <router-view> and <router-link>,\n// and injects $router and $route to all router-enabled child components\nVue.use(VueRouter)\n\nconst looper = [1, 2, 3]\n\nlooper.forEach((n) => {\n  let vueInstance\n  const mountEl = document.getElementById('mount' + n)\n  const unmountEl = document.getElementById('unmount' + n)\n\n  mountEl.addEventListener('click', () => {\n    // 2. Define route components\n    const Home = { template: '<div>home</div>' }\n    const Foo = { template: '<div>foo</div>' }\n\n    // 3. Create the router\n    const router = new VueRouter({\n      mode: 'history',\n      base: __dirname,\n      routes: [\n        { path: '/', component: Home },\n        { path: '/foo', component: Foo }\n      ]\n    })\n\n    // 4. Create and mount root instance.\n    // Make sure to inject the router.\n    // Route components will be rendered inside <router-view>.\n    vueInstance = new Vue({\n      router,\n      template: `\n        <div id=\"app-${n}\">\n          <h1>Basic</h1>\n          <ul>\n            <li><router-link to=\"/\">/</router-link></li>\n            <li><router-link to=\"/foo\">/foo</router-link></li>\n          </ul>\n          <router-view class=\"view\"></router-view>\n        </div>\n      `\n    }).$mount('#app-' + n)\n  })\n\n  unmountEl.addEventListener('click', () => {\n    vueInstance.$destroy()\n    vueInstance.$el.innerHTML = ''\n  })\n})\n"
  },
  {
    "path": "examples/multi-app/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n\n<button id=\"mount1\">Mount App 1</button>\n<button id=\"mount2\">Mount App 2</button>\n<button id=\"mount3\">Mount App 3</button>\n\n<hr />\n\n<button id=\"unmount1\">Unmount App 1</button>\n<button id=\"unmount2\">Unmount App 2</button>\n<button id=\"unmount3\">Unmount App 3</button>\n\n<hr />\n\npopstate count: <span id=\"popcount\"></span>\n\n<div id=\"app-1\"></div>\n<div id=\"app-2\"></div>\n<div id=\"app-3\"></div>\n\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/multi-app.js\"></script>"
  },
  {
    "path": "examples/named-routes/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>This is Home</div>' }\nconst Foo = { template: '<div>This is Foo</div>' }\nconst Bar = { template: '<div>This is Bar {{ $route.params.id }}</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', name: 'home', component: Home },\n    { path: '/foo', name: 'foo', component: Foo },\n    { path: '/bar/:id', name: 'bar', component: Bar }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Named Routes</h1>\n      <p>Current route name: {{ $route.name }}</p>\n      <ul>\n        <li><router-link :to=\"{ name: 'home' }\">home</router-link></li>\n        <li><router-link :to=\"{ name: 'foo' }\">foo</router-link></li>\n        <li><router-link :to=\"{ name: 'bar', params: { id: 123 }}\">bar</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/named-routes/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/named-routes.js\"></script>\n"
  },
  {
    "path": "examples/named-views/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Baz = { template: '<div>baz</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/',\n      // a single route can define multiple named components\n      // which will be rendered into <router-view>s with corresponding names.\n      components: {\n        default: Foo,\n        a: Bar,\n        b: Baz\n      }\n    },\n    {\n      path: '/other',\n      components: {\n        default: Baz,\n        a: Bar,\n        b: Foo\n      }\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Named Views</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/other\">/other</router-link></li>\n      </ul>\n      <router-view class=\"view one\"></router-view>\n      <router-view class=\"view two\" name=\"a\"></router-view>\n      <router-view class=\"view three\" name=\"b\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/named-views/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/named-views.js\"></script>\n"
  },
  {
    "path": "examples/navigation-guards/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>home</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\n\n/**\n * Signature of all route guards:\n * @param {Route} to\n * @param {Route} from\n * @param {Function} next\n *\n * See http://router.vuejs.org/en/advanced/navigation-guards.html\n * for more details.\n */\nfunction guardRoute (to, from, next) {\n  if (window.confirm(`Navigate to ${to.path}?`)) {\n    next()\n  } else if (window.confirm(`Redirect to /baz?`)) {\n    next('/baz')\n  } else {\n    next(false)\n  }\n}\n\n// Baz implements an in-component beforeRouteLeave hook\nconst Baz = {\n  data () {\n    return { saved: false }\n  },\n  template: `\n    <div>\n      <p>baz ({{ saved ? 'saved' : 'not saved' }})</p>\n      <button @click=\"saved = true\">save</button>\n    </div>\n  `,\n  beforeRouteLeave (to, from, next) {\n    if (\n      this.saved ||\n      window.confirm('Not saved, are you sure you want to navigate away?')\n    ) {\n      next()\n    } else {\n      next(false)\n    }\n  }\n}\n\n// Qux implements an in-component beforeRouteEnter hook\nconst Qux = {\n  data () {\n    return {\n      msg: null\n    }\n  },\n  template: `<div>{{ msg }}</div>`,\n  beforeRouteEnter (to, from, next) {\n    // Note that enter hooks do not have access to `this`\n    // because it is called before the component is even created.\n    // However, we can provide a callback to `next` which will\n    // receive the vm instance when the route has been confirmed.\n    //\n    // simulate an async data fetch.\n    // this pattern is useful when you want to stay at current route\n    // and only switch after the data has been fetched.\n    setTimeout(() => {\n      next(vm => {\n        vm.msg = 'Qux'\n      })\n    }, 300)\n  }\n}\n\n// Quux implements an in-component beforeRouteUpdate hook.\n// this hook is called when the component is reused, but the route is updated.\n// For example, when navigating from /quux/1 to /quux/2.\nconst Quux = {\n  data () {\n    return {\n      prevId: 0\n    }\n  },\n  template: `<div>id:{{ $route.params.id }} prevId:{{ prevId }}</div>`,\n  beforeRouteUpdate (to, from, next) {\n    this.prevId = from.params.id\n    next()\n  }\n}\n\nconst NestedParent = {\n  template: `\n  <div id=\"nested-parent\">\n    Nested Parent\n    <hr>\n    <router-link to=\"/parent/child/1\">/parent/child/1</router-link>\n    <router-link to=\"/parent/child/2\">/parent/child/2</router-link>\n    <hr>\n    <p id=\"bre-order\">\n      <span v-for=\"log in logs\">{{ log }} </span>\n    </p>\n    <!-- #705 -->\n    <!-- Some transitions, specifically out-in transitions, cause the view -->\n    <!-- that is transitioning in to appear significantly later than normal, -->\n    <!-- which can cause bugs as \"vm\" below in \"next(vm => ...)\" may not be -->\n    <!-- available at the time the callback is called -->\n    <transition name=\"fade\" mode=\"out-in\">\n      <router-view :key=\"$route.path\"/>\n    </transition>\n  </div>`,\n  data: () => ({ logs: [] }),\n  beforeRouteEnter (to, from, next) {\n    next(vm => {\n      vm.logs.push('parent')\n    })\n  }\n}\n\nconst GuardMixin = {\n  beforeRouteEnter (to, from, next) {\n    next(vm => {\n      vm.$parent.logs.push('mixin')\n    })\n  }\n}\n\nconst NestedChild = {\n  props: ['n'],\n  template: `<div>Child {{ n }}</div>`,\n  mixins: [GuardMixin],\n  beforeRouteEnter (to, from, next) {\n    next(vm => {\n      vm.$parent.logs.push('child ' + vm.n)\n    })\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n\n    // inline guard\n    { path: '/foo', component: Foo, beforeEnter: guardRoute },\n\n    // using meta properties on the route config\n    // and check them in a global before hook\n    { path: '/bar', component: Bar, meta: { needGuard: true }},\n\n    // Baz implements an in-component beforeRouteLeave hook\n    { path: '/baz', component: Baz },\n\n    // Qux implements an in-component beforeRouteEnter hook\n    { path: '/qux', component: Qux },\n\n    // in-component beforeRouteEnter hook for async components\n    {\n      path: '/qux-async',\n      component: resolve => {\n        setTimeout(() => {\n          resolve(Qux)\n        }, 0)\n      }\n    },\n\n    // in-component beforeRouteUpdate hook\n    { path: '/quux/:id', component: Quux },\n    {\n      path: '/parent',\n      component: NestedParent,\n      children: [\n        { path: 'child/1', component: NestedChild, props: { n: 1 }},\n        { path: 'child/2', component: NestedChild, props: { n: 2 }}\n      ]\n    }\n  ]\n})\n\nrouter.beforeEach((to, from, next) => {\n  if (to.matched.some(m => m.meta.needGuard)) {\n    guardRoute(to, from, next)\n  } else {\n    next()\n  }\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Navigation Guards</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n        <li><router-link to=\"/baz\">/baz</router-link></li>\n        <li><router-link to=\"/qux\">/qux</router-link></li>\n        <li><router-link to=\"/qux-async\">/qux-async</router-link></li>\n        <li><router-link to=\"/quux/1\">/quux/1</router-link></li>\n        <li><router-link to=\"/quux/2\">/quux/2</router-link></li>\n        <li><router-link to=\"/parent/child/2\">/parent/child/2</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/navigation-guards/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<style>\n.fade-enter-active, .fade-leave-active {\n  transition: opacity .5s ease;\n}\n.fade-enter, .fade-leave-active {\n  opacity: 0;\n}\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/navigation-guards.js\"></script>\n"
  },
  {
    "path": "examples/nested-router/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Foo = { template: `<div class=\"foo\"><h1>foo</h1></div>` }\nconst Bar = { template: `<div class=\"bar\"><h1>bar</h1></div>` }\n\nconst childRouter = new VueRouter({\n  mode: 'abstract',\n  routes: [\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar }\n  ]\n})\n\nconst Nested = {\n  router: childRouter,\n  template: `<div class=\"child\">\n    <p>Child router path: {{ $route.fullPath }}</p>\n    <ul>\n      <li><router-link to=\"/foo\">/foo</router-link></li>\n      <li><router-link to=\"/bar\">/bar</router-link></li>\n    </ul>\n    <router-view/>\n  </div>`\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/nested-router', component: Nested },\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <p>Root router path: {{ $route.fullPath }}</p>\n      <ul>\n        <li><router-link to=\"/nested-router\">/nested-router</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n      </ul>\n      <router-view></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/nested-router/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<style>\n#app { border: 1px solid red; }\n.child { border: 1px solid blue; padding: 0 15px; margin: 15px; }\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/nested-router.js\"></script>\n"
  },
  {
    "path": "examples/nested-routes/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\n// A route component can also contain <router-view> to render\n// nested children route components\nconst Parent = {\n  template: `\n    <div class=\"parent\">\n      <h2>Parent</h2>\n      <router-view class=\"child\"></router-view>\n    </div>\n  `\n}\n\nconst Default = { template: '<div>default</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Baz = { template: '<div>baz</div>' }\n\nconst Qux = {\n  template: `\n    <div class=\"nested-parent\">\n      <h3>qux</h3>\n      <router-link :to=\"{ name: 'quux' }\">/quux</router-link>\n      <router-view class=\"nested-child\"></router-view>\n    </div>\n  `\n}\nconst Quy = {\n  template: `\n    <div class=\"nested-parent-other\">\n      <h3>quy</h3>\n      <pre>{{ JSON.stringify(Object.keys($route.params)) }}</pre>\n    </div>\n  `\n}\nconst Quux = {\n  template: `<div>quux<router-link :to=\"{ name: 'quuy' }\">go to quuy</router-link></div>`\n}\nconst Quuy = { template: '<div>quuy</div>' }\nconst Zap = {\n  template: '<div><h3>zap</h3><pre>{{ $route.params.zapId }}</pre></div>'\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', redirect: '/parent' },\n    {\n      path: '/parent',\n      component: Parent,\n      children: [\n        // an empty path will be treated as the default, e.g.\n        // components rendered at /parent: Root -> Parent -> Default\n        { path: '', component: Default },\n\n        // components rendered at /parent/foo: Root -> Parent -> Foo\n        { path: 'foo', component: Foo },\n\n        // components rendered at /parent/bar: Root -> Parent -> Bar\n        { path: 'bar', component: Bar },\n\n        // NOTE absolute path here!\n        // this allows you to leverage the component nesting without being\n        // limited to the nested URL.\n        // components rendered at /baz: Root -> Parent -> Baz\n        { path: '/baz', component: Baz },\n\n        {\n          path: 'qux/:quxId',\n          component: Qux,\n          children: [\n            { path: 'quux', name: 'quux', component: Quux },\n            { path: 'quuy', name: 'quuy', component: Quuy }\n          ]\n        },\n\n        { path: 'quy/:quyId', component: Quy },\n\n        { name: 'zap', path: 'zap/:zapId?', component: Zap }\n      ]\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Nested Routes</h1>\n      <ul>\n        <li><router-link to=\"/parent\">/parent</router-link></li>\n        <li><router-link to=\"/parent/foo\">/parent/foo</router-link></li>\n        <li><router-link to=\"/parent/bar\">/parent/bar</router-link></li>\n        <li><router-link to=\"/baz\">/baz</router-link></li>\n        <li><router-link to=\"/parent/qux/123\">/parent/qux</router-link></li>\n        <li><router-link to=\"/parent/quy/123\">/parent/quy</router-link></li>\n        <li><router-link :to=\"{name: 'zap'}\">/parent/zap</router-link></li>\n        <li><router-link :to=\"{name: 'zap', params: {zapId: 1}}\">/parent/zap/1</router-link></li>\n        <li><router-link :to=\"{ params: { zapId: 2 }}\">{ params: { zapId: 2 }} (relative params)</router-link></li>\n        <li><router-link to=\"/parent/qux/1/quux\">/parent/qux/1/quux</router-link></li>\n        <li><router-link to=\"/parent/qux/2/quux\">/parent/qux/2/quux</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/nested-routes/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<style>\n.parent {\n  border: 1px solid #f66;\n  padding: 10px;\n}\n.child {\n  border: 1px solid #f66;\n  padding: 10px 20px;\n}\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/nested-routes.js\"></script>\n"
  },
  {
    "path": "examples/redirect/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<router-view></router-view>' }\nconst Default = { template: '<div>default</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Baz = { template: '<div>baz</div>' }\nconst WithParams = { template: '<div>{{ $route.params.id }}</div>' }\nconst Foobar = { template: '<div>foobar</div>' }\nconst FooBar = { template: '<div>FooBar</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home,\n      children: [\n        { path: '', component: Default },\n        { path: 'foo', component: Foo },\n        { path: 'bar', component: Bar },\n        { path: 'baz', name: 'baz', component: Baz },\n        { path: 'with-params/:id', component: WithParams },\n        // relative redirect to a sibling route\n        { path: 'relative-redirect', redirect: 'foo' }\n      ]\n    },\n    // absolute redirect\n    { path: '/absolute-redirect', redirect: '/bar' },\n    // dynamic redirect, note that the target route `to` is available for the redirect function\n    { path: '/dynamic-redirect/:id?',\n      redirect: to => {\n        const { hash, params, query } = to\n        if (query.to === 'foo') {\n          return { path: '/foo', query: null }\n        }\n        if (hash === '#baz') {\n          return { name: 'baz', hash: '' }\n        }\n        if (params.id) {\n          return '/with-params/:id'\n        } else {\n          return '/bar'\n        }\n      }\n    },\n    // named redirect\n    { path: '/named-redirect', redirect: { name: 'baz' }},\n\n    // redirect with params\n    { path: '/redirect-with-params/:id', redirect: '/with-params/:id' },\n\n    // redirect with caseSensitive\n    { path: '/foobar', component: Foobar, caseSensitive: true },\n\n    // redirect with pathToRegexpOptions\n    { path: '/FooBar', component: FooBar, pathToRegexpOptions: { sensitive: true }},\n\n    // catch all redirect\n    { path: '*', redirect: '/' }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Redirect</h1>\n      <ul>\n        <li><router-link to=\"/relative-redirect\">\n          /relative-redirect (redirects to /foo)\n        </router-link></li>\n\n        <li><router-link to=\"/relative-redirect?foo=bar\">\n          /relative-redirect?foo=bar (redirects to /foo?foo=bar)\n        </router-link></li>\n\n        <li><router-link to=\"/absolute-redirect\">\n          /absolute-redirect (redirects to /bar)\n        </router-link></li>\n\n        <li><router-link to=\"/dynamic-redirect\">\n          /dynamic-redirect (redirects to /bar)\n        </router-link></li>\n\n        <li><router-link to=\"/dynamic-redirect/123\">\n          /dynamic-redirect/123 (redirects to /with-params/123)\n        </router-link></li>\n\n        <li><router-link to=\"/dynamic-redirect?to=foo\">\n          /dynamic-redirect?to=foo (redirects to /foo)\n        </router-link></li>\n\n        <li><router-link to=\"/dynamic-redirect#baz\">\n          /dynamic-redirect#baz (redirects to /baz)\n        </router-link></li>\n\n        <li><router-link to=\"/named-redirect\">\n          /named-redirect (redirects to /baz)\n        </router-link></li>\n\n        <li><router-link to=\"/redirect-with-params/123\">\n          /redirect-with-params/123 (redirects to /with-params/123)\n        </router-link></li>\n\n        <li><router-link to=\"/foobar\">\n          /foobar\n        </router-link></li>\n\n        <li><router-link to=\"/FooBar\">\n          /FooBar\n        </router-link></li>\n\n        <li><router-link to=\"/not-found\">\n          /not-found (redirects to /)\n        </router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/redirect/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/redirect.js\"></script>\n"
  },
  {
    "path": "examples/restart-app/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nconst Home = { template: '<div>home</div>' }\nconst Foo = { template: '<div>foo</div>' }\n\nconst routes = [\n  { path: '/', component: Home },\n  { path: '/foo', component: Foo }\n]\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes\n})\n\n// track number of beforeResolve\nconst increment = name => {\n  const counter = document.getElementById(name)\n  counter.innerHTML++\n}\n\ndocument.getElementById('beforeEach').innerHTML = 0\nrouter.beforeEach((to, from, next) => {\n  increment('beforeEach')\n  next()\n})\n\ndocument.getElementById('beforeResolve').innerHTML = 0\nrouter.beforeResolve((to, from, next) => {\n  increment('beforeResolve')\n  next()\n})\n\ndocument.getElementById('afterEach').innerHTML = 0\nrouter.afterEach((to, from) => {\n  increment('afterEach')\n})\n\nVue.use(VueRouter)\n\nlet vueInstance\nconst mountEl = document.getElementById('mount')\nconst unmountEl = document.getElementById('unmount')\n\nmountEl.addEventListener('click', () => {\n  vueInstance = new Vue({\n    router,\n    template: `\n      <div id=\"app\">\n        <h1>Hello \"Restart-app\"</h1>\n        <ul>\n          <li><router-link to=\"/\">Go to Home</router-link></li>\n          <li><router-link to=\"/foo\">Go to Foo</router-link></li>\n        </ul>\n        <router-view id=\"view\"></router-view>\n      </div>\n    `\n  }).$mount('#app')\n})\n\nunmountEl.addEventListener('click', () => {\n  vueInstance.$destroy()\n  vueInstance.$el.innerHTML = ''\n})\n"
  },
  {
    "path": "examples/restart-app/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n\n<hr />\n\n<button id=\"mount\">mount</button>\n<button id=\"unmount\">unmount</button>\n\n<hr />\n\nCount beforeEach: <span id=\"beforeEach\"></span><br />\nCount beforeResolve: <span id=\"beforeResolve\"></span><br />\nCount afterEach: <span id=\"afterEach\"></span><br />\n\n<hr />\n\n<div id=\"app\"></div>\n\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/restart-app.js\"></script>"
  },
  {
    "path": "examples/route-alias/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Root = { template: '<div>root</div>' }\nconst Home = { template: '<div><h1>Home</h1><router-view></router-view></div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Baz = { template: '<div>baz</div>' }\nconst Default = { template: '<div>default</div>' }\nconst Nested = { template: '<router-view/>' }\nconst NestedFoo = { template: '<div>nested foo</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/root', component: Root, alias: '/root-alias' },\n    { path: '/home', component: Home,\n      children: [\n        // absolute alias\n        { path: 'foo', component: Foo, alias: '/foo' },\n        // relative alias (alias to /home/bar-alias)\n        { path: 'bar', component: Bar, alias: 'bar-alias' },\n        // multiple aliases\n        { path: 'baz', component: Baz, alias: ['/baz', 'baz-alias'] },\n        // default child route with empty string as alias.\n        { path: 'default', component: Default, alias: '' },\n        // nested alias\n        { path: 'nested', component: Nested, alias: 'nested-alias',\n          children: [\n            { path: 'foo', component: NestedFoo }\n          ]\n        }\n      ]\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Route Alias</h1>\n      <ul>\n        <li><router-link to=\"/root-alias\">\n          /root-alias (renders /root)\n        </router-link></li>\n\n        <li><router-link to=\"/foo\">\n          /foo (renders /home/foo)\n        </router-link></li>\n\n        <li><router-link to=\"/home/bar-alias\">\n          /home/bar-alias (renders /home/bar)\n        </router-link></li>\n\n        <li><router-link to=\"/baz\">\n          /baz (renders /home/baz)\n        </router-link></li>\n\n        <li><router-link to=\"/home/baz-alias\">\n          /home/baz-alias (renders /home/baz)\n        </router-link></li>\n\n        <li><router-link to=\"/home\">\n          /home (renders /home/default)\n        </router-link></li>\n\n        <li><router-link to=\"/home/nested-alias/foo\">\n          /home/nested-alias/foo (renders /home/nested/foo)\n        </router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/route-alias/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/route-alias.js\"></script>\n"
  },
  {
    "path": "examples/route-matching/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\n// The matching uses path-to-regexp, which is the matching engine used\n// by express as well, so the same matching rules apply.\n// For detailed rules, see https://github.com/pillarjs/path-to-regexp\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/' },\n    // params are denoted with a colon \":\"\n    { path: '/params/:foo/:bar' },\n    // a param can be made optional by adding \"?\"\n    { path: '/optional-params/:foo?' },\n    // a param can be followed by a regex pattern in parens\n    // this route will only be matched if :id is all numbers\n    { path: '/params-with-regex/:id(\\\\d+)' },\n    // asterisk can match anything\n    { path: '/asterisk/*' },\n    // make part of the path optional by wrapping with parens and add \"?\"\n    { path: '/optional-group/(foo/)?bar' }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Route Matching</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/params/foo/bar\">/params/foo/bar</router-link></li>\n        <li><router-link to=\"/optional-params\">/optional-params</router-link></li>\n        <li><router-link to=\"/optional-params/foo\">/optional-params/foo</router-link></li>\n        <li><router-link to=\"/params-with-regex/123\">/params-with-regex/123</router-link></li>\n        <li><router-link to=\"/params-with-regex/abc\">/params-with-regex/abc</router-link></li>\n        <li><router-link to=\"/asterisk/foo\">/asterisk/foo</router-link></li>\n        <li><router-link to=\"/asterisk/foo/bar\">/asterisk/foo/bar</router-link></li>\n        <li><router-link to=\"/optional-group/bar\">/optional-group/bar</router-link></li>\n        <li><router-link to=\"/optional-group/foo/bar\">/optional-group/foo/bar</router-link></li>\n      </ul>\n      <p>Route context</p>\n      <pre>{{ JSON.stringify($route, null, 2) }}</pre>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/route-matching/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/route-matching.js\"></script>\n"
  },
  {
    "path": "examples/route-params/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Log = {\n  template: `<div class=\"log\">id: {{ $route.params.id }}, type: {{ $route.params.type }}</div>`\n}\n\nconst Logs = {\n  template: `\n    <div>\n      <pre id=\"params\">{{ to.params }}</pre>\n      <router-link :to=\"to\" class=\"child-link\">{{ to.params.type }}</router-link>\n      <router-view></router-view>\n    </div>\n  `,\n  data () {\n    return {\n      to: {\n        name: 'items.logs.type',\n        params: { type: 'info' }\n      }\n    }\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    {\n      path: '/items/:id/logs',\n      component: Logs,\n      children: [\n        {\n          path: ':type',\n          name: 'items.logs.type',\n          component: Log\n        }\n      ]\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Route params</h1>\n      <ul>\n        <li><router-link to=\"/items/1/logs\">item #1</router-link></li>\n        <li><router-link to=\"/items/2/logs\">item #2</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/route-params/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/route-params.js\"></script>\n"
  },
  {
    "path": "examples/route-props/Hello.vue",
    "content": "<template>\n  <div>\n    <h2 class=\"hello\">Hello {{name}} {{ $attrs }}</h2>\n  </div>\n</template>\n\n<script>\n\nexport default {\n  props: {\n    name: {\n      type: String,\n      default: 'Vue!'\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/route-props/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport Hello from './Hello.vue'\n\nVue.use(VueRouter)\n\nfunction dynamicPropsFn (route) {\n  const now = new Date()\n  return {\n    name: (now.getFullYear() + parseInt(route.params.years)) + '!'\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Hello }, // No props, no nothing\n    { path: '/hello/:name', component: Hello, props: true }, // Pass route.params to props\n    { path: '/static', component: Hello, props: { name: 'world' }}, // static values\n    { path: '/dynamic/:years', component: Hello, props: dynamicPropsFn }, // custom logic for mapping between route and props\n    { path: '/attrs', component: Hello, props: { name: 'attrs' }}\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Route props</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/hello/you\">/hello/you</router-link></li>\n        <li><router-link to=\"/static\">/static</router-link></li>\n        <li><router-link to=\"/dynamic/1\">/dynamic/1</router-link></li>\n        <li><router-link to=\"/attrs\">/attrs</router-link></li>\n      </ul>\n      <router-view class=\"view\" foo=\"123\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/route-props/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/route-props.js\"></script>\n"
  },
  {
    "path": "examples/router-errors/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nconst component = {\n  template: `\n  <div>\n  {{ $route.fullPath }}\n  </div>\n  `\n}\n\nVue.use(VueRouter)\n\nconst router = new VueRouter({\n  routes: [\n    { path: '/', component }, { path: '/foo', component }\n  ]\n})\n\nwindow.router = router\n\nrouter.beforeEach((to, from, next) => {\n  console.log('from', from.fullPath)\n  console.log('going to', to.fullPath)\n  if (to.query.wait) {\n    setTimeout(() => next(), 100)\n  } else if (to.query.redirect) {\n    next(to.query.redirect)\n  } else if (to.query.abort) {\n    next(false)\n  } else {\n    next()\n  }\n})\n\nnew Vue({\n  el: '#app',\n  router\n})\n\n// 4 NAVIGATION ERROR CASES :\n\n// navigation duplicated\n// router.push('/foo')\n// router.push('/foo')\n\n// navigation cancelled\n// router.push('/foo?wait=y')\n// router.push('/')\n\n// navigation redirected\n// router.push('/foo?redirect=/')\n\n// navigation aborted\n// router.push('/foo?abort=y')\n"
  },
  {
    "path": "examples/router-errors/index.html",
    "content": "<!DOCTYPE html>\n<div id=\"app\">\n  <router-link to=\"/\">/</router-link>\n  <router-link to=\"/foo\">/foo</router-link>\n  <router-view></router-view>\n</div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/router-errors.js\"></script>\n"
  },
  {
    "path": "examples/scroll-behavior/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div class=\"home\">home</div>' }\nconst Foo = { template: '<div class=\"foo\">foo</div>' }\nconst Bar = {\n  template: `\n    <div class=\"bar\">\n      bar\n      <div style=\"height:1500px\"></div>\n      <p id=\"anchor\" style=\"height:500px\">Anchor</p>\n      <p id=\"anchor2\" style=\"height:500px\">Anchor2</p>\n      <p id=\"1number\">with number</p>\n    </div>\n  `\n}\n\n// scrollBehavior:\n// - only available in html5 history mode\n// - defaults to no scroll behavior\n// - return false to prevent scroll\nconst scrollBehavior = function (to, from, savedPosition) {\n  if (savedPosition) {\n    // savedPosition is only available for popstate navigations.\n    return savedPosition\n  } else {\n    const position = {}\n\n    // scroll to anchor by returning the selector\n    if (to.hash) {\n      position.selector = to.hash\n\n      // specify offset of the element\n      if (to.hash === '#anchor2') {\n        position.offset = { y: 100 }\n      }\n\n      // bypass #1number check\n      if (/^#\\d/.test(to.hash) || document.querySelector(to.hash)) {\n        return position\n      }\n\n      // if the returned position is falsy or an empty object,\n      // will retain current scroll position.\n      return false\n    }\n\n    return new Promise(resolve => {\n      // check if any matched route config has meta that requires scrolling to top\n      if (to.matched.some(m => m.meta.scrollToTop)) {\n        // coords will be used if no selector is provided,\n        // or if the selector didn't match any element.\n        position.x = 0\n        position.y = 0\n      }\n\n      // wait for the out transition to complete (if necessary)\n      this.app.$root.$once('triggerScroll', () => {\n        // if the resolved position is falsy or an empty object,\n        // will retain current scroll position.\n        resolve(position)\n      })\n    })\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  scrollBehavior,\n  routes: [\n    { path: '/', component: Home, meta: { scrollToTop: true }},\n    { path: '/foo', component: Foo },\n    { path: '/bar', component: Bar, meta: { scrollToTop: true }}\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Scroll Behavior</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n        <li><router-link to=\"/bar#anchor\">/bar#anchor</router-link></li>\n        <li><router-link to=\"/bar#anchor2\">/bar#anchor2</router-link></li>\n        <li><router-link to=\"/bar#1number\">/bar#1number</router-link></li>\n      </ul>\n      <transition name=\"fade\" mode=\"out-in\" @after-leave=\"afterLeave\">\n        <router-view class=\"view\"></router-view>\n      </transition>\n    </div>\n  `,\n  methods: {\n    afterLeave () {\n      this.$root.$emit('triggerScroll')\n    }\n  }\n}).$mount('#app')\n"
  },
  {
    "path": "examples/scroll-behavior/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\" />\n<style>\n  .fade-enter-active,\n  .fade-leave-active {\n    transition: opacity 0.5s ease;\n  }\n  .fade-enter,\n  .fade-leave-active {\n    opacity: 0;\n  }\n  .view {\n    border: 1px solid red;\n    height: 4500px;\n    position: relative;\n  }\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/scroll-behavior.js\"></script>\n"
  },
  {
    "path": "examples/server.js",
    "content": "const express = require('express')\nconst rewrite = require('express-urlrewrite')\nconst webpack = require('webpack')\nconst webpackDevMiddleware = require('webpack-dev-middleware')\nconst WebpackConfig = require('./webpack.config')\n\nconst app = express()\n\napp.use(\n  webpackDevMiddleware(webpack(WebpackConfig), {\n    publicPath: '/__build__/',\n    stats: {\n      colors: true,\n      chunks: false\n    }\n  })\n)\n\nconst fs = require('fs')\nconst path = require('path')\n\nfs.readdirSync(__dirname).forEach(file => {\n  if (fs.statSync(path.join(__dirname, file)).isDirectory()) {\n    app.use(rewrite('/' + file + '/*', '/' + file + '/index.html'))\n  }\n})\n\napp.use(express.static(__dirname))\n\nconst host = process.env.HOST || 'localhost'\nconst port = process.env.PORT || 8080\nmodule.exports = app.listen(port, host, () => {\n  console.log(`Server listening on http://${host}:${port}, Ctrl+C to stop`)\n})\n"
  },
  {
    "path": "examples/transitions/app.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n\nVue.use(VueRouter)\n\nconst Home = {\n  template: `\n    <div class=\"home\">\n      <h2>Home</h2>\n      <p>hello</p>\n    </div>\n  `\n}\n\nconst Parent = {\n  data () {\n    return {\n      transitionName: 'slide-left'\n    }\n  },\n  beforeRouteUpdate (to, from, next) {\n    const toDepth = to.path.split('/').length\n    const fromDepth = from.path.split('/').length\n    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'\n    next()\n  },\n  template: `\n    <div class=\"parent\">\n      <h2>Parent</h2>\n      <transition :name=\"transitionName\">\n        <router-view class=\"child-view\"></router-view>\n      </transition>\n    </div>\n  `\n}\n\nconst Default = { template: '<div class=\"default\">default</div>' }\nconst Foo = { template: '<div class=\"foo\">foo</div>' }\nconst Bar = { template: '<div class=\"bar\">bar</div>' }\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: __dirname,\n  routes: [\n    { path: '/', component: Home },\n    { path: '/parent', component: Parent,\n      children: [\n        { path: '', component: Default },\n        { path: 'foo', component: Foo },\n        { path: 'bar', component: Bar }\n      ]\n    }\n  ]\n})\n\nnew Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Transitions</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/parent\">/parent</router-link></li>\n        <li><router-link to=\"/parent/foo\">/parent/foo</router-link></li>\n        <li><router-link to=\"/parent/bar\">/parent/bar</router-link></li>\n      </ul>\n      <transition name=\"fade\" mode=\"out-in\">\n        <router-view class=\"view\"></router-view>\n      </transition>\n    </div>\n  `\n}).$mount('#app')\n"
  },
  {
    "path": "examples/transitions/index.html",
    "content": "<!DOCTYPE html>\n<link rel=\"stylesheet\" href=\"/global.css\">\n<style>\n.fade-enter-active, .fade-leave-active {\n  transition: opacity .75s ease;\n}\n.fade-enter, .fade-leave-active {\n  opacity: 0;\n}\n.child-view {\n  position: absolute;\n  transition: all .75s cubic-bezier(.55,0,.1,1);\n}\n.slide-left-enter, .slide-right-leave-active {\n  opacity: 0;\n  -webkit-transform: translate(30px, 0);\n  transform: translate(30px, 0);\n}\n.slide-left-leave-active, .slide-right-enter {\n  opacity: 0;\n  -webkit-transform: translate(-30px, 0);\n  transform: translate(-30px, 0);\n}\n</style>\n<a href=\"/\">&larr; Examples index</a>\n<div id=\"app\"></div>\n<script src=\"/__build__/shared.chunk.js\"></script>\n<script src=\"/__build__/transitions.js\"></script>\n"
  },
  {
    "path": "examples/webpack.config.js",
    "content": "const fs = require('fs')\nconst path = require('path')\nconst VuePlugin = require('vue-loader/lib/plugin')\n\nmodule.exports = {\n  // Expose __dirname to allow automatically setting basename.\n  context: __dirname,\n  node: {\n    __dirname: true\n  },\n\n  mode: process.env.NODE_ENV || 'development',\n\n  entry: fs.readdirSync(__dirname).reduce((entries, dir) => {\n    const fullDir = path.join(__dirname, dir)\n    const entry = path.join(fullDir, 'app.js')\n    if (fs.statSync(fullDir).isDirectory() && fs.existsSync(entry)) {\n      entries[dir] = ['es6-promise/auto', entry]\n    }\n\n    return entries\n  }, {}),\n\n  output: {\n    path: path.join(__dirname, '__build__'),\n    filename: '[name].js',\n    chunkFilename: '[id].chunk.js',\n    publicPath: '/__build__/'\n  },\n\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        exclude: /node_modules/,\n        use: 'babel-loader'\n      },\n      {\n        test: /\\.vue$/,\n        use: 'vue-loader'\n      },\n      {\n        test: /\\.css$/,\n        use: ['vue-style-loader', 'css-loader']\n      }\n    ]\n  },\n\n  resolve: {\n    alias: {\n      vue: 'vue/dist/vue.esm.js',\n      'vue-router': path.join(__dirname, '..', 'src'),\n      'vue-router/composables': path.join(__dirname, '..', 'src/composables')\n    }\n  },\n\n  optimization: {\n    splitChunks: {\n      cacheGroups: {\n        shared: {\n          name: 'shared',\n          chunks: 'initial',\n          minChunks: 2\n        }\n      }\n    }\n  },\n\n  plugins: [new VuePlugin()]\n}\n"
  },
  {
    "path": "flow/declarations.js",
    "content": "declare var document: Document;\n\ndeclare class RouteRegExp extends RegExp {\n  keys: Array<{ name: string, optional: boolean }>;\n}\n\ndeclare type PathToRegexpOptions = {\n  sensitive?: boolean,\n  strict?: boolean,\n  end?: boolean\n}\n\ndeclare module 'path-to-regexp' {\n  declare module.exports: {\n    (path: string, keys?: Array<?{ name: string }>, options?: PathToRegexpOptions): RouteRegExp;\n    compile: (path: string) => (params: Object) => string;\n  }\n}\n\ndeclare type Dictionary<T> = { [key: string]: T }\n\ndeclare type NavigationGuard = (\n  to: Route,\n  from: Route,\n  next: (to?: RawLocation | false | Function | void) => void\n) => any\n\ndeclare type AfterNavigationHook = (to: Route, from: Route) => any\n\ntype Position = { x: number, y: number };\ntype PositionResult = Position | { selector: string, offset?: Position } | void;\n\ndeclare type RouterOptions = {\n  routes?: Array<RouteConfig>;\n  mode?: string;\n  fallback?: boolean;\n  base?: string;\n  linkActiveClass?: string;\n  linkExactActiveClass?: string;\n  parseQuery?: (query: string) => Object;\n  stringifyQuery?: (query: Object) => string;\n  scrollBehavior?: (\n    to: Route,\n    from: Route,\n    savedPosition: ?Position\n  ) => PositionResult | Promise<PositionResult>;\n}\n\ndeclare type RedirectOption = RawLocation | ((to: Route) => RawLocation)\n\ndeclare type RouteConfig = {\n  path: string;\n  name?: string;\n  component?: any;\n  components?: Dictionary<any>;\n  redirect?: RedirectOption;\n  alias?: string | Array<string>;\n  children?: Array<RouteConfig>;\n  beforeEnter?: NavigationGuard;\n  meta?: any;\n  props?: boolean | Object | Function;\n  caseSensitive?: boolean;\n  pathToRegexpOptions?: PathToRegexpOptions;\n}\n\ndeclare type RouteRecord = {\n  path: string;\n  alias: Array<string>;\n  regex: RouteRegExp;\n  components: Dictionary<any>;\n  instances: Dictionary<any>;\n  enteredCbs: Dictionary<Array<Function>>;\n  name: ?string;\n  parent: ?RouteRecord;\n  redirect: ?RedirectOption;\n  matchAs: ?string;\n  beforeEnter: ?NavigationGuard;\n  meta: any;\n  props: boolean | Object | Function | Dictionary<boolean | Object | Function>;\n}\n\ndeclare type Location = {\n  _normalized?: boolean;\n  name?: string;\n  path?: string;\n  hash?: string;\n  query?: Dictionary<string>;\n  params?: Dictionary<string>;\n  append?: boolean;\n  replace?: boolean;\n}\n\ndeclare type RawLocation = string | Location\n\ndeclare type Route = {\n  path: string;\n  name: ?string;\n  hash: string;\n  query: Dictionary<string>;\n  params: Dictionary<string>;\n  fullPath: string;\n  matched: Array<RouteRecord>;\n  redirectedFrom?: string;\n  meta?: any;\n}\n"
  },
  {
    "path": "netlify.toml",
    "content": "[build]\n  ignore = \"git diff --quiet HEAD^ HEAD ./docs/\"\n  publish = \"docs/.vuepress/dist\"\n  command = \"yarn run docs:build\"\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vue-router\",\n  \"version\": \"3.6.5\",\n  \"description\": \"Official router for Vue.js 2\",\n  \"author\": \"Evan You\",\n  \"license\": \"MIT\",\n  \"main\": \"dist/vue-router.common.js\",\n  \"module\": \"dist/vue-router.esm.js\",\n  \"unpkg\": \"dist/vue-router.js\",\n  \"jsdelivr\": \"dist/vue-router.js\",\n  \"sideEffects\": false,\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/vuejs/vue-router.git\"\n  },\n  \"typings\": \"types/index.d.ts\",\n  \"files\": [\n    \"src\",\n    \"dist/*.js\",\n    \"dist/*.mjs\",\n    \"types/*.d.ts\",\n    \"composables.mjs\",\n    \"composables.js\",\n    \"composables.d.ts\",\n    \"vetur/tags.json\",\n    \"vetur/attributes.json\"\n  ],\n  \"exports\": {\n    \".\": {\n      \"import\": {\n        \"node\": \"./dist/vue-router.mjs\",\n        \"default\": \"./dist/vue-router.esm.js\"\n      },\n      \"require\": \"./dist/vue-router.common.js\",\n      \"types\": \"./types/index.d.ts\"\n    },\n    \"./composables\": {\n      \"import\": \"./composables.mjs\",\n      \"require\": \"./composables.js\",\n      \"types\": \"./composables.d.ts\"\n    },\n    \"./dist/*\": \"./dist/*\",\n    \"./types/*\": \"./types/*\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"vetur\": {\n    \"tags\": \"vetur/tags.json\",\n    \"attributes\": \"vetur/attributes.json\"\n  },\n  \"keywords\": [\n    \"vue\",\n    \"router\",\n    \"routing\"\n  ],\n  \"scripts\": {\n    \"dev\": \"node examples/server.js\",\n    \"dev:dist\": \"rollup -wm -c build/rollup.dev.config.js\",\n    \"build\": \"node build/build.js\",\n    \"lint\": \"eslint src examples test\",\n    \"test\": \"npm run lint && npm run flow && npm run test:unit && npm run test:e2e && npm run test:types\",\n    \"flow\": \"flow check\",\n    \"test:unit\": \"jasmine JASMINE_CONFIG_PATH=test/unit/jasmine.json\",\n    \"test:e2e\": \"node test/e2e/runner.js\",\n    \"test:e2e:ci\": \"node test/e2e/runner.js --local -e ie,android44 -c test/e2e/nightwatch.browserstack.js test/e2e/specs/active-links.js\",\n    \"test:e2e:ff\": \"node test/e2e/runner.js -e firefox -c test/e2e/nightwatch.config.js\",\n    \"test:e2e:ie9\": \"node test/e2e/runner.js --local -e ie9 -c test/e2e/nightwatch.browserstack.js --skiptags history,ie9-fail\",\n    \"test:types\": \"tsc -p types/test\",\n    \"docs\": \"vuepress dev docs\",\n    \"docs:build\": \"vuepress build docs\",\n    \"changelog\": \"conventional-changelog -p angular -r 2 -i CHANGELOG.md -s\",\n    \"release\": \"bash scripts/release.sh\",\n    \"commit\": \"git-cz\"\n  },\n  \"gitHooks\": {\n    \"pre-commit\": \"lint-staged\",\n    \"commit-msg\": \"node scripts/verifyCommitMsg.js\"\n  },\n  \"lint-staged\": {\n    \"*.{js,vue}\": [\n      \"eslint --fix\",\n      \"git add\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^17.0.0\",\n    \"@rollup/plugin-node-resolve\": \"^11.0.0\",\n    \"@vuepress/plugin-pwa\": \"^1.5.3\",\n    \"@vuepress/theme-vue\": \"^1.5.3\",\n    \"axios\": \"^0.28.0\",\n    \"babel-core\": \"^6.24.1\",\n    \"babel-eslint\": \"^10.0.2\",\n    \"babel-loader\": \"^7.1.3\",\n    \"babel-plugin-syntax-dynamic-import\": \"^6.18.0\",\n    \"babel-preset-env\": \"^1.6.1\",\n    \"babel-preset-flow-vue\": \"^1.0.0\",\n    \"browserstack-local\": \"^1.4.8\",\n    \"buble\": \"^0.19.8\",\n    \"chromedriver\": \"^96.0.0\",\n    \"conventional-changelog-cli\": \"^2.0.11\",\n    \"cross-spawn\": \"^7.0.3\",\n    \"css-loader\": \"^2.1.1\",\n    \"dotenv\": \"^8.2.0\",\n    \"es6-promise\": \"^4.2.8\",\n    \"eslint\": \"^4.19.1\",\n    \"eslint-plugin-flowtype\": \"^2.46.1\",\n    \"eslint-plugin-jasmine\": \"^2.10.1\",\n    \"eslint-plugin-vue-libs\": \"^2.1.0\",\n    \"express\": \"^4.17.1\",\n    \"express-urlrewrite\": \"^1.2.0\",\n    \"flow-bin\": \"^0.66.0\",\n    \"geckodriver\": \"^1.20.0\",\n    \"jasmine\": \"2.8.0\",\n    \"lint-staged\": \"^8.2.0\",\n    \"nightwatch\": \"^1.3.6\",\n    \"nightwatch-helpers\": \"^1.0.0\",\n    \"path-to-regexp\": \"^1.8.0\",\n    \"rollup\": \"^2.34.1\",\n    \"rollup-plugin-buble\": \"^0.19.8\",\n    \"rollup-plugin-flow-no-whitespace\": \"^1.0.0\",\n    \"rollup-plugin-replace\": \"^2.0.0\",\n    \"rollup-watch\": \"^4.0.0\",\n    \"selenium-server\": \"^3.141.59\",\n    \"terser\": \"^4.2.0\",\n    \"typescript\": \"^4.7.0\",\n    \"vue\": \"^2.7.0\",\n    \"vue-loader\": \"^15.9.3\",\n    \"vue-server-renderer\": \"^2.7.0\",\n    \"vue-template-compiler\": \"^2.7.0\",\n    \"vuepress\": \"^1.5.3\",\n    \"vuepress-theme-vue\": \"^1.1.1\",\n    \"webpack\": \"^4.35.2\",\n    \"webpack-dev-middleware\": \"^3.7.0\",\n    \"yorkie\": \"^2.0.0\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/vuejs/vue-router/issues\"\n  },\n  \"homepage\": \"https://github.com/vuejs/vue-router#readme\"\n}\n"
  },
  {
    "path": "scripts/release.sh",
    "content": "set -e\necho \"Current version:\" $(grep version package.json | sed -E 's/^.*\"(4[^\"]+)\".*$/\\1/')\necho \"Enter release version e.g. 3.3.0: \"\nread VERSION\n\nread -p \"Releasing v$VERSION - are you sure? (y/n)\" -n 1 -r\necho    # (optional) move to a new line\nif [[ $REPLY =~ ^[Yy]$ ]]\nthen\n  echo \"Releasing v$VERSION ...\"\n\n  # commit\n  VERSION=$VERSION npm run build\n  git add dist composables.*\n  git commit -m \"build: bundle $VERSION\"\n  npm version $VERSION --message \"chore(release): %s\"\n\n  # changelog\n  npm run changelog\n  echo \"Please check the git history and the changelog and press enter\"\n  read OKAY\n  git add CHANGELOG.md\n  git commit -m \"chore(changelog): $VERSION\"\n\n  # publish\n  git push origin refs/tags/v$VERSION\n  git push\n  npm publish --tag legacy\nfi\n"
  },
  {
    "path": "scripts/verifyCommitMsg.js",
    "content": "const chalk = require('chalk')  // eslint-disable-line\nconst msgPath = process.env.GIT_PARAMS\nconst msg = require('fs').readFileSync(msgPath, 'utf-8').trim()\n\nconst commitRE = /^(v\\d+\\.\\d+\\.\\d+(-(alpha|beta|rc.\\d+))?$)|((revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\\(.+\\))?: .{1,50})/\n\nif (!commitRE.test(msg)) {\n  console.log()\n  console.error(\n    `  ${chalk.bgRed.white(' ERROR ')} ${chalk.red(`invalid commit message format.`)}\\n\\n` +\n    chalk.red(`  Proper commit message format is required for automated changelog generation. Examples:\\n\\n`) +\n    `    ${chalk.green(`feat(compiler): add 'comments' option`)}\\n` +\n    `    ${chalk.green(`fix(v-model): handle events on blur (close #28)`)}\\n\\n` +\n    chalk.red(`  See .github/COMMIT_CONVENTION.md for more details.\\n`) +\n    chalk.red(`  You can also use ${chalk.cyan(`npm run commit`)} to interactively generate a commit message.\\n`)\n  )\n  process.exit(1)\n}\n"
  },
  {
    "path": "src/components/link.js",
    "content": "/* @flow */\n\nimport { createRoute, isSameRoute, isIncludedRoute } from '../util/route'\nimport { extend } from '../util/misc'\nimport { normalizeLocation } from '../util/location'\nimport { warn } from '../util/warn'\n\n// work around weird flow bug\nconst toTypes: Array<Function> = [String, Object]\nconst eventTypes: Array<Function> = [String, Array]\n\nconst noop = () => {}\n\nlet warnedCustomSlot\nlet warnedTagProp\nlet warnedEventProp\n\nexport default {\n  name: 'RouterLink',\n  props: {\n    to: {\n      type: toTypes,\n      required: true\n    },\n    tag: {\n      type: String,\n      default: 'a'\n    },\n    custom: Boolean,\n    exact: Boolean,\n    exactPath: Boolean,\n    append: Boolean,\n    replace: Boolean,\n    activeClass: String,\n    exactActiveClass: String,\n    ariaCurrentValue: {\n      type: String,\n      default: 'page'\n    },\n    event: {\n      type: eventTypes,\n      default: 'click'\n    }\n  },\n  render (h: Function) {\n    const router = this.$router\n    const current = this.$route\n    const { location, route, href } = router.resolve(\n      this.to,\n      current,\n      this.append\n    )\n\n    const classes = {}\n    const globalActiveClass = router.options.linkActiveClass\n    const globalExactActiveClass = router.options.linkExactActiveClass\n    // Support global empty active class\n    const activeClassFallback =\n      globalActiveClass == null ? 'router-link-active' : globalActiveClass\n    const exactActiveClassFallback =\n      globalExactActiveClass == null\n        ? 'router-link-exact-active'\n        : globalExactActiveClass\n    const activeClass =\n      this.activeClass == null ? activeClassFallback : this.activeClass\n    const exactActiveClass =\n      this.exactActiveClass == null\n        ? exactActiveClassFallback\n        : this.exactActiveClass\n\n    const compareTarget = route.redirectedFrom\n      ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)\n      : route\n\n    classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath)\n    classes[activeClass] = this.exact || this.exactPath\n      ? classes[exactActiveClass]\n      : isIncludedRoute(current, compareTarget)\n\n    const ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null\n\n    const handler = e => {\n      if (guardEvent(e)) {\n        if (this.replace) {\n          router.replace(location, noop)\n        } else {\n          router.push(location, noop)\n        }\n      }\n    }\n\n    const on = { click: guardEvent }\n    if (Array.isArray(this.event)) {\n      this.event.forEach(e => {\n        on[e] = handler\n      })\n    } else {\n      on[this.event] = handler\n    }\n\n    const data: any = { class: classes }\n\n    const scopedSlot =\n      !this.$scopedSlots.$hasNormal &&\n      this.$scopedSlots.default &&\n      this.$scopedSlots.default({\n        href,\n        route,\n        navigate: handler,\n        isActive: classes[activeClass],\n        isExactActive: classes[exactActiveClass]\n      })\n\n    if (scopedSlot) {\n      if (process.env.NODE_ENV !== 'production' && !this.custom) {\n        !warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\\n<router-link v-slot=\"{ navigate, href }\" custom></router-link>\\n')\n        warnedCustomSlot = true\n      }\n      if (scopedSlot.length === 1) {\n        return scopedSlot[0]\n      } else if (scopedSlot.length > 1 || !scopedSlot.length) {\n        if (process.env.NODE_ENV !== 'production') {\n          warn(\n            false,\n            `<router-link> with to=\"${\n              this.to\n            }\" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.`\n          )\n        }\n        return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)\n      }\n    }\n\n    if (process.env.NODE_ENV !== 'production') {\n      if ('tag' in this.$options.propsData && !warnedTagProp) {\n        warn(\n          false,\n          `<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.`\n        )\n        warnedTagProp = true\n      }\n      if ('event' in this.$options.propsData && !warnedEventProp) {\n        warn(\n          false,\n          `<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.`\n        )\n        warnedEventProp = true\n      }\n    }\n\n    if (this.tag === 'a') {\n      data.on = on\n      data.attrs = { href, 'aria-current': ariaCurrentValue }\n    } else {\n      // find the first <a> child and apply listener and href\n      const a = findAnchor(this.$slots.default)\n      if (a) {\n        // in case the <a> is a static node\n        a.isStatic = false\n        const aData = (a.data = extend({}, a.data))\n        aData.on = aData.on || {}\n        // transform existing events in both objects into arrays so we can push later\n        for (const event in aData.on) {\n          const handler = aData.on[event]\n          if (event in on) {\n            aData.on[event] = Array.isArray(handler) ? handler : [handler]\n          }\n        }\n        // append new listeners for router-link\n        for (const event in on) {\n          if (event in aData.on) {\n            // on[event] is always a function\n            aData.on[event].push(on[event])\n          } else {\n            aData.on[event] = handler\n          }\n        }\n\n        const aAttrs = (a.data.attrs = extend({}, a.data.attrs))\n        aAttrs.href = href\n        aAttrs['aria-current'] = ariaCurrentValue\n      } else {\n        // doesn't have <a> child, apply listener to self\n        data.on = on\n      }\n    }\n\n    return h(this.tag, data, this.$slots.default)\n  }\n}\n\nexport function guardEvent (e: any) {\n  // don't redirect with control keys\n  if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return\n  // don't redirect when preventDefault called\n  if (e.defaultPrevented) return\n  // don't redirect on right click\n  if (e.button !== undefined && e.button !== 0) return\n  // don't redirect if `target=\"_blank\"`\n  if (e.currentTarget && e.currentTarget.getAttribute) {\n    const target = e.currentTarget.getAttribute('target')\n    if (/\\b_blank\\b/i.test(target)) return\n  }\n  // this may be a Weex event which doesn't have this method\n  if (e.preventDefault) {\n    e.preventDefault()\n  }\n  return true\n}\n\nfunction findAnchor (children) {\n  if (children) {\n    let child\n    for (let i = 0; i < children.length; i++) {\n      child = children[i]\n      if (child.tag === 'a') {\n        return child\n      }\n      if (child.children && (child = findAnchor(child.children))) {\n        return child\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/components/view.js",
    "content": "import { warn } from '../util/warn'\nimport { extend } from '../util/misc'\nimport { handleRouteEntered } from '../util/route'\n\nexport default {\n  name: 'RouterView',\n  functional: true,\n  props: {\n    name: {\n      type: String,\n      default: 'default'\n    }\n  },\n  render (_, { props, children, parent, data }) {\n    // used by devtools to display a router-view badge\n    data.routerView = true\n\n    // directly use parent context's createElement() function\n    // so that components rendered by router-view can resolve named slots\n    const h = parent.$createElement\n    const name = props.name\n    const route = parent.$route\n    const cache = parent._routerViewCache || (parent._routerViewCache = {})\n\n    // determine current view depth, also check to see if the tree\n    // has been toggled inactive but kept-alive.\n    let depth = 0\n    let inactive = false\n    while (parent && parent._routerRoot !== parent) {\n      const vnodeData = parent.$vnode ? parent.$vnode.data : {}\n      if (vnodeData.routerView) {\n        depth++\n      }\n      if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {\n        inactive = true\n      }\n      parent = parent.$parent\n    }\n    data.routerViewDepth = depth\n\n    // render previous view if the tree is inactive and kept-alive\n    if (inactive) {\n      const cachedData = cache[name]\n      const cachedComponent = cachedData && cachedData.component\n      if (cachedComponent) {\n        // #2301\n        // pass props\n        if (cachedData.configProps) {\n          fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps)\n        }\n        return h(cachedComponent, data, children)\n      } else {\n        // render previous empty view\n        return h()\n      }\n    }\n\n    const matched = route.matched[depth]\n    const component = matched && matched.components[name]\n\n    // render empty node if no matched route or no config component\n    if (!matched || !component) {\n      cache[name] = null\n      return h()\n    }\n\n    // cache component\n    cache[name] = { component }\n\n    // attach instance registration hook\n    // this will be called in the instance's injected lifecycle hooks\n    data.registerRouteInstance = (vm, val) => {\n      // val could be undefined for unregistration\n      const current = matched.instances[name]\n      if (\n        (val && current !== vm) ||\n        (!val && current === vm)\n      ) {\n        matched.instances[name] = val\n      }\n    }\n\n    // also register instance in prepatch hook\n    // in case the same component instance is reused across different routes\n    ;(data.hook || (data.hook = {})).prepatch = (_, vnode) => {\n      matched.instances[name] = vnode.componentInstance\n    }\n\n    // register instance in init hook\n    // in case kept-alive component be actived when routes changed\n    data.hook.init = (vnode) => {\n      if (vnode.data.keepAlive &&\n        vnode.componentInstance &&\n        vnode.componentInstance !== matched.instances[name]\n      ) {\n        matched.instances[name] = vnode.componentInstance\n      }\n\n      // if the route transition has already been confirmed then we weren't\n      // able to call the cbs during confirmation as the component was not\n      // registered yet, so we call it here.\n      handleRouteEntered(route)\n    }\n\n    const configProps = matched.props && matched.props[name]\n    // save route and configProps in cache\n    if (configProps) {\n      extend(cache[name], {\n        route,\n        configProps\n      })\n      fillPropsinData(component, data, route, configProps)\n    }\n\n    return h(component, data, children)\n  }\n}\n\nfunction fillPropsinData (component, data, route, configProps) {\n  // resolve props\n  let propsToPass = data.props = resolveProps(route, configProps)\n  if (propsToPass) {\n    // clone to prevent mutation\n    propsToPass = data.props = extend({}, propsToPass)\n    // pass non-declared props as attrs\n    const attrs = data.attrs = data.attrs || {}\n    for (const key in propsToPass) {\n      if (!component.props || !(key in component.props)) {\n        attrs[key] = propsToPass[key]\n        delete propsToPass[key]\n      }\n    }\n  }\n}\n\nfunction resolveProps (route, config) {\n  switch (typeof config) {\n    case 'undefined':\n      return\n    case 'object':\n      return config\n    case 'function':\n      return config(route)\n    case 'boolean':\n      return config ? route.params : undefined\n    default:\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false,\n          `props in \"${route.path}\" is a ${typeof config}, ` +\n          `expecting an object, function or boolean.`\n        )\n      }\n  }\n}\n"
  },
  {
    "path": "src/composables/globals.js",
    "content": "import {\n  getCurrentInstance,\n  shallowReactive,\n  effectScope\n} from 'vue'\nimport { throwNoCurrentInstance } from './utils'\n\nexport function useRouter () {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useRouter')\n  }\n\n  return getCurrentInstance().proxy.$root.$router\n}\n\nexport function useRoute () {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useRoute')\n  }\n\n  const root = getCurrentInstance().proxy.$root\n  if (!root._$route) {\n    const route = effectScope(true).run(() =>\n      shallowReactive(Object.assign({}, root.$router.currentRoute))\n    )\n    root._$route = route\n\n    root.$router.afterEach(to => {\n      Object.assign(route, to)\n    })\n  }\n\n  return root._$route\n}\n"
  },
  {
    "path": "src/composables/guards.js",
    "content": "import { getCurrentInstance, onUnmounted } from 'vue'\nimport { throwNoCurrentInstance } from './utils'\nimport { useRouter } from './globals'\n\nexport function onBeforeRouteUpdate (guard) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('onBeforeRouteUpdate')\n  }\n\n  return useFilteredGuard(guard, isUpdateNavigation)\n}\nfunction isUpdateNavigation (to, from, depth) {\n  const toMatched = to.matched\n  const fromMatched = from.matched\n  return (\n    toMatched.length >= depth &&\n    toMatched\n      .slice(0, depth + 1)\n      .every((record, i) => record === fromMatched[i])\n  )\n}\n\nfunction isLeaveNavigation (to, from, depth) {\n  const toMatched = to.matched\n  const fromMatched = from.matched\n  return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]\n}\n\nexport function onBeforeRouteLeave (guard) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('onBeforeRouteLeave')\n  }\n\n  return useFilteredGuard(guard, isLeaveNavigation)\n}\n\nconst noop = () => {}\nfunction useFilteredGuard (guard, fn) {\n  const instance = getCurrentInstance()\n  const router = useRouter()\n\n  let target = instance.proxy\n  // find the nearest RouterView to know the depth\n  while (\n    target &&\n    target.$vnode &&\n    target.$vnode.data &&\n    target.$vnode.data.routerViewDepth == null\n  ) {\n    target = target.$parent\n  }\n\n  const depth =\n    target && target.$vnode && target.$vnode.data\n      ? target.$vnode.data.routerViewDepth\n      : null\n\n  if (depth != null) {\n    const removeGuard = router.beforeEach((to, from, next) => {\n      return fn(to, from, depth) ? guard(to, from, next) : next()\n    })\n\n    onUnmounted(removeGuard)\n    return removeGuard\n  }\n\n  return noop\n}\n"
  },
  {
    "path": "src/composables/index.js",
    "content": "export * from './guards'\nexport * from './globals'\nexport * from './useLink'\n"
  },
  {
    "path": "src/composables/useLink.js",
    "content": "import { computed, unref } from 'vue'\nimport { guardEvent } from '../components/link'\nimport { throwNoCurrentInstance } from './utils'\nimport { useRouter, useRoute } from './globals'\n\nfunction includesParams (outer, inner) {\n  for (const key in inner) {\n    const innerValue = inner[key]\n    const outerValue = outer[key]\n    if (typeof innerValue === 'string') {\n      if (innerValue !== outerValue) return false\n    } else {\n      if (\n        !Array.isArray(outerValue) ||\n        outerValue.length !== innerValue.length ||\n        innerValue.some((value, i) => value !== outerValue[i])\n      ) {\n        return false\n      }\n    }\n  }\n\n  return true\n}\n\n// helpers from vue router 4\n\nfunction isSameRouteLocationParamsValue (a, b) {\n  return Array.isArray(a)\n    ? isEquivalentArray(a, b)\n    : Array.isArray(b)\n      ? isEquivalentArray(b, a)\n      : a === b\n}\n\nfunction isEquivalentArray (a, b) {\n  return Array.isArray(b)\n    ? a.length === b.length && a.every((value, i) => value === b[i])\n    : a.length === 1 && a[0] === b\n}\n\nexport function isSameRouteLocationParams (a, b) {\n  if (Object.keys(a).length !== Object.keys(b).length) return false\n\n  for (const key in a) {\n    if (!isSameRouteLocationParamsValue(a[key], b[key])) return false\n  }\n\n  return true\n}\n\nexport function useLink (props) {\n  if (process.env.NODE_ENV !== 'production') {\n    throwNoCurrentInstance('useLink')\n  }\n\n  const router = useRouter()\n  const currentRoute = useRoute()\n\n  const resolvedRoute = computed(() => router.resolve(unref(props.to), currentRoute))\n\n  const activeRecordIndex = computed(() => {\n    const route = resolvedRoute.value.route\n    const { matched } = route\n    const { length } = matched\n    const routeMatched = matched[length - 1]\n    const currentMatched = currentRoute.matched\n    if (!routeMatched || !currentMatched.length) return -1\n    const index = currentMatched.indexOf(routeMatched)\n    if (index > -1) return index\n    // possible parent record\n    const parentRecord = currentMatched[currentMatched.length - 2]\n\n    return (\n      // we are dealing with nested routes\n      length > 1 &&\n        // if the parent and matched route have the same path, this link is\n        // referring to the empty child. Or we currently are on a different\n        // child of the same parent\n        parentRecord && parentRecord === routeMatched.parent\n    )\n  })\n\n  const isActive = computed(\n    () =>\n      activeRecordIndex.value > -1 &&\n      includesParams(currentRoute.params, resolvedRoute.value.route.params)\n  )\n  const isExactActive = computed(\n    () =>\n      activeRecordIndex.value > -1 &&\n      activeRecordIndex.value === currentRoute.matched.length - 1 &&\n      isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params)\n  )\n\n  const navigate = e => {\n    const href = resolvedRoute.value.route\n    if (guardEvent(e)) {\n      return props.replace\n        ? router.replace(href)\n        : router.push(href)\n    }\n    return Promise.resolve()\n  }\n\n  return {\n    href: computed(() => resolvedRoute.value.href),\n    route: computed(() => resolvedRoute.value.route),\n    isExactActive,\n    isActive,\n    navigate\n  }\n}\n"
  },
  {
    "path": "src/composables/utils.js",
    "content": "import { getCurrentInstance } from 'vue'\n\n// dev only warn if no current instance\n\nexport function throwNoCurrentInstance (method) {\n  if (!getCurrentInstance()) {\n    throw new Error(\n      `[vue-router]: Missing current instance. ${method}() must be called inside <script setup> or setup().`\n    )\n  }\n}\n"
  },
  {
    "path": "src/create-matcher.js",
    "content": "/* @flow */\n\nimport type VueRouter from './index'\nimport { resolvePath } from './util/path'\nimport { assert, warn } from './util/warn'\nimport { createRoute } from './util/route'\nimport { fillParams } from './util/params'\nimport { createRouteMap } from './create-route-map'\nimport { normalizeLocation } from './util/location'\nimport { decode } from './util/query'\n\nexport type Matcher = {\n  match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;\n  addRoutes: (routes: Array<RouteConfig>) => void;\n  addRoute: (parentNameOrRoute: string | RouteConfig, route?: RouteConfig) => void;\n  getRoutes: () => Array<RouteRecord>;\n};\n\nexport function createMatcher (\n  routes: Array<RouteConfig>,\n  router: VueRouter\n): Matcher {\n  const { pathList, pathMap, nameMap } = createRouteMap(routes)\n\n  function addRoutes (routes) {\n    createRouteMap(routes, pathList, pathMap, nameMap)\n  }\n\n  function addRoute (parentOrRoute, route) {\n    const parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined\n    // $flow-disable-line\n    createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent)\n\n    // add aliases of parent\n    if (parent && parent.alias.length) {\n      createRouteMap(\n        // $flow-disable-line route is defined if parent is\n        parent.alias.map(alias => ({ path: alias, children: [route] })),\n        pathList,\n        pathMap,\n        nameMap,\n        parent\n      )\n    }\n  }\n\n  function getRoutes () {\n    return pathList.map(path => pathMap[path])\n  }\n\n  function match (\n    raw: RawLocation,\n    currentRoute?: Route,\n    redirectedFrom?: Location\n  ): Route {\n    const location = normalizeLocation(raw, currentRoute, false, router)\n    const { name } = location\n\n    if (name) {\n      const record = nameMap[name]\n      if (process.env.NODE_ENV !== 'production') {\n        warn(record, `Route with name '${name}' does not exist`)\n      }\n      if (!record) return _createRoute(null, location)\n      const paramNames = record.regex.keys\n        .filter(key => !key.optional)\n        .map(key => key.name)\n\n      if (typeof location.params !== 'object') {\n        location.params = {}\n      }\n\n      if (currentRoute && typeof currentRoute.params === 'object') {\n        for (const key in currentRoute.params) {\n          if (!(key in location.params) && paramNames.indexOf(key) > -1) {\n            location.params[key] = currentRoute.params[key]\n          }\n        }\n      }\n\n      location.path = fillParams(record.path, location.params, `named route \"${name}\"`)\n      return _createRoute(record, location, redirectedFrom)\n    } else if (location.path) {\n      location.params = {}\n      for (let i = 0; i < pathList.length; i++) {\n        const path = pathList[i]\n        const record = pathMap[path]\n        if (matchRoute(record.regex, location.path, location.params)) {\n          return _createRoute(record, location, redirectedFrom)\n        }\n      }\n    }\n    // no match\n    return _createRoute(null, location)\n  }\n\n  function redirect (\n    record: RouteRecord,\n    location: Location\n  ): Route {\n    const originalRedirect = record.redirect\n    let redirect = typeof originalRedirect === 'function'\n      ? originalRedirect(createRoute(record, location, null, router))\n      : originalRedirect\n\n    if (typeof redirect === 'string') {\n      redirect = { path: redirect }\n    }\n\n    if (!redirect || typeof redirect !== 'object') {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(\n          false, `invalid redirect option: ${JSON.stringify(redirect)}`\n        )\n      }\n      return _createRoute(null, location)\n    }\n\n    const re: Object = redirect\n    const { name, path } = re\n    let { query, hash, params } = location\n    query = re.hasOwnProperty('query') ? re.query : query\n    hash = re.hasOwnProperty('hash') ? re.hash : hash\n    params = re.hasOwnProperty('params') ? re.params : params\n\n    if (name) {\n      // resolved named direct\n      const targetRecord = nameMap[name]\n      if (process.env.NODE_ENV !== 'production') {\n        assert(targetRecord, `redirect failed: named route \"${name}\" not found.`)\n      }\n      return match({\n        _normalized: true,\n        name,\n        query,\n        hash,\n        params\n      }, undefined, location)\n    } else if (path) {\n      // 1. resolve relative redirect\n      const rawPath = resolveRecordPath(path, record)\n      // 2. resolve params\n      const resolvedPath = fillParams(rawPath, params, `redirect route with path \"${rawPath}\"`)\n      // 3. rematch with existing query and hash\n      return match({\n        _normalized: true,\n        path: resolvedPath,\n        query,\n        hash\n      }, undefined, location)\n    } else {\n      if (process.env.NODE_ENV !== 'production') {\n        warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`)\n      }\n      return _createRoute(null, location)\n    }\n  }\n\n  function alias (\n    record: RouteRecord,\n    location: Location,\n    matchAs: string\n  ): Route {\n    const aliasedPath = fillParams(matchAs, location.params, `aliased route with path \"${matchAs}\"`)\n    const aliasedMatch = match({\n      _normalized: true,\n      path: aliasedPath\n    })\n    if (aliasedMatch) {\n      const matched = aliasedMatch.matched\n      const aliasedRecord = matched[matched.length - 1]\n      location.params = aliasedMatch.params\n      return _createRoute(aliasedRecord, location)\n    }\n    return _createRoute(null, location)\n  }\n\n  function _createRoute (\n    record: ?RouteRecord,\n    location: Location,\n    redirectedFrom?: Location\n  ): Route {\n    if (record && record.redirect) {\n      return redirect(record, redirectedFrom || location)\n    }\n    if (record && record.matchAs) {\n      return alias(record, location, record.matchAs)\n    }\n    return createRoute(record, location, redirectedFrom, router)\n  }\n\n  return {\n    match,\n    addRoute,\n    getRoutes,\n    addRoutes\n  }\n}\n\nfunction matchRoute (\n  regex: RouteRegExp,\n  path: string,\n  params: Object\n): boolean {\n  const m = path.match(regex)\n\n  if (!m) {\n    return false\n  } else if (!params) {\n    return true\n  }\n\n  for (let i = 1, len = m.length; i < len; ++i) {\n    const key = regex.keys[i - 1]\n    if (key) {\n      // Fix #1994: using * with props: true generates a param named 0\n      params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i]\n    }\n  }\n\n  return true\n}\n\nfunction resolveRecordPath (path: string, record: RouteRecord): string {\n  return resolvePath(path, record.parent ? record.parent.path : '/', true)\n}\n"
  },
  {
    "path": "src/create-route-map.js",
    "content": "/* @flow */\n\nimport Regexp from 'path-to-regexp'\nimport { cleanPath } from './util/path'\nimport { assert, warn } from './util/warn'\n\nexport function createRouteMap (\n  routes: Array<RouteConfig>,\n  oldPathList?: Array<string>,\n  oldPathMap?: Dictionary<RouteRecord>,\n  oldNameMap?: Dictionary<RouteRecord>,\n  parentRoute?: RouteRecord\n): {\n  pathList: Array<string>,\n  pathMap: Dictionary<RouteRecord>,\n  nameMap: Dictionary<RouteRecord>\n} {\n  // the path list is used to control path matching priority\n  const pathList: Array<string> = oldPathList || []\n  // $flow-disable-line\n  const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null)\n  // $flow-disable-line\n  const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null)\n\n  routes.forEach(route => {\n    addRouteRecord(pathList, pathMap, nameMap, route, parentRoute)\n  })\n\n  // ensure wildcard routes are always at the end\n  for (let i = 0, l = pathList.length; i < l; i++) {\n    if (pathList[i] === '*') {\n      pathList.push(pathList.splice(i, 1)[0])\n      l--\n      i--\n    }\n  }\n\n  if (process.env.NODE_ENV === 'development') {\n    // warn if routes do not include leading slashes\n    const found = pathList\n    // check for missing leading slash\n      .filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/')\n\n    if (found.length > 0) {\n      const pathNames = found.map(path => `- ${path}`).join('\\n')\n      warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \\n${pathNames}`)\n    }\n  }\n\n  return {\n    pathList,\n    pathMap,\n    nameMap\n  }\n}\n\nfunction addRouteRecord (\n  pathList: Array<string>,\n  pathMap: Dictionary<RouteRecord>,\n  nameMap: Dictionary<RouteRecord>,\n  route: RouteConfig,\n  parent?: RouteRecord,\n  matchAs?: string\n) {\n  const { path, name } = route\n  if (process.env.NODE_ENV !== 'production') {\n    assert(path != null, `\"path\" is required in a route configuration.`)\n    assert(\n      typeof route.component !== 'string',\n      `route config \"component\" for path: ${String(\n        path || name\n      )} cannot be a ` + `string id. Use an actual component instead.`\n    )\n\n    warn(\n      // eslint-disable-next-line no-control-regex\n      !/[^\\u0000-\\u007F]+/.test(path),\n      `Route with path \"${path}\" contains unencoded characters, make sure ` +\n        `your path is correctly encoded before passing it to the router. Use ` +\n        `encodeURI to encode static segments of your path.`\n    )\n  }\n\n  const pathToRegexpOptions: PathToRegexpOptions =\n    route.pathToRegexpOptions || {}\n  const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)\n\n  if (typeof route.caseSensitive === 'boolean') {\n    pathToRegexpOptions.sensitive = route.caseSensitive\n  }\n\n  const record: RouteRecord = {\n    path: normalizedPath,\n    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),\n    components: route.components || { default: route.component },\n    alias: route.alias\n      ? typeof route.alias === 'string'\n        ? [route.alias]\n        : route.alias\n      : [],\n    instances: {},\n    enteredCbs: {},\n    name,\n    parent,\n    matchAs,\n    redirect: route.redirect,\n    beforeEnter: route.beforeEnter,\n    meta: route.meta || {},\n    props:\n      route.props == null\n        ? {}\n        : route.components\n          ? route.props\n          : { default: route.props }\n  }\n\n  if (route.children) {\n    // Warn if route is named, does not redirect and has a default child route.\n    // If users navigate to this route by name, the default child will\n    // not be rendered (GH Issue #629)\n    if (process.env.NODE_ENV !== 'production') {\n      if (\n        route.name &&\n        !route.redirect &&\n        route.children.some(child => /^\\/?$/.test(child.path))\n      ) {\n        warn(\n          false,\n          `Named Route '${route.name}' has a default child route. ` +\n            `When navigating to this named route (:to=\"{name: '${\n              route.name\n            }'}\"), ` +\n            `the default child route will not be rendered. Remove the name from ` +\n            `this route and use the name of the default child route for named ` +\n            `links instead.`\n        )\n      }\n    }\n    route.children.forEach(child => {\n      const childMatchAs = matchAs\n        ? cleanPath(`${matchAs}/${child.path}`)\n        : undefined\n      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)\n    })\n  }\n\n  if (!pathMap[record.path]) {\n    pathList.push(record.path)\n    pathMap[record.path] = record\n  }\n\n  if (route.alias !== undefined) {\n    const aliases = Array.isArray(route.alias) ? route.alias : [route.alias]\n    for (let i = 0; i < aliases.length; ++i) {\n      const alias = aliases[i]\n      if (process.env.NODE_ENV !== 'production' && alias === path) {\n        warn(\n          false,\n          `Found an alias with the same value as the path: \"${path}\". You have to remove that alias. It will be ignored in development.`\n        )\n        // skip in dev to make it work\n        continue\n      }\n\n      const aliasRoute = {\n        path: alias,\n        children: route.children\n      }\n      addRouteRecord(\n        pathList,\n        pathMap,\n        nameMap,\n        aliasRoute,\n        parent,\n        record.path || '/' // matchAs\n      )\n    }\n  }\n\n  if (name) {\n    if (!nameMap[name]) {\n      nameMap[name] = record\n    } else if (process.env.NODE_ENV !== 'production' && !matchAs) {\n      warn(\n        false,\n        `Duplicate named routes definition: ` +\n          `{ name: \"${name}\", path: \"${record.path}\" }`\n      )\n    }\n  }\n}\n\nfunction compileRouteRegex (\n  path: string,\n  pathToRegexpOptions: PathToRegexpOptions\n): RouteRegExp {\n  const regex = Regexp(path, [], pathToRegexpOptions)\n  if (process.env.NODE_ENV !== 'production') {\n    const keys: any = Object.create(null)\n    regex.keys.forEach(key => {\n      warn(\n        !keys[key.name],\n        `Duplicate param keys in route with path: \"${path}\"`\n      )\n      keys[key.name] = true\n    })\n  }\n  return regex\n}\n\nfunction normalizePath (\n  path: string,\n  parent?: RouteRecord,\n  strict?: boolean\n): string {\n  if (!strict) path = path.replace(/\\/$/, '')\n  if (path[0] === '/') return path\n  if (parent == null) return path\n  return cleanPath(`${parent.path}/${path}`)\n}\n"
  },
  {
    "path": "src/entries/cjs.js",
    "content": "import VueRouter from '../router'\n\nexport default VueRouter\n"
  },
  {
    "path": "src/entries/esm.js",
    "content": "import VueRouter from '../router'\n\nexport const version = '__VERSION__'\nexport { isNavigationFailure, NavigationFailureType } from '../util/errors'\nexport { START as START_LOCATION } from '../util/route'\nexport { default as RouterLink } from '../components/link'\nexport { default as RouterView } from '../components/view'\n\n// we can't add the other composables here because people could still be using an older version of vue and that would\n// create a compilation error trying to import from vue\n\nexport default VueRouter\n"
  },
  {
    "path": "src/history/abstract.js",
    "content": "/* @flow */\n\nimport type Router from '../index'\nimport { History } from './base'\nimport { NavigationFailureType, isNavigationFailure } from '../util/errors'\n\nexport class AbstractHistory extends History {\n  index: number\n  stack: Array<Route>\n\n  constructor (router: Router, base: ?string) {\n    super(router, base)\n    this.stack = []\n    this.index = -1\n  }\n\n  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    this.transitionTo(\n      location,\n      route => {\n        this.stack = this.stack.slice(0, this.index + 1).concat(route)\n        this.index++\n        onComplete && onComplete(route)\n      },\n      onAbort\n    )\n  }\n\n  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    this.transitionTo(\n      location,\n      route => {\n        this.stack = this.stack.slice(0, this.index).concat(route)\n        onComplete && onComplete(route)\n      },\n      onAbort\n    )\n  }\n\n  go (n: number) {\n    const targetIndex = this.index + n\n    if (targetIndex < 0 || targetIndex >= this.stack.length) {\n      return\n    }\n    const route = this.stack[targetIndex]\n    this.confirmTransition(\n      route,\n      () => {\n        const prev = this.current\n        this.index = targetIndex\n        this.updateRoute(route)\n        this.router.afterHooks.forEach(hook => {\n          hook && hook(route, prev)\n        })\n      },\n      err => {\n        if (isNavigationFailure(err, NavigationFailureType.duplicated)) {\n          this.index = targetIndex\n        }\n      }\n    )\n  }\n\n  getCurrentLocation () {\n    const current = this.stack[this.stack.length - 1]\n    return current ? current.fullPath : '/'\n  }\n\n  ensureURL () {\n    // noop\n  }\n}\n"
  },
  {
    "path": "src/history/base.js",
    "content": "/* @flow */\n\nimport { _Vue } from '../install'\nimport type Router from '../index'\nimport { inBrowser } from '../util/dom'\nimport { runQueue } from '../util/async'\nimport { warn } from '../util/warn'\nimport { START, isSameRoute, handleRouteEntered } from '../util/route'\nimport {\n  flatten,\n  flatMapComponents,\n  resolveAsyncComponents\n} from '../util/resolve-components'\nimport {\n  createNavigationDuplicatedError,\n  createNavigationCancelledError,\n  createNavigationRedirectedError,\n  createNavigationAbortedError,\n  isError,\n  isNavigationFailure,\n  NavigationFailureType\n} from '../util/errors'\nimport { handleScroll } from '../util/scroll'\n\nexport class History {\n  router: Router\n  base: string\n  current: Route\n  pending: ?Route\n  cb: (r: Route) => void\n  ready: boolean\n  readyCbs: Array<Function>\n  readyErrorCbs: Array<Function>\n  errorCbs: Array<Function>\n  listeners: Array<Function>\n  cleanupListeners: Function\n\n  // implemented by sub-classes\n  +go: (n: number) => void\n  +push: (loc: RawLocation, onComplete?: Function, onAbort?: Function) => void\n  +replace: (\n    loc: RawLocation,\n    onComplete?: Function,\n    onAbort?: Function\n  ) => void\n  +ensureURL: (push?: boolean) => void\n  +getCurrentLocation: () => string\n  +setupListeners: Function\n\n  constructor (router: Router, base: ?string) {\n    this.router = router\n    this.base = normalizeBase(base)\n    // start with a route object that stands for \"nowhere\"\n    this.current = START\n    this.pending = null\n    this.ready = false\n    this.readyCbs = []\n    this.readyErrorCbs = []\n    this.errorCbs = []\n    this.listeners = []\n  }\n\n  listen (cb: Function) {\n    this.cb = cb\n  }\n\n  onReady (cb: Function, errorCb: ?Function) {\n    if (this.ready) {\n      cb()\n    } else {\n      this.readyCbs.push(cb)\n      if (errorCb) {\n        this.readyErrorCbs.push(errorCb)\n      }\n    }\n  }\n\n  onError (errorCb: Function) {\n    this.errorCbs.push(errorCb)\n  }\n\n  transitionTo (\n    location: RawLocation,\n    onComplete?: Function,\n    onAbort?: Function\n  ) {\n    let route\n    // catch redirect option https://github.com/vuejs/vue-router/issues/3201\n    try {\n      route = this.router.match(location, this.current)\n    } catch (e) {\n      this.errorCbs.forEach(cb => {\n        cb(e)\n      })\n      // Exception should still be thrown\n      throw e\n    }\n    const prev = this.current\n    this.confirmTransition(\n      route,\n      () => {\n        this.updateRoute(route)\n        onComplete && onComplete(route)\n        this.ensureURL()\n        this.router.afterHooks.forEach(hook => {\n          hook && hook(route, prev)\n        })\n\n        // fire ready cbs once\n        if (!this.ready) {\n          this.ready = true\n          this.readyCbs.forEach(cb => {\n            cb(route)\n          })\n        }\n      },\n      err => {\n        if (onAbort) {\n          onAbort(err)\n        }\n        if (err && !this.ready) {\n          // Initial redirection should not mark the history as ready yet\n          // because it's triggered by the redirection instead\n          // https://github.com/vuejs/vue-router/issues/3225\n          // https://github.com/vuejs/vue-router/issues/3331\n          if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {\n            this.ready = true\n            this.readyErrorCbs.forEach(cb => {\n              cb(err)\n            })\n          }\n        }\n      }\n    )\n  }\n\n  confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {\n    const current = this.current\n    this.pending = route\n    const abort = err => {\n      // changed after adding errors with\n      // https://github.com/vuejs/vue-router/pull/3047 before that change,\n      // redirect and aborted navigation would produce an err == null\n      if (!isNavigationFailure(err) && isError(err)) {\n        if (this.errorCbs.length) {\n          this.errorCbs.forEach(cb => {\n            cb(err)\n          })\n        } else {\n          if (process.env.NODE_ENV !== 'production') {\n            warn(false, 'uncaught error during route navigation:')\n          }\n          console.error(err)\n        }\n      }\n      onAbort && onAbort(err)\n    }\n    const lastRouteIndex = route.matched.length - 1\n    const lastCurrentIndex = current.matched.length - 1\n    if (\n      isSameRoute(route, current) &&\n      // in the case the route map has been dynamically appended to\n      lastRouteIndex === lastCurrentIndex &&\n      route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]\n    ) {\n      this.ensureURL()\n      if (route.hash) {\n        handleScroll(this.router, current, route, false)\n      }\n      return abort(createNavigationDuplicatedError(current, route))\n    }\n\n    const { updated, deactivated, activated } = resolveQueue(\n      this.current.matched,\n      route.matched\n    )\n\n    const queue: Array<?NavigationGuard> = [].concat(\n      // in-component leave guards\n      extractLeaveGuards(deactivated),\n      // global before hooks\n      this.router.beforeHooks,\n      // in-component update hooks\n      extractUpdateHooks(updated),\n      // in-config enter guards\n      activated.map(m => m.beforeEnter),\n      // async components\n      resolveAsyncComponents(activated)\n    )\n\n    const iterator = (hook: NavigationGuard, next) => {\n      if (this.pending !== route) {\n        return abort(createNavigationCancelledError(current, route))\n      }\n      try {\n        hook(route, current, (to: any) => {\n          if (to === false) {\n            // next(false) -> abort navigation, ensure current URL\n            this.ensureURL(true)\n            abort(createNavigationAbortedError(current, route))\n          } else if (isError(to)) {\n            this.ensureURL(true)\n            abort(to)\n          } else if (\n            typeof to === 'string' ||\n            (typeof to === 'object' &&\n              (typeof to.path === 'string' || typeof to.name === 'string'))\n          ) {\n            // next('/') or next({ path: '/' }) -> redirect\n            abort(createNavigationRedirectedError(current, route))\n            if (typeof to === 'object' && to.replace) {\n              this.replace(to)\n            } else {\n              this.push(to)\n            }\n          } else {\n            // confirm transition and pass on the value\n            next(to)\n          }\n        })\n      } catch (e) {\n        abort(e)\n      }\n    }\n\n    runQueue(queue, iterator, () => {\n      // wait until async components are resolved before\n      // extracting in-component enter guards\n      const enterGuards = extractEnterGuards(activated)\n      const queue = enterGuards.concat(this.router.resolveHooks)\n      runQueue(queue, iterator, () => {\n        if (this.pending !== route) {\n          return abort(createNavigationCancelledError(current, route))\n        }\n        this.pending = null\n        onComplete(route)\n        if (this.router.app) {\n          this.router.app.$nextTick(() => {\n            handleRouteEntered(route)\n          })\n        }\n      })\n    })\n  }\n\n  updateRoute (route: Route) {\n    this.current = route\n    this.cb && this.cb(route)\n  }\n\n  setupListeners () {\n    // Default implementation is empty\n  }\n\n  teardown () {\n    // clean up event listeners\n    // https://github.com/vuejs/vue-router/issues/2341\n    this.listeners.forEach(cleanupListener => {\n      cleanupListener()\n    })\n    this.listeners = []\n\n    // reset current history route\n    // https://github.com/vuejs/vue-router/issues/3294\n    this.current = START\n    this.pending = null\n  }\n}\n\nfunction normalizeBase (base: ?string): string {\n  if (!base) {\n    if (inBrowser) {\n      // respect <base> tag\n      const baseEl = document.querySelector('base')\n      base = (baseEl && baseEl.getAttribute('href')) || '/'\n      // strip full URL origin\n      base = base.replace(/^https?:\\/\\/[^\\/]+/, '')\n    } else {\n      base = '/'\n    }\n  }\n  // make sure there's the starting slash\n  if (base.charAt(0) !== '/') {\n    base = '/' + base\n  }\n  // remove trailing slash\n  return base.replace(/\\/$/, '')\n}\n\nfunction resolveQueue (\n  current: Array<RouteRecord>,\n  next: Array<RouteRecord>\n): {\n  updated: Array<RouteRecord>,\n  activated: Array<RouteRecord>,\n  deactivated: Array<RouteRecord>\n} {\n  let i\n  const max = Math.max(current.length, next.length)\n  for (i = 0; i < max; i++) {\n    if (current[i] !== next[i]) {\n      break\n    }\n  }\n  return {\n    updated: next.slice(0, i),\n    activated: next.slice(i),\n    deactivated: current.slice(i)\n  }\n}\n\nfunction extractGuards (\n  records: Array<RouteRecord>,\n  name: string,\n  bind: Function,\n  reverse?: boolean\n): Array<?Function> {\n  const guards = flatMapComponents(records, (def, instance, match, key) => {\n    const guard = extractGuard(def, name)\n    if (guard) {\n      return Array.isArray(guard)\n        ? guard.map(guard => bind(guard, instance, match, key))\n        : bind(guard, instance, match, key)\n    }\n  })\n  return flatten(reverse ? guards.reverse() : guards)\n}\n\nfunction extractGuard (\n  def: Object | Function,\n  key: string\n): NavigationGuard | Array<NavigationGuard> {\n  if (typeof def !== 'function') {\n    // extend now so that global mixins are applied.\n    def = _Vue.extend(def)\n  }\n  return def.options[key]\n}\n\nfunction extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {\n  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)\n}\n\nfunction extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {\n  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)\n}\n\nfunction bindGuard (guard: NavigationGuard, instance: ?_Vue): ?NavigationGuard {\n  if (instance) {\n    return function boundRouteGuard () {\n      return guard.apply(instance, arguments)\n    }\n  }\n}\n\nfunction extractEnterGuards (\n  activated: Array<RouteRecord>\n): Array<?Function> {\n  return extractGuards(\n    activated,\n    'beforeRouteEnter',\n    (guard, _, match, key) => {\n      return bindEnterGuard(guard, match, key)\n    }\n  )\n}\n\nfunction bindEnterGuard (\n  guard: NavigationGuard,\n  match: RouteRecord,\n  key: string\n): NavigationGuard {\n  return function routeEnterGuard (to, from, next) {\n    return guard(to, from, cb => {\n      if (typeof cb === 'function') {\n        if (!match.enteredCbs[key]) {\n          match.enteredCbs[key] = []\n        }\n        match.enteredCbs[key].push(cb)\n      }\n      next(cb)\n    })\n  }\n}\n"
  },
  {
    "path": "src/history/hash.js",
    "content": "/* @flow */\n\nimport type Router from '../index'\nimport { History } from './base'\nimport { cleanPath } from '../util/path'\nimport { getLocation } from './html5'\nimport { setupScroll, handleScroll } from '../util/scroll'\nimport { pushState, replaceState, supportsPushState } from '../util/push-state'\n\nexport class HashHistory extends History {\n  constructor (router: Router, base: ?string, fallback: boolean) {\n    super(router, base)\n    // check history fallback deeplinking\n    if (fallback && checkFallback(this.base)) {\n      return\n    }\n    ensureSlash()\n  }\n\n  // this is delayed until the app mounts\n  // to avoid the hashchange listener being fired too early\n  setupListeners () {\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    const router = this.router\n    const expectScroll = router.options.scrollBehavior\n    const supportsScroll = supportsPushState && expectScroll\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll())\n    }\n\n    const handleRoutingEvent = () => {\n      const current = this.current\n      if (!ensureSlash()) {\n        return\n      }\n      this.transitionTo(getHash(), route => {\n        if (supportsScroll) {\n          handleScroll(this.router, route, current, true)\n        }\n        if (!supportsPushState) {\n          replaceHash(route.fullPath)\n        }\n      })\n    }\n    const eventType = supportsPushState ? 'popstate' : 'hashchange'\n    window.addEventListener(\n      eventType,\n      handleRoutingEvent\n    )\n    this.listeners.push(() => {\n      window.removeEventListener(eventType, handleRoutingEvent)\n    })\n  }\n\n  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    const { current: fromRoute } = this\n    this.transitionTo(\n      location,\n      route => {\n        pushHash(route.fullPath)\n        handleScroll(this.router, route, fromRoute, false)\n        onComplete && onComplete(route)\n      },\n      onAbort\n    )\n  }\n\n  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    const { current: fromRoute } = this\n    this.transitionTo(\n      location,\n      route => {\n        replaceHash(route.fullPath)\n        handleScroll(this.router, route, fromRoute, false)\n        onComplete && onComplete(route)\n      },\n      onAbort\n    )\n  }\n\n  go (n: number) {\n    window.history.go(n)\n  }\n\n  ensureURL (push?: boolean) {\n    const current = this.current.fullPath\n    if (getHash() !== current) {\n      push ? pushHash(current) : replaceHash(current)\n    }\n  }\n\n  getCurrentLocation () {\n    return getHash()\n  }\n}\n\nfunction checkFallback (base) {\n  const location = getLocation(base)\n  if (!/^\\/#/.test(location)) {\n    window.location.replace(cleanPath(base + '/#' + location))\n    return true\n  }\n}\n\nfunction ensureSlash (): boolean {\n  const path = getHash()\n  if (path.charAt(0) === '/') {\n    return true\n  }\n  replaceHash('/' + path)\n  return false\n}\n\nexport function getHash (): string {\n  // We can't use window.location.hash here because it's not\n  // consistent across browsers - Firefox will pre-decode it!\n  let href = window.location.href\n  const index = href.indexOf('#')\n  // empty path\n  if (index < 0) return ''\n\n  href = href.slice(index + 1)\n\n  return href\n}\n\nfunction getUrl (path) {\n  const href = window.location.href\n  const i = href.indexOf('#')\n  const base = i >= 0 ? href.slice(0, i) : href\n  return `${base}#${path}`\n}\n\nfunction pushHash (path) {\n  if (supportsPushState) {\n    pushState(getUrl(path))\n  } else {\n    window.location.hash = path\n  }\n}\n\nfunction replaceHash (path) {\n  if (supportsPushState) {\n    replaceState(getUrl(path))\n  } else {\n    window.location.replace(getUrl(path))\n  }\n}\n"
  },
  {
    "path": "src/history/html5.js",
    "content": "/* @flow */\n\nimport type Router from '../index'\nimport { History } from './base'\nimport { cleanPath } from '../util/path'\nimport { START } from '../util/route'\nimport { setupScroll, handleScroll } from '../util/scroll'\nimport { pushState, replaceState, supportsPushState } from '../util/push-state'\n\nexport class HTML5History extends History {\n  _startLocation: string\n\n  constructor (router: Router, base: ?string) {\n    super(router, base)\n\n    this._startLocation = getLocation(this.base)\n  }\n\n  setupListeners () {\n    if (this.listeners.length > 0) {\n      return\n    }\n\n    const router = this.router\n    const expectScroll = router.options.scrollBehavior\n    const supportsScroll = supportsPushState && expectScroll\n\n    if (supportsScroll) {\n      this.listeners.push(setupScroll())\n    }\n\n    const handleRoutingEvent = () => {\n      const current = this.current\n\n      // Avoiding first `popstate` event dispatched in some browsers but first\n      // history route not updated since async guard at the same time.\n      const location = getLocation(this.base)\n      if (this.current === START && location === this._startLocation) {\n        return\n      }\n\n      this.transitionTo(location, route => {\n        if (supportsScroll) {\n          handleScroll(router, route, current, true)\n        }\n      })\n    }\n    window.addEventListener('popstate', handleRoutingEvent)\n    this.listeners.push(() => {\n      window.removeEventListener('popstate', handleRoutingEvent)\n    })\n  }\n\n  go (n: number) {\n    window.history.go(n)\n  }\n\n  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    const { current: fromRoute } = this\n    this.transitionTo(location, route => {\n      pushState(cleanPath(this.base + route.fullPath))\n      handleScroll(this.router, route, fromRoute, false)\n      onComplete && onComplete(route)\n    }, onAbort)\n  }\n\n  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    const { current: fromRoute } = this\n    this.transitionTo(location, route => {\n      replaceState(cleanPath(this.base + route.fullPath))\n      handleScroll(this.router, route, fromRoute, false)\n      onComplete && onComplete(route)\n    }, onAbort)\n  }\n\n  ensureURL (push?: boolean) {\n    if (getLocation(this.base) !== this.current.fullPath) {\n      const current = cleanPath(this.base + this.current.fullPath)\n      push ? pushState(current) : replaceState(current)\n    }\n  }\n\n  getCurrentLocation (): string {\n    return getLocation(this.base)\n  }\n}\n\nexport function getLocation (base: string): string {\n  let path = window.location.pathname\n  const pathLowerCase = path.toLowerCase()\n  const baseLowerCase = base.toLowerCase()\n  // base=\"/a\" shouldn't turn path=\"/app\" into \"/a/pp\"\n  // https://github.com/vuejs/vue-router/issues/3555\n  // so we ensure the trailing slash in the base\n  if (base && ((pathLowerCase === baseLowerCase) ||\n    (pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {\n    path = path.slice(base.length)\n  }\n  return (path || '/') + window.location.search + window.location.hash\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import VueRouter from './entries/cjs'\n\nexport default VueRouter\n"
  },
  {
    "path": "src/install.js",
    "content": "import View from './components/view'\nimport Link from './components/link'\n\nexport let _Vue\n\nexport function install (Vue) {\n  if (install.installed && _Vue === Vue) return\n  install.installed = true\n\n  _Vue = Vue\n\n  const isDef = v => v !== undefined\n\n  const registerInstance = (vm, callVal) => {\n    let i = vm.$options._parentVnode\n    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {\n      i(vm, callVal)\n    }\n  }\n\n  Vue.mixin({\n    beforeCreate () {\n      if (isDef(this.$options.router)) {\n        this._routerRoot = this\n        this._router = this.$options.router\n        this._router.init(this)\n        Vue.util.defineReactive(this, '_route', this._router.history.current)\n      } else {\n        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this\n      }\n      registerInstance(this, this)\n    },\n    destroyed () {\n      registerInstance(this)\n    }\n  })\n\n  Object.defineProperty(Vue.prototype, '$router', {\n    get () { return this._routerRoot._router }\n  })\n\n  Object.defineProperty(Vue.prototype, '$route', {\n    get () { return this._routerRoot._route }\n  })\n\n  Vue.component('RouterView', View)\n  Vue.component('RouterLink', Link)\n\n  const strats = Vue.config.optionMergeStrategies\n  // use the same hook merging strategy for route hooks\n  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created\n}\n"
  },
  {
    "path": "src/router.js",
    "content": "/* @flow */\n\nimport { install } from './install'\nimport { START } from './util/route'\nimport { assert, warn } from './util/warn'\nimport { inBrowser } from './util/dom'\nimport { cleanPath } from './util/path'\nimport { createMatcher } from './create-matcher'\nimport { normalizeLocation } from './util/location'\nimport { supportsPushState } from './util/push-state'\nimport { handleScroll } from './util/scroll'\nimport { isNavigationFailure, NavigationFailureType } from './util/errors'\n\nimport { HashHistory } from './history/hash'\nimport { HTML5History } from './history/html5'\nimport { AbstractHistory } from './history/abstract'\n\nimport type { Matcher } from './create-matcher'\n\nexport default class VueRouter {\n  static install: () => void\n  static version: string\n  static isNavigationFailure: Function\n  static NavigationFailureType: any\n  static START_LOCATION: Route\n\n  app: any\n  apps: Array<any>\n  ready: boolean\n  readyCbs: Array<Function>\n  options: RouterOptions\n  mode: string\n  history: HashHistory | HTML5History | AbstractHistory\n  matcher: Matcher\n  fallback: boolean\n  beforeHooks: Array<?NavigationGuard>\n  resolveHooks: Array<?NavigationGuard>\n  afterHooks: Array<?AfterNavigationHook>\n\n  constructor (options: RouterOptions = {}) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(this instanceof VueRouter, `Router must be called with the new operator.`)\n    }\n    this.app = null\n    this.apps = []\n    this.options = options\n    this.beforeHooks = []\n    this.resolveHooks = []\n    this.afterHooks = []\n    this.matcher = createMatcher(options.routes || [], this)\n\n    let mode = options.mode || 'hash'\n    this.fallback =\n      mode === 'history' && !supportsPushState && options.fallback !== false\n    if (this.fallback) {\n      mode = 'hash'\n    }\n    if (!inBrowser) {\n      mode = 'abstract'\n    }\n    this.mode = mode\n\n    switch (mode) {\n      case 'history':\n        this.history = new HTML5History(this, options.base)\n        break\n      case 'hash':\n        this.history = new HashHistory(this, options.base, this.fallback)\n        break\n      case 'abstract':\n        this.history = new AbstractHistory(this, options.base)\n        break\n      default:\n        if (process.env.NODE_ENV !== 'production') {\n          assert(false, `invalid mode: ${mode}`)\n        }\n    }\n  }\n\n  match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route {\n    return this.matcher.match(raw, current, redirectedFrom)\n  }\n\n  get currentRoute (): ?Route {\n    return this.history && this.history.current\n  }\n\n  init (app: any /* Vue component instance */) {\n    process.env.NODE_ENV !== 'production' &&\n      assert(\n        install.installed,\n        `not installed. Make sure to call \\`Vue.use(VueRouter)\\` ` +\n          `before creating root instance.`\n      )\n\n    this.apps.push(app)\n\n    // set up app destroyed handler\n    // https://github.com/vuejs/vue-router/issues/2639\n    app.$once('hook:destroyed', () => {\n      // clean out app from this.apps array once destroyed\n      const index = this.apps.indexOf(app)\n      if (index > -1) this.apps.splice(index, 1)\n      // ensure we still have a main app or null if no apps\n      // we do not release the router so it can be reused\n      if (this.app === app) this.app = this.apps[0] || null\n\n      if (!this.app) this.history.teardown()\n    })\n\n    // main app previously initialized\n    // return as we don't need to set up new history listener\n    if (this.app) {\n      return\n    }\n\n    this.app = app\n\n    const history = this.history\n\n    if (history instanceof HTML5History || history instanceof HashHistory) {\n      const handleInitialScroll = routeOrError => {\n        const from = history.current\n        const expectScroll = this.options.scrollBehavior\n        const supportsScroll = supportsPushState && expectScroll\n\n        if (supportsScroll && 'fullPath' in routeOrError) {\n          handleScroll(this, routeOrError, from, false)\n        }\n      }\n      const setupListeners = routeOrError => {\n        history.setupListeners()\n        handleInitialScroll(routeOrError)\n      }\n      history.transitionTo(\n        history.getCurrentLocation(),\n        setupListeners,\n        setupListeners\n      )\n    }\n\n    history.listen(route => {\n      this.apps.forEach(app => {\n        app._route = route\n      })\n    })\n  }\n\n  beforeEach (fn: Function): Function {\n    return registerHook(this.beforeHooks, fn)\n  }\n\n  beforeResolve (fn: Function): Function {\n    return registerHook(this.resolveHooks, fn)\n  }\n\n  afterEach (fn: Function): Function {\n    return registerHook(this.afterHooks, fn)\n  }\n\n  onReady (cb: Function, errorCb?: Function) {\n    this.history.onReady(cb, errorCb)\n  }\n\n  onError (errorCb: Function) {\n    this.history.onError(errorCb)\n  }\n\n  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    // $flow-disable-line\n    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n      return new Promise((resolve, reject) => {\n        this.history.push(location, resolve, reject)\n      })\n    } else {\n      this.history.push(location, onComplete, onAbort)\n    }\n  }\n\n  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {\n    // $flow-disable-line\n    if (!onComplete && !onAbort && typeof Promise !== 'undefined') {\n      return new Promise((resolve, reject) => {\n        this.history.replace(location, resolve, reject)\n      })\n    } else {\n      this.history.replace(location, onComplete, onAbort)\n    }\n  }\n\n  go (n: number) {\n    this.history.go(n)\n  }\n\n  back () {\n    this.go(-1)\n  }\n\n  forward () {\n    this.go(1)\n  }\n\n  getMatchedComponents (to?: RawLocation | Route): Array<any> {\n    const route: any = to\n      ? to.matched\n        ? to\n        : this.resolve(to).route\n      : this.currentRoute\n    if (!route) {\n      return []\n    }\n    return [].concat.apply(\n      [],\n      route.matched.map(m => {\n        return Object.keys(m.components).map(key => {\n          return m.components[key]\n        })\n      })\n    )\n  }\n\n  resolve (\n    to: RawLocation,\n    current?: Route,\n    append?: boolean\n  ): {\n    location: Location,\n    route: Route,\n    href: string,\n    // for backwards compat\n    normalizedTo: Location,\n    resolved: Route\n  } {\n    current = current || this.history.current\n    const location = normalizeLocation(to, current, append, this)\n    const route = this.match(location, current)\n    const fullPath = route.redirectedFrom || route.fullPath\n    const base = this.history.base\n    const href = createHref(base, fullPath, this.mode)\n    return {\n      location,\n      route,\n      href,\n      // for backwards compat\n      normalizedTo: location,\n      resolved: route\n    }\n  }\n\n  getRoutes () {\n    return this.matcher.getRoutes()\n  }\n\n  addRoute (parentOrRoute: string | RouteConfig, route?: RouteConfig) {\n    this.matcher.addRoute(parentOrRoute, route)\n    if (this.history.current !== START) {\n      this.history.transitionTo(this.history.getCurrentLocation())\n    }\n  }\n\n  addRoutes (routes: Array<RouteConfig>) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.')\n    }\n    this.matcher.addRoutes(routes)\n    if (this.history.current !== START) {\n      this.history.transitionTo(this.history.getCurrentLocation())\n    }\n  }\n}\n\nfunction registerHook (list: Array<any>, fn: Function): Function {\n  list.push(fn)\n  return () => {\n    const i = list.indexOf(fn)\n    if (i > -1) list.splice(i, 1)\n  }\n}\n\nfunction createHref (base: string, fullPath: string, mode) {\n  var path = mode === 'hash' ? '#' + fullPath : fullPath\n  return base ? cleanPath(base + '/' + path) : path\n}\n\n// We cannot remove this as it would be a breaking change\nVueRouter.install = install\nVueRouter.version = '__VERSION__'\nVueRouter.isNavigationFailure = isNavigationFailure\nVueRouter.NavigationFailureType = NavigationFailureType\nVueRouter.START_LOCATION = START\n\nif (inBrowser && window.Vue) {\n  window.Vue.use(VueRouter)\n}\n"
  },
  {
    "path": "src/util/async.js",
    "content": "/* @flow */\n\nexport function runQueue (queue: Array<?NavigationGuard>, fn: Function, cb: Function) {\n  const step = index => {\n    if (index >= queue.length) {\n      cb()\n    } else {\n      if (queue[index]) {\n        fn(queue[index], () => {\n          step(index + 1)\n        })\n      } else {\n        step(index + 1)\n      }\n    }\n  }\n  step(0)\n}\n"
  },
  {
    "path": "src/util/dom.js",
    "content": "/* @flow */\n\nexport const inBrowser = typeof window !== 'undefined'\n"
  },
  {
    "path": "src/util/errors.js",
    "content": "// When changing thing, also edit router.d.ts\nexport const NavigationFailureType = {\n  redirected: 2,\n  aborted: 4,\n  cancelled: 8,\n  duplicated: 16\n}\n\nexport function createNavigationRedirectedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.redirected,\n    `Redirected when going from \"${from.fullPath}\" to \"${stringifyRoute(\n      to\n    )}\" via a navigation guard.`\n  )\n}\n\nexport function createNavigationDuplicatedError (from, to) {\n  const error = createRouterError(\n    from,\n    to,\n    NavigationFailureType.duplicated,\n    `Avoided redundant navigation to current location: \"${from.fullPath}\".`\n  )\n  // backwards compatible with the first introduction of Errors\n  error.name = 'NavigationDuplicated'\n  return error\n}\n\nexport function createNavigationCancelledError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.cancelled,\n    `Navigation cancelled from \"${from.fullPath}\" to \"${\n      to.fullPath\n    }\" with a new navigation.`\n  )\n}\n\nexport function createNavigationAbortedError (from, to) {\n  return createRouterError(\n    from,\n    to,\n    NavigationFailureType.aborted,\n    `Navigation aborted from \"${from.fullPath}\" to \"${\n      to.fullPath\n    }\" via a navigation guard.`\n  )\n}\n\nfunction createRouterError (from, to, type, message) {\n  const error = new Error(message)\n  error._isRouter = true\n  error.from = from\n  error.to = to\n  error.type = type\n\n  return error\n}\n\nconst propertiesToLog = ['params', 'query', 'hash']\n\nfunction stringifyRoute (to) {\n  if (typeof to === 'string') return to\n  if ('path' in to) return to.path\n  const location = {}\n  propertiesToLog.forEach(key => {\n    if (key in to) location[key] = to[key]\n  })\n  return JSON.stringify(location, null, 2)\n}\n\nexport function isError (err) {\n  return Object.prototype.toString.call(err).indexOf('Error') > -1\n}\n\nexport function isNavigationFailure (err, errorType) {\n  return (\n    isError(err) &&\n    err._isRouter &&\n    (errorType == null || err.type === errorType)\n  )\n}\n"
  },
  {
    "path": "src/util/location.js",
    "content": "/* @flow */\n\nimport type VueRouter from '../index'\nimport { parsePath, resolvePath } from './path'\nimport { resolveQuery } from './query'\nimport { fillParams } from './params'\nimport { warn } from './warn'\nimport { extend } from './misc'\n\nexport function normalizeLocation (\n  raw: RawLocation,\n  current: ?Route,\n  append: ?boolean,\n  router: ?VueRouter\n): Location {\n  let next: Location = typeof raw === 'string' ? { path: raw } : raw\n  // named target\n  if (next._normalized) {\n    return next\n  } else if (next.name) {\n    next = extend({}, raw)\n    const params = next.params\n    if (params && typeof params === 'object') {\n      next.params = extend({}, params)\n    }\n    return next\n  }\n\n  // relative params\n  if (!next.path && next.params && current) {\n    next = extend({}, next)\n    next._normalized = true\n    const params: any = extend(extend({}, current.params), next.params)\n    if (current.name) {\n      next.name = current.name\n      next.params = params\n    } else if (current.matched.length) {\n      const rawPath = current.matched[current.matched.length - 1].path\n      next.path = fillParams(rawPath, params, `path ${current.path}`)\n    } else if (process.env.NODE_ENV !== 'production') {\n      warn(false, `relative params navigation requires a current route.`)\n    }\n    return next\n  }\n\n  const parsedPath = parsePath(next.path || '')\n  const basePath = (current && current.path) || '/'\n  const path = parsedPath.path\n    ? resolvePath(parsedPath.path, basePath, append || next.append)\n    : basePath\n\n  const query = resolveQuery(\n    parsedPath.query,\n    next.query,\n    router && router.options.parseQuery\n  )\n\n  let hash = next.hash || parsedPath.hash\n  if (hash && hash.charAt(0) !== '#') {\n    hash = `#${hash}`\n  }\n\n  return {\n    _normalized: true,\n    path,\n    query,\n    hash\n  }\n}\n"
  },
  {
    "path": "src/util/misc.js",
    "content": "export function extend (a, b) {\n  for (const key in b) {\n    a[key] = b[key]\n  }\n  return a\n}\n"
  },
  {
    "path": "src/util/params.js",
    "content": "/* @flow */\n\nimport { warn } from './warn'\nimport Regexp from 'path-to-regexp'\n\n// $flow-disable-line\nconst regexpCompileCache: {\n  [key: string]: Function\n} = Object.create(null)\n\nexport function fillParams (\n  path: string,\n  params: ?Object,\n  routeMsg: string\n): string {\n  params = params || {}\n  try {\n    const filler =\n      regexpCompileCache[path] ||\n      (regexpCompileCache[path] = Regexp.compile(path))\n\n    // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}\n    // and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string\n    if (typeof params.pathMatch === 'string') params[0] = params.pathMatch\n\n    return filler(params, { pretty: true })\n  } catch (e) {\n    if (process.env.NODE_ENV !== 'production') {\n      // Fix #3072 no warn if `pathMatch` is string\n      warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`)\n    }\n    return ''\n  } finally {\n    // delete the 0 if it was added\n    delete params[0]\n  }\n}\n"
  },
  {
    "path": "src/util/path.js",
    "content": "/* @flow */\n\nexport function resolvePath (\n  relative: string,\n  base: string,\n  append?: boolean\n): string {\n  const firstChar = relative.charAt(0)\n  if (firstChar === '/') {\n    return relative\n  }\n\n  if (firstChar === '?' || firstChar === '#') {\n    return base + relative\n  }\n\n  const stack = base.split('/')\n\n  // remove trailing segment if:\n  // - not appending\n  // - appending to trailing slash (last segment is empty)\n  if (!append || !stack[stack.length - 1]) {\n    stack.pop()\n  }\n\n  // resolve relative path\n  const segments = relative.replace(/^\\//, '').split('/')\n  for (let i = 0; i < segments.length; i++) {\n    const segment = segments[i]\n    if (segment === '..') {\n      stack.pop()\n    } else if (segment !== '.') {\n      stack.push(segment)\n    }\n  }\n\n  // ensure leading slash\n  if (stack[0] !== '') {\n    stack.unshift('')\n  }\n\n  return stack.join('/')\n}\n\nexport function parsePath (path: string): {\n  path: string;\n  query: string;\n  hash: string;\n} {\n  let hash = ''\n  let query = ''\n\n  const hashIndex = path.indexOf('#')\n  if (hashIndex >= 0) {\n    hash = path.slice(hashIndex)\n    path = path.slice(0, hashIndex)\n  }\n\n  const queryIndex = path.indexOf('?')\n  if (queryIndex >= 0) {\n    query = path.slice(queryIndex + 1)\n    path = path.slice(0, queryIndex)\n  }\n\n  return {\n    path,\n    query,\n    hash\n  }\n}\n\nexport function cleanPath (path: string): string {\n  return path.replace(/\\/(?:\\s*\\/)+/g, '/')\n}\n"
  },
  {
    "path": "src/util/push-state.js",
    "content": "/* @flow */\n\nimport { inBrowser } from './dom'\nimport { saveScrollPosition } from './scroll'\nimport { genStateKey, setStateKey, getStateKey } from './state-key'\nimport { extend } from './misc'\n\nexport const supportsPushState =\n  inBrowser &&\n  (function () {\n    const ua = window.navigator.userAgent\n\n    if (\n      (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&\n      ua.indexOf('Mobile Safari') !== -1 &&\n      ua.indexOf('Chrome') === -1 &&\n      ua.indexOf('Windows Phone') === -1\n    ) {\n      return false\n    }\n\n    return window.history && typeof window.history.pushState === 'function'\n  })()\n\nexport function pushState (url?: string, replace?: boolean) {\n  saveScrollPosition()\n  // try...catch the pushState call to get around Safari\n  // DOM Exception 18 where it limits to 100 pushState calls\n  const history = window.history\n  try {\n    if (replace) {\n      // preserve existing history state as it could be overriden by the user\n      const stateCopy = extend({}, history.state)\n      stateCopy.key = getStateKey()\n      history.replaceState(stateCopy, '', url)\n    } else {\n      history.pushState({ key: setStateKey(genStateKey()) }, '', url)\n    }\n  } catch (e) {\n    window.location[replace ? 'replace' : 'assign'](url)\n  }\n}\n\nexport function replaceState (url?: string) {\n  pushState(url, true)\n}\n"
  },
  {
    "path": "src/util/query.js",
    "content": "/* @flow */\n\nimport { warn } from './warn'\n\nconst encodeReserveRE = /[!'()*]/g\nconst encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16)\nconst commaRE = /%2C/g\n\n// fixed encodeURIComponent which is more conformant to RFC3986:\n// - escapes [!'()*]\n// - preserve commas\nconst encode = str =>\n  encodeURIComponent(str)\n    .replace(encodeReserveRE, encodeReserveReplacer)\n    .replace(commaRE, ',')\n\nexport function decode (str: string) {\n  try {\n    return decodeURIComponent(str)\n  } catch (err) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(false, `Error decoding \"${str}\". Leaving it intact.`)\n    }\n  }\n  return str\n}\n\nexport function resolveQuery (\n  query: ?string,\n  extraQuery: Dictionary<string> = {},\n  _parseQuery: ?Function\n): Dictionary<string> {\n  const parse = _parseQuery || parseQuery\n  let parsedQuery\n  try {\n    parsedQuery = parse(query || '')\n  } catch (e) {\n    process.env.NODE_ENV !== 'production' && warn(false, e.message)\n    parsedQuery = {}\n  }\n  for (const key in extraQuery) {\n    const value = extraQuery[key]\n    parsedQuery[key] = Array.isArray(value)\n      ? value.map(castQueryParamValue)\n      : castQueryParamValue(value)\n  }\n  return parsedQuery\n}\n\nconst castQueryParamValue = value => (value == null || typeof value === 'object' ? value : String(value))\n\nfunction parseQuery (query: string): Dictionary<string> {\n  const res = {}\n\n  query = query.trim().replace(/^(\\?|#|&)/, '')\n\n  if (!query) {\n    return res\n  }\n\n  query.split('&').forEach(param => {\n    const parts = param.replace(/\\+/g, ' ').split('=')\n    const key = decode(parts.shift())\n    const val = parts.length > 0 ? decode(parts.join('=')) : null\n\n    if (res[key] === undefined) {\n      res[key] = val\n    } else if (Array.isArray(res[key])) {\n      res[key].push(val)\n    } else {\n      res[key] = [res[key], val]\n    }\n  })\n\n  return res\n}\n\nexport function stringifyQuery (obj: Dictionary<string>): string {\n  const res = obj\n    ? Object.keys(obj)\n      .map(key => {\n        const val = obj[key]\n\n        if (val === undefined) {\n          return ''\n        }\n\n        if (val === null) {\n          return encode(key)\n        }\n\n        if (Array.isArray(val)) {\n          const result = []\n          val.forEach(val2 => {\n            if (val2 === undefined) {\n              return\n            }\n            if (val2 === null) {\n              result.push(encode(key))\n            } else {\n              result.push(encode(key) + '=' + encode(val2))\n            }\n          })\n          return result.join('&')\n        }\n\n        return encode(key) + '=' + encode(val)\n      })\n      .filter(x => x.length > 0)\n      .join('&')\n    : null\n  return res ? `?${res}` : ''\n}\n"
  },
  {
    "path": "src/util/resolve-components.js",
    "content": "/* @flow */\n\nimport { _Vue } from '../install'\nimport { warn } from './warn'\nimport { isError } from '../util/errors'\n\nexport function resolveAsyncComponents (matched: Array<RouteRecord>): Function {\n  return (to, from, next) => {\n    let hasAsync = false\n    let pending = 0\n    let error = null\n\n    flatMapComponents(matched, (def, _, match, key) => {\n      // if it's a function and doesn't have cid attached,\n      // assume it's an async component resolve function.\n      // we are not using Vue's default async resolving mechanism because\n      // we want to halt the navigation until the incoming component has been\n      // resolved.\n      if (typeof def === 'function' && def.cid === undefined) {\n        hasAsync = true\n        pending++\n\n        const resolve = once(resolvedDef => {\n          if (isESModule(resolvedDef)) {\n            resolvedDef = resolvedDef.default\n          }\n          // save resolved on async factory in case it's used elsewhere\n          def.resolved = typeof resolvedDef === 'function'\n            ? resolvedDef\n            : _Vue.extend(resolvedDef)\n          match.components[key] = resolvedDef\n          pending--\n          if (pending <= 0) {\n            next()\n          }\n        })\n\n        const reject = once(reason => {\n          const msg = `Failed to resolve async component ${key}: ${reason}`\n          process.env.NODE_ENV !== 'production' && warn(false, msg)\n          if (!error) {\n            error = isError(reason)\n              ? reason\n              : new Error(msg)\n            next(error)\n          }\n        })\n\n        let res\n        try {\n          res = def(resolve, reject)\n        } catch (e) {\n          reject(e)\n        }\n        if (res) {\n          if (typeof res.then === 'function') {\n            res.then(resolve, reject)\n          } else {\n            // new syntax in Vue 2.3\n            const comp = res.component\n            if (comp && typeof comp.then === 'function') {\n              comp.then(resolve, reject)\n            }\n          }\n        }\n      }\n    })\n\n    if (!hasAsync) next()\n  }\n}\n\nexport function flatMapComponents (\n  matched: Array<RouteRecord>,\n  fn: Function\n): Array<?Function> {\n  return flatten(matched.map(m => {\n    return Object.keys(m.components).map(key => fn(\n      m.components[key],\n      m.instances[key],\n      m, key\n    ))\n  }))\n}\n\nexport function flatten (arr: Array<any>): Array<any> {\n  return Array.prototype.concat.apply([], arr)\n}\n\nconst hasSymbol =\n  typeof Symbol === 'function' &&\n  typeof Symbol.toStringTag === 'symbol'\n\nfunction isESModule (obj) {\n  return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')\n}\n\n// in Webpack 2, require.ensure now also returns a Promise\n// so the resolve/reject functions may get called an extra time\n// if the user uses an arrow function shorthand that happens to\n// return that Promise.\nfunction once (fn) {\n  let called = false\n  return function (...args) {\n    if (called) return\n    called = true\n    return fn.apply(this, args)\n  }\n}\n"
  },
  {
    "path": "src/util/route.js",
    "content": "/* @flow */\n\nimport type VueRouter from '../index'\nimport { stringifyQuery } from './query'\n\nconst trailingSlashRE = /\\/?$/\n\nexport function createRoute (\n  record: ?RouteRecord,\n  location: Location,\n  redirectedFrom?: ?Location,\n  router?: VueRouter\n): Route {\n  const stringifyQuery = router && router.options.stringifyQuery\n\n  let query: any = location.query || {}\n  try {\n    query = clone(query)\n  } catch (e) {}\n\n  const route: Route = {\n    name: location.name || (record && record.name),\n    meta: (record && record.meta) || {},\n    path: location.path || '/',\n    hash: location.hash || '',\n    query,\n    params: location.params || {},\n    fullPath: getFullPath(location, stringifyQuery),\n    matched: record ? formatMatch(record) : []\n  }\n  if (redirectedFrom) {\n    route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery)\n  }\n  return Object.freeze(route)\n}\n\nfunction clone (value) {\n  if (Array.isArray(value)) {\n    return value.map(clone)\n  } else if (value && typeof value === 'object') {\n    const res = {}\n    for (const key in value) {\n      res[key] = clone(value[key])\n    }\n    return res\n  } else {\n    return value\n  }\n}\n\n// the starting route that represents the initial state\nexport const START = createRoute(null, {\n  path: '/'\n})\n\nfunction formatMatch (record: ?RouteRecord): Array<RouteRecord> {\n  const res = []\n  while (record) {\n    res.unshift(record)\n    record = record.parent\n  }\n  return res\n}\n\nfunction getFullPath (\n  { path, query = {}, hash = '' },\n  _stringifyQuery\n): string {\n  const stringify = _stringifyQuery || stringifyQuery\n  return (path || '/') + stringify(query) + hash\n}\n\nexport function isSameRoute (a: Route, b: ?Route, onlyPath: ?boolean): boolean {\n  if (b === START) {\n    return a === b\n  } else if (!b) {\n    return false\n  } else if (a.path && b.path) {\n    return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||\n      a.hash === b.hash &&\n      isObjectEqual(a.query, b.query))\n  } else if (a.name && b.name) {\n    return (\n      a.name === b.name &&\n      (onlyPath || (\n        a.hash === b.hash &&\n      isObjectEqual(a.query, b.query) &&\n      isObjectEqual(a.params, b.params))\n      )\n    )\n  } else {\n    return false\n  }\n}\n\nfunction isObjectEqual (a = {}, b = {}): boolean {\n  // handle null value #1566\n  if (!a || !b) return a === b\n  const aKeys = Object.keys(a).sort()\n  const bKeys = Object.keys(b).sort()\n  if (aKeys.length !== bKeys.length) {\n    return false\n  }\n  return aKeys.every((key, i) => {\n    const aVal = a[key]\n    const bKey = bKeys[i]\n    if (bKey !== key) return false\n    const bVal = b[key]\n    // query values can be null and undefined\n    if (aVal == null || bVal == null) return aVal === bVal\n    // check nested equality\n    if (typeof aVal === 'object' && typeof bVal === 'object') {\n      return isObjectEqual(aVal, bVal)\n    }\n    return String(aVal) === String(bVal)\n  })\n}\n\nexport function isIncludedRoute (current: Route, target: Route): boolean {\n  return (\n    current.path.replace(trailingSlashRE, '/').indexOf(\n      target.path.replace(trailingSlashRE, '/')\n    ) === 0 &&\n    (!target.hash || current.hash === target.hash) &&\n    queryIncludes(current.query, target.query)\n  )\n}\n\nfunction queryIncludes (current: Dictionary<string>, target: Dictionary<string>): boolean {\n  for (const key in target) {\n    if (!(key in current)) {\n      return false\n    }\n  }\n  return true\n}\n\nexport function handleRouteEntered (route: Route) {\n  for (let i = 0; i < route.matched.length; i++) {\n    const record = route.matched[i]\n    for (const name in record.instances) {\n      const instance = record.instances[name]\n      const cbs = record.enteredCbs[name]\n      if (!instance || !cbs) continue\n      delete record.enteredCbs[name]\n      for (let i = 0; i < cbs.length; i++) {\n        if (!instance._isBeingDestroyed) cbs[i](instance)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/util/scroll.js",
    "content": "/* @flow */\n\nimport type Router from '../index'\nimport { assert } from './warn'\nimport { getStateKey, setStateKey } from './state-key'\nimport { extend } from './misc'\n\nconst positionStore = Object.create(null)\n\nexport function setupScroll () {\n  // Prevent browser scroll behavior on History popstate\n  if ('scrollRestoration' in window.history) {\n    window.history.scrollRestoration = 'manual'\n  }\n  // Fix for #1585 for Firefox\n  // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678\n  // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with\n  // window.location.protocol + '//' + window.location.host\n  // location.host contains the port and location.hostname doesn't\n  const protocolAndPath = window.location.protocol + '//' + window.location.host\n  const absolutePath = window.location.href.replace(protocolAndPath, '')\n  // preserve existing history state as it could be overriden by the user\n  const stateCopy = extend({}, window.history.state)\n  stateCopy.key = getStateKey()\n  window.history.replaceState(stateCopy, '', absolutePath)\n  window.addEventListener('popstate', handlePopState)\n  return () => {\n    window.removeEventListener('popstate', handlePopState)\n  }\n}\n\nexport function handleScroll (\n  router: Router,\n  to: Route,\n  from: Route,\n  isPop: boolean\n) {\n  if (!router.app) {\n    return\n  }\n\n  const behavior = router.options.scrollBehavior\n  if (!behavior) {\n    return\n  }\n\n  if (process.env.NODE_ENV !== 'production') {\n    assert(typeof behavior === 'function', `scrollBehavior must be a function`)\n  }\n\n  // wait until re-render finishes before scrolling\n  router.app.$nextTick(() => {\n    const position = getScrollPosition()\n    const shouldScroll = behavior.call(\n      router,\n      to,\n      from,\n      isPop ? position : null\n    )\n\n    if (!shouldScroll) {\n      return\n    }\n\n    if (typeof shouldScroll.then === 'function') {\n      shouldScroll\n        .then(shouldScroll => {\n          scrollToPosition((shouldScroll: any), position)\n        })\n        .catch(err => {\n          if (process.env.NODE_ENV !== 'production') {\n            assert(false, err.toString())\n          }\n        })\n    } else {\n      scrollToPosition(shouldScroll, position)\n    }\n  })\n}\n\nexport function saveScrollPosition () {\n  const key = getStateKey()\n  if (key) {\n    positionStore[key] = {\n      x: window.pageXOffset,\n      y: window.pageYOffset\n    }\n  }\n}\n\nfunction handlePopState (e) {\n  saveScrollPosition()\n  if (e.state && e.state.key) {\n    setStateKey(e.state.key)\n  }\n}\n\nfunction getScrollPosition (): ?Object {\n  const key = getStateKey()\n  if (key) {\n    return positionStore[key]\n  }\n}\n\nfunction getElementPosition (el: Element, offset: Object): Object {\n  const docEl: any = document.documentElement\n  const docRect = docEl.getBoundingClientRect()\n  const elRect = el.getBoundingClientRect()\n  return {\n    x: elRect.left - docRect.left - offset.x,\n    y: elRect.top - docRect.top - offset.y\n  }\n}\n\nfunction isValidPosition (obj: Object): boolean {\n  return isNumber(obj.x) || isNumber(obj.y)\n}\n\nfunction normalizePosition (obj: Object): Object {\n  return {\n    x: isNumber(obj.x) ? obj.x : window.pageXOffset,\n    y: isNumber(obj.y) ? obj.y : window.pageYOffset\n  }\n}\n\nfunction normalizeOffset (obj: Object): Object {\n  return {\n    x: isNumber(obj.x) ? obj.x : 0,\n    y: isNumber(obj.y) ? obj.y : 0\n  }\n}\n\nfunction isNumber (v: any): boolean {\n  return typeof v === 'number'\n}\n\nconst hashStartsWithNumberRE = /^#\\d/\n\nfunction scrollToPosition (shouldScroll, position) {\n  const isObject = typeof shouldScroll === 'object'\n  if (isObject && typeof shouldScroll.selector === 'string') {\n    // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]\n    // but at the same time, it doesn't make much sense to select an element with an id and an extra selector\n    const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line\n      ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line\n      : document.querySelector(shouldScroll.selector)\n\n    if (el) {\n      let offset =\n        shouldScroll.offset && typeof shouldScroll.offset === 'object'\n          ? shouldScroll.offset\n          : {}\n      offset = normalizeOffset(offset)\n      position = getElementPosition(el, offset)\n    } else if (isValidPosition(shouldScroll)) {\n      position = normalizePosition(shouldScroll)\n    }\n  } else if (isObject && isValidPosition(shouldScroll)) {\n    position = normalizePosition(shouldScroll)\n  }\n\n  if (position) {\n    // $flow-disable-line\n    if ('scrollBehavior' in document.documentElement.style) {\n      window.scrollTo({\n        left: position.x,\n        top: position.y,\n        // $flow-disable-line\n        behavior: shouldScroll.behavior\n      })\n    } else {\n      window.scrollTo(position.x, position.y)\n    }\n  }\n}\n"
  },
  {
    "path": "src/util/state-key.js",
    "content": "/* @flow */\nimport { inBrowser } from './dom'\n\n// use User Timing api (if present) for more accurate key precision\nconst Time =\n  inBrowser && window.performance && window.performance.now\n    ? window.performance\n    : Date\n\nexport function genStateKey (): string {\n  return Time.now().toFixed(3)\n}\n\nlet _key: string = genStateKey()\n\nexport function getStateKey () {\n  return _key\n}\n\nexport function setStateKey (key: string) {\n  return (_key = key)\n}\n"
  },
  {
    "path": "src/util/warn.js",
    "content": "/* @flow */\n\nexport function assert (condition: any, message: string) {\n  if (!condition) {\n    throw new Error(`[vue-router] ${message}`)\n  }\n}\n\nexport function warn (condition: any, message: string) {\n  if (!condition) {\n    typeof console !== 'undefined' && console.warn(`[vue-router] ${message}`)\n  }\n}\n\n"
  },
  {
    "path": "test/.eslintrc",
    "content": "{\n  \"env\": {\n    \"jasmine\": true\n  }\n}\n"
  },
  {
    "path": "test/e2e/.eslintrc",
    "content": "{\n  \"env\": {\n    \"browser\": true\n  }\n}\n"
  },
  {
    "path": "test/e2e/browserstack-send-status.js",
    "content": "const axios = require('axios')\n\nconst BS_USER = process.env.BS_USER\nconst BS_KEY = process.env.BS_KEY\n\nfunction getKey (client) {\n  // const { capabilities, currentTest } = client\n  // originally i wanted to use this but it turns out the information changes\n  // on the afterEach, making the key non valid. But because every environment\n  // runs on a different thread, the sessionMap object is only shared for a given\n  // environment, so only using the name of the test (currentTest.module) seems to be\n  // enough\n  // return `${capabilities.platform}::${capabilities.browserName}@${\n  //   capabilities.version\n  // } ${currentTest.module}: ${currentTest.name}`\n\n  return `${client.currentTest.module}: ${client.currentTest.name}`\n}\n\nfunction shouldSkipBrowserstackReporting (client) {\n  return !BS_USER || !BS_KEY || client.options.selenium_port !== 80\n}\n\n/**\n * Generates an object with beforeEach and afterEach functions to be added\n * to every test suite. It cannot be added globably because these must be\n * executed before each test (instead of each test suite as it does in globalModules)\n */\nmodule.exports = function sendStatus () {\n  const sessionMap = Object.create(null)\n\n  return {\n    beforeEach (browser, cb) {\n      // avoid running if missing credentials\n      if (shouldSkipBrowserstackReporting(this.client)) return cb()\n      // retrieve the session and save it to the map\n      const key = getKey(this.client)\n      browser.session(({ sessionId }) => {\n        sessionMap[key] = sessionId\n        cb()\n      })\n    },\n\n    afterEach (browser, cb) {\n      // avoid running if missing credentials\n      if (shouldSkipBrowserstackReporting(this.client)) return cb()\n      const key = getKey(this.client)\n      const { results } = this.client.currentTest\n      const sessionId = sessionMap[key]\n\n      if (!sessionId) {\n        console.warn('❌ Cannot find sessionId for ' + key)\n        return cb()\n      }\n\n      if (results.errors > 0 || results.failed > 0) {\n        const reason = results.lastError.message\n        console.log('Found failed test', reason)\n        axios\n          .put(\n            `https://api.browserstack.com/automate/sessions/${sessionId}.json`,\n            {\n              // change the name so it's easier to find\n              name: key,\n              status: 'failed',\n              reason\n            },\n            {\n              auth: {\n                username: BS_USER,\n                password: BS_KEY\n              }\n            }\n          )\n          .catch(err => {\n            console.log('❌ Failed changing status for sessions', err)\n          })\n          .then(() => {\n            console.log('✅ Sent for', sessionId)\n            cb()\n          })\n      } else {\n        cb()\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "test/e2e/nightwatch.browserstack.js",
    "content": "/**\n * Running tests on remote browsers\n */\n\nconst BS_USER = process.env.BS_USER\nconst BS_KEY = process.env.BS_KEY\n\nconst nwConf = {\n  src_folders: ['test/e2e/specs'],\n  output_folder: 'test/e2e/reports',\n  custom_commands_path: ['node_modules/nightwatch-helpers/commands'],\n  custom_assertions_path: ['node_modules/nightwatch-helpers/assertions'],\n  // set to true when testing on multiple browsers (-e chrome,firefox) to display tests as they pass instead of waiting for everything to be finished\n  live_output: true,\n\n  // this couldn't work at the end, so we used ./browserstack-send-status.js\n  // globals_path: resolve(__dirname, './globalModules.js'),\n\n  selenium: {\n    start_process: false,\n    host: 'hub-cloud.browserstack.com',\n    port: 80\n  },\n\n  common_capabilities: {\n    'browserstack.user': BS_USER,\n    'browserstack.key': BS_KEY,\n    name: 'Bstack-[Nightwatch] Vue Router Parallel Test',\n    'browserstack.local': true,\n    'browserstack.video': false,\n    acceptSslCerts: true,\n    resolution: '1024x768'\n  },\n\n  test_settings: {\n    // default: {},\n\n    chrome: {\n      desiredCapabilities: {\n        browser: 'chrome'\n      }\n    },\n\n    chromeQt: {\n      desiredCapabilities: {\n        browser: 'chrome',\n        browser_version: '49.0'\n      }\n    },\n\n    firefox: {\n      desiredCapabilities: {\n        browser: 'firefox'\n      }\n    },\n\n    safari: {\n      desiredCapabilities: {\n        os: 'OS X',\n        os_version: 'Mojave',\n        browser: 'Safari',\n        browser_version: '12.0'\n      }\n    },\n\n    safari6: {\n      desiredCapabilities: {\n        os: 'OS X',\n        os_version: 'Lion',\n        browser: 'Safari',\n        browser_version: '6.0'\n      }\n    },\n\n    ie9: {\n      desiredCapabilities: {\n        browser: 'internet explorer',\n        browser_version: '9'\n        // name: 'Bstack-[Nightwatch] Vue Router',\n        // 'browserstack.video': true\n      }\n    },\n\n    ie: {\n      desiredCapabilities: {\n        browser: 'internet explorer',\n        browser_version: '11'\n        // name: 'Bstack-[Nightwatch] Vue Router',\n        // 'browserstack.video': true\n      }\n    },\n\n    android44: {\n      desiredCapabilities: {\n        device: 'Google Nexus 5',\n        realMobile: 'true',\n        os_version: '4.4'\n      }\n    },\n\n    ios7: {\n      desiredCapabilities: {\n        device: 'iPhone 7',\n        realMobile: 'true',\n        os_version: '10'\n      }\n    }\n  }\n}\n\n// Code to copy seleniumhost/port into test settings\nfor (const setting in nwConf.test_settings) {\n  const config = nwConf.test_settings[setting]\n  config['selenium_host'] = nwConf.selenium.host\n  config['selenium_port'] = nwConf.selenium.port\n\n  // merge common_capabilities\n  for (const key in nwConf.common_capabilities) {\n    // fallback to common_capabilities\n    config['desiredCapabilities'][key] =\n      config['desiredCapabilities'][key] || nwConf.common_capabilities[key]\n  }\n}\n\nmodule.exports = nwConf\n"
  },
  {
    "path": "test/e2e/nightwatch.config.js",
    "content": "// yarn nightwatch -e chrome,safari,firefox\n\nmodule.exports = {\n  src_folders: ['test/e2e/specs'],\n  output_folder: 'test/e2e/reports',\n  custom_commands_path: ['node_modules/nightwatch-helpers/commands'],\n  custom_assertions_path: ['node_modules/nightwatch-helpers/assertions'],\n  // set to true when testing on multiple browsers (-e chrome,firefox) to display tests as they pass instead of waiting for everything to be finished\n  live_output: false,\n\n  selenium: {\n    start_process: true,\n    server_path: require('selenium-server').path,\n    host: '127.0.0.1',\n    port: 4444,\n    cli_args: {\n      'webdriver.chrome.driver': require('chromedriver').path,\n      'webdriver.gecko.driver': require('geckodriver').path\n    }\n  },\n\n  test_settings: {\n    default: {\n      selenium_port: 4444,\n      selenium_host: 'localhost',\n      silent: true,\n      screenshots: {\n        enabled: true,\n        on_failure: true,\n        on_error: false,\n        path: 'test/e2e/screenshots'\n      },\n      desiredCapabilities: {\n        browserName: 'chrome',\n        acceptSslCerts: true,\n        chromeOptions: {\n          // https://github.com/nightwatchjs/nightwatch/releases/tag/v1.1.12\n          w3c: false,\n          args: ['window-size=1280,800', 'headless']\n        }\n      }\n    },\n\n    chrome: {\n      desiredCapabilities: {\n        browserName: 'chrome',\n        acceptSslCerts: true,\n        chromeOptions: {\n          // https://github.com/nightwatchjs/nightwatch/releases/tag/v1.1.12\n          w3c: false,\n          args: ['window-size=1280,800']\n        }\n      }\n    },\n\n    safari: {\n      desiredCapabilities: {\n        browserName: 'safari',\n        acceptSslCerts: true\n      }\n    },\n\n    firefox: {\n      desiredCapabilities: {\n        browserName: 'firefox',\n        acceptSslCerts: true\n      }\n    },\n\n    ie: {\n      desiredCapabilities: {\n        browser: 'internet explorer'\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "test/e2e/runner.js",
    "content": "/**\n * Running tests\n *\n * By default tests are run locally on chrome headless\n * $ node test/e2e/runner.js\n *\n * You can run a specific test by passing it, or pass various tests\n * $ node test/e2e/runner.js test/e2e/specs/basic.js test/e2e/specs/redirect.js\n *\n * You can specify a list of browsers to run from nightwatch.config.js with -e separated by a comma\n * $ node test/e2e/runner.js -e safari,firefox\n *\n * If you are already running the dev server with `yarn run serve`, you can pass the --dev option to avoid launching the server\n * $ node test/e2e/runner.js --dev\n * **Make sure to pass the option at the end**\n *\n * __For maintainers only__\n * You can trigger tests on Browserstack on other browsers by passing the --local option\n * It's also required to pass the list of browsers to test on to avoid launching too many tests. Available options are located inside nightwatch.browserstack.js\n * $ node test/e2e/runner.js --local -e ie,chrome50\n */\n\nrequire('dotenv').config()\nconst { resolve } = require('path')\nconst Nightwatch = require('nightwatch')\nconst args = process.argv.slice(2)\n\n// if we are running yarn dev locally, we can pass --dev to avoid launching another server instance\nconst server =\n  args.indexOf('--dev') > -1 ? null : require('../../examples/server')\n\n// allow running browserstack local\nconst isLocal = args.indexOf('--local') > -1\n\nconst DEFAULT_CONFIG = './nightwatch.json'\nconst NW_CONFIG = isLocal\n  ? resolve(__dirname, './nightwatch.browserstack.js')\n  : resolve(__dirname, './nightwatch.config.js')\n\n// check -c option is passed when usig multiple environments\nif (args.indexOf('-c') < 0) {\n  // check if multiple envs are provided. The way Nightwatch works\n  // requires to explicitely provide the conf\n  const envs = args[args.indexOf('-e') + 1]\n  if (envs && envs.indexOf(',') > -1) {\n    console.warn(\n      `Specify the conf when providing multiple browsers:\\n$ yarn run test:e2e ${args.join(\n        ' '\n      )} -c ${NW_CONFIG}`\n    )\n    process.exit(1)\n  }\n} else if (isLocal) {\n  const conf = args[args.indexOf('-c') + 1]\n  if (resolve('.', conf) !== NW_CONFIG) {\n    console.warn('The passed config should be', NW_CONFIG)\n    process.exit(1)\n  }\n}\n\nfunction adaptArgv (argv) {\n  // take every remaining argument and treat it as a test file\n  // this allows to run `node test/e2e/runner.js test/e2e/basic.js`\n  argv.retries = process.env.CI ? 1 : 0\n  argv.test = argv['_'].slice(0)\n\n  if (argv.c === DEFAULT_CONFIG && argv.config === DEFAULT_CONFIG) {\n    argv.config = argv.c = NW_CONFIG\n  }\n  // Nightwatch does not accept an array with one element\n  if (argv.test.length === 1) argv.test = argv.test[0]\n\n  // debugging easily\n  // console.log(argv)\n  // process.exit(0)\n}\n\nprocess.mainModule.filename = resolve(\n  __dirname,\n  '../../node_modules/.bin/nightwatch'\n)\n\nif (isLocal) {\n  if (isLocal && (!process.env.BS_USER || !process.env.BS_KEY)) {\n    console.log(\n      'Hey!\\n',\n      'You are missing credentials for Browserstack.\\n',\n      'If you are a contributor, this is normal, credentials are private. These tests must be run by a maintainer of vue-router',\n      'If you are a maintainer, make sure to create your `.env` file with both `BS_USER` and `BS_KEY` variables!'\n    )\n    // fail if testing locally\n    process.exit(process.env.CI ? 0 : 1)\n  }\n\n  let bsLocal\n  const browserstack = require('browserstack-local')\n  Nightwatch.bs_local = bsLocal = new browserstack.Local()\n  bsLocal.start({ key: process.env.BS_KEY }, error => {\n    if (error) throw error\n\n    console.log('Connected. Now testing...')\n    try {\n      Nightwatch.cli(argv => {\n        adaptArgv(argv)\n        Nightwatch.CliRunner(argv)\n          .setup(null, () => {\n            // NOTE: I don't know when this is running or if it does\n            // Code to stop browserstack local after end of parallel test\n            bsLocal.stop(() => {\n              server && server.close()\n              process.exit(0)\n            })\n          })\n          .runTests()\n          .then(() => {\n            // Code to stop browserstack local after end of single test\n            bsLocal.stop(() => {\n              server && server.close()\n              process.exit(0)\n            })\n          })\n          .catch(() => {\n            server && server.close()\n            // fail execution\n            process.exit(1)\n          })\n      })\n    } catch (err) {\n      console.error(err)\n      bsLocal.stop(() => {\n        process.exit(1)\n      })\n    }\n  })\n} else {\n  // create the Nightwatch CLI runner\n  Nightwatch.cli(argv => {\n    adaptArgv(argv)\n    const runner = Nightwatch.CliRunner(argv)\n\n    // setup and run tests\n    runner\n      .setup()\n      .startWebDriver()\n      .then(() => runner.runTests())\n      .then(() => {\n        runner.stopWebDriver()\n        server && server.close()\n        process.exit(0)\n      })\n      .catch(err => {\n        server && server.close()\n        console.error(err)\n        process.exit(1)\n      })\n  })\n}\n"
  },
  {
    "path": "test/e2e/specs/.prettierrc",
    "content": "{\n  \"printWidth\": 120\n}\n"
  },
  {
    "path": "test/e2e/specs/active-links.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history', 'active', 'router-link'],\n\n  /** @type {import('nightwatch').NightwatchTest} */\n  'active links': function (browser) {\n    browser\n      .url('http://localhost:8080/active-links/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 22)\n      // assert correct href with base\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/active-links/')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/active-links/')\n      .assert.attributeContains('li:nth-child(3) a', 'href', '/active-links/users')\n      .assert.attributeContains('li:nth-child(4) a', 'href', '/active-links/users')\n      .assert.attributeContains('li:nth-child(5) a', 'href', '/active-links/users/evan')\n      .assert.attributeContains('li:nth-child(6) a', 'href', '/active-links/users/evan#foo')\n      .assert.attributeContains('li:nth-child(7) a', 'href', '/active-links/users/evan?foo=bar')\n      .assert.attributeContains('li:nth-child(8) a', 'href', '/active-links/users/evan?foo=bar')\n      .assert.attributeContains('li:nth-child(9) a', 'href', '/active-links/users/evan?foo=bar&baz=qux')\n      .assert.attributeContains('li:nth-child(10) a', 'href', '/active-links/about')\n      .assert.attributeContains('li:nth-child(11) a', 'href', '/active-links/about')\n      .assert.attributeContains('li:nth-child(12) a', 'href', '/active-links/gallery')\n      .assert.attributeContains('li:nth-child(13) a', 'href', '/active-links/gallery/')\n      .assert.attributeContains('li:nth-child(14) a', 'href', '/active-links/gallery/image2')\n      .assert.attributeContains('li:nth-child(15) a', 'href', '/active-links/gallery/image1')\n      .assert.attributeContains('li:nth-child(16) a', 'href', '/active-links/redirect-gallery')\n      .assert.attributeContains('li:nth-child(17) a', 'href', '/active-links/redirect-gallery')\n      .assert.attributeContains('li:nth-child(18) a', 'href', '/active-links/redirect-image')\n      .assert.attributeContains('li:nth-child(19) a', 'href', '/active-links/redirect-image')\n      .assert.containsText('.view', 'Home')\n      .assert.not.attributeEquals(`li:nth-child(3) a`, 'aria-current', 'page')\n\n    assertActiveLinks(1, [1, 2], null, [1, 2])\n    assertActiveLinks(2, [1, 2], null, [1, 2])\n    assertActiveLinks(3, [1, 3, 4], null, [3, 4])\n    assertActiveLinks(4, [1, 3, 4], null, [3, 4])\n    assertActiveLinks(5, [1, 3, 5], null, [5])\n    assertActiveLinks(6, [1, 3, 5, 6], null, [6])\n    assertActiveLinks(7, [1, 3, 5, 7, 8], null, [7, 8])\n    assertActiveLinks(8, [1, 3, 5, 7, 8], null, [7, 8])\n    assertActiveLinks(9, [1, 3, 5, 7, 9], null, [9])\n    assertActiveLinks(10, [1, 10], [11], [10], [11])\n    assertActiveLinks(11, [1, 10], [11], [10], [11])\n\n    // redirects\n    assertActiveLinks(12, [1, 12, 13, 15], null, [15])\n    assertActiveLinks(13, [1, 12, 13, 15], null, [15])\n    assertActiveLinks(14, [1, 12, 13, 14], null, [14])\n    assertActiveLinks(15, [1, 12, 13, 15], null, [15])\n    // different level redirect\n    assertActiveLinks(16, [1, 12, 13, 15], null, [15])\n    assertActiveLinks(17, [1, 12, 13, 15], null, [15])\n    assertActiveLinks(18, [1, 12, 13, 15], null, [15])\n    assertActiveLinks(19, [1, 12, 13, 15], null, [15])\n\n    // exact-path\n    assertActiveLinks(20, [20, 21], null, [20, 21])\n    assertActiveLinks(21, [20, 21], null, [20, 21])\n    assertActiveLinks(22, [22], null, [22])\n\n    browser.end()\n\n    function assertActiveLinks (n, activeA, activeLI, exactActiveA, exactActiveLI) {\n      browser.click(`li:nth-child(${n}) a`)\n      activeA.forEach(i => {\n        browser.assert.cssClassPresent(`li:nth-child(${i}) a`, 'router-link-active')\n      })\n      activeLI &&\n        activeLI.forEach(i => {\n          browser.assert.cssClassPresent(`li:nth-child(${i})`, 'router-link-active')\n        })\n      exactActiveA.forEach(i => {\n        browser.assert\n          .cssClassPresent(`li:nth-child(${i}) a`, 'router-link-exact-active')\n          .assert.cssClassPresent(`li:nth-child(${i}) a`, 'router-link-active')\n          .assert.attributeEquals(`li:nth-child(${i}) a`, 'aria-current', 'page')\n      })\n      exactActiveLI &&\n        exactActiveLI.forEach(i => {\n          browser.assert\n            .cssClassPresent(`li:nth-child(${i})`, 'router-link-exact-active')\n            .assert.cssClassPresent(`li:nth-child(${i})`, 'router-link-active')\n            .assert.attributeEquals(`li:nth-child(${i}) a`, 'aria-current', 'page')\n        })\n    }\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/auth-flow.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'auth flow': function (browser) {\n    browser\n      .url('http://localhost:8080/auth-flow/')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('#app p', 'You are logged out')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/auth-flow/login?redirect=%2Fdashboard')\n      .assert.containsText('#app h2', 'Login')\n      .assert.containsText('#app p', 'You need to login first.')\n\n      .click('button')\n      .assert.urlEquals('http://localhost:8080/auth-flow/login?redirect=%2Fdashboard')\n      .assert.elementPresent('.error')\n\n      .setValue('input[type=password]', 'password1')\n      .click('button')\n      .assert.urlEquals('http://localhost:8080/auth-flow/dashboard')\n      .assert.containsText('#app h2', 'Dashboard')\n      .assert.containsText('#app p', 'Yay you made it!')\n\n      // reload\n      .url('http://localhost:8080/auth-flow/')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('#app p', 'You are logged in')\n\n      // navigate when logged in\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/auth-flow/dashboard')\n      .assert.containsText('#app h2', 'Dashboard')\n      .assert.containsText('#app p', 'Yay you made it!')\n\n      // directly visit dashboard when logged in\n      .url('http://localhost:8080/auth-flow/dashboard')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/auth-flow/dashboard')\n      .assert.containsText('#app h2', 'Dashboard')\n      .assert.containsText('#app p', 'Yay you made it!')\n\n      // log out\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/auth-flow/')\n      .assert.containsText('#app p', 'You are logged out')\n\n      // directly visit dashboard when logged out\n      .url('http://localhost:8080/auth-flow/dashboard')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/auth-flow/login?redirect=%2Fdashboard')\n      .assert.containsText('#app h2', 'Login')\n      .assert.containsText('#app p', 'You need to login first.')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/basic.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  basic: function (browser) {\n    browser\n      .url('http://localhost:8080/basic/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li', 12)\n      .assert.count('li a', 12)\n      // assert correct href with base\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/basic/')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/basic/foo')\n      .assert.attributeContains('li:nth-child(3) a', 'href', '/basic/bar')\n      .assert.attributeContains('li:nth-child(4) a', 'href', '/basic/bar')\n      .assert.attributeContains('li:nth-child(5) a', 'href', '/basic/%C3%A9')\n      .assert.attributeContains('li:nth-child(6) a', 'href', '/basic/%C3%A9?t=%25%C3%B1')\n      .assert.attributeContains('li:nth-child(7) a', 'href', '/basic/%C3%A9#%25%C3%B1')\n      .assert.attributeContains('li:nth-child(8) a', 'href', '/basic/foo')\n      .assert.attributeContains('li:nth-child(10) a', 'href', '/basic/query/A%')\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/basic/foo')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/basic/bar')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/basic/')\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(4) a')\n      .assert.urlEquals('http://localhost:8080/basic/bar')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/basic/%C3%A9')\n      .assert.containsText('.view', 'unicode')\n\n      // check initial visit\n      .url('http://localhost:8080/basic/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'foo')\n      .url('http://localhost:8080/basic/%C3%A9')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'unicode')\n\n      // regression onComplete\n      // https://github.com/vuejs/vue-router/issues/2721\n      .assert.containsText('#counter', '0')\n      .click('#navigate-btn')\n      .assert.containsText('#counter', '1')\n      .click('#navigate-btn')\n      .assert.containsText('#counter', '2')\n\n      // scoped slot\n      .assert.containsText('li:nth-child(8) a', '/foo (with v-slot)')\n      .click('li:nth-child(8) a')\n      .assert.urlEquals('http://localhost:8080/basic/foo')\n      .assert.containsText('.view', 'foo')\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/basic/foo')\n      .assert.containsText('.view', 'foo')\n      .assert.cssClassPresent('li:nth-child(8)', 'active')\n      .assert.cssClassPresent('li:nth-child(8)', 'exact-active')\n      .assert.attributeEquals('li:nth-child(8) a', 'class', '')\n\n      // encoded percentage as path param\n      // https://github.com/vuejs/vue-router/issues/2725\n      .url('http://localhost:8080/basic/query/A%25')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'query: \"A%\"')\n      .click('li:nth-child(10) a')\n      .assert.urlEquals('http://localhost:8080/basic/query/A%25')\n      .assert.containsText('.view', 'query: \"A%\"')\n\n      // Listener cleanup\n      .assert.containsText('#popstate-count', '1 popstate listeners')\n      .click('#unmount')\n      .assert.containsText('#popstate-count', '0 popstate listeners')\n\n      .end()\n  },\n\n  'cancelling ongoing navigations': function (browser) {\n    browser\n      .url('http://localhost:8080/basic/?delay=200')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'home')\n      // go to foo with a delay\n      .click('li:nth-child(12) a')\n      .click('li:nth-child(11) a')\n      .waitFor(300)\n      // we should stay at /basic after the delay\n      .assert.urlEquals('http://localhost:8080/basic/?delay=200')\n      .assert.containsText('.view', 'home')\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/composables.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'useRoute() + useRouter()': function (browser) {\n    browser\n      .url('http://localhost:8080/composables/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li', 4)\n      .assert.count('li a', 4)\n      .assert.containsText('.view', 'Home')\n\n      .click('li:nth-child(2) a')\n      .assert.containsText('.view', 'About')\n      .click('li:nth-child(1) a')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('#start-route', '/')\n      .assert.containsText('#fullpath', '/')\n\n      .click('button#nav')\n      .assert.containsText('#fullpath', '/?n=1')\n\n      .end()\n  },\n\n  'useLink()': function (browser) {\n    browser\n      .url('http://localhost:8080/composables/')\n      .waitForElementVisible('#app', 1000)\n\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('#nested-active', '/composables/nested: false, false')\n      .click('li:nth-child(3) a')\n      .assert.containsText('.view', 'NestedEmpty')\n      .assert.containsText('#nested-active', '/composables/nested: true, true')\n      .click('li:nth-child(4) a')\n      .assert.containsText('.view', 'NestedA')\n      .assert.containsText('#nested-active', '/composables/nested: true, false')\n      .click('#nested-active')\n      .assert.containsText('.view', 'NestedEmpty')\n      .assert.containsText('#nested-active', '/composables/nested: true, true')\n\n      .end()\n  }\n\n}\n"
  },
  {
    "path": "test/e2e/specs/data-fetching.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': [],\n\n  'data fetching': function (browser) {\n    browser\n      .url('http://localhost:8080/data-fetching/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 4)\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(2) a')\n      .waitForElementNotPresent('.loading', 500)\n      .assert.containsText('.post h2', 'sunt aut facere')\n      .assert.containsText('.post p', 'quia et suscipit')\n\n      .click('li:nth-child(3) a')\n      .waitForElementNotPresent('.loading', 500)\n      .assert.containsText('.post h2', 'qui est esse')\n      .assert.containsText('.post p', 'est rerum tempore')\n\n      .click('li:nth-child(4) a')\n      .waitForElementNotPresent('.loading', 500)\n      .assert.elementNotPresent('.content')\n      .assert.containsText('.error', 'Post not found')\n\n      .click('li:nth-child(1) a')\n      .assert.elementNotPresent('.post')\n      .assert.containsText('.view', 'home')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/hash-mode.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['hash', 'ie9-fail'],\n\n  'Hash mode': function (browser) {\n    browser\n      .url('http://localhost:8080/hash-mode/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li', 12)\n      .assert.count('li a', 11)\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/hash-mode/#/')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/hash-mode/#/foo')\n      .assert.attributeContains('li:nth-child(3) a', 'href', '/hash-mode/#/bar')\n      .assert.attributeContains('li:nth-child(5) a', 'href', '/hash-mode/#/%C3%A9')\n      .assert.attributeContains('li:nth-child(6) a', 'href', '/hash-mode/#/%C3%A9/%C3%B1')\n      .assert.attributeContains('li:nth-child(7) a', 'href', '/hash-mode/#/%C3%A9/%C3%B1?t=%25%C3%B1')\n      .assert.attributeContains('li:nth-child(9) a', 'href', '/hash-mode/#/query/A%')\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/hash-mode/#/foo')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/hash-mode/#/bar')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/hash-mode/#/')\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(4)')\n      .assert.urlEquals('http://localhost:8080/hash-mode/#/bar')\n      .assert.containsText('.view', 'bar')\n\n      // check initial visit\n      .url('http://localhost:8080/hash-mode/#/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'foo')\n      // direct visit encoded unicode\n      .url('http://localhost:8080/hash-mode/#/%C3%A9')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'unicode')\n      // direct visit raw unicode\n      .url('http://localhost:8080/hash-mode/#/%C3%A9/%C3%B1')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'unicode: ñ')\n      // TODO: Doesn't seem to work on PhantomJS\n      // .click('li:nth-child(7)')\n      // .assert.urlEquals('http://localhost:8080/hash-mode/#/%C3%A9/%C3%B1?t=%25')\n      // .assert.containsText('.view', 'unicode: ñ')\n      // .assert.containsText('#query-t', '%')\n      // direct visit\n      .url('http://localhost:8080/hash-mode/#/%C3%A9/%C3%B1?t=%25')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'unicode: ñ')\n      .assert.containsText('#query-t', '%')\n\n      // percentage as path param\n      // https://github.com/vuejs/vue-router/issues/2725\n      .url('http://localhost:8080/hash-mode/#/query/A%25')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'query: \"A%\"')\n      .click('li:nth-child(9) a')\n      .assert.urlEquals('http://localhost:8080/hash-mode/#/query/A%25')\n      .assert.containsText('.view', 'query: \"A%\"')\n\n      // Listener cleanup\n      .assert.containsText('#popstate-count', '1 popstate listeners')\n      .click('#unmount')\n      .assert.containsText('#popstate-count', '0 popstate listeners')\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/hash-scroll-behavior.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['hash', 'ie9-fail'],\n\n  'scroll behavior': function (browser) {\n    browser\n      .url('http://localhost:8080/hash-scroll-behavior/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 5)\n      .assert.containsText('.view', 'home')\n\n      .execute(function () {\n        window.scrollTo(0, 100)\n      })\n      .click('li:nth-child(2) a')\n      .assert.containsText('.view', 'foo')\n      .execute(function () {\n        window.scrollTo(0, 200)\n        window.history.back()\n      })\n      .assert.containsText('.view', 'home')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 100\n        },\n        null,\n        'restore scroll position on back'\n      )\n\n      // scroll on a popped entry\n      .execute(function () {\n        window.scrollTo(0, 50)\n        window.history.forward()\n      })\n      .assert.containsText('.view', 'foo')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 200\n        },\n        null,\n        'restore scroll position on forward'\n      )\n\n      .execute(function () {\n        window.history.back()\n      })\n      .assert.containsText('.view', 'home')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 50\n        },\n        null,\n        'restore scroll position on back again'\n      )\n\n      .click('li:nth-child(3) a')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 0\n        },\n        null,\n        'scroll to top on new entry'\n      )\n\n      .click('li:nth-child(4) a')\n      .assert.evaluate(\n        function () {\n          return document.getElementById('anchor').getBoundingClientRect().top < 1\n        },\n        null,\n        'scroll to anchor'\n      )\n\n      // scroll back to top so we can click the butotn\n      .execute(function () {\n        window.scrollTo(0, 0)\n      })\n      .click('li:nth-child(5) a')\n      .assert.evaluate(\n        function () {\n          return document.getElementById('anchor2').getBoundingClientRect().top < 101\n        },\n        null,\n        'scroll to anchor with offset'\n      )\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/history-state.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'history state': function (browser) {\n    browser\n      .url('http://localhost:8080/scroll-behavior/')\n      .waitForElementVisible('#app', 1000)\n\n      .execute(function () {\n        window.scrollTo(0, 100)\n        const key = window.history.state.key\n        window.history.replaceState({ key, foo: 'foo' }, '', window.location.pathname)\n      })\n      .url('http://localhost:8080/scroll-behavior/')\n      .waitForElementVisible('#app', 1000)\n      .assert.evaluate(function () {\n        return window.history.state.foo === 'foo'\n      }, null, 'keeps existing state when reloading')\n\n      // check on navigation\n      .url('http://localhost:8080/basic/')\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/basic/foo')\n      .execute(function () {\n        window.scrollTo(0, 100)\n        const key = window.history.state.key\n        window.history.replaceState({ key, foo: 'foo' }, '', window.location.pathname)\n      })\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/basic/bar')\n      .execute(function () {\n        window.history.back()\n      })\n      .assert.evaluate(function () {\n        return window.history.state.foo === 'foo'\n      }, null, 'keeps existing state when navigating back')\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/basic/bar')\n      .execute(function () {\n        window.scrollTo(0, 100)\n        const key = window.history.state.key\n        window.history.replaceState({ key, bar: 'bar' }, '', window.location.pathname)\n      })\n      .click('li:nth-child(9) a')\n      .assert.urlEquals('http://localhost:8080/basic/foo')\n      .assert.evaluate(function () {\n        return window.history.state.bar === 'bar'\n      }, null, 'keeps existing state when replacing')\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/keepalive-view.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': [],\n\n  'keepalive view': function (browser) {\n    browser\n      .url('http://localhost:8080/keepalive-view/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 10)\n\n      .click('li:nth-child(1) a')\n      .assert.containsText('.view', 'index child1')\n\n      .click('li:nth-child(2) a')\n      .assert.containsText('.view', 'index child2')\n\n      .click('li:nth-child(3) a')\n      .assert.containsText('.view', 'home')\n\n      // back to index child1 and check it\n      .click('li:nth-child(1) a')\n      .assert.containsText('.view', 'index child1')\n\n      // beforeRouteEnter guard with keep alive\n      // https://github.com/vuejs/vue-router/issues/2561\n      .click('li:nth-child(4) a')\n      .assert.containsText('.view', 'with-guard1: 1')\n      .click('li:nth-child(3) a')\n      .assert.containsText('.view', 'home')\n      .click('li:nth-child(5) a')\n      .assert.containsText('.view', 'with-guard2: 2')\n      .click('li:nth-child(4) a')\n      .assert.containsText('.view', 'with-guard1: 3')\n\n      // keep-alive deeply nested router-views\n      // https://github.com/vuejs/vue-router/issues/2923\n      .click('li:nth-child(6) a')\n      .assert.containsText('.view', 'index child1')\n      .click('li:nth-child(3) a')\n      .assert.containsText('.view', 'home')\n      .click('li:nth-child(7) a')\n      .assert.containsText('.view', 'index child2')\n\n      // missing props in nested routes with keep alive\n      // https://github.com/vuejs/vue-router/issues/2301\n      .click('li:nth-child(8) a')\n      .assert.containsText('.view', 'msg: from parent')\n      .click('li:nth-child(9) a')\n      .assert.containsText('.view', 'msg: from parent\\nprops from route config is: from child')\n      .click('li:nth-child(10) a')\n      .assert.containsText('.view', 'no missing prop warn')\n      .click('li:nth-child(9) a')\n      .assert.containsText('.view', 'msg: from parent\\nprops from route config is: from child')\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/lazy-loading-before-mount.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': [],\n\n  'lazy loading before mount': function (browser) {\n    browser\n      .url('http://localhost:8080/lazy-loading-before-mount/')\n      // wait for the Foo component to be resolved\n      .click('#load-button')\n      .waitForElementVisible('.foo', 1000)\n      .assert.containsText('.view', 'This is Foo')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/lazy-loading.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'lazy loading': function (browser) {\n    browser\n      .url('http://localhost:8080/lazy-loading/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 5)\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(2) a')\n      .assert.containsText('.view', 'This is Foo!')\n\n      .click('li:nth-child(3) a')\n      .assert.containsText('.view', 'This is Bar!')\n\n      .click('li:nth-child(1) a')\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(4) a')\n      .assert.containsText('.view', 'This is Bar!')\n      .assert.containsText('.view h3', 'Baz')\n\n      // test initial visit\n      .url('http://localhost:8080/lazy-loading/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'This is Foo!')\n\n      .url('http://localhost:8080/lazy-loading/bar/baz')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'This is Bar!')\n      .assert.containsText('.view h3', 'Baz')\n\n      // lazy loading with dynamic params: https://github.com/vuejs/vue-router/issues/2719\n      // direct visit\n      .url('http://localhost:8080/lazy-loading/a/b/c')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', '/a/b/c')\n      // coming from another url\n      .url('http://localhost:8080/lazy-loading/')\n      .waitForElementVisible('#app', 1000)\n      .click('li:nth-child(5) a')\n      .waitForElementVisible('#tagged-path', 1000)\n      .assert.containsText('.view', '/a/b/c')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/multi-app.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  basic: function (browser) {\n    browser\n      .url('http://localhost:8080/multi-app/')\n      .waitForElementVisible('#mount1', 1000)\n      .assert.containsText('#popcount', '0')\n      .click('#mount1')\n      .waitForElementVisible('#app-1 > *', 1000)\n      .assert.containsText('#popcount', '1')\n      .click('#mount2')\n      .waitForElementVisible('#app-2 > *', 1000)\n      .assert.containsText('#popcount', '2')\n      .click('#mount3')\n      .waitForElementVisible('#app-3 > *', 1000)\n      .assert.containsText('#popcount', '3')\n\n      // They should all be displaying the home page\n      .assert.containsText('#app-1', 'home')\n      .assert.containsText('#app-2', 'home')\n      .assert.containsText('#app-3', 'home')\n\n      // Navigate to foo route\n      .click('#app-1 li:nth-child(2) a')\n      .assert.containsText('#app-1', 'foo')\n\n      .click('#app-2 li:nth-child(2) a')\n      .assert.containsText('#app-2', 'foo')\n\n      .click('#app-3 li:nth-child(2) a')\n      .assert.containsText('#app-3', 'foo')\n\n      // Unmount all apps\n      .assert.containsText('#popcount', '3')\n      .click('#unmount1')\n      .assert.containsText('#popcount', '2')\n      .click('#unmount2')\n      .assert.containsText('#popcount', '1')\n      .click('#unmount3')\n      .assert.containsText('#popcount', '0')\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/named-routes.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'named routes': function (browser) {\n    browser\n      .url('http://localhost:8080/named-routes/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 3)\n      // assert correct href with base\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/named-routes/')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/named-routes/foo')\n      .assert.attributeContains('li:nth-child(3) a', 'href', '/named-routes/bar')\n      .assert.containsText('p', 'Current route name: home')\n      .assert.containsText('.view', 'Home')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/named-routes/foo')\n      .assert.containsText('p', 'Current route name: foo')\n      .assert.containsText('.view', 'Foo')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/named-routes/bar/123')\n      .assert.containsText('p', 'Current route name: bar')\n      .assert.containsText('.view', 'Bar 123')\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/named-routes/')\n      .assert.containsText('p', 'Current route name: home')\n      .assert.containsText('.view', 'Home')\n\n      // check initial visit\n      .url('http://localhost:8080/named-routes/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('p', 'Current route name: foo')\n      .assert.containsText('.view', 'Foo')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/named-views.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'named views': function (browser) {\n    browser\n      .url('http://localhost:8080/named-views/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 2)\n      // assert correct href with base\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/named-views/')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/named-views/other')\n\n      .assert.containsText('.view.one', 'foo')\n      .assert.containsText('.view.two', 'bar')\n      .assert.containsText('.view.three', 'baz')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/named-views/other')\n      .assert.containsText('.view.one', 'baz')\n      .assert.containsText('.view.two', 'bar')\n      .assert.containsText('.view.three', 'foo')\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/named-views/')\n      .assert.containsText('.view.one', 'foo')\n      .assert.containsText('.view.two', 'bar')\n      .assert.containsText('.view.three', 'baz')\n\n      // check initial visit\n      .url('http://localhost:8080/named-views/other')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view.one', 'baz')\n      .assert.containsText('.view.two', 'bar')\n      .assert.containsText('.view.three', 'foo')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/navigation-guards.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'navigation guards with alerts': function (browser) {\n    browser\n      .url('http://localhost:8080/navigation-guards/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 9)\n      .assert.containsText('.view', 'home')\n\n    // alert commands not available in phantom\n    if (process.env.PHANTOMJS) return\n\n    browser\n      .click('li:nth-child(2) a')\n      .dismissAlert()\n      .waitFor(100)\n      .dismissAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(2) a')\n      .acceptAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/foo')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .dismissAlert()\n      .waitFor(100)\n      .dismissAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/foo')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .acceptAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/bar')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(2) a')\n      .dismissAlert()\n      .waitFor(100)\n      .acceptAlert() // redirect to baz\n      .assert.urlEquals('http://localhost:8080/navigation-guards/baz')\n      .assert.containsText('.view', 'baz (not saved)')\n\n      .click('li:nth-child(2) a')\n      .dismissAlert() // not saved\n      .assert.urlEquals('http://localhost:8080/navigation-guards/baz')\n      .assert.containsText('.view', 'baz (not saved)')\n\n      .click('li:nth-child(2) a')\n      .acceptAlert() // not saved, force leave\n      .waitFor(100)\n      .dismissAlert() // should trigger foo's guard\n      .waitFor(100)\n      .dismissAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/baz')\n      .assert.containsText('.view', 'baz')\n\n      .click('li:nth-child(2) a')\n      .acceptAlert()\n      .waitFor(100)\n      .acceptAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/foo')\n      .assert.containsText('.view', 'foo')\n\n    // test initial visit\n    browser\n      .url('http://localhost:8080/navigation-guards/foo')\n      .dismissAlert()\n      .waitFor(100)\n      .dismissAlert()\n      // should redirect to root\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      // and should not render anything\n      .assert.elementNotPresent('.view')\n\n      .url('http://localhost:8080/navigation-guards/foo')\n      .acceptAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/foo')\n      .assert.containsText('.view', 'foo')\n\n      .url('http://localhost:8080/navigation-guards/bar')\n      .dismissAlert()\n      .waitFor(100)\n      .dismissAlert()\n      // should redirect to root\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      // and should not render anything\n      .assert.elementNotPresent('.view')\n\n      .url('http://localhost:8080/navigation-guards/bar')\n      .acceptAlert()\n      .assert.urlEquals('http://localhost:8080/navigation-guards/bar')\n      .assert.containsText('.view', 'bar')\n  },\n  'navigation guards': function (browser) {\n    browser\n      // back to home\n      .url('http://localhost:8080/navigation-guards/')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'home')\n\n      .click('li:nth-child(4) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/baz')\n      .assert.containsText('.view', 'baz (not saved)')\n      .click('button')\n      .assert.containsText('.view', 'baz (saved)')\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      .assert.containsText('.view', 'home')\n\n      // in-component guard\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      .assert.containsText('.view', 'home')\n      .waitFor(300)\n      .assert.urlEquals('http://localhost:8080/navigation-guards/qux')\n      .assert.containsText('.view', 'Qux')\n\n      // async component + in-component guard\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      .assert.containsText('.view', 'home')\n      .click('li:nth-child(6) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/')\n      .assert.containsText('.view', 'home')\n      .waitFor(300)\n      .assert.urlEquals('http://localhost:8080/navigation-guards/qux-async')\n      .assert.containsText('.view', 'Qux')\n\n      // beforeRouteUpdate\n      .click('li:nth-child(7) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/quux/1')\n      .assert.containsText('.view', 'id:1 prevId:0')\n      .click('li:nth-child(8) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/quux/2')\n      .assert.containsText('.view', 'id:2 prevId:1')\n      .click('li:nth-child(7) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/quux/1')\n      .assert.containsText('.view', 'id:1 prevId:2')\n\n      // beforeRouteEnter order in children\n      .click('li:nth-child(9) a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/parent/child/2')\n      .assert.containsText('#bre-order', 'parent mixin child 2')\n      .click('#nested-parent a')\n      .assert.urlEquals('http://localhost:8080/navigation-guards/parent/child/1')\n      .assert.containsText('#bre-order', 'parent mixin child 2 mixin child 1')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/nested-router.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  basic: function (browser) {\n    browser\n      .url('http://localhost:8080/nested-router/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 3)\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/nested-router/nested-router')\n      .assert.containsText('.child', 'Child router path: /')\n      .assert.count('li a', 5)\n\n      .click('.child li:nth-child(1) a')\n      .assert.containsText('.child', 'Child router path: /foo')\n      .assert.containsText('.child .foo', 'foo')\n\n      .click('.child li:nth-child(2) a')\n      .assert.containsText('.child', 'Child router path: /bar')\n      .assert.containsText('.child .bar', 'bar')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/nested-router/foo')\n      .assert.elementNotPresent('.child')\n      .assert.containsText('#app', 'foo')\n      .assert.count('li a', 3)\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/nested-routes.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'nested routes': function (browser) {\n    browser\n      .url('http://localhost:8080/nested-routes/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 11)\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'default')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/foo')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/bar')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(4) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/baz')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'baz')\n\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/qux/123')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'qux')\n\n      .click('.nested-parent a')\n      .assert.urlEquals(\n        'http://localhost:8080/nested-routes/parent/qux/123/quux'\n      )\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'qux')\n      .assert.containsText('.view', 'quux')\n\n      .click('li:nth-child(6) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/quy/123')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'quy')\n      .assert.evaluate(\n        function () {\n          var params = JSON.parse(document.querySelector('pre').textContent)\n          return JSON.stringify(params) === JSON.stringify(['quyId'])\n        },\n        null,\n        'quyId'\n      )\n\n      .click('li:nth-child(8) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/zap/1')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'zap')\n      .assert.evaluate(\n        function () {\n          var zapId = document.querySelector('pre').textContent\n          return zapId === '1'\n        },\n        null,\n        'zapId'\n      )\n\n      .click('li:nth-child(7) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/zap')\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'zap')\n      .assert.evaluate(\n        function () {\n          var zapId = document.querySelector('pre').textContent\n          return zapId === ''\n        },\n        null,\n        'optional zapId'\n      )\n\n      // test relative params\n      .click('li:nth-child(9) a')\n      .assert.evaluate(\n        function () {\n          var zapId = document.querySelector('pre').textContent\n          return zapId === '2'\n        },\n        null,\n        'relative params'\n      )\n\n      .click('li:nth-child(10) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/qux/1/quux')\n      .click('li:nth-child(11) a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/qux/2/quux')\n      .click('.nested-child a')\n      .assert.urlEquals('http://localhost:8080/nested-routes/parent/qux/2/quuy')\n\n      // check initial visit\n      .url('http://localhost:8080/nested-routes/parent/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'foo')\n      .url('http://localhost:8080/nested-routes/baz')\n      .waitForElementVisible('#app', 1000)\n      .assert.containsText('.view', 'Parent')\n      .assert.containsText('.view', 'baz')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/redirect.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  redirect: function (browser) {\n    browser\n      .url('http://localhost:8080/redirect/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 12)\n      // assert correct href with base\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/redirect/relative-redirect')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/redirect/relative-redirect?foo=bar')\n      .assert.attributeContains('li:nth-child(3) a', 'href', '/redirect/absolute-redirect')\n      .assert.attributeContains('li:nth-child(4) a', 'href', '/redirect/dynamic-redirect')\n      .assert.attributeContains('li:nth-child(5) a', 'href', '/redirect/dynamic-redirect/123')\n      .assert.attributeContains('li:nth-child(6) a', 'href', '/redirect/dynamic-redirect?to=foo')\n      .assert.attributeContains('li:nth-child(7) a', 'href', '/redirect/dynamic-redirect#baz')\n      .assert.attributeContains('li:nth-child(8) a', 'href', '/redirect/named-redirect')\n      .assert.attributeContains('li:nth-child(9) a', 'href', '/redirect/redirect-with-params/123')\n      .assert.attributeContains('li:nth-child(10) a', 'href', '/redirect/foobar')\n      .assert.attributeContains('li:nth-child(11) a', 'href', '/redirect/FooBar')\n      .assert.attributeContains('li:nth-child(12) a', 'href', '/not-found')\n\n      .assert.containsText('.view', 'default')\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/redirect/foo')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/redirect/foo?foo=bar')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/redirect/bar')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(4) a')\n      .assert.urlEquals('http://localhost:8080/redirect/bar')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/redirect/with-params/123')\n      .assert.containsText('.view', '123')\n\n      .click('li:nth-child(6) a')\n      .assert.urlEquals('http://localhost:8080/redirect/foo')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(7) a')\n      .assert.urlEquals('http://localhost:8080/redirect/baz')\n      .assert.containsText('.view', 'baz')\n\n      .click('li:nth-child(8) a')\n      .assert.urlEquals('http://localhost:8080/redirect/baz')\n      .assert.containsText('.view', 'baz')\n\n      .click('li:nth-child(9) a')\n      .assert.urlEquals('http://localhost:8080/redirect/with-params/123')\n      .assert.containsText('.view', '123')\n\n      .click('li:nth-child(10) a')\n      .assert.urlEquals('http://localhost:8080/redirect/foobar')\n      .assert.containsText('.view', 'foobar')\n\n      .click('li:nth-child(11) a')\n      .assert.urlEquals('http://localhost:8080/redirect/FooBar')\n      .assert.containsText('.view', 'FooBar')\n\n      .click('li:nth-child(12) a')\n      .assert.urlEquals('http://localhost:8080/redirect/')\n      .assert.containsText('.view', 'default')\n\n      // check initial visit\n      .url('http://localhost:8080/redirect/relative-redirect')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/foo')\n      .assert.containsText('.view', 'foo')\n\n      .url('http://localhost:8080/redirect/relative-redirect?foo=bar')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/foo?foo=bar')\n      .assert.containsText('.view', 'foo')\n\n      .url('http://localhost:8080/redirect/absolute-redirect')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/bar')\n      .assert.containsText('.view', 'bar')\n\n      .url('http://localhost:8080/redirect/dynamic-redirect')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/bar')\n      .assert.containsText('.view', 'bar')\n\n      .url('http://localhost:8080/redirect/dynamic-redirect/123')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/with-params/123')\n      .assert.containsText('.view', '123')\n\n      .url('http://localhost:8080/redirect/dynamic-redirect?to=foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/foo')\n      .assert.containsText('.view', 'foo')\n\n      .url('http://localhost:8080/redirect/dynamic-redirect#baz')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/baz')\n      .assert.containsText('.view', 'baz')\n\n      .url('http://localhost:8080/redirect/named-redirect')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/baz')\n      .assert.containsText('.view', 'baz')\n\n      .url('http://localhost:8080/redirect/redirect-with-params/123')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/with-params/123')\n      .assert.containsText('.view', '123')\n\n      .url('http://localhost:8080/redirect/foobar')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/foobar')\n      .assert.containsText('.view', 'foobar')\n\n      .url('http://localhost:8080/redirect/FooBar')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/FooBar')\n      .assert.containsText('.view', 'FooBar')\n\n      .url('http://localhost:8080/redirect/not-found')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/redirect/')\n      .assert.containsText('.view', 'default')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/restart-app.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  basic: function (browser) {\n    browser\n      .url('http://localhost:8080/restart-app/')\n      .waitForElementVisible('#mount', 1000)\n      .assert.containsText('#beforeEach', '0')\n      .assert.containsText('#beforeResolve', '0')\n      .assert.containsText('#afterEach', '0')\n\n      // Mounting will trigger hooks\n      .click('#mount')\n      .waitForElementVisible('#app > *', 1000)\n      .assert.containsText('#beforeEach', '1')\n      .assert.containsText('#beforeResolve', '1')\n      .assert.containsText('#afterEach', '1')\n      .assert.containsText('#view', 'home')\n\n      // Navigate to foo route will trigger hooks\n      .click('#app li:nth-child(2) a')\n      .assert.containsText('#beforeEach', '2')\n      .assert.containsText('#beforeResolve', '2')\n      .assert.containsText('#afterEach', '2')\n      .assert.containsText('#view', 'foo')\n\n      // Unmount\n      .click('#unmount')\n      .assert.containsText('#app', '')\n\n      // Second mounting will trigger hooks\n      .click('#mount')\n      .waitForElementVisible('#app > *', 1000)\n      .assert.containsText('#beforeEach', '3')\n      .assert.containsText('#beforeResolve', '3')\n      .assert.containsText('#afterEach', '3')\n      .assert.containsText('#view', 'foo')\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/route-alias.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'route alias': function (browser) {\n    browser\n      .url('http://localhost:8080/route-alias/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 7)\n      // assert correct href with base\n      .assert.attributeContains('li:nth-child(1) a', 'href', '/root-alias')\n      .assert.attributeContains('li:nth-child(2) a', 'href', '/route-alias/foo')\n      .assert.attributeContains('li:nth-child(3) a', 'href', '/route-alias/home/bar-alias')\n      .assert.attributeContains('li:nth-child(4) a', 'href', '/route-alias/baz')\n      .assert.attributeContains('li:nth-child(5) a', 'href', '/route-alias/home/baz-alias')\n      .assert.attributeEquals('li:nth-child(6) a', 'href', 'http://localhost:8080/route-alias/home')\n      .assert.attributeContains('li:nth-child(7) a', 'href', '/route-alias/home/nested-alias/foo')\n\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/root-alias')\n      .assert.containsText('.view', 'root')\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/foo')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'foo')\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/home/bar-alias')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'bar')\n\n      .click('li:nth-child(4) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/baz')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'baz')\n\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/home/baz-alias')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'baz')\n\n      .click('li:nth-child(6) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/home')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'default')\n\n      .click('li:nth-child(7) a')\n      .assert.urlEquals('http://localhost:8080/route-alias/home/nested-alias/foo')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'nested foo')\n\n      // check initial visit\n      .url('http://localhost:8080/route-alias/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/route-alias/foo')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'foo')\n\n      .url('http://localhost:8080/route-alias/home/bar-alias')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/route-alias/home/bar-alias')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'bar')\n\n      .url('http://localhost:8080/route-alias/baz')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/route-alias/baz')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'baz')\n\n      .url('http://localhost:8080/route-alias/home/baz-alias')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/route-alias/home/baz-alias')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'baz')\n\n      .url('http://localhost:8080/route-alias/home')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/route-alias/home')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'default')\n\n      .url('http://localhost:8080/route-alias/home/nested-alias/foo')\n      .waitForElementVisible('#app', 1000)\n      .assert.urlEquals('http://localhost:8080/route-alias/home/nested-alias/foo')\n      .assert.containsText('.view', 'Home')\n      .assert.containsText('.view', 'nested foo')\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/route-matching.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': [],\n\n  'route-matching': function (browser) {\n    browser\n      .url('http://localhost:8080/route-matching/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 10)\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '' &&\n            route.fullPath === '/' &&\n            JSON.stringify(route.params) === JSON.stringify({})\n          )\n        },\n        null,\n        '/'\n      )\n\n      .click('li:nth-child(2) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/params/:foo/:bar' &&\n            route.fullPath === '/params/foo/bar' &&\n            JSON.stringify(route.params) ===\n              JSON.stringify({\n                foo: 'foo',\n                bar: 'bar'\n              })\n          )\n        },\n        null,\n        '/params/foo/bar'\n      )\n\n      .click('li:nth-child(3) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/optional-params/:foo?' &&\n            route.fullPath === '/optional-params' &&\n            JSON.stringify(route.params) === JSON.stringify({})\n          )\n        },\n        null,\n        '/optional-params'\n      )\n\n      .click('li:nth-child(4) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/optional-params/:foo?' &&\n            route.fullPath === '/optional-params/foo' &&\n            JSON.stringify(route.params) ===\n              JSON.stringify({\n                foo: 'foo'\n              })\n          )\n        },\n        null,\n        '/optional-params/foo'\n      )\n\n      .click('li:nth-child(5) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/params-with-regex/:id(\\\\d+)' &&\n            route.fullPath === '/params-with-regex/123' &&\n            JSON.stringify(route.params) ===\n              JSON.stringify({\n                id: '123'\n              })\n          )\n        },\n        null,\n        '/params-with-regex/123'\n      )\n\n      .click('li:nth-child(6) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 0 &&\n            route.fullPath === '/params-with-regex/abc' &&\n            JSON.stringify(route.params) === JSON.stringify({})\n          )\n        },\n        null,\n        '/params-with-regex/abc'\n      )\n\n      .click('li:nth-child(7) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/asterisk/*' &&\n            route.fullPath === '/asterisk/foo' &&\n            JSON.stringify(route.params) ===\n              JSON.stringify({\n                pathMatch: 'foo'\n              })\n          )\n        },\n        null,\n        '/asterisk/foo'\n      )\n\n      .click('li:nth-child(8) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/asterisk/*' &&\n            route.fullPath === '/asterisk/foo/bar' &&\n            JSON.stringify(route.params) ===\n              JSON.stringify({\n                pathMatch: 'foo/bar'\n              })\n          )\n        },\n        null,\n        '/asterisk/foo/bar'\n      )\n\n      .click('li:nth-child(9) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/optional-group/(foo/)?bar' &&\n            route.fullPath === '/optional-group/bar' &&\n            JSON.stringify(route.params) === JSON.stringify({})\n          )\n        },\n        null,\n        '/optional-group/bar'\n      )\n\n      .click('li:nth-child(10) a')\n      .assert.evaluate(\n        function () {\n          var route = JSON.parse(document.querySelector('pre').textContent)\n          return (\n            route.matched.length === 1 &&\n            route.matched[0].path === '/optional-group/(foo/)?bar' &&\n            route.fullPath === '/optional-group/foo/bar' &&\n            JSON.stringify(route.params) ===\n              JSON.stringify({\n                pathMatch: 'foo/'\n              })\n          )\n        },\n        null,\n        '/optional-group/foo/bar'\n      )\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/route-params.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'route-params': function (browser) {\n    browser\n      .url('http://localhost:8080/route-params/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 2)\n\n      // https://github.com/vuejs/vue-router/issues/2800\n      .click('li:nth-child(1) a')\n      .assert.urlEquals('http://localhost:8080/route-params/items/1/logs')\n      .assert.containsText('#params', JSON.stringify({ type: 'info' }, null, 2))\n      .click('.child-link')\n      .assert.urlEquals('http://localhost:8080/route-params/items/1/logs/info')\n      .assert.containsText('.log', 'id: 1, type: info')\n      // https://github.com/vuejs/vue-router/issues/2938\n      .assert.containsText('#params', JSON.stringify({ type: 'info' }, null, 2))\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/route-params/items/2/logs')\n      .click('.child-link')\n      .assert.urlEquals('http://localhost:8080/route-params/items/2/logs/info')\n      .assert.containsText('.log', 'id: 2, type: info')\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/route-props.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'route-props': function (browser) {\n    const $attrs = ' { \"foo\": \"123\" }'\n\n    browser\n      .url('http://localhost:8080/route-props/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 5)\n\n      .assert.urlEquals('http://localhost:8080/route-props/')\n      .assert.containsText('.hello', 'Hello Vue!' + $attrs)\n\n      .click('li:nth-child(2) a')\n      .assert.urlEquals('http://localhost:8080/route-props/hello/you')\n      .assert.containsText('.hello', 'Hello you' + $attrs)\n\n      .click('li:nth-child(3) a')\n      .assert.urlEquals('http://localhost:8080/route-props/static')\n      .assert.containsText('.hello', 'Hello world' + $attrs)\n\n      .click('li:nth-child(4) a')\n      .assert.urlEquals('http://localhost:8080/route-props/dynamic/1')\n      .assert.containsText('.hello', 'Hello ' + (new Date().getFullYear() + 1) + '!' + $attrs)\n\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/route-props/attrs')\n      .assert.containsText('.hello', 'Hello attrs' + $attrs)\n\n      // should be consistent\n      .click('li:nth-child(4) a')\n      .click('li:nth-child(5) a')\n      .assert.urlEquals('http://localhost:8080/route-props/attrs')\n      .assert.containsText('.hello', 'Hello attrs' + $attrs)\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/scroll-behavior.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  'scroll behavior': function (browser) {\n    const TIMEOUT = 2000\n\n    browser\n      .url('http://localhost:8080/scroll-behavior/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 6)\n      .assert.containsText('.view', 'home')\n\n      .execute(function () {\n        window.scrollTo(0, 100)\n      })\n      .click('li:nth-child(2) a')\n      .waitForElementPresent('.view.foo', TIMEOUT)\n      .assert.containsText('.view', 'foo')\n      .execute(function () {\n        window.scrollTo(0, 200)\n        window.history.back()\n      })\n      .waitForElementPresent('.view.home', TIMEOUT)\n      .assert.containsText('.view', 'home')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 100\n        },\n        null,\n        'restore scroll position on back'\n      )\n      .execute(function () {\n        window.scrollTo(0, 100)\n      })\n      .click('li:nth-child(2) a')\n      .waitForElementPresent('.view.foo', TIMEOUT)\n      .assert.containsText('.view', 'foo')\n      .execute(function () {\n        window.scrollTo(0, 200)\n        window.history.back()\n      })\n      .waitForElementPresent('.view.home', TIMEOUT)\n      .assert.containsText('.view', 'home')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 100\n        },\n        null,\n        'restore scroll position on back with manual restoration'\n      )\n      .execute(function () {\n        history.scrollRestoration = 'auto'\n      })\n\n      // scroll on a popped entry\n      .execute(function () {\n        window.scrollTo(0, 50)\n        window.history.forward()\n      })\n      .waitForElementPresent('.view.foo', TIMEOUT)\n      .assert.containsText('.view', 'foo')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 200\n        },\n        null,\n        'restore scroll position on forward'\n      )\n\n      .execute(function () {\n        window.history.back()\n      })\n      .waitForElementPresent('.view.home', TIMEOUT)\n      .assert.containsText('.view', 'home')\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 50\n        },\n        null,\n        'restore scroll position on back again'\n      )\n\n      .click('li:nth-child(3) a')\n      .waitForElementPresent('.view.bar', TIMEOUT)\n      .assert.evaluate(\n        function () {\n          return window.pageYOffset === 0\n        },\n        null,\n        'scroll to top on new entry'\n      )\n\n      .perform(() => {\n        for (let i = 0; i < 2; i++) {\n          browser\n            .click('li:nth-child(4) a')\n            .assert.evaluate(\n              function () {\n                return document.getElementById('anchor').getBoundingClientRect().top < 1\n              },\n              null,\n              (i === 0) ? 'scroll to anchor' : 'scroll to same anchor again'\n            )\n        }\n      })\n\n      .click('li:nth-child(5) a')\n      .assert.evaluate(\n        function () {\n          return document.getElementById('anchor2').getBoundingClientRect().top < 101\n        },\n        null,\n        'scroll to anchor with offset'\n      )\n      .click('li:nth-child(6) a')\n      .assert.evaluate(\n        function () {\n          return document.getElementById('1number').getBoundingClientRect().top < 1\n        },\n        null,\n        'scroll to anchor that starts with number'\n      )\n\n      .url('http://localhost:8080/scroll-behavior/bar#anchor')\n      .execute(function () {\n        location.reload(true)\n      })\n      .waitForElementVisible('#app', 1000)\n      .assert.evaluate(\n        function () {\n          return document.getElementById('anchor').getBoundingClientRect().top < 1\n        },\n        null,\n        'scroll to anchor on load'\n      )\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/e2e/specs/transitions.js",
    "content": "const bsStatus = require('../browserstack-send-status')\n\nmodule.exports = {\n  ...bsStatus(),\n\n  '@tags': ['history'],\n\n  transitions: function (browser) {\n    const TIMEOUT = 2000\n\n    browser\n      .url('http://localhost:8080/transitions/')\n      .waitForElementVisible('#app', 1000)\n      .assert.count('li a', 4)\n\n      .click('li:nth-child(2) a')\n      .assert.cssClassPresent('.view.home', 'fade-leave-active')\n      .waitForElementPresent('.view.parent', TIMEOUT)\n      .assert.cssClassPresent('.view.parent', 'fade-enter-active')\n      .assert.cssClassNotPresent('.child-view.default', 'slide-left-enter-active')\n      .waitForElementNotPresent('.view.parent.fade-enter-active', TIMEOUT)\n\n      .click('li:nth-child(3) a')\n      .assert.cssClassPresent('.child-view.default', 'slide-left-leave-active')\n      .assert.cssClassPresent('.child-view.foo', 'slide-left-enter-active')\n      .waitForElementNotPresent('.child-view.default', TIMEOUT)\n\n      .click('li:nth-child(4) a')\n      .assert.cssClassPresent('.child-view.foo', 'slide-left-leave-active')\n      .assert.cssClassPresent('.child-view.bar', 'slide-left-enter-active')\n      .waitForElementNotPresent('.child-view.foo', TIMEOUT)\n\n      .click('li:nth-child(2) a')\n      .assert.cssClassPresent('.child-view.bar', 'slide-right-leave-active')\n      .assert.cssClassPresent('.child-view.default', 'slide-right-enter-active')\n      .waitForElementNotPresent('.child-view.bar', TIMEOUT)\n\n      .click('li:nth-child(1) a')\n      .assert.cssClassPresent('.view.parent', 'fade-leave-active')\n      .waitForElementPresent('.view.home', TIMEOUT)\n      .assert.cssClassPresent('.view.home', 'fade-enter-active')\n      .waitForElementNotPresent('.view.home.fade-enter-active', TIMEOUT)\n\n      .end()\n  }\n}\n"
  },
  {
    "path": "test/unit/.eslintrc",
    "content": "{\n  \"env\": {\n    \"jasmine\": true\n  },\n  \"plugins\": [\n    \"jasmine\"\n  ]\n}\n"
  },
  {
    "path": "test/unit/jasmine.json",
    "content": "{\n  \"spec_dir\": \"test/unit/specs\",\n  \"spec_files\": [\n    \"*.spec.js\"\n  ],\n  \"helpers\": [\n    \"../../../node_modules/babel-register/lib/node.js\"\n  ]\n}\n"
  },
  {
    "path": "test/unit/specs/abstract-history.spec.js",
    "content": "import Vue from 'vue'\nimport VueRouter from '../../../src/index'\n\nVue.use(VueRouter)\n\nconst delay = t => new Promise(resolve => setTimeout(resolve, t))\n\ndescribe('abstract history', () => {\n  it('run afterEach after initial navigation', done => {\n    const router = new VueRouter({ mode: 'abstract' })\n    const afterEach = jasmine.createSpy('afterEach')\n    const onReady = jasmine.createSpy('ready')\n    const onError = jasmine.createSpy('error')\n    router.afterEach(afterEach)\n    router.onReady(onReady, onError)\n\n    router.push('/').finally(() => {\n      expect(onReady).toHaveBeenCalled()\n      expect(onError).not.toHaveBeenCalled()\n      expect(afterEach).toHaveBeenCalled()\n      done()\n    })\n  })\n\n  it('run afterEach after router.go', done => {\n    const router = new VueRouter({ mode: 'abstract' })\n    const afterEach = jasmine.createSpy('afterEach')\n\n    router\n      .push('/')\n      .then(() => router.push('/foo'))\n      .then(() => {\n        router.afterEach(afterEach)\n        router.go(-1)\n        return delay(30)\n      })\n      .finally(() => {\n        expect(afterEach).toHaveBeenCalled()\n        done()\n      })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/api.spec.js",
    "content": "import Router from '../../../src/index'\nimport Vue from 'vue'\n\ndescribe('router.onReady', () => {\n  it('should work', done => {\n    const calls = []\n\n    const router = new Router({\n      mode: 'abstract',\n      routes: [\n        {\n          path: '/a',\n          component: {\n            name: 'A',\n            beforeRouteEnter: (to, from, next) => {\n              setTimeout(() => {\n                calls.push(2)\n                next()\n              }, 1)\n            }\n          }\n        }\n      ]\n    })\n\n    router.beforeEach((to, from, next) => {\n      setTimeout(() => {\n        calls.push(1)\n        next()\n      }, 1)\n    })\n\n    router.onReady(() => {\n      expect(calls).toEqual([1, 2])\n      // sync call when already ready\n      router.onReady(() => {\n        calls.push(3)\n      })\n      expect(calls).toEqual([1, 2, 3])\n      done()\n    })\n\n    router.push('/a')\n    expect(calls).toEqual([])\n  })\n})\n\ndescribe('route matching', () => {\n  it('resolves parent params when using current route', () => {\n    const router = new Router({\n      mode: 'abstract',\n      routes: [\n        {\n          path: '/a/:id',\n          component: { name: 'A' },\n          children: [{ name: 'b', path: 'b', component: { name: 'B' }}]\n        }\n      ]\n    })\n\n    router.push('/a/1')\n\n    const { route, resolved } = router.resolve({ name: 'b' })\n    expect(route.params).toEqual({ id: '1' })\n    expect(resolved.params).toEqual({ id: '1' })\n  })\n\n  it('can override currentRoute', () => {\n    const router = new Router({\n      mode: 'abstract',\n      routes: [\n        {\n          path: '/a/:id',\n          component: { name: 'A' },\n          children: [{ name: 'b', path: 'b', component: { name: 'B' }}]\n        }\n      ]\n    })\n\n    router.push('/a/1')\n\n    const { route, resolved } = router.resolve({ name: 'b' }, { params: { id: '2' }, path: '/a/2' })\n    expect(route.params).toEqual({ id: '2' })\n    expect(resolved.params).toEqual({ id: '2' })\n  })\n})\n\ndescribe('router.addRoutes', () => {\n  it('should work', () => {\n    const router = new Router({\n      mode: 'abstract',\n      routes: [\n        { path: '/a', component: { name: 'A' }}\n      ]\n    })\n\n    router.push('/a')\n    let components = router.getMatchedComponents()\n    expect(components.length).toBe(1)\n    expect(components[0].name).toBe('A')\n\n    router.push('/b')\n    components = router.getMatchedComponents()\n    expect(components.length).toBe(0)\n\n    router.addRoutes([\n      { path: '/b', component: { name: 'B' }}\n    ])\n    components = router.getMatchedComponents()\n    expect(components.length).toBe(1)\n    expect(components[0].name).toBe('B')\n\n    // make sure it preserves previous routes\n    router.push('/a')\n    components = router.getMatchedComponents()\n    expect(components.length).toBe(1)\n    expect(components[0].name).toBe('A')\n  })\n\n  it('allows navigating to the same as current location', () => {\n    const router = new Router({\n      routes: [\n        { path: '/', component: {}},\n        { path: '*', component: {}}\n      ]\n    })\n\n    router.push('/not-found')\n\n    expect(router.currentRoute.params).toEqual({ pathMatch: '/not-found' })\n    router.addRoutes([{ path: '/not-found', component: {}}])\n\n    // the navigation should have changed locations\n    expect(router.currentRoute.params).toEqual({})\n  })\n})\n\ndescribe('router.push/replace', () => {\n  let calls = []\n  let router, spy1, spy2\n\n  const Foo = {\n    beforeRouteEnter (to, from, next) {\n      calls.push(3)\n      setTimeout(() => {\n        calls.push(4)\n        next()\n      }, 1)\n    }\n  }\n\n  beforeEach(() => {\n    calls = []\n    spy1 = jasmine.createSpy('complete')\n    spy2 = jasmine.createSpy('abort')\n\n    router = new Router({\n      routes: [\n        { path: '/foo', component: Foo }\n      ]\n    })\n\n    router.beforeEach((to, from, next) => {\n      calls.push(1)\n      setTimeout(() => {\n        calls.push(2)\n        next()\n      }, 1)\n    })\n  })\n  describe('callbacks', () => {\n    it('push does not return a Promise when a callback is passed', done => {\n      expect(router.push('/foo', done)).toEqual(undefined)\n    })\n\n    it('push complete', done => {\n      router.push('/foo', () => {\n        expect(calls).toEqual([1, 2, 3, 4])\n        done()\n      })\n    })\n\n    it('push abort', done => {\n      router.push('/foo', spy1, spy2)\n      router.push('/bar', () => {\n        expect(calls).toEqual([1, 1, 2, 2])\n        expect(spy1).not.toHaveBeenCalled()\n        expect(spy2).toHaveBeenCalled()\n        done()\n      })\n    })\n\n    it('replace does not return a Promise when a callback is passed', done => {\n      expect(router.replace('/foo', done)).toEqual(undefined)\n    })\n\n    it('replace complete', done => {\n      router.replace('/foo', () => {\n        expect(calls).toEqual([1, 2, 3, 4])\n        done()\n      })\n    })\n\n    it('replace abort', done => {\n      router.replace('/foo', spy1, spy2)\n      router.replace('/bar', () => {\n        expect(calls).toEqual([1, 1, 2, 2])\n        expect(spy1).not.toHaveBeenCalled()\n        expect(spy2).toHaveBeenCalled()\n        done()\n      })\n    })\n  })\n\n  describe('promises', () => {\n    it('push complete', done => {\n      router.push('/foo')\n        .then(spy1)\n        .finally(() => {\n          expect(calls).toEqual([1, 2, 3, 4])\n          expect(spy1).toHaveBeenCalledWith(router.currentRoute)\n          done()\n        })\n    })\n\n    it('push abort', done => {\n      router.push('/foo').catch(spy2)\n      router.push('/bar').finally(() => {\n        expect(calls).toEqual([1, 1, 2, 2])\n        expect(spy1).not.toHaveBeenCalled()\n        expect(spy2).toHaveBeenCalled()\n        done()\n      })\n    })\n\n    it('replace complete', done => {\n      router.replace('/foo')\n        .then(spy1)\n        .finally(() => {\n          expect(calls).toEqual([1, 2, 3, 4])\n          expect(spy1).toHaveBeenCalledWith(router.currentRoute)\n          done()\n        })\n    })\n\n    it('replace abort', done => {\n      router.replace('/foo').catch(spy2)\n      router.replace('/bar').finally(() => {\n        expect(calls).toEqual([1, 1, 2, 2])\n        expect(spy1).not.toHaveBeenCalled()\n        expect(spy2).toHaveBeenCalled()\n        done()\n      })\n    })\n  })\n})\n\ndescribe('router app destroy handling', () => {\n  Vue.use(Router)\n\n  let router, app1, app2, app3\n\n  beforeEach(() => {\n    router = new Router({\n      mode: 'abstract',\n      routes: [\n        { path: '/', component: { name: 'A' }}\n      ]\n    })\n\n    // Add main app\n    app1 = new Vue({\n      router,\n      render (h) { return h('div') }\n    })\n\n    // Add 2nd app\n    app2 = new Vue({\n      router,\n      render (h) { return h('div') }\n    })\n\n    // Add 3rd app\n    app3 = new Vue({\n      router,\n      render (h) { return h('div') }\n    })\n  })\n\n  it('all apps point to the same router instance', () => {\n    expect(app1.$router).toBe(app2.$router)\n    expect(app2.$router).toBe(app3.$router)\n  })\n\n  it('should have all 3 registered apps', () => {\n    expect(app1.$router.app).toBe(app1)\n    expect(app1.$router.apps.length).toBe(3)\n    expect(app1.$router.apps[0]).toBe(app1)\n    expect(app1.$router.apps[1]).toBe(app2)\n    expect(app1.$router.apps[2]).toBe(app3)\n  })\n\n  it('should remove 2nd destroyed app from this.apps', () => {\n    app2.$destroy()\n    expect(app1.$router.app).toBe(app1)\n    expect(app1.$router.apps.length).toBe(2)\n    expect(app1.$router.apps[0]).toBe(app1)\n    expect(app1.$router.apps[1]).toBe(app3)\n  })\n\n  it('should remove 1st destroyed app and replace current app', () => {\n    app1.$destroy()\n    expect(app3.$router.app).toBe(app2)\n    expect(app3.$router.apps.length).toBe(2)\n    expect(app3.$router.apps[0]).toBe(app2)\n    expect(app1.$router.apps[1]).toBe(app3)\n  })\n\n  it('should remove all apps', () => {\n    app1.$destroy()\n    app3.$destroy()\n    app2.$destroy()\n    expect(app3.$router.app).toBe(null)\n    expect(app3.$router.apps.length).toBe(0)\n  })\n\n  it('should keep current app if already defined', () => {\n    const app4 = new Vue({\n      router,\n      render (h) { return h('div') }\n    })\n    expect(app4.$router.app).toBe(app1)\n    expect(app4.$router.apps.length).toBe(4)\n    expect(app4.$router.apps[3]).toBe(app4)\n  })\n\n  it('should replace current app if none is assigned when creating the app', () => {\n    app1.$destroy()\n    app3.$destroy()\n    app2.$destroy()\n    const app4 = new Vue({\n      router,\n      render (h) { return h('div') }\n    })\n    expect(router.app).toBe(app4)\n    expect(app4.$router).toBe(router)\n    expect(app4.$router.apps.length).toBe(1)\n    expect(app4.$router.apps[0]).toBe(app4)\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/async.spec.js",
    "content": "import { runQueue } from '../../../src/util/async'\n\ndescribe('Async utils', () => {\n  describe('runQueue', () => {\n    it('should work', done => {\n      const calls = []\n      const queue = [1, 2, 3, 4, 5].map(i => next => {\n        calls.push(i)\n        setTimeout(next, 0)\n      })\n      runQueue(queue, (fn, next) => fn(next), () => {\n        expect(calls).toEqual([1, 2, 3, 4, 5])\n        done()\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/create-map.spec.js",
    "content": "/*eslint-disable no-undef*/\nimport { createRouteMap } from '../../../src/create-route-map'\n\nconst Home = { template: '<div>This is Home</div>' }\nconst Foo = { template: '<div>This is Foo</div>' }\nconst FooBar = { template: '<div>This is FooBar</div>' }\nconst Foobar = { template: '<div>This is foobar</div>' }\nconst Bar = { template: '<div>This is Bar <router-view></router-view></div>' }\nconst Baz = { template: '<div>This is Baz</div>' }\n\nconst routes = [\n  { path: '/', name: 'home', component: Home },\n  { path: '/foo', name: 'foo', component: Foo },\n  { path: '*', name: 'wildcard', component: Baz },\n  {\n    path: '/bar',\n    name: 'bar',\n    component: Bar,\n    children: [\n      {\n        path: '',\n        component: Baz,\n        name: 'bar.baz'\n      }\n    ]\n  },\n  {\n    path: '/bar-redirect',\n    name: 'bar-redirect',\n    redirect: { name: 'bar-redirect.baz' },\n    component: Bar,\n    children: [\n      {\n        path: '',\n        component: Baz,\n        name: 'bar-redirect.baz'\n      }\n    ]\n  }\n]\n\ndescribe('Creating Route Map', function () {\n  let maps\n\n  beforeAll(function () {\n    spyOn(console, 'warn')\n    maps = createRouteMap(routes)\n  })\n\n  beforeEach(function () {\n    console.warn.calls.reset()\n    process.env.NODE_ENV = 'production'\n  })\n\n  it('has a pathMap object for default subroute at /bar/', function () {\n    expect(maps.pathMap['/bar/']).not.toBeUndefined()\n  })\n\n  it('has a pathList which places wildcards at the end', () => {\n    expect(maps.pathList).toEqual([\n      '',\n      '/foo',\n      '/bar/',\n      '/bar',\n      '/bar-redirect/',\n      '/bar-redirect',\n      '*'\n    ])\n  })\n\n  it(\"has a nameMap object for default subroute at 'bar.baz'\", function () {\n    expect(maps.nameMap['bar.baz']).not.toBeUndefined()\n  })\n\n  it('in development, has logged a warning concerning named route of parent and default subroute', function () {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap(routes)\n    expect(console.warn).toHaveBeenCalledTimes(1)\n    expect(console.warn.calls.argsFor(0)[0]).toMatch(\n      \"vue-router] Named Route 'bar'\"\n    )\n  })\n\n  it('warns about unencoded entities', function () {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap([{ path: '/é', component: Home }])\n    expect(console.warn).toHaveBeenCalledTimes(1)\n    expect(console.warn.calls.argsFor(0)[0]).toMatch(\n      'vue-router] Route with path \"/é\"'\n    )\n  })\n\n  it('in development, throws if path is missing', function () {\n    process.env.NODE_ENV = 'development'\n    expect(() => {\n      maps = createRouteMap([{ component: Bar }])\n    }).toThrowError(/\"path\" is required/)\n  })\n\n  it('in production, it has not logged this warning', function () {\n    maps = createRouteMap(routes)\n    expect(console.warn).not.toHaveBeenCalled()\n  })\n\n  it('in development, warn duplicate param keys', () => {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap([\n      {\n        path: '/foo/:id',\n        component: Foo,\n        children: [{ path: 'bar/:id', component: Bar }]\n      }\n    ])\n    expect(console.warn).toHaveBeenCalled()\n    expect(console.warn.calls.argsFor(0)[0]).toMatch(\n      'vue-router] Duplicate param keys in route with path: \"/foo/:id/bar/:id\"'\n    )\n  })\n\n  it('in development, warns about alias and path having the same value', () => {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap([\n      {\n        path: '/foo-alias',\n        component: Foo,\n        alias: '/foo-alias'\n      }\n    ])\n    expect(console.warn).toHaveBeenCalled()\n    expect(console.warn.calls.argsFor(0)[0]).toMatch(\n      'vue-router] Found an alias with the same value as the path: \"/foo-alias\"'\n    )\n  })\n\n  it('in development, warns about one alias (in an array) having the same value as the path', () => {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap([\n      {\n        path: '/foo-alias',\n        component: Foo,\n        alias: ['/bar', '/foo-alias']\n      }\n    ])\n    expect(console.warn).toHaveBeenCalled()\n    expect(console.warn.calls.argsFor(0)[0]).toMatch(\n      'vue-router] Found an alias with the same value as the path: \"/foo-alias\"'\n    )\n  })\n\n  it('in development, warn if a path is missing a leading slash', function () {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap([\n      { path: 'bar', name: 'bar', component: Bar }\n    ])\n    expect(console.warn).toHaveBeenCalledTimes(1)\n    expect(console.warn.calls.argsFor(0)[0]).toEqual('[vue-router] Non-nested routes must include a leading slash character. Fix the following routes: \\n- bar')\n  })\n\n  it('in development, it does not log the missing leading slash when routes are valid', function () {\n    process.env.NODE_ENV = 'development'\n    maps = createRouteMap([\n      { path: '/bar', name: 'bar', component: Bar }\n    ])\n    expect(console.warn).not.toHaveBeenCalled()\n  })\n\n  it('in production, it does not log the missing leading slash warning', function () {\n    process.env.NODE_ENV = 'production'\n    maps = createRouteMap([\n      { path: 'bar', name: 'bar', component: Bar }\n    ])\n    expect(console.warn).not.toHaveBeenCalled()\n  })\n\n  describe('path-to-regexp options', function () {\n    const routes = [\n      { path: '/foo', name: 'foo', component: Foo },\n      { path: '/bar', name: 'bar', component: Bar, caseSensitive: false },\n      {\n        path: '/FooBar',\n        name: 'FooBar',\n        component: FooBar,\n        caseSensitive: true\n      },\n      {\n        path: '/foobar',\n        name: 'foobar',\n        component: Foobar,\n        caseSensitive: true\n      }\n    ]\n\n    it('caseSensitive option in route', function () {\n      const { nameMap } = createRouteMap(routes)\n\n      expect(nameMap.FooBar.regex.ignoreCase).toBe(false)\n      expect(nameMap.bar.regex.ignoreCase).toBe(true)\n      expect(nameMap.foo.regex.ignoreCase).toBe(true)\n    })\n\n    it('pathToRegexpOptions option in route', function () {\n      const { nameMap } = createRouteMap([\n        {\n          name: 'foo',\n          path: '/foo',\n          component: Foo,\n          pathToRegexpOptions: {\n            sensitive: true\n          }\n        },\n        {\n          name: 'bar',\n          path: '/bar',\n          component: Bar,\n          pathToRegexpOptions: {\n            sensitive: false\n          }\n        }\n      ])\n\n      expect(nameMap.foo.regex.ignoreCase).toBe(false)\n      expect(nameMap.bar.regex.ignoreCase).toBe(true)\n    })\n\n    it('caseSensitive over pathToRegexpOptions in route', function () {\n      const { nameMap } = createRouteMap([\n        {\n          name: 'foo',\n          path: '/foo',\n          component: Foo,\n          caseSensitive: true,\n          pathToRegexpOptions: {\n            sensitive: false\n          }\n        }\n      ])\n\n      expect(nameMap.foo.regex.ignoreCase).toBe(false)\n    })\n\n    it('keeps trailing slashes with strict mode', function () {\n      const { pathList } = createRouteMap([\n        {\n          path: '/foo/',\n          component: Foo,\n          pathToRegexpOptions: {\n            strict: true\n          }\n        },\n        {\n          path: '/bar/',\n          component: Foo\n        }\n      ])\n\n      expect(pathList).toEqual(['/foo/', '/bar'])\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/create-matcher.spec.js",
    "content": "/*eslint-disable no-undef*/\nimport { createMatcher } from '../../../src/create-matcher'\n\nconst routes = [\n  { path: '/', name: 'home', component: { name: 'home' }},\n  { path: '/foo', name: 'foo', component: { name: 'foo' }},\n  { path: '/baz/:testparam', name: 'baz', component: { name: 'baz' }},\n  { path: '/error/*', name: 'error', component: { name: 'error' }},\n  { path: '*', props: true, name: 'notFound', component: { name: 'notFound' }}\n]\n\ndescribe('Creating Matcher', function () {\n  let match\n\n  beforeAll(function () {\n    spyOn(console, 'warn')\n    match = createMatcher(routes).match\n  })\n\n  beforeEach(function () {\n    console.warn.calls.reset()\n    process.env.NODE_ENV = 'production'\n  })\n\n  it('can add nested routes', function () {\n    const component = { name: 'fake' }\n    const matcher = createMatcher([\n      {\n        path: '/p',\n        name: 'parent',\n        children: [\n          { path: 'a', name: 'a', component },\n          {\n            path: 'c',\n            name: 'child',\n            component,\n            children: [{ path: 'n', name: 'nested', component }]\n          }\n        ]\n      },\n      {\n        // easier to debug tests\n        path: '*', name: 'not-found', component\n      }\n    ])\n\n    matcher.addRoute({ path: '/b', name: 'b', component })\n    matcher.addRoute('parent', { path: 'b', name: 'p-b', component })\n    matcher.addRoute('child', { path: 'b', name: 'p-c-b', component })\n\n    expect(matcher.match('/b').name).toBe('b')\n    expect(matcher.match('/p/b').name).toBe('p-b')\n    expect(matcher.match('/p/c/b').name).toBe('p-c-b')\n    expect(matcher.match('/p/c/n').name).toBe('nested')\n  })\n\n  it('can get all routes', function () {\n    const component = { name: 'fake' }\n    const matcher = createMatcher([])\n\n    expect(matcher.getRoutes()).toEqual([])\n\n    matcher.addRoute({ path: '/b', name: 'b', component })\n    expect(matcher.getRoutes().length).toBe(1)\n\n    matcher.addRoute({ path: '/c', name: 'c', alias: ['/a', '/d'], component })\n    expect(matcher.getRoutes().length).toBe(4)\n\n    matcher.addRoute('b', { path: 'd', component })\n    expect(matcher.getRoutes().length).toBe(5)\n\n    matcher.addRoute('c', { path: 'd', component })\n    expect(matcher.getRoutes().length).toBe(8)\n  })\n\n  it('in development, has logged a warning if a named route does not exist', function () {\n    process.env.NODE_ENV = 'development'\n    const { name, matched } = match({ name: 'bar' }, routes[0])\n    expect(matched.length).toBe(0)\n    expect(name).toBe('bar')\n    expect(console.warn).toHaveBeenCalled()\n    expect(console.warn.calls.argsFor(0)[0]).toMatch(\n      \"Route with name 'bar' does not exist\"\n    )\n  })\n\n  it('in production, it has not logged this warning', function () {\n    match({ name: 'foo' }, routes[0])\n    expect(console.warn).not.toHaveBeenCalled()\n  })\n\n  it('matches named route with params without warning', function () {\n    process.env.NODE_ENV = 'development'\n    const { name, path, params } = match({\n      name: 'baz',\n      params: { testparam: 'testvalue' }\n    })\n    expect(console.warn).not.toHaveBeenCalled()\n    expect(name).toEqual('baz')\n    expect(path).toEqual('/baz/testvalue')\n    expect(params).toEqual({ testparam: 'testvalue' })\n  })\n\n  it('matches asterisk routes with a default param name without warning', function () {\n    process.env.NODE_ENV = 'development'\n    const { params } = match(\n      { name: 'notFound', params: { pathMatch: '/not-found' }},\n      routes[0]\n    )\n    expect(console.warn).not.toHaveBeenCalled()\n    expect(params).toEqual({ pathMatch: '/not-found' })\n  })\n\n  it('matches partial asterisk routes with a default param name without warning', function () {\n    process.env.NODE_ENV = 'development'\n    const { params, path } = match(\n      { name: 'error', params: { pathMatch: 'some' }},\n      routes[0]\n    )\n    expect(console.warn).not.toHaveBeenCalled()\n    expect(params).toEqual({ pathMatch: 'some' })\n    expect(path).toEqual('/error/some')\n  })\n\n  it('matches named catch-all route with empty pathMath param without warning', function () {\n    process.env.NODE_ENV = 'development'\n    match(\n      { name: 'notFound', params: { pathMatch: '' }},\n      routes[0]\n    )\n    expect(console.warn).not.toHaveBeenCalled()\n  })\n\n  it('matches asterisk routes with a default param name', function () {\n    const { params } = match({ path: '/not-found' }, routes[0])\n    expect(params).toEqual({ pathMatch: '/not-found' })\n  })\n\n  it('allows an empty pathMatch', function () {\n    process.env.NODE_ENV = 'development'\n    const pathForErrorRoute = match(\n      { name: 'error', params: { pathMatch: '' }},\n      routes[0]\n    ).path\n    const pathForNotFoundRoute = match(\n      { name: 'notFound', params: { pathMatch: '' }},\n      routes[0]\n    ).path\n\n    expect(console.warn).not.toHaveBeenCalled()\n    expect(pathForErrorRoute).toEqual('/error/')\n    expect(pathForNotFoundRoute).toEqual('/')\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/custom-query.spec.js",
    "content": "import Vue from 'vue'\nimport VueRouter from '../../../src/index'\n\nVue.use(VueRouter)\n\ndescribe('custom query parse/stringify', () => {\n  it('should work', () => {\n    const router = new VueRouter({\n      parseQuery: () => ({ foo: 1 }),\n      stringifyQuery: () => '?foo=1'\n    })\n\n    router.push('/?bar=2')\n\n    expect(router.currentRoute.query).toEqual({ foo: 1 })\n    expect(router.currentRoute.fullPath).toEqual('/?foo=1')\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/discrete-components.spec.js",
    "content": "import Vue from 'vue'\nimport VueRouter from '../../../src/index'\n\ndescribe('[Vue Instance].$route bindings', () => {\n  describe('boundToSingleVueInstance', () => {\n    it('updates $route on all instances', () => {\n      const router = new VueRouter({\n        routes: [\n          { path: '/', component: { name: 'foo' }},\n          { path: '/bar', component: { name: 'bar' }}\n        ]\n      })\n      const app1 = new Vue({ router })\n      const app2 = new Vue({ router })\n      expect(app1.$route.path).toBe('/')\n      expect(app2.$route.path).toBe('/')\n      router.push('/bar')\n      expect(app1.$route.path).toBe('/bar')\n      expect(app2.$route.path).toBe('/bar')\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/error-handling.spec.js",
    "content": "import Vue from 'vue'\nimport VueRouter from '../../../src/index'\nimport { NavigationFailureType } from '../../../src/util/errors'\n\nVue.use(VueRouter)\n\ndescribe('error handling', () => {\n  beforeEach(function () {\n    process.env.NODE_ENV = 'development'\n  })\n\n  it('onReady errors', done => {\n    const router = new VueRouter()\n    const err = new Error('foo')\n    router.beforeEach(() => {\n      throw err\n    })\n    router.onError(() => {})\n\n    const onReady = jasmine.createSpy('ready')\n    const onError = jasmine.createSpy('error')\n    const onPromiseReject = jasmine.createSpy('promise reject')\n    router.onReady(onReady, onError)\n\n    router\n      .push('/')\n      .catch(onPromiseReject)\n      .finally(() => {\n        expect(onReady).not.toHaveBeenCalled()\n        expect(onError).toHaveBeenCalledWith(err)\n        expect(onPromiseReject).toHaveBeenCalled()\n        done()\n      })\n  })\n\n  it('navigation errors', done => {\n    const router = new VueRouter()\n    const err = new Error('foo')\n    const spy = jasmine.createSpy('error')\n    const spy1 = jasmine.createSpy('promise reject')\n    router.onError(spy)\n\n    router.push('/')\n    router.beforeEach(() => {\n      throw err\n    })\n\n    router\n      .push('/foo')\n      .catch(spy1)\n      .finally(() => {\n        expect(spy).toHaveBeenCalledWith(err)\n        expect(spy1).toHaveBeenCalled()\n        done()\n      })\n  })\n\n  it('NavigationDuplicated error', done => {\n    const router = new VueRouter()\n\n    router.push('/foo')\n    router.push('/foo').catch(err => {\n      expect(err.type).toBe(NavigationFailureType.duplicated)\n      expect(VueRouter.isNavigationFailure(err)).toBe(true)\n      expect(\n        VueRouter.isNavigationFailure(err, NavigationFailureType.duplicated)\n      ).toBe(true)\n      done()\n    })\n  })\n\n  it('NavigationCancelled error', done => {\n    const router = new VueRouter()\n\n    router.beforeEach((to, from, next) => {\n      setTimeout(() => next(), 100)\n    })\n\n    router.push('/foo').catch(err => {\n      expect(err.type).toBe(NavigationFailureType.cancelled)\n      done()\n    })\n    router.push('/')\n  })\n\n  it('NavigationCancelled error for nested async navigation', done => {\n    const component = {\n      template: `<img />`,\n      beforeRouteEnter (to, from, next) {\n        setTimeout(() => next(), 100)\n      }\n    }\n    const router = new VueRouter({\n      routes: [{ path: '/a', component }]\n    })\n\n    router.push('/a').catch(err => {\n      expect(err.type).toBe(NavigationFailureType.cancelled)\n      done()\n    })\n    router.push('/')\n  })\n\n  it('NavigationRedirected error', done => {\n    const router = new VueRouter()\n\n    router.beforeEach((to, from, next) => {\n      if (to.query.redirect) {\n        next(to.query.redirect)\n      }\n    })\n\n    router.push('/foo?redirect=/').catch(err => {\n      expect(err.type).toBe(NavigationFailureType.redirected)\n      expect(err.from.path).toBe('/')\n      expect(err.to.path).toBe('/foo')\n      done()\n    })\n  })\n\n  it('NavigationAborted error', done => {\n    const router = new VueRouter()\n\n    router.beforeEach((to, from, next) => {\n      next(false)\n    })\n\n    router.push('/foo').catch(err => {\n      expect(err.type).toBe(NavigationFailureType.aborted)\n      done()\n    })\n  })\n\n  it('async component errors', done => {\n    spyOn(console, 'warn')\n    const err = new Error('foo')\n    const spy1 = jasmine.createSpy('error')\n    const spy2 = jasmine.createSpy('error')\n    const spy3 = jasmine.createSpy('promise reject')\n    const Comp = () => {\n      throw err\n    }\n    const router = new VueRouter({\n      routes: [{ path: '/', component: Comp }]\n    })\n\n    router.onError(spy1)\n    router.onReady(() => {}, spy2)\n\n    router\n      .push('/')\n      .catch(spy3)\n      .finally(() => {\n        expect(spy1).toHaveBeenCalledWith(err)\n        expect(spy2).toHaveBeenCalledWith(err)\n        expect(spy3).toHaveBeenCalled()\n        expect(console.warn).toHaveBeenCalledTimes(1)\n        done()\n      })\n  })\n\n  // https://github.com/vuejs/vue-router/issues/3225\n  it('should trigger onReady onSuccess when redirecting', done => {\n    const router = new VueRouter({\n      routes: [\n        { path: '/', component: {}},\n        { path: '/foo', component: {}}\n      ]\n    })\n\n    const onError = jasmine.createSpy('onError')\n    const onReadySuccess = jasmine.createSpy('onReadySuccess')\n    const onReadyFail = jasmine.createSpy('onReadyFail')\n    router.onError(onError)\n    router.onReady(onReadySuccess, onReadyFail)\n\n    router.beforeEach((to, from, next) => {\n      if (to.path === '/') next('/foo')\n      else next()\n    })\n\n    const pushCatch = jasmine.createSpy('pushCatch')\n\n    // initial navigation\n    router\n      .push('/')\n      .catch(pushCatch)\n      .finally(() => {\n        expect(router.currentRoute.path).toBe('/foo')\n        expect(onReadyFail).not.toHaveBeenCalled()\n        // in 3.2.0 it was called with undefined\n        // expect(pushCatch).not.toHaveBeenCalled()\n        expect(onError).not.toHaveBeenCalled()\n        expect(onReadySuccess).toHaveBeenCalled()\n        done()\n      })\n  })\n\n  it('should trigger onError if error is thrown inside redirect option', done => {\n    const error = new Error('foo')\n    const config = [\n      {\n        path: '/oldpath/:part',\n        redirect: to => {\n          throw error\n        }\n      }\n    ]\n\n    const router = new VueRouter({\n      routes: config\n    })\n\n    const onError = jasmine.createSpy('onError')\n    router.onError(onError)\n    const pushCatch = jasmine.createSpy('pushCatch')\n\n    router\n      .push('/oldpath/test')\n      .catch(pushCatch)\n      .finally(() => {\n        expect(pushCatch).toHaveBeenCalledWith(error)\n        expect(onError).toHaveBeenCalledWith(error)\n        done()\n      })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/location.spec.js",
    "content": "import { normalizeLocation } from '../../../src/util/location'\n\ndescribe('Location utils', () => {\n  describe('normalizeLocation', () => {\n    it('string', () => {\n      const loc = normalizeLocation('/abc?foo=bar&baz=qux#hello')\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/abc')\n      expect(loc.hash).toBe('#hello')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({\n        foo: 'bar',\n        baz: 'qux'\n      }))\n    })\n\n    it('empty string', function () {\n      const loc = normalizeLocation('', { path: '/abc' })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/abc')\n      expect(loc.hash).toBe('')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({}))\n    })\n\n    it('undefined', function () {\n      const loc = normalizeLocation({}, { path: '/abc' })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/abc')\n      expect(loc.hash).toBe('')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({}))\n    })\n\n    it('relative', () => {\n      const loc = normalizeLocation('abc?foo=bar&baz=qux#hello', {\n        path: '/root/next'\n      })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/root/abc')\n      expect(loc.hash).toBe('#hello')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({\n        foo: 'bar',\n        baz: 'qux'\n      }))\n    })\n\n    it('relative append', () => {\n      const loc = normalizeLocation('abc?foo=bar&baz=qux#hello', {\n        path: '/root/next'\n      }, true)\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/root/next/abc')\n      expect(loc.hash).toBe('#hello')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({\n        foo: 'bar',\n        baz: 'qux'\n      }))\n    })\n\n    it('relative query & hash', () => {\n      const loc = normalizeLocation('?foo=bar&baz=qux#hello', {\n        path: '/root/next'\n      })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/root/next')\n      expect(loc.hash).toBe('#hello')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({\n        foo: 'bar',\n        baz: 'qux'\n      }))\n    })\n\n    it('relative params (named)', () => {\n      const loc = normalizeLocation({ params: { lang: 'fr' }}, {\n        name: 'hello',\n        params: { lang: 'en', id: 'foo' }\n      })\n      expect(loc._normalized).toBe(true)\n      expect(loc.name).toBe('hello')\n      expect(loc.params).toEqual({ lang: 'fr', id: 'foo' })\n    })\n\n    it('relative params (non-named)', () => {\n      const loc = normalizeLocation({ params: { lang: 'fr' }}, {\n        path: '/en/foo',\n        params: { lang: 'en', id: 'foo' },\n        matched: [{ path: '/:lang(en|fr)/:id' }]\n      })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/fr/foo')\n    })\n\n    it('custom regex can be case insensitive', () => {\n      const loc = normalizeLocation({ params: { lang: 'FR' }}, {\n        path: '/en/foo',\n        params: { lang: 'en', id: 'foo' },\n        matched: [{ path: '/:lang(en|fr)/:id' }]\n      })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/FR/foo')\n    })\n\n    it('relative append', () => {\n      const loc = normalizeLocation({ path: 'a' }, { path: '/b' }, true)\n      expect(loc.path).toBe('/b/a')\n      const loc2 = normalizeLocation({ path: 'a', append: true }, { path: '/b' })\n      expect(loc2.path).toBe('/b/a')\n    })\n\n    it('object', () => {\n      const loc = normalizeLocation({\n        path: '/abc?foo=bar#hello',\n        query: { baz: 'qux' },\n        hash: 'lol'\n      })\n      expect(loc._normalized).toBe(true)\n      expect(loc.path).toBe('/abc')\n      expect(loc.hash).toBe('#lol')\n      expect(JSON.stringify(loc.query)).toBe(JSON.stringify({\n        foo: 'bar',\n        baz: 'qux'\n      }))\n    })\n\n    it('skip normalized', () => {\n      const loc1 = {\n        _normalized: true,\n        path: '/abc?foo=bar#hello',\n        query: { baz: 'qux' },\n        hash: 'lol'\n      }\n      const loc2 = normalizeLocation(loc1)\n      expect(loc1).toBe(loc2)\n    })\n\n    it('creates copies when not normalized', () => {\n      const l1 = { name: 'foo' }\n      expect(normalizeLocation(l1)).not.toBe(l1)\n      const l2 = { path: '/foo' }\n      expect(normalizeLocation(l2)).not.toBe(l2)\n      const l3 = { path: '/foo', query: { foo: 'foo' }}\n      expect(normalizeLocation(l3)).not.toBe(l3)\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/node.spec.js",
    "content": "import Vue from 'vue'\nimport VueRouter from '../../../src/index'\n\nVue.use(VueRouter)\n\ndescribe('Usage in Node', () => {\n  it('should be in abstract mode', () => {\n    const router = new VueRouter()\n    expect(router.mode).toBe('abstract')\n  })\n\n  it('should be able to navigate without app instance', () => {\n    const router = new VueRouter({\n      routes: [\n        { path: '/', component: { name: 'foo' }},\n        { path: '/bar', component: { name: 'bar' }}\n      ]\n    })\n    router.push('/bar')\n    expect(router.history.current.path).toBe('/bar')\n  })\n\n  it('getMatchedComponents', () => {\n    const Foo = { name: 'foo' }\n    const Bar = { name: 'bar' }\n    const Baz = { name: 'baz' }\n    const router = new VueRouter({\n      routes: [\n        { path: '/', component: Foo },\n        {\n          path: '/bar',\n          component: Bar,\n          children: [{ path: 'baz', component: Baz }]\n        }\n      ]\n    })\n    expect(router.getMatchedComponents('/')).toEqual([Foo])\n    expect(router.getMatchedComponents('/bar/baz')).toEqual([Bar, Baz])\n  })\n\n  it('should navigate through history with same consecutive routes in history stack', () => {\n    const success = jasmine.createSpy('complete')\n    const error = jasmine.createSpy('error')\n    const router = new VueRouter({\n      routes: [\n        { path: '/', component: { name: 'foo' }},\n        { path: '/bar', component: { name: 'bar' }}\n      ]\n    })\n    router.push('/', success, error)\n    expect(success).toHaveBeenCalledTimes(1)\n    expect(error).toHaveBeenCalledTimes(0)\n    router.push('/bar', success, error)\n    expect(success).toHaveBeenCalledTimes(2)\n    expect(error).toHaveBeenCalledTimes(0)\n    router.push('/', success, error)\n    expect(success).toHaveBeenCalledTimes(3)\n    expect(error).toHaveBeenCalledTimes(0)\n    router.replace('/bar', success, error)\n    expect(success).toHaveBeenCalledTimes(4)\n    expect(error).toHaveBeenCalledTimes(0)\n\n    expect(router.history.current.path).toBe('/bar')\n    router.back()\n    expect(router.history.current.path).toBe('/bar')\n    router.back()\n    expect(router.history.current.path).toBe('/')\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/onReady.spec.js",
    "content": "import Vue from 'vue'\nimport VueRouter from '../../../src/index'\n\nVue.use(VueRouter)\n\ndescribe('onReady order', () => {\n  function factory () {\n    const router = new VueRouter({\n      mode: 'abstract',\n      routes: [\n        { path: '/', component: {}},\n        { path: '/foo', component: {}}\n      ]\n    })\n\n    return { router }\n  }\n\n  it('should trigger onReady after push with redirect', done => {\n    const { router } = factory()\n\n    let n = 0\n    const count = 2\n    router.onReady(() => {\n      expect(router.currentRoute.path).toBe('/foo')\n      if (++n === count) done()\n    })\n\n    router.beforeEach((to, from, next) => {\n      if (to.path === '/') next('/foo')\n      else next()\n    })\n\n    router.push('/').catch(() => {\n      expect(router.currentRoute.path).toBe('/foo')\n      if (++n === count) done()\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/path.spec.js",
    "content": "import { resolvePath, parsePath, cleanPath } from '../../../src/util/path'\n\ndescribe('Path utils', () => {\n  describe('resolvePath', () => {\n    it('absolute', () => {\n      const path = resolvePath('/a', '/b')\n      expect(path).toBe('/a')\n    })\n\n    it('relative', () => {\n      const path = resolvePath('c/d', '/b')\n      expect(path).toBe('/c/d')\n    })\n\n    it('relative with append', () => {\n      const path = resolvePath('c/d', '/b', true)\n      expect(path).toBe('/b/c/d')\n    })\n\n    it('relative parent', () => {\n      const path = resolvePath('../d', '/a/b/c')\n      expect(path).toBe('/a/d')\n    })\n\n    it('relative parent with append', () => {\n      const path = resolvePath('../d', '/a/b/c', true)\n      expect(path).toBe('/a/b/d')\n    })\n\n    it('relative query', () => {\n      const path = resolvePath('?foo=bar', '/a/b')\n      expect(path).toBe('/a/b?foo=bar')\n    })\n\n    it('relative hash', () => {\n      const path = resolvePath('#hi', '/a/b')\n      expect(path).toBe('/a/b#hi')\n    })\n  })\n\n  describe('parsePath', () => {\n    it('plain', () => {\n      const res = parsePath('/a')\n      expect(res.path).toBe('/a')\n      expect(res.hash).toBe('')\n      expect(res.query).toBe('')\n    })\n\n    it('query', () => {\n      const res = parsePath('/a?foo=bar???')\n      expect(res.path).toBe('/a')\n      expect(res.hash).toBe('')\n      expect(res.query).toBe('foo=bar???')\n    })\n\n    it('hash', () => {\n      const res = parsePath('/a#haha#hoho')\n      expect(res.path).toBe('/a')\n      expect(res.hash).toBe('#haha#hoho')\n      expect(res.query).toBe('')\n    })\n\n    it('both', () => {\n      const res = parsePath('/a?foo=bar#ok?baz=qux')\n      expect(res.path).toBe('/a')\n      expect(res.hash).toBe('#ok?baz=qux')\n      expect(res.query).toBe('foo=bar')\n    })\n  })\n\n  describe('cleanPath', () => {\n    it('should work', () => {\n      const path = cleanPath('//a//b//d/')\n      expect(path).toBe('/a/b/d/')\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/query.spec.js",
    "content": "import { resolveQuery, stringifyQuery } from '../../../src/util/query'\n\ndescribe('Query utils', () => {\n  describe('resolveQuery', () => {\n    it('should work', () => {\n      const query = resolveQuery('foo=bar&foo=k', { baz: 'qux' })\n      expect(JSON.stringify(query)).toBe(\n        JSON.stringify({\n          foo: ['bar', 'k'],\n          baz: 'qux'\n        })\n      )\n    })\n\n    it('should turn empty params into null', () => {\n      expect(resolveQuery('?foo&bar=&arr=1&arr&arr=2')).toEqual({\n        foo: null,\n        bar: '',\n        arr: ['1', null, '2']\n      })\n    })\n\n    it('should keep undefined and null query values', () => {\n      const query = resolveQuery('', { a: undefined, b: null })\n      expect(query).toEqual({ a: undefined, b: null })\n    })\n\n    it('should keep objects query values', () => {\n      const query = resolveQuery('', { a: { nested: 'o' }, b: [{ a: true }] })\n      expect(query).toEqual({ a: { nested: 'o' }, b: [{ a: true }] })\n    })\n\n    it('should keep null query values in arrays', () => {\n      const query = resolveQuery('', { baz: [null, '2'] })\n      expect(query).toEqual({ baz: [null, '2'] })\n    })\n\n    it('should cast query values into string', () => {\n      const query = resolveQuery('foo=bar&foo=k', { baz: 1 })\n      expect(query.baz).toBe('1')\n    })\n\n    it('should cast query array values into string', () => {\n      const query = resolveQuery('foo=bar&foo=k', { baz: [1, '2'] })\n      expect(query.baz).toEqual(['1', '2'])\n    })\n  })\n\n  describe('stringifyQuery', () => {\n    it('should work', () => {\n      expect(\n        stringifyQuery({\n          foo: 'bar',\n          baz: 'qux',\n          arr: [1, 2]\n        })\n      ).toBe('?foo=bar&baz=qux&arr=1&arr=2')\n    })\n\n    it('should add only the key with null', () => {\n      expect(\n        stringifyQuery({\n          foo: null,\n          bar: '',\n          arr: [1, null, 3]\n        })\n      ).toBe('?foo&bar=&arr=1&arr&arr=3')\n    })\n\n    it('should escape reserved chars', () => {\n      expect(\n        stringifyQuery({\n          a: '*()!'\n        })\n      ).toBe('?a=%2a%28%29%21')\n    })\n\n    it('should preserve commas', () => {\n      expect(\n        stringifyQuery({\n          list: '1,2,3'\n        })\n      ).toBe('?list=1,2,3')\n    })\n  })\n})\n"
  },
  {
    "path": "test/unit/specs/route.spec.js",
    "content": "import { isSameRoute, isIncludedRoute } from '../../../src/util/route'\n\ndescribe('Route utils', () => {\n  describe('isSameRoute', () => {\n    it('path', () => {\n      const a = {\n        path: '/a',\n        hash: '#hi',\n        query: { foo: 'bar', arr: [1, 2] }\n      }\n      const b = {\n        path: '/a/', // Allow trailing slash\n        hash: '#hi',\n        query: { arr: ['1', '2'], foo: 'bar' }\n      }\n      expect(isSameRoute(a, b)).toBe(true)\n    })\n\n    it('name', () => {\n      const a = {\n        path: '/abc',\n        name: 'a',\n        hash: '#hi',\n        query: { foo: 'bar', arr: [1, 2] }\n      }\n      const b = {\n        name: 'a',\n        hash: '#hi',\n        query: { arr: ['1', '2'], foo: 'bar' }\n      }\n      expect(isSameRoute(a, b)).toBe(true)\n    })\n\n    it('nested query', () => {\n      const a = {\n        path: '/abc',\n        query: { foo: { bar: 'bar' }, arr: [1, 2] }\n      }\n      const b = {\n        path: '/abc',\n        query: { arr: [1, 2], foo: { bar: 'bar' }}\n      }\n      const c = {\n        path: '/abc',\n        query: { arr: [1, 2], foo: { bar: 'not bar' }}\n      }\n      expect(isSameRoute(a, b)).toBe(true)\n      expect(isSameRoute(a, c)).toBe(false)\n    })\n\n    it('queries with null values', () => {\n      const a = {\n        path: '/abc',\n        query: { foo: null }\n      }\n      const b = {\n        path: '/abc',\n        query: { foo: null }\n      }\n      const c = {\n        path: '/abc',\n        query: { foo: 5 }\n      }\n      expect(() => isSameRoute(a, b)).not.toThrow()\n      expect(() => isSameRoute(a, c)).not.toThrow()\n      expect(isSameRoute(a, b)).toBe(true)\n      expect(isSameRoute(a, c)).toBe(false)\n    })\n\n    it('queries with undefined values', () => {\n      const a = {\n        path: '/abc',\n        query: { a: 'x' }\n      }\n      const b = {\n        path: '/abc',\n        query: { id: undefined }\n      }\n      const c = {\n        path: '/abc',\n        query: {}\n      }\n      expect(() => isSameRoute(a, b)).not.toThrow()\n      expect(() => isSameRoute(a, c)).not.toThrow()\n      expect(() => isSameRoute(b, c)).not.toThrow()\n      expect(isSameRoute(a, b)).toBe(false)\n      expect(isSameRoute(a, c)).toBe(false)\n      // NOTE: in reality this should be true but because we check queries as\n      // objects, they are different objects. We should check queries as their\n      // string representation instead\n      expect(isSameRoute(b, c)).toBe(false)\n      expect(isSameRoute(c, b)).toBe(false)\n    })\n  })\n\n  describe('isIncludedRoute', () => {\n    it('path', () => {\n      const a = { path: '/a/b' }\n      const b = { path: '/a' }\n      const c = { path: '/a/b/c' }\n      const d = { path: '/a/b/' }\n      expect(isIncludedRoute(a, b)).toBe(true)\n      expect(isIncludedRoute(a, c)).toBe(false)\n      expect(isIncludedRoute(a, d)).toBe(true)\n    })\n\n    it('with hash', () => {\n      const a = { path: '/a/b', hash: '#a' }\n      const b = { path: '/a' }\n      const c = { path: '/a', hash: '#a' }\n      const d = { path: '/a', hash: '#b' }\n      expect(isIncludedRoute(a, b)).toBe(true)\n      expect(isIncludedRoute(a, c)).toBe(true)\n      expect(isIncludedRoute(a, d)).toBe(false)\n    })\n\n    it('with query', () => {\n      const a = { path: '/a/b', query: { foo: 'bar', baz: 'qux' }}\n      const b = { path: '/a', query: {}}\n      const c = { path: '/a', query: { foo: 'bar' }}\n      const d = { path: '/a', query: { foo: 'bar', a: 'b' }}\n      expect(isIncludedRoute(a, b)).toBe(true)\n      expect(isIncludedRoute(a, c)).toBe(true)\n      expect(isIncludedRoute(a, d)).toBe(false)\n    })\n\n    it('with both', () => {\n      const a = { path: '/a/b', query: { foo: 'bar', baz: 'qux' }, hash: '#a' }\n      const b = { path: '/a', query: {}}\n      const c = { path: '/a', query: { foo: 'bar' }}\n      const d = { path: '/a', query: { foo: 'bar' }, hash: '#b' }\n      const e = { path: '/a', query: { a: 'b' }, hash: '#a' }\n      expect(isIncludedRoute(a, b)).toBe(true)\n      expect(isIncludedRoute(a, c)).toBe(true)\n      expect(isIncludedRoute(a, d)).toBe(false)\n      expect(isIncludedRoute(a, e)).toBe(false)\n    })\n\n    it('trailing slash', () => {\n      const a = { path: '/users' }\n      const b = { path: '/user' }\n      const c = { path: '/users/' }\n      expect(isIncludedRoute(a, b)).toBe(false)\n      expect(isIncludedRoute(a, c)).toBe(true)\n\n      const d = { path: '/users/hello/world' }\n      const e = { path: '/users/hello' }\n      const f = { path: '/users/hello-world' }\n      expect(isIncludedRoute(d, e)).toBe(true)\n      expect(isIncludedRoute(d, f)).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "types/composables.d.ts",
    "content": "import type { ComputedRef, Ref } from 'vue'\nimport type { Route, NavigationGuard, default as VueRouter } from './index'\n\n/**\n * Returns the current route location. Equivalent to using `$route` inside templates.\n */\nexport function useRoute(): Route\n\n/**\n * Returns the router instance. Equivalent to using `$router` inside templates.\n */\nexport function useRouter(): VueRouter\n\n/**\n * Add a navigation guard that triggers whenever the current location is about to be updated. Similar to beforeRouteUpdate but can be used in any component. The guard is removed when the component is unmounted.\n *\n * @param updateGuard\n */\nexport function onBeforeRouteUpdate(updateGuard: NavigationGuard): void\n\n/**\n * Add a navigation guard that triggers whenever the component for the current location is about to be left. Similar to beforeRouteLeave but can be used in any component. The guard is removed when the component is unmounted.\n *\n * @param leaveGuard\n */\nexport function onBeforeRouteLeave(leaveGuard: NavigationGuard): void\n\nexport interface RouterLinkOptions {\n  /**\n   * Route Location the link should navigate to when clicked on.\n   */\n  to: Route | Ref<Route>\n  /**\n   * Calls `router.replace` instead of `router.push`.\n   */\n  replace?: boolean\n}\n\n/**\n * Vue Router 4 `useLink()` function. Note the active behavior is different from Vue Router 3 as highlighted in the\n * migration guide (https://router.vuejs.org/guide/migration/index.html#removal-of-the-exact-prop-in-router-link)\n *\n * @param props - object containing a `to` property with the location\n */\nexport function useLink({ to, replace }: RouterLinkOptions): {\n  route: ComputedRef<Route>,\n  isActive: ComputedRef<boolean>,\n  isExactActive: ComputedRef<boolean>,\n  href: ComputedRef<string>,\n  navigate: () => Promise<void>,\n}\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "import './vue'\nimport { VueRouter, RouterLink, RouterView, START_LOCATION, NavigationFailureType, isNavigationFailure } from './router'\n\nexport default VueRouter\nexport { RouterView, RouterLink, START_LOCATION, NavigationFailureType, isNavigationFailure }\n\nexport type {\n  RouterMode,\n  RouteMeta,\n  RawLocation,\n  RedirectOption,\n  RouterOptions,\n  RouteConfig,\n  RouteRecord,\n  RouteRecordPublic,\n  Location,\n  Route,\n  NavigationGuard,\n  NavigationGuardNext,\n  NavigationFailure\n} from './router'\n\nimport './composables'\n"
  },
  {
    "path": "types/router.d.ts",
    "content": "import Vue, {\n  PluginFunction,\n  AsyncComponent,\n  VNode,\n  Component as _Component\n} from 'vue'\n\ntype Component =\n  | {}\n  | _Component<any, any, any, any>\n  | AsyncComponent<any, any, any, any>\n\ntype Dictionary<T> = { [key: string]: T }\ntype ErrorHandler = (err: Error) => void\n\nexport type RouterMode = 'hash' | 'history' | 'abstract'\nexport type RawLocation = string | Location\nexport type RedirectOption = RawLocation | ((to: Route) => RawLocation)\nexport type NavigationGuardNext<V extends Vue = Vue> = (\n  to?: RawLocation | false | ((vm: V) => any) | void\n) => void\n\nexport type NavigationGuard<V extends Vue = Vue> = (\n  to: Route,\n  from: Route,\n  next: NavigationGuardNext<V>\n) => any\n\n/**\n * Router instance.\n */\nexport declare class VueRouter {\n  constructor(options?: RouterOptions)\n\n  app: Vue\n  /**\n   * Original options object passed to create the Router\n   */\n  options: RouterOptions\n  /**\n   * Configured mode when creating the Router instance.\n   */\n  mode: RouterMode\n  /**\n   * Current {@link Route}\n   */\n  currentRoute: Route\n\n  /**\n   * Add a navigation guard that executes before any navigation.\n   *\n   * @param guard - navigation guard to add\n   * @returns a function that removes the registered guard\n   *\n   * @example\n   * ```js\n   * router.beforeEach((to, from, next) => {\n   *   // must call `next`\n   * })\n   * ```\n   */\n  beforeEach(guard: NavigationGuard): () => void\n  /**\n   * Add a navigation guard that executes before navigation is about to be resolved. At this state all component have\n   * been fetched and other navigation guards have been successful.\n   *\n   * @param guard - navigation guard to add\n   * @returns a function that removes the registered guard\n   *\n   * @example\n   * ```js\n   * router.beforeResolve((to, from, next) => {\n   *   // must call `next`\n   * })\n   * ```\n   */\n  beforeResolve(guard: NavigationGuard): () => void\n  /**\n   * Add a navigation hook that is executed after every navigation. Returns a function that removes the registered hook.\n   *\n   * @param hook - navigation hook to add\n   * @returns a function that removes the registered guard\n   *\n   * @example\n   * ```js\n   * router.afterEach((to, from) => {\n   *   console.log('after navigation')\n   * })\n   * ```\n   */\n  afterEach(hook: (to: Route, from: Route) => any): () => void\n  /**\n   * Programmatically navigate to a new URL by pushing an entry in the history stack.\n   *\n   * @param to Route location to navigate to\n   */\n  push(to: RawLocation): Promise<Route>\n  /**\n   * Programmatically navigate to a new URL by pushing an entry in the history stack.\n   *\n   * @param to Route location to navigate to\n   * @param onComplete Navigation success callback\n   * @param onAbort Navigation aborted callback\n   */\n  push(\n    to: RawLocation,\n    onComplete?: (route: Route) => void,\n    onAbort?: ErrorHandler\n  ): void\n  /**\n   * Programmatically navigate to a new URL by replacing the current entry in the history stack.\n   *\n   * @param to Route location to navigate to\n   */\n  replace(to: RawLocation): Promise<Route>\n  /**\n   * Programmatically navigate to a new URL by replacing the current entry in the history stack.\n   *\n   * @param to Route location to navigate to\n   * @param onComplete Navigation success callback\n   * @param onAbort Navigation aborted callback\n   */\n  replace(\n    to: RawLocation,\n    onComplete?: (route: Route) => void,\n    onAbort?: ErrorHandler\n  ): void\n  /**\n   * Allows you to move forward or backward through the history. Calls `history.go()`.\n   *\n   * @param delta The position in the history to which you want to move, relative to the current page\n   */\n  go(n: number): void\n  /**\n   * Go back in history if possible by calling `history.back()`. Equivalent to `router.go(-1)`.\n   */\n  back(): void\n  /**\n   * Go forward in history if possible by calling `history.forward()`. Equivalent to `router.go(1)`.\n   */\n  forward(): void\n  match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route\n  getMatchedComponents(to?: RawLocation | Route): Component[]\n  /**\n   * This method queues a callback to be called when the router has completed the initial navigation, which means it has\n   * resolved all async enter hooks and async components that are associated with the initial route.\n   *\n   * This is useful in server-side rendering to ensure consistent output on both the server and the client.\n   * @param cb onReady callback.\n   * @param errorCb errorCb will be called when the initial route resolution runs into an error (e.g. failed to resolve\n   * an async component).\n   */\n  onReady(cb: () => void, errorCb?: ErrorHandler): void\n  /**\n   * Adds an error handler that is called every time a non caught error happens during navigation. This includes errors\n   * thrown synchronously and asynchronously, errors returned or passed to `next` in any navigation guard, and errors\n   * occurred when trying to resolve an async component that is required to render a route.\n   *\n   * @param handler - error handler to register\n   */\n  onError(cb: ErrorHandler): void\n  /**\n   * @deprecated use {@link addRoute | router.addRoute()} instead\n   */\n  addRoutes(routes: RouteConfig[]): void\n  /**\n   * Add a new {@link RouteConfig | route record} as the child of an existing route. If the route has a `name` and there\n   * is already an existing one with the same one, it overwrites it.\n   *\n   * @param parentName - Parent Route Record where `route` should be appended at\n   * @param route - Route Record to add\n   */\n  addRoute(parentName: string, route: RouteConfig): void\n  /**\n   * Add a new {@link RouteConfig | route} to the router. If the route has a `name` and there is already an existing one\n   * with the same one, it overwrites it.\n   * @param route - Route Record to add\n   */\n  addRoute(route: RouteConfig): void\n  /**\n   * Get the list of all the active route records.\n   */\n  getRoutes(): RouteRecordPublic[]\n\n  /**\n   *\n   * @param to Route location\n   * @param current current is the current Route by default (most of the time you don't need to change this)\n   * @param append allows you to append the path to the `current` route (as with `router-link`)\n   */\n  resolve(\n    to: RawLocation,\n    current?: Route,\n    append?: boolean\n  ): {\n    location: Location\n    route: Route\n    href: string\n    /**\n     * backwards compat\n     */\n    normalizedTo: Location\n    /**\n     * backwards compat\n     */\n    resolved: Route\n  }\n  /**\n   * @internal\n   */\n  static install: PluginFunction<never>\n  static version: string\n\n  static isNavigationFailure: typeof isNavigationFailure\n  static NavigationFailureType: {\n    [k in keyof typeof NavigationFailureType]: NavigationFailureType\n  }\n\n  static START_LOCATION: Route\n}\n\n/**\n * Enumeration with all possible types for navigation failures.\n *\n * Can be passed to {@link isNavigationFailure} to check for specific failures.\n */\nexport enum NavigationFailureType {\n  /**\n   * @internal\n   */\n  redirected = 2,\n  /**\n   * An aborted navigation is a navigation that failed because a navigation guard returned `false` or called\n   * `next(false)`\n   */\n  aborted = 4,\n  /**\n   * A cancelled navigation is a navigation that failed because a more recent navigation finished started (not\n   * necessarily finished).\n   */\n  cancelled = 8,\n  /**\n   * A duplicated navigation is a navigation that failed because it was initiated while already being at the exact same\n   * location.\n   */\n  duplicated = 16\n}\n\n/**\n * Extended Error that contains extra information regarding a failed navigation.\n */\nexport interface NavigationFailure extends Error {\n  /**\n   * Route location we were navigating from\n   */\n  from: Route\n  /**\n   * Route location we were navigating to\n   */\n  to: Route\n  /**\n   * Type of the navigation. One of {@link NavigationFailureType}\n   */\n  type: NavigationFailureType.aborted | NavigationFailureType.cancelled | NavigationFailureType.duplicated\n}\n\n/**\n * Check if an object is a {@link NavigationFailure}.\n */\nexport declare function isNavigationFailure(error: any, type?: NavigationFailureType): error is NavigationFailure\n\ntype Position = { x: number; y: number }\ntype PositionResult = Position | { selector: string; offset?: Position, behavior?: ScrollBehavior } | void\n\n\n/**\n * Options to initialize a {@link VueRouter} instance.\n */\nexport interface RouterOptions {\n  routes?: RouteConfig[]\n  /**\n   * Configure the router mode.\n   *\n   * default: `\"hash\"` (in browser) | `\"abstract\"` (in Node.js)\n   *\n   * available values: `\"hash\" | \"history\" | \"abstract\"`\n   * - `\"hash\"`: uses the URL hash for routing. Works in all Vue-supported browsers, including those that do not support\n   *   HTML5 History API.\n   * - `\"history\"`: requires HTML5 History API and server config. See HTML5 History Mode.\n   * - `\"abstract\"`: works in all JavaScript environments, e.g. server-side with Node.js. **The router will\n   *   automatically be forced into this mode if no browser API is present.**\n   */\n  mode?: RouterMode\n  fallback?: boolean\n  base?: string\n  /**\n   * Default class applied to active {@link RouterLink}. If none is provided, `router-link-active` will be applied.\n   */\n  linkActiveClass?: string\n  /**\n   * Default class applied to active {@link RouterLink}. If none is provided, `router-link-exact-active` will be\n   * applied.\n   */\n  linkExactActiveClass?: string\n  /**\n   * Custom implementation to parse a query. See its counterpart, {@link stringifyQuery}.\n   */\n  parseQuery?: (query: string) => Object\n  /**\n   * Custom implementation to stringify a query object. Should not prepend a leading `?`. {@link parseQuery} counterpart\n   * to handle query parsing.\n   */\n  stringifyQuery?: (query: Object) => string\n  /**\n   * Function to control scrolling when navigating between pages. Can return a Promise to delay scrolling.\n   *\n   * For more details see {@link Scroll Behavior}.\n   */\n  scrollBehavior?: (\n    to: Route,\n    from: Route,\n    savedPosition: Position | void\n  ) => PositionResult | Promise<PositionResult> | undefined | null\n}\n\ntype RoutePropsFunction = (route: Route) => Object\n\nexport interface PathToRegexpOptions {\n  sensitive?: boolean\n  strict?: boolean\n  end?: boolean\n}\n\ninterface _RouteConfigBase {\n  path: string\n  name?: string\n  children?: RouteConfig[]\n  redirect?: RedirectOption\n  alias?: string | string[]\n  meta?: RouteMeta\n  beforeEnter?: NavigationGuard\n  caseSensitive?: boolean\n  pathToRegexpOptions?: PathToRegexpOptions\n}\n\ninterface RouteConfigSingleView extends _RouteConfigBase {\n  component?: Component\n  props?: boolean | Object | RoutePropsFunction\n}\n\ninterface RouteConfigMultipleViews extends _RouteConfigBase {\n  components?: Dictionary<Component>\n  props?: Dictionary<boolean | Object | RoutePropsFunction>\n}\n\nexport type RouteConfig = RouteConfigSingleView | RouteConfigMultipleViews\n\nexport interface RouteRecord {\n  path: string\n  regex: RegExp\n  components: Dictionary<Component>\n  instances: Dictionary<Vue>\n  name?: string\n  parent?: RouteRecord\n  redirect?: RedirectOption\n  matchAs?: string\n  meta: RouteMeta\n  beforeEnter?: (\n    route: Route,\n    redirect: (location: RawLocation) => void,\n    next: () => void\n  ) => any\n  props:\n    | boolean\n    | Object\n    | RoutePropsFunction\n    | Dictionary<boolean | Object | RoutePropsFunction>\n}\n\nexport interface RouteRecordPublic {\n  path: string\n  components: Dictionary<Component>\n  instances: Dictionary<Vue>\n  name?: string\n  redirect?: RedirectOption\n  meta: any\n  beforeEnter?: (\n    route: Route,\n    redirect: (location: RawLocation) => void,\n    next: () => void\n  ) => any\n  props:\n    | boolean\n    | Object\n    | RoutePropsFunction\n    | Dictionary<boolean | Object | RoutePropsFunction>\n}\n\n\nexport interface Location {\n  name?: string\n  path?: string\n  hash?: string\n  query?: Dictionary<string | (string | null)[] | null | undefined>\n  params?: Dictionary<string>\n  append?: boolean\n  replace?: boolean\n}\n\nexport interface Route {\n  path: string\n  name?: string | null\n  hash: string\n  query: Dictionary<string | (string | null)[]>\n  params: Dictionary<string>\n  fullPath: string\n  matched: RouteRecord[]\n  redirectedFrom?: string\n  meta?: RouteMeta\n}\n\nexport interface RouteMeta extends Record<string | number | symbol, any> {}\n\nexport interface RouterLinkProps {\n  /**\n   * Denotes the target route of the link. When clicked, the value of the `to` prop will be passed to\n   * `router.push()` internally, so the value can be either a string or a location descriptor object.\n   */\n  to: string | Location\n  /**\n   * Setting `replace` prop will call `router.replace()` instead of `router.push()` when clicked, so the navigation will\n   * not create a new history record.\n   *\n   * @default false\n   */\n  replace?: boolean\n  /**\n   * Setting `append` prop always appends the relative path to the current path. For example, assuming we are navigating\n   * from `/a` to a relative link `b`, without `append` we will end up at `/b`, but with append we will end up at\n   * `/a/b`.\n   *\n   * @default false\n   */\n  append?: boolean\n  /**\n   * Sometimes we want <RouterLink> to render as another tag, e.g <li>. Then we can use tag prop to specify which tag to\n   * render to, and it will still listen to click events for navigation.\n   *\n   * @default \"a\"\n   */\n  tag?: string\n  /**\n   * Configure the active CSS class applied when the link is active. Note the default value can also be configured\n   * globally via the `linkActiveClass` router constructor option.\n   *\n   * @default \"router-link-active\"\n   */\n  activeClass?: string\n  /**\n   * The default active class matching behavior is **inclusive match**. For example, `<RouterLink to=\"/a\">` will get\n   * this class applied as long as the current path starts with `/a/` or is `/a`.\n   *\n   * @default false\n   */\n  exact?: boolean\n  /**\n   * Allows matching only using the `path` section of the url, effectively ignoring the `query` and the `hash` sections.\n   *\n   * @default false\n   */\n  exactPath?: boolean\n  /**\n   * Configure the active CSS class applied when the link is active with exact path match. Note the default value can\n   * also be configured globally via the `linkExactPathActiveClass` router constructor option.\n   *\n   * @default \"router-link-exact-path-active\"\n   */\n  exactPathActiveClass?: string\n\n  /**\n   * Specify the event(s) that can trigger the link navigation.\n   *\n   * @default 'click'\n   */\n  event?: string | ReadonlyArray<string>\n  /**\n   * Configure the active CSS class applied when the link is active with exact match. Note the default value can also be\n   * configured globally via the `linkExactActiveClass` router constructor option.\n   *\n   * @default \"router-link-exact-active\"\n   */\n  exactActiveClass?: string\n  /**\n   * Configure the value of `aria-current` when the link is active with exact match. It must be one of the allowed\n   * values for [aria-current](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the\n   * default of page should be the best fit.\n   *\n   * @default \"page\"\n   */\n  ariaCurrentValue?:\n    | 'page'\n    | 'step'\n    | 'location'\n    | 'date'\n    | 'time'\n    | 'true'\n    | 'false'\n}\n\nexport interface RouterLinkSlotArgument {\n  /**\n   * resolved url. This would be the `href` attribute of an `a` element\n   */\n  href: string\n  /**\n   * resolved normalized location\n   */\n  route: Route\n  /**\n   * function to trigger the navigation. It will automatically prevent events when necessary, the same way `RouterLink`\n   * does\n   */\n  navigate: (e?: MouseEvent) => Promise<undefined | NavigationFailure>\n  /**\n   * `true` if the [active class](https://v3.router.vuejs.org/api/#active-class) should be applied. Allows to apply an\n   * arbitrary class\n   */\n  isActive: boolean\n  /**\n   * `true` if the [exact active class](https://v3.router.vuejs.org/api/#exact-active-class) should be applied. Allows\n   * to apply an arbitrary class\n   */\n  isExactActive: boolean\n}\n\n/**\n * Component to render a link that triggers a navigation on click.\n */\nexport declare const RouterLink: new () => {\n  $props: RouterLinkProps\n  $scopedSlots: {\n    default?: ({\n      href,\n      route,\n      navigate,\n      isActive,\n      isExactActive\n    }: RouterLinkSlotArgument) => VNode[] | undefined\n  }\n}\n\nexport interface RouterViewProps {\n  /**\n   * When a {@link RouterView | `<RouterView />`} has a name, it will render the component with the corresponding name\n   * in the matched route record's components option. See [Named\n   * Views](https://v3.router.vuejs.org/guide/essentials/named-views.html) for an example.\n   *\n   * @default \"default\"\n   */\n  name?: string\n}\n\n/**\n * Component to display the current route the user is at.\n */\nexport declare const RouterView: new () => {\n  $props: RouterViewProps\n}\n\n/**\n * Initial route location where the router is. Can be used in navigation guards to differentiate the initial navigation.\n */\nexport declare const START_LOCATION: Route\n"
  },
  {
    "path": "types/test/index.ts",
    "content": "import Vue, { ComponentOptions, AsyncComponent, Component } from 'vue'\n\nimport VueRouter from '../index'\nimport {\n  Route,\n  RouteRecord,\n  RedirectOption,\n  NavigationFailure,\n  NavigationFailureType\n} from '../index'\n\nVue.use(VueRouter)\n\nconst Home = { template: '<div>home</div>' }\nconst Foo = { template: '<div>foo</div>' }\nconst Bar = { template: '<div>bar</div>' }\nconst Abc = { template: '<div>abc</div>' }\nconst Async = () => Promise.resolve({ template: '<div>async</div>' })\n\nlet err: any\nif (\n  VueRouter.isNavigationFailure(err, VueRouter.NavigationFailureType.aborted)\n) {\n  err.from.fullPath.split('/')\n}\n\nlet navigationFailure = new Error() as NavigationFailure\nnavigationFailure.to.fullPath.split('/')\n\nconst Hook: ComponentOptions<Vue> = {\n  template: '<div>hook</div>',\n\n  beforeRouteEnter(to, from, next) {\n    route.params\n    next('/')\n    next({ path: '/' })\n    next(vm => {\n      vm.$router\n    })\n  },\n\n  beforeRouteLeave(to, from, next) {\n    route.params\n    next('/')\n    next({ path: '/' })\n    next()\n  },\n\n  beforeRouteUpdate(to, from, next) {\n    route.params\n    next('/')\n    next({ path: '/' })\n    next()\n  }\n}\n\nconst JSXComponent = () => {\n  $props: {\n  }\n}\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: '/',\n  fallback: false,\n  linkActiveClass: 'active',\n  linkExactActiveClass: 'exact-active',\n  scrollBehavior: (to, from, savedPosition) => {\n    if (from.path === '/') {\n      return { selector: '#app' }\n    }\n\n    if (from.path === '/offset') {\n      return { selector: '#foo', offset: { x: 0, y: 100 } }\n    }\n\n    if (to.path === '/child') {\n      return\n    }\n\n    if (savedPosition) {\n      return savedPosition\n    }\n\n    return Promise.resolve({\n      x: 0,\n      y: 0\n    })\n  },\n  routes: [\n    {\n      path: '/foo',\n      component: Home,\n      children: [{ path: '', component: Home }]\n    },\n    {\n      path: '/foo',\n      components: { default: Home },\n      children: [{ path: '', component: Home }]\n    },\n    {\n      path: '/',\n      name: 'home',\n      component: Home,\n      children: [\n        {\n          path: 'child',\n          components: {\n            default: Foo,\n            bar: Bar,\n            abc: Abc,\n            asyncComponent: Async,\n            JSXComponent\n          },\n          meta: { auth: true, nested: { foo: '' } },\n          beforeEnter(to, from, next) {\n            to.params\n            from.params\n            next({ name: 'home' })\n            next()\n          },\n          props: {\n            default: true,\n            bar: { id: 123 },\n            abc: route => route.params,\n            asyncComponent: (route: Route) => route.params\n          }\n        },\n        {\n          path: 'children',\n          redirect: to => {\n            to.params\n            return '/child'\n          }\n        }\n      ]\n    },\n    { path: '/home', alias: '/' },\n    { path: '/foo', props: true },\n    { path: '/bar', props: { id: 123 } },\n    { path: '/baz', props: (route: Route) => route.params },\n    { path: '*', redirect: '/' }\n  ]\n})\n\nconst App: Vue = router.app\nconst mode: string = router.mode\n\nconst route: Route = router.currentRoute\nconst path: string = route.path\nconst name: string | undefined | null = route.name\nconst hash: string = route.hash\nconst query: string | (string | null)[] | null = route.query['foo']\nconst params: string = route.params['bar']\nconst fullPath: string = route.fullPath\nconst redirectedFrom: string | undefined = route.redirectedFrom\nconst meta: any = route.meta\nconst matched: RouteRecord[] = route.matched\n\nmatched.forEach(m => {\n  const path: string = m.path\n  const components: {\n    [key: string]: Component | AsyncComponent | {}\n  } = m.components\n  const instances: { [key: string]: Vue } = m.instances\n  const name: string | undefined | null = m.name\n  const parent: RouteRecord | undefined = m.parent\n  const redirect: RedirectOption | undefined = m.redirect\n})\n\nconst unregister = router.beforeEach((to, from, next) => {\n  to.params\n  next('/')\n  next()\n})\n\nunregister()\n\nrouter.beforeResolve((to, from, next) => {\n  to.params\n  from.params\n  next()\n})\n\nrouter.afterEach((to, from) => {\n  to.params\n  from.params\n})\n\nrouter.push({\n  path: '/',\n  params: {\n    foo: 'foo'\n  },\n  query: {\n    bar: 'bar',\n    empty: null,\n    removed: undefined,\n    withEmpty: ['1', null],\n    foo: ['foo1', 'foo2']\n  },\n  hash: 'hash'\n})\nrouter.replace({ name: 'home' })\n\nrouter.push(\n  '/',\n  () => {},\n  () => {}\n)\nrouter.replace(\n  '/foo',\n  () => {},\n  () => {}\n)\n\n// promises\n\nrouter\n  .push('/')\n  .then(route => {\n    route.fullPath\n  })\n  .catch(() => {})\n\nrouter.onReady(() => {})\n\nrouter.addRoutes([{ path: '/more' }])\n\nrouter.go(-1)\nrouter.back()\nrouter.forward()\n\nconst Components: (\n  | Component\n  | AsyncComponent\n  | {}\n)[] = router.getMatchedComponents()\n\nconst match: Route = router.match('/more')\n\nconst vm = new Vue({\n  router,\n  template: `\n    <div id=\"app\">\n      <h1>Basic</h1>\n      <ul>\n        <li><router-link to=\"/\">/</router-link></li>\n        <li><router-link to=\"/foo\">/foo</router-link></li>\n        <li><router-link to=\"/bar\">/bar</router-link></li>\n      </ul>\n      <router-view class=\"view\"></router-view>\n    </div>\n  `\n}).$mount('#app')\n\nvm.$router.push('/')\nvm.$route.params\n"
  },
  {
    "path": "types/test/meta.ts",
    "content": "import VueRouter from '../index'\n\nconst component = { template: '<div>home</div>' }\n\ndeclare module '../index' {\n  export interface RouteMeta {\n    requiresAuth?: boolean\n    nested: { foo: string }\n  }\n}\n\nconst router = new VueRouter({\n  routes: [\n    {\n      path: '/',\n      component,\n      meta: {\n        requiresAuth: true,\n        // still allowed\n        other: true,\n        nested: {\n          foo: 'bar'\n        }\n      }\n    },\n    {\n      path: '/foo',\n      component,\n      // @ts-expect-error\n      meta: {}\n    }\n  ]\n})\n\nrouter.beforeEach(to => {\n  // should pass\n  if (to.meta!.requiresAuth === true) {\n  }\n  // still pass because any\n  if (to.meta!.lol === true) {\n  }\n  // @ts-expect-error: nested will never be true\n  if (to.meta!.nested === true) {\n  }\n})\n"
  },
  {
    "path": "types/test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"module\": \"es2015\",\n    \"moduleResolution\": \"node\",\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"lib\": [\"es5\", \"dom\", \"es2015.promise\", \"es2015.iterable\", \"es2015.core\"]\n  },\n  \"include\": [\"*.ts\", \"../*.d.ts\"]\n}\n"
  },
  {
    "path": "types/vue.d.ts",
    "content": "/**\n * Augment the typings of Vue.js\n */\n\nimport Vue from 'vue'\nimport VueRouter, { Route, NavigationGuard } from './index'\n\ndeclare module 'vue/types/vue' {\n  interface Vue {\n    $router: VueRouter\n    $route: Route\n  }\n}\n\ndeclare module 'vue/types/options' {\n  interface ComponentOptions<V extends Vue> {\n    router?: VueRouter\n    beforeRouteEnter?: NavigationGuard<V>\n    beforeRouteLeave?: NavigationGuard<V>\n    beforeRouteUpdate?: NavigationGuard<V>\n  }\n}\n"
  },
  {
    "path": "vetur/attributes.json",
    "content": "{\n  \"name\": {\n    \"type\": \"string\",\n    \"description\": \"When a `<router-view>` has a `name` prop, it will render the component with the corresponding name in the matched route record's components option.\"\n  },\n  \"to\": {\n    \"description\": \"Denotes the target route of the link. When clicked, the value of the `to` prop will be internally passed to `router.push()`, so the value can be either a string or a location descriptor object.\"\n  },\n  \"append\": {\n    \"type\": \"boolean\",\n    \"description\": \"Setting the append prop always appends the relative path to the current path. For example, assuming we are navigating from /a to a relative link b, without append we will end up at /b, but with append we will end up at /a/b.\"\n  },\n  \"tag\": {\n    \"description\": \"Specify which tag to render to, and it will still listen to click events for navigation. By default, an `a` tag is rendered.\"\n  },\n  \"event\": {\n    \"description\": \"Specify the event(s) that can trigger the link navigation. By default, the `click` event triggers a navigation.\"\n  },\n  \"replace\": {\n    \"type\": \"boolean\",\n    \"description\": \"Call `router.replace()` instead of `router.push()` when the link is clicked, so the navigation replaces the current history entry.\"\n  },\n  \"exact\": {\n    \"description\": \"The default active class matching behavior is inclusive match. For example, `<router-link to=\\\"/a\\\">` will get this class applied as long as the current path starts with /a/ or is /a.\\nOne consequence of this is that `<router-link to=\\\"/\\\">` will be active for every route! To force the link into \\\"exact match mode\\\", use the exact prop: `<router-link to=\\\"/\\\" exact>`\"\n  },\n  \"active-class\": {\n    \"type\": \"string\",\n    \"description\": \"Configure the active CSS class applied when the link is active. Note the default value can also be configured globally via the `linkActiveClass` router constructor option.\"\n  },\n  \"exact-active-class\": {\n    \"type\": \"string\",\n    \"description\": \"Configure the active CSS class applied when the link is exactly active. Note the default value can also be configured globally via the `linkExactActiveClass` router constructor option.\"\n  },\n  \"aria-current-value\": {\n    \"options\": [\"page\", \"step\", \"location\", \"date\", \"time\", \"true\", \"false\"],\n    \"description\": \"Configure the value of `aria-current` when the link is active with exact match. It must be one of the [allowed values for `aria-current`](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the default of `page` should be the best fit.\"\n  }\n}\n"
  },
  {
    "path": "vetur/tags.json",
    "content": "{\n  \"router-view\": {\n    \"attributes\": [\"name\"],\n    \"description\": \"Component that renders the matched component for the current location. Components rendered by `<router-view>` can also contain their own `<router-view>` to render nested routes.\"\n  },\n  \"router-link\": {\n    \"attributes\": [\n      \"to\",\n      \"replace\",\n      \"append\",\n      \"tag\",\n      \"active-class\",\n      \"exact\",\n      \"event\",\n      \"exact-active-class\",\n      \"aria-current-value\"\n    ],\n    \"description\": \"Component that renders an `<a>` with the correct `href` attribute and click listeners to trigger a local navigation when clicked. Can also customize its rendering by providing the `custom` prop and using its `v-slot` API.\"\n  }\n}\n"
  }
]