diff --git a/ctf-frontend/element-variables.scss b/ctf-frontend/element-variables.scss
deleted file mode 100644
index 0bcc381..0000000
--- a/ctf-frontend/element-variables.scss
+++ /dev/null
@@ -1,710 +0,0 @@
-/* Element Chalk Variables */
-
-/* Transition
--------------------------- */
-$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default;
-$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
-$--fade-linear-transition: opacity 200ms linear !default;
-$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1) 100ms, opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) 100ms !default;
-$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default;
-$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default;
-
-/* Colors
--------------------------- */
-$--color-white: #fff !default;
-$--color-black: #000 !default;
-
-$--color-primary: #409EFF !default;
-$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */
-$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */
-$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */
-$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */
-$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */
-$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */
-$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */
-$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */
-$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */
-
-$--color-success: #67c23a !default;
-$--color-warning: #eb9e05 !default;
-$--color-danger: #fa5555 !default;
-$--color-info: #878d99 !default;
-
-$--color-success-light: mix($--color-white, $--color-success, 80%) !default;
-$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default;
-$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default;
-$--color-info-light: mix($--color-white, $--color-info, 80%) !default;
-
-$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default;
-$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default;
-$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default;
-$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default;
-
-$--color-text-primary: #2d2f33 !default;
-$--color-text-regular: #5a5e66 !default;
-$--color-text-secondary: #878d99 !default;
-$--color-text-placeholder: #b4bccc !default;
-
-/* Link
--------------------------- */
-$--link-color: $--color-primary-light-2 !default;
-$--link-hover-color: $--color-primary !default;
-
-/* Background
--------------------------- */
-$--background-color-base: #f5f7fa !default;
-
-/* Border
--------------------------- */
-$--border-width-base: 1px !default;
-$--border-style-base: solid !default;
-$--border-color-base: #d8dce5 !default;
-$--border-color-light: #dfe4ed !default;
-$--border-color-lighter: #e6ebf5 !default;
-$--border-color-extra-light: #edf2fc !default;
-$--border-color-hover: $--color-text-placeholder !default;
-$--border-base: $--border-width-base $--border-style-base $--border-color-base !default;
-$--border-radius-base: 4px !default;
-$--border-radius-small: 2px !default;
-$--border-radius-circle: 100% !default;
-
-/* Box-shadow
--------------------------- */
-$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default;
-$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default;
-$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default;
-
-/* Fill
--------------------------- */
-$--fill-base: $--color-white !default;
-
-/* Font
--------------------------- */
-$--font-path: 'fonts' !default;
-$--font-size-base: 14px !default;
-$--font-size-small: 13px !default;
-$--font-size-large: 18px !default;
-$--font-color-disabled-base: #bbb !default;
-$--font-weight-primary: 500 !default;
-$--font-line-height-primary: 24px !default;
-
-/* Size
--------------------------- */
-$--size-base: 14px !default;
-
-/* z-index
--------------------------- */
-$--index-normal: 1 !default;
-$--index-top: 1000 !default;
-$--index-popper: 2000 !default;
-
-/* Disable base
--------------------------- */
-$--disabled-fill-base: $--background-color-base !default;
-$--disabled-color-base: $--color-text-placeholder !default;
-$--disabled-border-base: $--border-color-light !default;
-
-/* Icon
--------------------------- */
-$--icon-color: #666 !default;
-$--icon-color-base: $--color-info !default;
-
-/* Checkbox
--------------------------- */
-$--checkbox-font-size: 14px !default;
-$--checkbox-font-weight: $--font-weight-primary !default;
-$--checkbox-color: $--color-text-regular !default;
-$--checkbox-input-height: 14px !default;
-$--checkbox-input-width: 14px !default;
-$--checkbox-input-border-radius: $--border-radius-small !default;
-$--checkbox-input-fill: $--color-white !default;
-$--checkbox-input-border: $--border-base !default;
-$--checkbox-input-border-color: $--border-color-base !default;
-$--checkbox-icon-color: $--color-white !default;
-
-$--checkbox-disabled-input-border-color: $--border-color-base !default;
-$--checkbox-disabled-input-fill: #edf2fc !default;
-$--checkbox-disabled-icon-color: $--color-text-placeholder !default;
-
-$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default;
-$--checkbox-disabled-checked-input-border-color: $--border-color-base !default;
-$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default;
-
-$--checkbox-checked-text-color: $--color-primary !default;
-$--checkbox-checked-input-border-color: $--color-primary !default;
-$--checkbox-checked-input-fill: $--color-primary !default;
-$--checkbox-checked-icon-color: $--fill-base !default;
-
-$--checkbox-input-border-color-hover: $--color-primary !default;
-
-$--checkbox-bordered-height: 40px !default;
-$--checkbox-bordered-padding: 9px 20px 9px 10px !default;
-$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default;
-$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default;
-$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default;
-$--checkbox-bordered-medium-input-height: 14px !default;
-$--checkbox-bordered-medium-input-width: 14px !default;
-$--checkbox-bordered-medium-height: 36px !default;
-$--checkbox-bordered-small-input-height: 12px !default;
-$--checkbox-bordered-small-input-width: 12px !default;
-$--checkbox-bordered-small-height: 32px !default;
-$--checkbox-bordered-mini-input-height: 12px !default;
-$--checkbox-bordered-mini-input-width: 12px !default;
-$--checkbox-bordered-mini-height: 28px !default;
-
-$--checkbox-button-font-size: $--font-size-base !default;
-$--checkbox-button-checked-fill: $--color-primary !default;
-$--checkbox-button-checked-color: $--color-white !default;
-$--checkbox-button-checked-border-color: $--color-primary !default;
-
-
-
-/* Radio
--------------------------- */
-$--radio-font-size: 14px !default;
-$--radio-font-weight: $--font-weight-primary !default;
-$--radio-color: $--color-text-regular !default;
-$--radio-input-height: 14px !default;
-$--radio-input-width: 14px !default;
-$--radio-input-border-radius: $--border-radius-circle !default;
-$--radio-input-fill: $--color-white !default;
-$--radio-input-border: $--border-base !default;
-$--radio-input-border-color: $--border-color-base !default;
-$--radio-icon-color: $--color-white !default;
-
-$--radio-disabled-input-border-color: $--disabled-border-base !default;
-$--radio-disabled-input-fill: $--disabled-fill-base !default;
-$--radio-disabled-icon-color: $--disabled-fill-base !default;
-
-$--radio-disabled-checked-input-border-color: $--disabled-border-base !default;
-$--radio-disabled-checked-input-fill: $--disabled-fill-base !default;
-$--radio-disabled-checked-icon-color: $--color-text-placeholder !default;
-
-$--radio-checked-text-color: $--color-primary !default;
-$--radio-checked-input-border-color: $--color-primary !default;
-$--radio-checked-input-fill: $--color-white !default;
-$--radio-checked-icon-color: $--color-primary !default;
-
-$--radio-input-border-color-hover: $--color-primary !default;
-
-$--radio-bordered-height: 40px !default;
-$--radio-bordered-padding: 12px 20px 0 10px !default;
-$--radio-bordered-medium-padding: 10px 20px 0 10px !default;
-$--radio-bordered-small-padding: 8px 15px 0 10px !default;
-$--radio-bordered-mini-padding: 6px 15px 0 10px !default;
-$--radio-bordered-medium-input-height: 14px !default;
-$--radio-bordered-medium-input-width: 14px !default;
-$--radio-bordered-medium-height: 36px !default;
-$--radio-bordered-small-input-height: 12px !default;
-$--radio-bordered-small-input-width: 12px !default;
-$--radio-bordered-small-height: 32px !default;
-$--radio-bordered-mini-input-height: 12px !default;
-$--radio-bordered-mini-input-width: 12px !default;
-$--radio-bordered-mini-height: 28px !default;
-
-$--radio-button-font-size: $--font-size-base !default;
-$--radio-button-checked-fill: $--color-primary !default;
-$--radio-button-checked-color: $--color-white !default;
-$--radio-button-checked-border-color: $--color-primary !default;
-$--radio-button-disabled-checked-fill: $--border-color-extra-light !default;
-
-/* Select
--------------------------- */
-$--select-border-color-hover: $--border-color-hover !default;
-$--select-disabled-border: $--disabled-border-base !default;
-$--select-font-size: $--font-size-base !default;
-$--select-close-hover-color: $--color-text-secondary !default;
-
-$--select-input-color: $--color-text-placeholder !default;
-$--select-multiple-input-color: #666 !default;
-$--select-input-focus-background: $--color-primary !default;
-$--select-input-font-size: 14px !default;
-
-$--select-option-color: $--color-text-regular !default;
-$--select-option-disabled-color: $--color-text-placeholder !default;
-$--select-option-disabled-background: $--color-white !default;
-$--select-option-height: 34px !default;
-$--select-option-hover-background: $--background-color-base !default;
-$--select-option-selected: $--color-primary !default;
-$--select-option-selected-hover: $--background-color-base !default;
-
-$--select-group-color: $--color-info !default;
-$--select-group-height: 30px !default;
-$--select-group-font-size: 12px !default;
-
-$--select-dropdown-background: $--color-white !default;
-$--select-dropdown-shadow: $--box-shadow-light !default;
-$--select-dropdown-empty-color: #999 !default;
-$--select-dropdown-max-height: 274px !default;
-$--select-dropdown-padding: 6px 0 !default;
-$--select-dropdown-empty-padding: 10px 0 !default;
-$--select-dropdown-border: solid 1px $--border-color-light !default;
-
-/* Alert
--------------------------- */
-$--alert-padding: 8px 16px !default;
-$--alert-border-radius: $--border-radius-base !default;
-$--alert-title-font-size: 13px !default;
-$--alert-description-font-size: 12px !default;
-$--alert-close-font-size: 12px !default;
-$--alert-close-customed-font-size: 13px !default;
-
-$--alert-success-color: $--color-success-lighter !default;
-$--alert-info-color: $--color-info-lighter !default;
-$--alert-warning-color: $--color-warning-lighter !default;
-$--alert-danger-color: $--color-danger-lighter !default;
-
-$--alert-icon-size: 16px !default;
-$--alert-icon-large-size: 28px !default;
-
-/* Message Box
--------------------------- */
-$--msgbox-width: 420px !default;
-$--msgbox-border-radius: 4px !default;
-$--msgbox-font-size: $--font-size-large !default;
-$--msgbox-content-font-size: $--font-size-base !default;
-$--msgbox-content-color: $--color-text-regular !default;
-$--msgbox-error-font-size: 12px !default;
-$--msgbox-padding-primary: 15px !default;
-
-$--msgbox-success-color: $--color-success !default;
-$--msgbox-info-color: $--color-info !default;
-$--msgbox-warning-color: $--color-warning !default;
-$--msgbox-danger-color: $--color-danger !default;
-
-/* Message
--------------------------- */
-$--message-shadow: $--box-shadow-base !default;
-$--message-min-width: 380px !default;
-$--message-background-color: #edf2fc !default;
-$--message-padding: 15px 15px 15px 20px !default;
-$--message-content-color: $--color-text-regular !default;
-$--message-close-color: $--color-text-placeholder !default;
-$--message-close-size: 16px !default;
-$--message-close-hover-color: $--color-text-secondary !default;
-
-$--message-success-color: $--color-success !default;
-$--message-info-color: $--color-info !default;
-$--message-warning-color: $--color-warning !default;
-$--message-danger-color: $--color-danger !default;
-
-/* Notification
--------------------------- */
-$--notification-width: 330px !default;
-$--notification-padding: 14px 26px 14px 13px !default;
-$--notification-raduis: 8px !default;
-$--notification-shadow: $--box-shadow-light !default;
-$--notification-border-color: $--border-color-lighter !default;
-$--notification-icon-size: 24px !default;
-$--notification-close-font-size: $--message-close-size !default;
-$--notification-group-margin: 13px !default;
-$--notification-font-size: $--font-size-base !default;
-$--notification-color: $--color-text-regular !default;
-$--notification-title-font-size: 16px !default;
-$--notification-title-color: $--color-text-primary !default;
-
-$--notification-close-color: $--color-text-secondary !default;
-$--notification-close-hover-color: $--color-text-regular !default;
-
-$--notification-success-color: $--color-success !default;
-$--notification-info-color: $--color-info !default;
-$--notification-warning-color: $--color-warning !default;
-$--notification-danger-color: $--color-danger !default;
-
-/* Input
--------------------------- */
-$--input-font-size: $--font-size-base !default;
-$--input-color: $--color-text-regular !default;
-$--input-width: 140px !default;
-$--input-height: 40px !default;
-$--input-border: $--border-base !default;
-$--input-border-color: $--border-color-base !default;
-$--input-border-radius: $--border-radius-base !default;
-$--input-border-color-hover: $--border-color-hover !default;
-$--input-fill: $--color-white !default;
-$--input-fill-disabled: $--disabled-fill-base !default;
-$--input-color-disabled: $--font-color-disabled-base !default;
-$--input-icon-color: $--color-text-placeholder !default;
-$--input-placeholder-color: $--color-text-placeholder !default;
-$--input-max-width: 314px !default;
-
-$--input-hover-border: $--border-color-hover !default;
-
-$--input-focus-border: $--color-primary !default;
-$--input-focus-fill: $--color-white !default;
-
-$--input-disabled-fill: $--disabled-fill-base !default;
-$--input-disabled-border: $--disabled-border-base !default;
-$--input-disabled-color: $--disabled-color-base !default;
-$--input-disabled-placeholder-color: $--color-text-placeholder !default;
-
-$--input-medium-font-size: 14px !default;
-$--input-medium-height: 36px !default;
-
-$--input-small-font-size: 13px !default;
-$--input-small-height: 32px !default;
-
-$--input-mini-font-size: 12px !default;
-$--input-mini-height: 28px !default;
-
-/* Cascader
--------------------------- */
-$--cascader-menu-fill: $--fill-base !default;
-$--cascader-menu-font-size: $--font-size-base !default;
-$--cascader-menu-radius: $--border-radius-base !default;
-$--cascader-menu-border: $--border-base !default;
-$--cascader-menu-border-color: $--border-color-base !default;
-$--cascader-menu-border-width: $--border-width-base !default;
-$--cascader-menu-color: $--color-text-regular !default;
-$--cascader-menu-option-color-active: $--color-text-secondary !default;
-$--cascader-menu-option-fill-active: rgba($--color-text-secondary, 0.12) !default;
-$--cascader-menu-option-color-hover: $--color-text-regular !default;
-$--cascader-menu-option-fill-hover: rgba($--color-text-primary, 0.06) !default;
-$--cascader-menu-option-color-disabled: #999 !default;
-$--cascader-menu-option-fill-disabled: rgba($--color-black, 0.06) !default;
-$--cascader-menu-option-empty-color: #666 !default;
-$--cascader-menu-group-color: #999 !default;
-$--cascader-menu-shadow: 0 1px 2px rgba($--color-black, 0.14), 0 0 3px rgba($--color-black, 0.14) !default;
-$--cascader-menu-option-pinyin-color: #999 !default;
-$--cascader-menu-submenu-shadow: 1px 1px 2px rgba($--color-black, 0.14), 1px 0 2px rgba($--color-black, 0.14) !default;
-
-/* Group
--------------------------- */
-$--group-option-flex: 0 0 (1/5) * 100% !default;
-$--group-option-offset-bottom: 12px !default;
-$--group-option-fill-hover: rgba($--color-black, 0.06) !default;
-$--group-title-color: $--color-black !default;
-$--group-title-font-size: $--font-size-base !default;
-$--group-title-width: 66px !default;
-
-/* Tab
--------------------------- */
-$--tab-font-size: $--font-size-base !default;
-$--tab-border-line: 1px solid #e4e4e4 !default;
-$--tab-header-color-active: $--color-text-secondary !default;
-$--tab-header-color-hover: $--color-text-regular !default;
-$--tab-header-color: $--color-text-regular !default;
-$--tab-header-fill-active: rgba($--color-black, 0.06) !default;
-$--tab-header-fill-hover: rgba($--color-black, 0.06) !default;
-$--tab-vertical-header-width: 90px !default;
-$--tab-vertical-header-count-color: $--color-white !default;
-$--tab-vertical-header-count-fill: $--color-text-secondary !default;
-
-/* Button
--------------------------- */
-$--button-font-size: 14px !default;
-$--button-font-weight: $--font-weight-primary !default;
-$--button-border-radius: $--border-radius-base !default;
-$--button-padding-vertical: 12px !default;
-$--button-padding-horizontal: 20px !default;
-
-$--button-medium-font-size: 14px !default;
-$--button-medium-border-radius: $--border-radius-base !default;
-$--button-medium-padding-vertical: 10px !default;
-$--button-medium-padding-horizontal: 20px !default;
-
-$--button-small-font-size: 12px !default;
-$--button-small-border-radius: #{$--border-radius-base - 1} !default;
-$--button-small-padding-vertical: 9px !default;
-$--button-small-padding-horizontal: 15px !default;
-
-$--button-mini-font-size: 12px !default;
-$--button-mini-border-radius: #{$--border-radius-base - 1} !default;
-$--button-mini-padding-vertical: 7px !default;
-$--button-mini-padding-horizontal: 15px !default;
-
-$--button-default-color: $--color-text-regular !default;
-$--button-default-fill: $--color-white !default;
-$--button-default-border: $--border-color-base !default;
-
-$--button-disabled-color: $--color-text-placeholder !default;
-$--button-disabled-fill: $--color-white !default;
-$--button-disabled-border: $--border-color-lighter !default;
-
-$--button-primary-border: $--color-primary !default;
-$--button-primary-color: $--color-white !default;
-$--button-primary-fill: $--color-primary !default;
-
-$--button-success-border: $--color-success !default;
-$--button-success-color: $--color-white !default;
-$--button-success-fill: $--color-success !default;
-
-$--button-warning-border: $--color-warning !default;
-$--button-warning-color: $--color-white !default;
-$--button-warning-fill: $--color-warning !default;
-
-$--button-danger-border: $--color-danger !default;
-$--button-danger-color: $--color-white !default;
-$--button-danger-fill: $--color-danger !default;
-
-$--button-info-border: $--color-info !default;
-$--button-info-color: $--color-white !default;
-$--button-info-fill: $--color-info !default;
-
-$--button-hover-tint-percent: 20% !default;
-$--button-active-shade-percent: 10% !default;
-
-
-/* cascader
--------------------------- */
-$--cascader-height: 200px !default;
-
-/* Switch
--------------------------- */
-$--switch-on-color: $--color-primary !default;
-$--switch-off-color: $--border-color-base !default;
-$--switch-disabled-color: $--border-color-lighter !default;
-$--switch-disabled-text-color: $--color-text-placeholder !default;
-
-$--switch-font-size: $--font-size-base !default;
-$--switch-core-border-radius: 10px !default;
-$--switch-width: 40px !default;
-$--switch-height: 20px !default;
-$--switch-button-size: 16px !default;
-
-/* Dialog
--------------------------- */
-$--dialog-background-color: $--color-primary-light-4 !default;
-$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default;
-$--dialog-close-hover-color: $--color-primary !default;
-$--dialog-title-font-size: $--font-size-large !default;
-$--dialog-font-size: 14px !default;
-$--dialog-line-height: $--font-line-height-primary !default;
-$--dialog-padding-primary: 15px !default;
-
-/* Table
--------------------------- */
-$--table-border: 1px solid $--border-color-lighter !default;
-$--table-text-color: $--color-text-regular !default;
-$--table-header-color: $--color-text-secondary !default;
-$--table-row-hover-background: $--background-color-base !default;
-$--table-current-row-background: $--color-primary-light-9 !default;
-$--table-header-background: $--color-text-secondary !default;
-$--table-footer-background: $--color-text-placeholder !default;
-$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default;
-
-/* Pagination
--------------------------- */
-$--pagination-font-size: 13px !default;
-$--pagination-fill: $--color-white !default;
-$--pagination-color: $--color-text-primary !default;
-$--pagination-border-radius: 3px !default;
-$--pagination-button-color: $--color-text-primary !default;
-$--pagination-button-width: 35.5px !default;
-$--pagination-button-height: 28px !default;
-$--pagination-button-disabled-color: $--color-text-placeholder !default;
-$--pagination-button-disabled-fill: $--color-white !default;
-$--pagination-hover-fill: $--color-primary !default;
-$--pagination-hover-color: $--color-white !default;
-
-/* Popover
--------------------------- */
-$--popover-fill: $--color-white !default;
-$--popover-font-size: $--font-size-base !default;
-$--popover-border-color: $--border-color-lighter !default;
-$--popover-arrow-size: 6px !default;
-$--popover-padding: 12px !default;
-$--popover-padding-large: 18px 20px !default;
-$--popover-title-font-size: 16px !default;
-$--popover-title-color: $--color-text-primary !default;
-
-/* Tooltip
--------------------------- */
-$--tooltip-fill: $--color-text-primary !default;
-$--tooltip-color: $--color-white !default;
-$--tooltip-font-size: 12px !default;
-$--tooltip-border-color: $--color-text-primary !default;
-$--tooltip-arrow-size: 6px !default;
-$--tooltip-padding: 10px !default;
-
-/* Tag
--------------------------- */
-$--tag-padding: 0 10px !default;
-$--tag-fill: rgba($--color-primary, 0.10) !default;
-$--tag-color: $--color-primary !default;
-$--tag-border: rgba($--color-primary, 0.20) !default;
-$--tag-font-size: 12px !default;
-$--tag-border-radius: 4px !default;
-
-$--tag-info-fill: rgba($--color-info, 0.10) !default;
-$--tag-info-border: rgba($--color-info, 0.20) !default;
-$--tag-info-color: $--color-info !default;
-
-$--tag-primary-fill: rgba($--color-primary, 0.10) !default;
-$--tag-primary-border: rgba($--color-primary, 0.20) !default;
-$--tag-primary-color: $--color-primary !default;
-
-$--tag-success-fill: rgba($--color-success, 0.10) !default;
-$--tag-success-border: rgba($--color-success, 0.20) !default;
-$--tag-success-color: $--color-success !default;
-
-$--tag-warning-fill: rgba($--color-warning, 0.10) !default;
-$--tag-warning-border: rgba($--color-warning, 0.20) !default;
-$--tag-warning-color: $--color-warning !default;
-
-$--tag-danger-fill: rgba($--color-danger, 0.10) !default;
-$--tag-danger-border: rgba($--color-danger, 0.20) !default;
-$--tag-danger-color: $--color-danger !default;
-
-/* Tree
--------------------------- */
-$--tree-node-hover-color: $--background-color-base !default;
-$--tree-text-color: $--color-text-regular !default;
-$--tree-expand-icon-color: $--color-text-placeholder !default;
-
-/* Dropdown
--------------------------- */
-$--dropdown-menu-box-shadow: $--box-shadow-light !default;
-$--dropdown-menuItem-hover-fill: $--color-primary-light-9 !default;
-$--dropdown-menuItem-hover-color: $--link-color !default;
-
-/* Badge
--------------------------- */
-$--badge-fill: $--color-danger !default;
-$--badge-radius: 10px !default;
-$--badge-font-size: 12px !default;
-$--badge-padding: 6px !default;
-$--badge-size: 18px !default;
-
-/* Card
---------------------------*/
-$--card-border-color: $--border-color-lighter !default;
-$--card-border-radius: 4px !default;
-$--card-padding: 20px !default;
-
-/* Slider
---------------------------*/
-$--slider-main-background-color: $--color-primary !default;
-$--slider-runway-background-color: $--border-color-light !default;
-$--slider-button-hover-color: mix($--color-primary, black, 97%) !default;
-$--slider-stop-background-color: $--color-white !default;
-$--slider-disable-color: $--color-text-placeholder !default;
-
-$--slider-margin: 16px 0 !default;
-$--slider-border-radius: 3px !default;
-$--slider-height: 6px !default;
-$--slider-button-size: 16px !default;
-$--slider-button-wrapper-size: 36px !default;
-$--slider-button-wrapper-offset: -15px !default;
-
-/* Steps
---------------------------*/
-$--steps-border-color: $--disabled-border-base !default;
-$--steps-border-radius: 4px !default;
-$--steps-padding: 20px !default;
-
-/* Menu
---------------------------*/
-$--menu-item-color: $--color-text-primary !default;
-$--menu-item-fill: $--color-white !default;
-$--menu-item-hover-fill: $--color-primary-light-9 !default;
-
-/* Rate
---------------------------*/
-$--rate-height: 20px !default;
-$--rate-font-size: $--font-size-base !default;
-$--rate-icon-size: 18px !default;
-$--rate-icon-margin: 6px !default;
-$--rate-icon-color: $--color-text-placeholder !default;
-
-/* DatePicker
---------------------------*/
-$--datepicker-color: $--color-text-regular !default;
-$--datepicker-off-color: $--color-text-placeholder !default;
-$--datepicker-header-color: $--color-text-regular !default;
-$--datepicker-icon-color: $--color-text-primary !default;
-$--datepicker-border-color: $--disabled-border-base !default;
-$--datepicker-inner-border-color: #e4e4e4 !default;
-$--datepicker-inrange-color: $--border-color-extra-light !default;
-$--datepicker-inrange-hover-color: $--border-color-extra-light !default;
-$--datepicker-active-color: $--color-primary !default;
-$--datepicker-text-hover-color: $--color-primary !default;
-$--datepicker-cell-hover-color: #fff !default;
-
-/* Loading
---------------------------*/
-$--loading-spinner-size: 42px !default;
-$--loading-fullscreen-spinner-size: 50px !default;
-
-/* Scrollbar
---------------------------*/
-$--scrollbar-background-color: rgba($--color-text-secondary, .3) !default;
-$--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default;
-
-/* Carousel
---------------------------*/
-$--carousel-arrow-font-size: 12px !default;
-$--carousel-arrow-size: 36px !default;
-$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default;
-$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default;
-$--carousel-indicator-width: 30px !default;
-$--carousel-indicator-height: 2px !default;
-$--carousel-indicator-padding-horizontal: 4px !default;
-$--carousel-indicator-padding-vertical: 12px !default;
-$--carousel-indicator-out-color: $--border-color-hover !default;
-
-/* Collapse
---------------------------*/
-$--collapse-border-color: $--border-color-lighter !default;
-$--collapse-header-height: 48px !default;
-$--collapse-header-padding: 20px !default;
-$--collapse-header-fill: $--color-white !default;
-$--collapse-header-color: $--color-text-primary !default;
-$--collapse-header-size: 13px !default;
-$--collapse-content-fill: $--color-white !default;
-$--collapse-content-size: 13px !default;
-$--collapse-content-color: $--color-text-primary !default;
-
-/* Transfer
---------------------------*/
-$--transfer-border-color: $--border-color-lighter !default;
-$--transfer-border-radius: $--border-radius-base !default;
-$--transfer-panel-width: 200px !default;
-$--transfer-panel-header-height: 40px !default;
-$--transfer-panel-header-background: $--background-color-base !default;
-$--transfer-panel-footer-height: 40px !default;
-$--transfer-panel-body-height: 246px !default;
-$--transfer-item-height: 30px !default;
-$--transfer-item-hover-background: $--color-text-secondary !default;
-$--transfer-filter-height: 32px !default;
-
-/* Header
- --------------------------*/
-$--header-padding: 0 20px !default;
-
-/* Footer
---------------------------*/
-$--footer-padding: 0 20px !default;
-
-/* Main
---------------------------*/
-$--main-padding: 20px !default;
-
-/* Break-point
---------------------------*/
-$--sm: 768px !default;
-$--md: 992px !default;
-$--lg: 1200px !default;
-$--xl: 1920px !default;
-
-$--breakpoints: (
- 'xs' : (max-width: $--sm),
- 'sm' : (min-width: $--sm),
- 'md' : (min-width: $--md),
- 'lg' : (min-width: $--lg),
- 'xl' : (min-width: $--xl)
-);
-
-$--breakpoints-spec: (
- 'xs-only' : (max-width: $--sm - 1),
- 'sm-and-up' : (min-width: $--sm),
- 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md} - 1)",
- 'sm-and-down': (max-width: $--md - 1),
- 'md-and-up' : (min-width: $--md),
- 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg } - 1)",
- 'md-and-down': (max-width: $--lg - 1),
- 'lg-and-up' : (min-width: $--lg),
- 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl } - 1)",
- 'lg-and-down': (max-width: $--xl - 1),
- 'xl-only' : (min-width: $--xl),
-);
diff --git a/ctf-frontend/package.json b/ctf-frontend/package.json
index 487d64e..d1347d8 100644
--- a/ctf-frontend/package.json
+++ b/ctf-frontend/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"vue": "^2.5.2",
+ "vue-cookies": "^1.5.13",
"vue-router": "^3.0.1"
},
"devDependencies": {
diff --git a/ctf-frontend/src/App.vue b/ctf-frontend/src/App.vue
index bf074d1..3c7cfc7 100644
--- a/ctf-frontend/src/App.vue
+++ b/ctf-frontend/src/App.vue
@@ -7,17 +7,12 @@ body
-
-
-
diff --git a/ctf-frontend/src/components/index.vue b/ctf-frontend/src/components/index.vue
index c8115f2..7b4b1e3 100644
--- a/ctf-frontend/src/components/index.vue
+++ b/ctf-frontend/src/components/index.vue
@@ -15,7 +15,7 @@ export default {
}
-
+
diff --git a/ctf-frontend/src/components/login.vue b/ctf-frontend/src/components/login.vue
index 9761a2f..75973e1 100644
--- a/ctf-frontend/src/components/login.vue
+++ b/ctf-frontend/src/components/login.vue
@@ -1,19 +1,54 @@
-
-
+
+ form(@submit.prevent="login")
+ fieldset
+ legend Вход
+ label(for="username") Логин
+ input(v-model="username" required id="username" type="text" placeholder="Логин")
+ label(for="password") Пароль
+ input(v-model="password" required id="pasword" type="password" placeholder="Пароль")
+ button(type="submit") Вход
-
+
diff --git a/ctf-frontend/src/components/navbar.vue b/ctf-frontend/src/components/navbar.vue
index a708025..d46be57 100644
--- a/ctf-frontend/src/components/navbar.vue
+++ b/ctf-frontend/src/components/navbar.vue
@@ -1,34 +1,33 @@
nav
- h1 CTFЦТФ {{ auth.username }}
+ h1 CTFЦТФ
ul
li(v-for="item in mainNavbar")
router-link(:to="item.component") {{item.name}}
ul(v-if="isLoggedIn")
li
- rouuter-link(to="cabinet") Личный кабинет
- li(v-on:click="logOut()")
- ul(v-if="!(isLoggedIn)")
+ router-link(to="account") Личный кабинет
li
- router-link(to="login")
+ a(v-on:click="logOut()") Выход
+ ul(v-if="!isLoggedIn")
li
- router-link(to="register")
+ router-link(to="login") Вход
+ li
+ router-link(to="register") Регистрация
-
-
diff --git a/ctf-frontend/src/components/register.vue b/ctf-frontend/src/components/register.vue
index 9761a2f..114154d 100644
--- a/ctf-frontend/src/components/register.vue
+++ b/ctf-frontend/src/components/register.vue
@@ -1,19 +1,54 @@
-
-
+
+form(@submit.prevent="login")
+ fieldset
+ legend Регистрация
+ label(for="username") Логин
+ input(v-model="username" required id="username" type="text" placeholder="Логин")
+ label(for="password") Пароль
+ input(v-model="password" required id="pasword" type="password" placeholder="Пароль")
+ button(type="submit") Регистрация
-
+
diff --git a/ctf-frontend/src/components/scoreboard.vue b/ctf-frontend/src/components/scoreboard.vue
index 9761a2f..6f2e0e5 100644
--- a/ctf-frontend/src/components/scoreboard.vue
+++ b/ctf-frontend/src/components/scoreboard.vue
@@ -1,19 +1,34 @@
-
-
+
+table
+ tr(v-for="user in this.list")
+ td(v-for="characteristics in user")
-
+
diff --git a/ctf-frontend/src/components/task.vue b/ctf-frontend/src/components/task.vue
index 9761a2f..3fed1e1 100644
--- a/ctf-frontend/src/components/task.vue
+++ b/ctf-frontend/src/components/task.vue
@@ -1,19 +1,48 @@
-
-
+
+div
+ h1 {{task.name}}
+ p {{task.description}}
+ span {{task.category}}
+ span {{task.cost}}
+ span(v-if="task.solved") Решено
+ ul(v-for="name in task.solved_by")
+ li {{name}}
-
+
diff --git a/ctf-frontend/src/components/taskList.vue b/ctf-frontend/src/components/taskList.vue
index 9761a2f..0473b25 100644
--- a/ctf-frontend/src/components/taskList.vue
+++ b/ctf-frontend/src/components/taskList.vue
@@ -1,19 +1,40 @@
-
-
+
+ul
+ li(v-for="item in list")
+ h1(v-on:click="open(item.id)") {{ item.name }}
+ h2 {{ item.cost }}
+ span {{ item.category }}
-
diff --git a/ctf-frontend/src/components/template.vue b/ctf-frontend/src/components/template.vue
deleted file mode 100644
index 8e787e2..0000000
--- a/ctf-frontend/src/components/template.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/ctf-frontend/src/http-common.js b/ctf-frontend/src/http-common.js
index a9d71d7..43faebe 100644
--- a/ctf-frontend/src/http-common.js
+++ b/ctf-frontend/src/http-common.js
@@ -1,8 +1,8 @@
-import axios from 'axios';
+import axios from 'axios'
export const HTTP = axios.create({
baseURL: "http://dmitriyp.ru:2052/api/",
headers: {
- Authorization: "Token" + token
+ Authorization: "Token " + window.$cookies.get('token')
}
});
\ No newline at end of file
diff --git a/ctf-frontend/src/main.js b/ctf-frontend/src/main.js
index 4b6c18c..bd2f011 100644
--- a/ctf-frontend/src/main.js
+++ b/ctf-frontend/src/main.js
@@ -3,21 +3,20 @@
import Vue from 'vue'
import App from './App'
import router from './router'
+import VueCookies from 'vue-cookies'
+import Router from 'vue-router'
+
+VueCookies.config('1d')
Vue.config.productionTip = false
+Vue.use(VueCookies)
+Vue.use(Router)
/* eslint-disable no-new */
new Vue({
el: '#app',
- data () {
- return {
- auth: {
- username: "",
- token: "",
- }
- }
- },
- router,
+ router: router,
template: '',
+ render: (h) => h(App),
components: { App }
})
diff --git a/ctf-frontend/src/router/index.js b/ctf-frontend/src/router/index.js
index 9f054ca..0f38416 100644
--- a/ctf-frontend/src/router/index.js
+++ b/ctf-frontend/src/router/index.js
@@ -1,15 +1,12 @@
import Vue from 'vue'
import Router from 'vue-router'
+import vueCookies from 'vue-cookies'
import index from '@/components/index'
import login from '@/components/login'
import register from '@/components/register'
import scoreboard from '@/components/scoreboard'
import taskList from '@/components/taskList'
import task from '@/components/task'
-import account from '@/components/account'
-
-
-Vue.use(Router)
export default new Router({
mode: 'history',
@@ -17,37 +14,39 @@ export default new Router({
{
path: '/',
name: 'index',
- component: index
+ component: index,
+ meta: {title: 'Главная'}
},
{
path: '/login',
name: 'login',
- component: login
+ component: login,
+ meta: {title: 'Вход'}
},
{
path: '/register',
name: 'register',
- component: register
+ component: register,
+ meta: {title: 'Регистрация'}
},
{
path: '/scoreboard',
name: 'scoreboard',
- component: scoreboard
+ component: scoreboard,
+ meta: {title: 'Таььлица результатов'}
},
{
path: '/taskList',
name: 'taskList',
- component: taskList
+ component: taskList,
+ meta: {title: 'Список задач'}
},
{
- path: '/task',
+ path: '/task/:id',
name: 'task',
- component: task
- },
- {
- path: '/tausk',
- name: 'account',
- component: account
+ component: task,
+ props: true,
+ meta: {title: 'Задача'}
},
]
})
diff --git a/ctf-frontend/yarn.lock b/ctf-frontend/yarn.lock
index 329a3cf..de599da 100644
--- a/ctf-frontend/yarn.lock
+++ b/ctf-frontend/yarn.lock
@@ -7308,6 +7308,11 @@ void-elements@^2.0.1:
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
+vue-cookies@^1.5.13:
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/vue-cookies/-/vue-cookies-1.5.13.tgz#b1ca79a2663bf9a4f36982557011cab5ee2196c0"
+ integrity sha512-8pjpXnvbNWx1Lft0t3MJnW+ylv0Wa2Tb6Ch617u/pQah3+SfXUZZdkh3EL3bSpe/Sw2Wdw3+DhycgQsKANSxXg==
+
vue-hot-reload-api@^2.2.0:
version "2.3.4"
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity
index 747e6f5..9a4c7b8 100644
--- a/node_modules/.yarn-integrity
+++ b/node_modules/.yarn-integrity
@@ -6,14 +6,16 @@
"flags": [],
"linkedModules": [],
"topLevelPatterns": [
- "axios@^0.19.0"
+ "axios@^0.19.0",
+ "vue-router@^3.1.3"
],
"lockfileEntries": {
"axios@^0.19.0": "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8",
"debug@=3.1.0": "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261",
"follow-redirects@1.5.10": "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a",
"is-buffer@^2.0.2": "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725",
- "ms@2.0.0": "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ "ms@2.0.0": "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8",
+ "vue-router@^3.1.3": "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.3.tgz#e6b14fabc0c0ee9fda0e2cbbda74b350e28e412b"
},
"files": [],
"artifacts": {}
diff --git a/node_modules/vue-router/CHANGELOG.md b/node_modules/vue-router/CHANGELOG.md
new file mode 100644
index 0000000..c25e2ff
--- /dev/null
+++ b/node_modules/vue-router/CHANGELOG.md
@@ -0,0 +1,140 @@
+## [3.1.3](https://github.com/vuejs/vue-router/compare/v3.1.2...v3.1.3) (2019-08-30)
+
+### Bug Fixes
+
+- **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)
+
+### Features
+
+- **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)
+- 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)
+
+## [3.1.2](https://github.com/vuejs/vue-router/compare/v3.1.1...v3.1.2) (2019-08-08)
+
+### Bug Fixes
+
+- **types:** prioritize promise based push/replace ([1243e8b](https://github.com/vuejs/vue-router/commit/1243e8b))
+
+### Reverts
+
+- "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
+
+## [3.1.1](https://github.com/vuejs/vue-router/compare/v3.1.0...v3.1.1) (2019-08-06)
+
+### Bug Fixes
+
+- **link:** silence back navigations errors ([59b6da3](https://github.com/vuejs/vue-router/commit/59b6da3))
+
+# [3.1.0](https://github.com/vuejs/vue-router/compare/v3.0.7...v3.1.0) (2019-08-06)
+
+### Bug Fixes
+
+- **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)
+- **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)
+- **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)
+- adapt error to work on IE9 ([527d6d5](https://github.com/vuejs/vue-router/commit/527d6d5))
+
+### Features
+
+- **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)
+- **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)
+- 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)
+- scoped slot for link ([e289dde](https://github.com/vuejs/vue-router/commit/e289dde))
+- warn the user for invalid uses of v-slot with Link ([44c63a9](https://github.com/vuejs/vue-router/commit/44c63a9))
+
+## [3.0.7](https://github.com/vuejs/vue-router/compare/v3.0.6...v3.0.7) (2019-07-03)
+
+### Bug Fixes
+
+- 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))
+- 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)
+
+## [3.0.6](https://github.com/vuejs/vue-router/compare/v3.0.5...v3.0.6) (2019-04-17)
+
+### Bug Fixes
+
+- 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)
+
+## [3.0.5](https://github.com/vuejs/vue-router/compare/v3.0.4...v3.0.5) (2019-04-15)
+
+### Bug Fixes
+
+- 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)
+- **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))
+- **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)
+
+## [3.0.4](https://github.com/vuejs/vue-router/compare/v3.0.3...v3.0.4) (2019-04-12)
+
+### Bug Fixes
+
+- 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)
+- **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)
+
+### Features
+
+- **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))
+
+## [3.0.3](https://github.com/vuejs/vue-router/compare/v3.0.2...v3.0.3) (2019-04-08)
+
+### Bug Fixes
+
+- 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)
+- **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)
+- **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)
+- **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)
+
+## [3.0.2](https://github.com/vuejs/vue-router/compare/v3.0.1...v3.0.2) (2018-11-23)
+
+### Bug Fixes
+
+- **errors:** throws with invalid route objects ([#1893](https://github.com/vuejs/vue-router/issues/1893)) ([c837666](https://github.com/vuejs/vue-router/commit/c837666))
+- 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))
+- 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))
+- 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)
+- 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)
+- **hash:** support unicode in initial route ([8369c6b](https://github.com/vuejs/vue-router/commit/8369c6b))
+- **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))
+- **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)
+
+### Features
+
+- call scrollBehavior with app context ([#1804](https://github.com/vuejs/vue-router/issues/1804)) ([c93a734](https://github.com/vuejs/vue-router/commit/c93a734))
+
+## [3.0.1](https://github.com/vuejs/vue-router/compare/v3.0.0...v3.0.1) (2017-10-13)
+
+### Bug Fixes
+
+- fix props-passing regression ([02ff792](https://github.com/vuejs/vue-router/commit/02ff792)), closes [#1800](https://github.com/vuejs/vue-router/issues/1800)
+
+## [3.0.0](https://github.com/vuejs/vue-router/compare/v2.8.0...v3.0.0) (2017-10-11)
+
+### Features
+
+- **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))
+
+### BREAKING CHANGES
+
+- **typings:** It is no longer compatible with the old Vue typings
+
+## [2.8.0](https://github.com/vuejs/vue-router/compare/v2.7.0...v2.8.0) (2017-10-11)
+
+### Bug Fixes
+
+- allow insllation on extended Vue copies ([f62c5d6](https://github.com/vuejs/vue-router/commit/f62c5d6))
+- 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))
+- 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)
+- 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))
+- 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)
+- resolve native ES modules ([8a28426](https://github.com/vuejs/vue-router/commit/8a28426))
+- 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))
+
+### Features
+
+- enhance hashHistory to support scrollBehavior ([#1662](https://github.com/vuejs/vue-router/issues/1662)) ([1422eb5](https://github.com/vuejs/vue-router/commit/1422eb5))
+- scrollBehavior accept returning a promise ([#1758](https://github.com/vuejs/vue-router/issues/1758)) ([ce13b55](https://github.com/vuejs/vue-router/commit/ce13b55))
+
+# [2.7.0](https://github.com/vuejs/vue-router/compare/v2.6.0...v2.7.0) (2017-06-29)
+
+### Features
+
+- auto resolve ES module default when resolving async components ([d539788](https://github.com/vuejs/vue-router/commit/d539788))
diff --git a/node_modules/vue-router/LICENSE b/node_modules/vue-router/LICENSE
new file mode 100644
index 0000000..888e2cc
--- /dev/null
+++ b/node_modules/vue-router/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2013-present Evan You
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/vue-router/README.md b/node_modules/vue-router/README.md
new file mode 100644
index 0000000..b375363
--- /dev/null
+++ b/node_modules/vue-router/README.md
@@ -0,0 +1,82 @@
+# vue-router [](https://circleci.com/gh/vuejs/vue-router)
+
+> This is vue-router 3.0 which works only with Vue 2.0. For the 1.x router see the [1.0 branch](https://github.com/vuejs/vue-router/tree/1.0).
+
+### Introduction
+
+`vue-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:
+
+- Nested route/view mapping
+- Modular, component-based router configuration
+- Route params, query, wildcards
+- View transition effects powered by Vue.js' transition system
+- Fine-grained navigation control
+- Links with automatic active CSS classes
+- HTML5 history mode or hash mode, with auto-fallback in IE9
+- Customizable Scroll Behavior
+
+Get started with the [documentation](http://router.vuejs.org), or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see how to run them below).
+
+### Development Setup
+
+``` bash
+# install deps
+npm install
+
+# build dist files
+npm run build
+
+# serve examples at localhost:8080
+npm run dev
+
+# lint & run all tests
+npm test
+
+# serve docs at localhost:8080
+npm run docs
+```
+
+## Releasing
+
+- `yarn run release`
+ - Ensure tests are passing `yarn run test`
+ - Build dist files `VERSION= yarn run build`
+ - Build changelog `yarn run changelog`
+ - Commit dist files `git add dist CHANGELOG.md && git commit -m "[build $VERSION]"`
+ - Publish a new version `npm version $VERSION --message "[release] $VERSION"
+ - Push tags `git push origin refs/tags/v$VERSION && git push`
+ - Publish to npm `npm publish`
+
+## Questions
+
+For 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.
+
+## Issues
+
+Please 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.
+
+## Contribution
+
+Please make sure to read the [Contributing Guide](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md) before making a pull request.
+
+## Changelog
+
+Details changes for each release are documented in the [release notes](https://github.com/vuejs/vue-router/releases).
+
+## Stay In Touch
+
+- For latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs)
+
+## License
+
+[MIT](http://opensource.org/licenses/MIT)
+
+Copyright (c) 2013-present Evan You
+
+## Special Thanks
+
+
+
+
+
+Special thanks to [BrowserStack](https://www.browserstack.com) for letting the maintainers use their service to debug browser specific issues.
diff --git a/node_modules/vue-router/dist/vue-router.common.js b/node_modules/vue-router/dist/vue-router.common.js
new file mode 100644
index 0000000..4825f4c
--- /dev/null
+++ b/node_modules/vue-router/dist/vue-router.common.js
@@ -0,0 +1,2884 @@
+/*!
+ * vue-router v3.1.3
+ * (c) 2019 Evan You
+ * @license MIT
+ */
+'use strict';
+
+/* */
+
+function assert (condition, message) {
+ if (!condition) {
+ throw new Error(("[vue-router] " + message))
+ }
+}
+
+function warn (condition, message) {
+ if (process.env.NODE_ENV !== 'production' && !condition) {
+ typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
+ }
+}
+
+function isError (err) {
+ return Object.prototype.toString.call(err).indexOf('Error') > -1
+}
+
+function isExtendedError (constructor, err) {
+ return (
+ err instanceof constructor ||
+ // _name is to support IE9 too
+ (err && (err.name === constructor.name || err._name === constructor._name))
+ )
+}
+
+function extend (a, b) {
+ for (var key in b) {
+ a[key] = b[key];
+ }
+ return a
+}
+
+var View = {
+ name: 'RouterView',
+ functional: true,
+ props: {
+ name: {
+ type: String,
+ default: 'default'
+ }
+ },
+ render: function render (_, ref) {
+ var props = ref.props;
+ var children = ref.children;
+ var parent = ref.parent;
+ var data = ref.data;
+
+ // used by devtools to display a router-view badge
+ data.routerView = true;
+
+ // directly use parent context's createElement() function
+ // so that components rendered by router-view can resolve named slots
+ var h = parent.$createElement;
+ var name = props.name;
+ var route = parent.$route;
+ var cache = parent._routerViewCache || (parent._routerViewCache = {});
+
+ // determine current view depth, also check to see if the tree
+ // has been toggled inactive but kept-alive.
+ var depth = 0;
+ var inactive = false;
+ while (parent && parent._routerRoot !== parent) {
+ var vnodeData = parent.$vnode && parent.$vnode.data;
+ if (vnodeData) {
+ if (vnodeData.routerView) {
+ depth++;
+ }
+ if (vnodeData.keepAlive && parent._inactive) {
+ inactive = true;
+ }
+ }
+ parent = parent.$parent;
+ }
+ data.routerViewDepth = depth;
+
+ // render previous view if the tree is inactive and kept-alive
+ if (inactive) {
+ return h(cache[name], data, children)
+ }
+
+ var matched = route.matched[depth];
+ // render empty node if no matched route
+ if (!matched) {
+ cache[name] = null;
+ return h()
+ }
+
+ var component = cache[name] = matched.components[name];
+
+ // attach instance registration hook
+ // this will be called in the instance's injected lifecycle hooks
+ data.registerRouteInstance = function (vm, val) {
+ // val could be undefined for unregistration
+ var current = matched.instances[name];
+ if (
+ (val && current !== vm) ||
+ (!val && current === vm)
+ ) {
+ matched.instances[name] = val;
+ }
+ }
+
+ // also register instance in prepatch hook
+ // in case the same component instance is reused across different routes
+ ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
+ matched.instances[name] = vnode.componentInstance;
+ };
+
+ // register instance in init hook
+ // in case kept-alive component be actived when routes changed
+ data.hook.init = function (vnode) {
+ if (vnode.data.keepAlive &&
+ vnode.componentInstance &&
+ vnode.componentInstance !== matched.instances[name]
+ ) {
+ matched.instances[name] = vnode.componentInstance;
+ }
+ };
+
+ // resolve props
+ var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
+ if (propsToPass) {
+ // clone to prevent mutation
+ propsToPass = data.props = extend({}, propsToPass);
+ // pass non-declared props as attrs
+ var attrs = data.attrs = data.attrs || {};
+ for (var key in propsToPass) {
+ if (!component.props || !(key in component.props)) {
+ attrs[key] = propsToPass[key];
+ delete propsToPass[key];
+ }
+ }
+ }
+
+ return h(component, data, children)
+ }
+};
+
+function resolveProps (route, config) {
+ switch (typeof config) {
+ case 'undefined':
+ return
+ case 'object':
+ return config
+ case 'function':
+ return config(route)
+ case 'boolean':
+ return config ? route.params : undefined
+ default:
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false,
+ "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " +
+ "expecting an object, function or boolean."
+ );
+ }
+ }
+}
+
+/* */
+
+var encodeReserveRE = /[!'()*]/g;
+var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
+var commaRE = /%2C/g;
+
+// fixed encodeURIComponent which is more conformant to RFC3986:
+// - escapes [!'()*]
+// - preserve commas
+var encode = function (str) { return encodeURIComponent(str)
+ .replace(encodeReserveRE, encodeReserveReplacer)
+ .replace(commaRE, ','); };
+
+var decode = decodeURIComponent;
+
+function resolveQuery (
+ query,
+ extraQuery,
+ _parseQuery
+) {
+ if ( extraQuery === void 0 ) extraQuery = {};
+
+ var parse = _parseQuery || parseQuery;
+ var parsedQuery;
+ try {
+ parsedQuery = parse(query || '');
+ } catch (e) {
+ process.env.NODE_ENV !== 'production' && warn(false, e.message);
+ parsedQuery = {};
+ }
+ for (var key in extraQuery) {
+ parsedQuery[key] = extraQuery[key];
+ }
+ return parsedQuery
+}
+
+function parseQuery (query) {
+ var res = {};
+
+ query = query.trim().replace(/^(\?|#|&)/, '');
+
+ if (!query) {
+ return res
+ }
+
+ query.split('&').forEach(function (param) {
+ var parts = param.replace(/\+/g, ' ').split('=');
+ var key = decode(parts.shift());
+ var val = parts.length > 0
+ ? decode(parts.join('='))
+ : null;
+
+ if (res[key] === undefined) {
+ res[key] = val;
+ } else if (Array.isArray(res[key])) {
+ res[key].push(val);
+ } else {
+ res[key] = [res[key], val];
+ }
+ });
+
+ return res
+}
+
+function stringifyQuery (obj) {
+ var res = obj ? Object.keys(obj).map(function (key) {
+ var val = obj[key];
+
+ if (val === undefined) {
+ return ''
+ }
+
+ if (val === null) {
+ return encode(key)
+ }
+
+ if (Array.isArray(val)) {
+ var result = [];
+ val.forEach(function (val2) {
+ if (val2 === undefined) {
+ return
+ }
+ if (val2 === null) {
+ result.push(encode(key));
+ } else {
+ result.push(encode(key) + '=' + encode(val2));
+ }
+ });
+ return result.join('&')
+ }
+
+ return encode(key) + '=' + encode(val)
+ }).filter(function (x) { return x.length > 0; }).join('&') : null;
+ return res ? ("?" + res) : ''
+}
+
+/* */
+
+var trailingSlashRE = /\/?$/;
+
+function createRoute (
+ record,
+ location,
+ redirectedFrom,
+ router
+) {
+ var stringifyQuery = router && router.options.stringifyQuery;
+
+ var query = location.query || {};
+ try {
+ query = clone(query);
+ } catch (e) {}
+
+ var route = {
+ name: location.name || (record && record.name),
+ meta: (record && record.meta) || {},
+ path: location.path || '/',
+ hash: location.hash || '',
+ query: query,
+ params: location.params || {},
+ fullPath: getFullPath(location, stringifyQuery),
+ matched: record ? formatMatch(record) : []
+ };
+ if (redirectedFrom) {
+ route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);
+ }
+ return Object.freeze(route)
+}
+
+function clone (value) {
+ if (Array.isArray(value)) {
+ return value.map(clone)
+ } else if (value && typeof value === 'object') {
+ var res = {};
+ for (var key in value) {
+ res[key] = clone(value[key]);
+ }
+ return res
+ } else {
+ return value
+ }
+}
+
+// the starting route that represents the initial state
+var START = createRoute(null, {
+ path: '/'
+});
+
+function formatMatch (record) {
+ var res = [];
+ while (record) {
+ res.unshift(record);
+ record = record.parent;
+ }
+ return res
+}
+
+function getFullPath (
+ ref,
+ _stringifyQuery
+) {
+ var path = ref.path;
+ var query = ref.query; if ( query === void 0 ) query = {};
+ var hash = ref.hash; if ( hash === void 0 ) hash = '';
+
+ var stringify = _stringifyQuery || stringifyQuery;
+ return (path || '/') + stringify(query) + hash
+}
+
+function isSameRoute (a, b) {
+ if (b === START) {
+ return a === b
+ } else if (!b) {
+ return false
+ } else if (a.path && b.path) {
+ return (
+ a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query)
+ )
+ } else if (a.name && b.name) {
+ return (
+ a.name === b.name &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query) &&
+ isObjectEqual(a.params, b.params)
+ )
+ } else {
+ return false
+ }
+}
+
+function isObjectEqual (a, b) {
+ if ( a === void 0 ) a = {};
+ if ( b === void 0 ) b = {};
+
+ // handle null value #1566
+ if (!a || !b) { return a === b }
+ var aKeys = Object.keys(a);
+ var bKeys = Object.keys(b);
+ if (aKeys.length !== bKeys.length) {
+ return false
+ }
+ return aKeys.every(function (key) {
+ var aVal = a[key];
+ var bVal = b[key];
+ // check nested equality
+ if (typeof aVal === 'object' && typeof bVal === 'object') {
+ return isObjectEqual(aVal, bVal)
+ }
+ return String(aVal) === String(bVal)
+ })
+}
+
+function isIncludedRoute (current, target) {
+ return (
+ current.path.replace(trailingSlashRE, '/').indexOf(
+ target.path.replace(trailingSlashRE, '/')
+ ) === 0 &&
+ (!target.hash || current.hash === target.hash) &&
+ queryIncludes(current.query, target.query)
+ )
+}
+
+function queryIncludes (current, target) {
+ for (var key in target) {
+ if (!(key in current)) {
+ return false
+ }
+ }
+ return true
+}
+
+/* */
+
+function resolvePath (
+ relative,
+ base,
+ append
+) {
+ var firstChar = relative.charAt(0);
+ if (firstChar === '/') {
+ return relative
+ }
+
+ if (firstChar === '?' || firstChar === '#') {
+ return base + relative
+ }
+
+ var stack = base.split('/');
+
+ // remove trailing segment if:
+ // - not appending
+ // - appending to trailing slash (last segment is empty)
+ if (!append || !stack[stack.length - 1]) {
+ stack.pop();
+ }
+
+ // resolve relative path
+ var segments = relative.replace(/^\//, '').split('/');
+ for (var i = 0; i < segments.length; i++) {
+ var segment = segments[i];
+ if (segment === '..') {
+ stack.pop();
+ } else if (segment !== '.') {
+ stack.push(segment);
+ }
+ }
+
+ // ensure leading slash
+ if (stack[0] !== '') {
+ stack.unshift('');
+ }
+
+ return stack.join('/')
+}
+
+function parsePath (path) {
+ var hash = '';
+ var query = '';
+
+ var hashIndex = path.indexOf('#');
+ if (hashIndex >= 0) {
+ hash = path.slice(hashIndex);
+ path = path.slice(0, hashIndex);
+ }
+
+ var queryIndex = path.indexOf('?');
+ if (queryIndex >= 0) {
+ query = path.slice(queryIndex + 1);
+ path = path.slice(0, queryIndex);
+ }
+
+ return {
+ path: path,
+ query: query,
+ hash: hash
+ }
+}
+
+function cleanPath (path) {
+ return path.replace(/\/\//g, '/')
+}
+
+var isarray = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Expose `pathToRegexp`.
+ */
+var pathToRegexp_1 = pathToRegexp;
+var parse_1 = parse;
+var compile_1 = compile;
+var tokensToFunction_1 = tokensToFunction;
+var tokensToRegExp_1 = tokensToRegExp;
+
+/**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+var PATH_REGEXP = new RegExp([
+ // Match escaped characters that would otherwise appear in future matches.
+ // This allows the user to escape special characters that won't transform.
+ '(\\\\.)',
+ // Match Express-style parameters and un-named parameters with a prefix
+ // and optional suffixes. Matches appear as:
+ //
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
+].join('|'), 'g');
+
+/**
+ * Parse a string for the raw tokens.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!Array}
+ */
+function parse (str, options) {
+ var tokens = [];
+ var key = 0;
+ var index = 0;
+ var path = '';
+ var defaultDelimiter = options && options.delimiter || '/';
+ var res;
+
+ while ((res = PATH_REGEXP.exec(str)) != null) {
+ var m = res[0];
+ var escaped = res[1];
+ var offset = res.index;
+ path += str.slice(index, offset);
+ index = offset + m.length;
+
+ // Ignore already escaped sequences.
+ if (escaped) {
+ path += escaped[1];
+ continue
+ }
+
+ var next = str[index];
+ var prefix = res[2];
+ var name = res[3];
+ var capture = res[4];
+ var group = res[5];
+ var modifier = res[6];
+ var asterisk = res[7];
+
+ // Push the current path onto the tokens.
+ if (path) {
+ tokens.push(path);
+ path = '';
+ }
+
+ var partial = prefix != null && next != null && next !== prefix;
+ var repeat = modifier === '+' || modifier === '*';
+ var optional = modifier === '?' || modifier === '*';
+ var delimiter = res[2] || defaultDelimiter;
+ var pattern = capture || group;
+
+ tokens.push({
+ name: name || key++,
+ prefix: prefix || '',
+ delimiter: delimiter,
+ optional: optional,
+ repeat: repeat,
+ partial: partial,
+ asterisk: !!asterisk,
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
+ });
+ }
+
+ // Match any characters still remaining.
+ if (index < str.length) {
+ path += str.substr(index);
+ }
+
+ // If the path exists, push it onto the end.
+ if (path) {
+ tokens.push(path);
+ }
+
+ return tokens
+}
+
+/**
+ * Compile a string to a template function for the path.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!function(Object=, Object=)}
+ */
+function compile (str, options) {
+ return tokensToFunction(parse(str, options))
+}
+
+/**
+ * Prettier encoding of URI path segments.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeURIComponentPretty (str) {
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeAsterisk (str) {
+ return encodeURI(str).replace(/[?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Expose a method for transforming tokens into the path function.
+ */
+function tokensToFunction (tokens) {
+ // Compile all the tokens into regexps.
+ var matches = new Array(tokens.length);
+
+ // Compile all the patterns before compilation.
+ for (var i = 0; i < tokens.length; i++) {
+ if (typeof tokens[i] === 'object') {
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
+ }
+ }
+
+ return function (obj, opts) {
+ var path = '';
+ var data = obj || {};
+ var options = opts || {};
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
+
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ path += token;
+
+ continue
+ }
+
+ var value = data[token.name];
+ var segment;
+
+ if (value == null) {
+ if (token.optional) {
+ // Prepend partial segment prefixes.
+ if (token.partial) {
+ path += token.prefix;
+ }
+
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to be defined')
+ }
+ }
+
+ if (isarray(value)) {
+ if (!token.repeat) {
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
+ }
+
+ if (value.length === 0) {
+ if (token.optional) {
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
+ }
+ }
+
+ for (var j = 0; j < value.length; j++) {
+ segment = encode(value[j]);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
+ }
+
+ path += (j === 0 ? token.prefix : token.delimiter) + segment;
+ }
+
+ continue
+ }
+
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
+ }
+
+ path += token.prefix + segment;
+ }
+
+ return path
+ }
+}
+
+/**
+ * Escape a regular expression string.
+ *
+ * @param {string} str
+ * @return {string}
+ */
+function escapeString (str) {
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
+}
+
+/**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param {string} group
+ * @return {string}
+ */
+function escapeGroup (group) {
+ return group.replace(/([=!:$\/()])/g, '\\$1')
+}
+
+/**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param {!RegExp} re
+ * @param {Array} keys
+ * @return {!RegExp}
+ */
+function attachKeys (re, keys) {
+ re.keys = keys;
+ return re
+}
+
+/**
+ * Get the flags for a regexp from the options.
+ *
+ * @param {Object} options
+ * @return {string}
+ */
+function flags (options) {
+ return options.sensitive ? '' : 'i'
+}
+
+/**
+ * Pull out keys from a regexp.
+ *
+ * @param {!RegExp} path
+ * @param {!Array} keys
+ * @return {!RegExp}
+ */
+function regexpToRegexp (path, keys) {
+ // Use a negative lookahead to match only capturing groups.
+ var groups = path.source.match(/\((?!\?)/g);
+
+ if (groups) {
+ for (var i = 0; i < groups.length; i++) {
+ keys.push({
+ name: i,
+ prefix: null,
+ delimiter: null,
+ optional: false,
+ repeat: false,
+ partial: false,
+ asterisk: false,
+ pattern: null
+ });
+ }
+ }
+
+ return attachKeys(path, keys)
+}
+
+/**
+ * Transform an array into a regexp.
+ *
+ * @param {!Array} path
+ * @param {Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function arrayToRegexp (path, keys, options) {
+ var parts = [];
+
+ for (var i = 0; i < path.length; i++) {
+ parts.push(pathToRegexp(path[i], keys, options).source);
+ }
+
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
+
+ return attachKeys(regexp, keys)
+}
+
+/**
+ * Create a path regexp from string input.
+ *
+ * @param {string} path
+ * @param {!Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function stringToRegexp (path, keys, options) {
+ return tokensToRegExp(parse(path, options), keys, options)
+}
+
+/**
+ * Expose a function for taking tokens and returning a RegExp.
+ *
+ * @param {!Array} tokens
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function tokensToRegExp (tokens, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ var strict = options.strict;
+ var end = options.end !== false;
+ var route = '';
+
+ // Iterate over the tokens and create our regexp string.
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ route += escapeString(token);
+ } else {
+ var prefix = escapeString(token.prefix);
+ var capture = '(?:' + token.pattern + ')';
+
+ keys.push(token);
+
+ if (token.repeat) {
+ capture += '(?:' + prefix + capture + ')*';
+ }
+
+ if (token.optional) {
+ if (!token.partial) {
+ capture = '(?:' + prefix + '(' + capture + '))?';
+ } else {
+ capture = prefix + '(' + capture + ')?';
+ }
+ } else {
+ capture = prefix + '(' + capture + ')';
+ }
+
+ route += capture;
+ }
+ }
+
+ var delimiter = escapeString(options.delimiter || '/');
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
+
+ // In non-strict mode we allow a slash at the end of match. If the path to
+ // match already ends with a slash, we remove it for consistency. The slash
+ // is valid at the end of a path match, not in the middle. This is important
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
+ if (!strict) {
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
+ }
+
+ if (end) {
+ route += '$';
+ } else {
+ // In non-ending mode, we need the capturing groups to match as much as
+ // possible by using a positive lookahead to the end or next path segment.
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
+ }
+
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
+}
+
+/**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param {(string|RegExp|Array)} path
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function pathToRegexp (path, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ if (path instanceof RegExp) {
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
+ }
+
+ if (isarray(path)) {
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
+ }
+
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
+}
+pathToRegexp_1.parse = parse_1;
+pathToRegexp_1.compile = compile_1;
+pathToRegexp_1.tokensToFunction = tokensToFunction_1;
+pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
+
+/* */
+
+// $flow-disable-line
+var regexpCompileCache = Object.create(null);
+
+function fillParams (
+ path,
+ params,
+ routeMsg
+) {
+ params = params || {};
+ try {
+ var filler =
+ regexpCompileCache[path] ||
+ (regexpCompileCache[path] = pathToRegexp_1.compile(path));
+
+ // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
+ if (params.pathMatch) { params[0] = params.pathMatch; }
+
+ return filler(params, { pretty: true })
+ } catch (e) {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
+ }
+ return ''
+ } finally {
+ // delete the 0 if it was added
+ delete params[0];
+ }
+}
+
+/* */
+
+function normalizeLocation (
+ raw,
+ current,
+ append,
+ router
+) {
+ var next = typeof raw === 'string' ? { path: raw } : raw;
+ // named target
+ if (next._normalized) {
+ return next
+ } else if (next.name) {
+ return extend({}, raw)
+ }
+
+ // relative params
+ if (!next.path && next.params && current) {
+ next = extend({}, next);
+ next._normalized = true;
+ var params = extend(extend({}, current.params), next.params);
+ if (current.name) {
+ next.name = current.name;
+ next.params = params;
+ } else if (current.matched.length) {
+ var rawPath = current.matched[current.matched.length - 1].path;
+ next.path = fillParams(rawPath, params, ("path " + (current.path)));
+ } else if (process.env.NODE_ENV !== 'production') {
+ warn(false, "relative params navigation requires a current route.");
+ }
+ return next
+ }
+
+ var parsedPath = parsePath(next.path || '');
+ var basePath = (current && current.path) || '/';
+ var path = parsedPath.path
+ ? resolvePath(parsedPath.path, basePath, append || next.append)
+ : basePath;
+
+ var query = resolveQuery(
+ parsedPath.query,
+ next.query,
+ router && router.options.parseQuery
+ );
+
+ var hash = next.hash || parsedPath.hash;
+ if (hash && hash.charAt(0) !== '#') {
+ hash = "#" + hash;
+ }
+
+ return {
+ _normalized: true,
+ path: path,
+ query: query,
+ hash: hash
+ }
+}
+
+/* */
+
+// work around weird flow bug
+var toTypes = [String, Object];
+var eventTypes = [String, Array];
+
+var noop = function () {};
+
+var Link = {
+ name: 'RouterLink',
+ props: {
+ to: {
+ type: toTypes,
+ required: true
+ },
+ tag: {
+ type: String,
+ default: 'a'
+ },
+ exact: Boolean,
+ append: Boolean,
+ replace: Boolean,
+ activeClass: String,
+ exactActiveClass: String,
+ event: {
+ type: eventTypes,
+ default: 'click'
+ }
+ },
+ render: function render (h) {
+ var this$1 = this;
+
+ var router = this.$router;
+ var current = this.$route;
+ var ref = router.resolve(
+ this.to,
+ current,
+ this.append
+ );
+ var location = ref.location;
+ var route = ref.route;
+ var href = ref.href;
+
+ var classes = {};
+ var globalActiveClass = router.options.linkActiveClass;
+ var globalExactActiveClass = router.options.linkExactActiveClass;
+ // Support global empty active class
+ var activeClassFallback =
+ globalActiveClass == null ? 'router-link-active' : globalActiveClass;
+ var exactActiveClassFallback =
+ globalExactActiveClass == null
+ ? 'router-link-exact-active'
+ : globalExactActiveClass;
+ var activeClass =
+ this.activeClass == null ? activeClassFallback : this.activeClass;
+ var exactActiveClass =
+ this.exactActiveClass == null
+ ? exactActiveClassFallback
+ : this.exactActiveClass;
+
+ var compareTarget = route.redirectedFrom
+ ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)
+ : route;
+
+ classes[exactActiveClass] = isSameRoute(current, compareTarget);
+ classes[activeClass] = this.exact
+ ? classes[exactActiveClass]
+ : isIncludedRoute(current, compareTarget);
+
+ var handler = function (e) {
+ if (guardEvent(e)) {
+ if (this$1.replace) {
+ router.replace(location, noop);
+ } else {
+ router.push(location, noop);
+ }
+ }
+ };
+
+ var on = { click: guardEvent };
+ if (Array.isArray(this.event)) {
+ this.event.forEach(function (e) {
+ on[e] = handler;
+ });
+ } else {
+ on[this.event] = handler;
+ }
+
+ var data = { class: classes };
+
+ var scopedSlot =
+ !this.$scopedSlots.$hasNormal &&
+ this.$scopedSlots.default &&
+ this.$scopedSlots.default({
+ href: href,
+ route: route,
+ navigate: handler,
+ isActive: classes[activeClass],
+ isExactActive: classes[exactActiveClass]
+ });
+
+ if (scopedSlot) {
+ if (scopedSlot.length === 1) {
+ return scopedSlot[0]
+ } else if (scopedSlot.length > 1 || !scopedSlot.length) {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false,
+ ("RouterLink with to=\"" + (this.props.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child.")
+ );
+ }
+ return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)
+ }
+ }
+
+ if (this.tag === 'a') {
+ data.on = on;
+ data.attrs = { href: href };
+ } else {
+ // find the first child and apply listener and href
+ var a = findAnchor(this.$slots.default);
+ if (a) {
+ // in case the is a static node
+ a.isStatic = false;
+ var aData = (a.data = extend({}, a.data));
+ aData.on = aData.on || {};
+ // transform existing events in both objects into arrays so we can push later
+ for (var event in aData.on) {
+ var handler$1 = aData.on[event];
+ if (event in on) {
+ aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];
+ }
+ }
+ // append new listeners for router-link
+ for (var event$1 in on) {
+ if (event$1 in aData.on) {
+ // on[event] is always a function
+ aData.on[event$1].push(on[event$1]);
+ } else {
+ aData.on[event$1] = handler;
+ }
+ }
+
+ var aAttrs = (a.data.attrs = extend({}, a.data.attrs));
+ aAttrs.href = href;
+ } else {
+ // doesn't have child, apply listener to self
+ data.on = on;
+ }
+ }
+
+ return h(this.tag, data, this.$slots.default)
+ }
+};
+
+function guardEvent (e) {
+ // don't redirect with control keys
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
+ // don't redirect when preventDefault called
+ if (e.defaultPrevented) { return }
+ // don't redirect on right click
+ if (e.button !== undefined && e.button !== 0) { return }
+ // don't redirect if `target="_blank"`
+ if (e.currentTarget && e.currentTarget.getAttribute) {
+ var target = e.currentTarget.getAttribute('target');
+ if (/\b_blank\b/i.test(target)) { return }
+ }
+ // this may be a Weex event which doesn't have this method
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ return true
+}
+
+function findAnchor (children) {
+ if (children) {
+ var child;
+ for (var i = 0; i < children.length; i++) {
+ child = children[i];
+ if (child.tag === 'a') {
+ return child
+ }
+ if (child.children && (child = findAnchor(child.children))) {
+ return child
+ }
+ }
+ }
+}
+
+var _Vue;
+
+function install (Vue) {
+ if (install.installed && _Vue === Vue) { return }
+ install.installed = true;
+
+ _Vue = Vue;
+
+ var isDef = function (v) { return v !== undefined; };
+
+ var registerInstance = function (vm, callVal) {
+ var i = vm.$options._parentVnode;
+ if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
+ i(vm, callVal);
+ }
+ };
+
+ Vue.mixin({
+ beforeCreate: function beforeCreate () {
+ if (isDef(this.$options.router)) {
+ this._routerRoot = this;
+ this._router = this.$options.router;
+ this._router.init(this);
+ Vue.util.defineReactive(this, '_route', this._router.history.current);
+ } else {
+ this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
+ }
+ registerInstance(this, this);
+ },
+ destroyed: function destroyed () {
+ registerInstance(this);
+ }
+ });
+
+ Object.defineProperty(Vue.prototype, '$router', {
+ get: function get () { return this._routerRoot._router }
+ });
+
+ Object.defineProperty(Vue.prototype, '$route', {
+ get: function get () { return this._routerRoot._route }
+ });
+
+ Vue.component('RouterView', View);
+ Vue.component('RouterLink', Link);
+
+ var strats = Vue.config.optionMergeStrategies;
+ // use the same hook merging strategy for route hooks
+ strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
+}
+
+/* */
+
+var inBrowser = typeof window !== 'undefined';
+
+/* */
+
+function createRouteMap (
+ routes,
+ oldPathList,
+ oldPathMap,
+ oldNameMap
+) {
+ // the path list is used to control path matching priority
+ var pathList = oldPathList || [];
+ // $flow-disable-line
+ var pathMap = oldPathMap || Object.create(null);
+ // $flow-disable-line
+ var nameMap = oldNameMap || Object.create(null);
+
+ routes.forEach(function (route) {
+ addRouteRecord(pathList, pathMap, nameMap, route);
+ });
+
+ // ensure wildcard routes are always at the end
+ for (var i = 0, l = pathList.length; i < l; i++) {
+ if (pathList[i] === '*') {
+ pathList.push(pathList.splice(i, 1)[0]);
+ l--;
+ i--;
+ }
+ }
+
+ if (process.env.NODE_ENV === 'development') {
+ // warn if routes do not include leading slashes
+ var found = pathList
+ // check for missing leading slash
+ .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });
+
+ if (found.length > 0) {
+ var pathNames = found.map(function (path) { return ("- " + path); }).join('\n');
+ warn(false, ("Non-nested routes must include a leading slash character. Fix the following routes: \n" + pathNames));
+ }
+ }
+
+ return {
+ pathList: pathList,
+ pathMap: pathMap,
+ nameMap: nameMap
+ }
+}
+
+function addRouteRecord (
+ pathList,
+ pathMap,
+ nameMap,
+ route,
+ parent,
+ matchAs
+) {
+ var path = route.path;
+ var name = route.name;
+ if (process.env.NODE_ENV !== 'production') {
+ assert(path != null, "\"path\" is required in a route configuration.");
+ assert(
+ typeof route.component !== 'string',
+ "route config \"component\" for path: " + (String(
+ path || name
+ )) + " cannot be a " + "string id. Use an actual component instead."
+ );
+ }
+
+ var pathToRegexpOptions =
+ route.pathToRegexpOptions || {};
+ var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);
+
+ if (typeof route.caseSensitive === 'boolean') {
+ pathToRegexpOptions.sensitive = route.caseSensitive;
+ }
+
+ var record = {
+ path: normalizedPath,
+ regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
+ components: route.components || { default: route.component },
+ instances: {},
+ name: name,
+ parent: parent,
+ matchAs: matchAs,
+ redirect: route.redirect,
+ beforeEnter: route.beforeEnter,
+ meta: route.meta || {},
+ props:
+ route.props == null
+ ? {}
+ : route.components
+ ? route.props
+ : { default: route.props }
+ };
+
+ if (route.children) {
+ // Warn if route is named, does not redirect and has a default child route.
+ // If users navigate to this route by name, the default child will
+ // not be rendered (GH Issue #629)
+ if (process.env.NODE_ENV !== 'production') {
+ if (
+ route.name &&
+ !route.redirect &&
+ route.children.some(function (child) { return /^\/?$/.test(child.path); })
+ ) {
+ warn(
+ false,
+ "Named Route '" + (route.name) + "' has a default child route. " +
+ "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
+ "the default child route will not be rendered. Remove the name from " +
+ "this route and use the name of the default child route for named " +
+ "links instead."
+ );
+ }
+ }
+ route.children.forEach(function (child) {
+ var childMatchAs = matchAs
+ ? cleanPath((matchAs + "/" + (child.path)))
+ : undefined;
+ addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
+ });
+ }
+
+ if (!pathMap[record.path]) {
+ pathList.push(record.path);
+ pathMap[record.path] = record;
+ }
+
+ if (route.alias !== undefined) {
+ var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];
+ for (var i = 0; i < aliases.length; ++i) {
+ var alias = aliases[i];
+ if (process.env.NODE_ENV !== 'production' && alias === path) {
+ warn(
+ false,
+ ("Found an alias with the same value as the path: \"" + path + "\". You have to remove that alias. It will be ignored in development.")
+ );
+ // skip in dev to make it work
+ continue
+ }
+
+ var aliasRoute = {
+ path: alias,
+ children: route.children
+ };
+ addRouteRecord(
+ pathList,
+ pathMap,
+ nameMap,
+ aliasRoute,
+ parent,
+ record.path || '/' // matchAs
+ );
+ }
+ }
+
+ if (name) {
+ if (!nameMap[name]) {
+ nameMap[name] = record;
+ } else if (process.env.NODE_ENV !== 'production' && !matchAs) {
+ warn(
+ false,
+ "Duplicate named routes definition: " +
+ "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
+ );
+ }
+ }
+}
+
+function compileRouteRegex (
+ path,
+ pathToRegexpOptions
+) {
+ var regex = pathToRegexp_1(path, [], pathToRegexpOptions);
+ if (process.env.NODE_ENV !== 'production') {
+ var keys = Object.create(null);
+ regex.keys.forEach(function (key) {
+ warn(
+ !keys[key.name],
+ ("Duplicate param keys in route with path: \"" + path + "\"")
+ );
+ keys[key.name] = true;
+ });
+ }
+ return regex
+}
+
+function normalizePath (
+ path,
+ parent,
+ strict
+) {
+ if (!strict) { path = path.replace(/\/$/, ''); }
+ if (path[0] === '/') { return path }
+ if (parent == null) { return path }
+ return cleanPath(((parent.path) + "/" + path))
+}
+
+/* */
+
+
+
+function createMatcher (
+ routes,
+ router
+) {
+ var ref = createRouteMap(routes);
+ var pathList = ref.pathList;
+ var pathMap = ref.pathMap;
+ var nameMap = ref.nameMap;
+
+ function addRoutes (routes) {
+ createRouteMap(routes, pathList, pathMap, nameMap);
+ }
+
+ function match (
+ raw,
+ currentRoute,
+ redirectedFrom
+ ) {
+ var location = normalizeLocation(raw, currentRoute, false, router);
+ var name = location.name;
+
+ if (name) {
+ var record = nameMap[name];
+ if (process.env.NODE_ENV !== 'production') {
+ warn(record, ("Route with name '" + name + "' does not exist"));
+ }
+ if (!record) { return _createRoute(null, location) }
+ var paramNames = record.regex.keys
+ .filter(function (key) { return !key.optional; })
+ .map(function (key) { return key.name; });
+
+ if (typeof location.params !== 'object') {
+ location.params = {};
+ }
+
+ if (currentRoute && typeof currentRoute.params === 'object') {
+ for (var key in currentRoute.params) {
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
+ location.params[key] = currentRoute.params[key];
+ }
+ }
+ }
+
+ location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
+ return _createRoute(record, location, redirectedFrom)
+ } else if (location.path) {
+ location.params = {};
+ for (var i = 0; i < pathList.length; i++) {
+ var path = pathList[i];
+ var record$1 = pathMap[path];
+ if (matchRoute(record$1.regex, location.path, location.params)) {
+ return _createRoute(record$1, location, redirectedFrom)
+ }
+ }
+ }
+ // no match
+ return _createRoute(null, location)
+ }
+
+ function redirect (
+ record,
+ location
+ ) {
+ var originalRedirect = record.redirect;
+ var redirect = typeof originalRedirect === 'function'
+ ? originalRedirect(createRoute(record, location, null, router))
+ : originalRedirect;
+
+ if (typeof redirect === 'string') {
+ redirect = { path: redirect };
+ }
+
+ if (!redirect || typeof redirect !== 'object') {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false, ("invalid redirect option: " + (JSON.stringify(redirect)))
+ );
+ }
+ return _createRoute(null, location)
+ }
+
+ var re = redirect;
+ var name = re.name;
+ var path = re.path;
+ var query = location.query;
+ var hash = location.hash;
+ var params = location.params;
+ query = re.hasOwnProperty('query') ? re.query : query;
+ hash = re.hasOwnProperty('hash') ? re.hash : hash;
+ params = re.hasOwnProperty('params') ? re.params : params;
+
+ if (name) {
+ // resolved named direct
+ var targetRecord = nameMap[name];
+ if (process.env.NODE_ENV !== 'production') {
+ assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
+ }
+ return match({
+ _normalized: true,
+ name: name,
+ query: query,
+ hash: hash,
+ params: params
+ }, undefined, location)
+ } else if (path) {
+ // 1. resolve relative redirect
+ var rawPath = resolveRecordPath(path, record);
+ // 2. resolve params
+ var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
+ // 3. rematch with existing query and hash
+ return match({
+ _normalized: true,
+ path: resolvedPath,
+ query: query,
+ hash: hash
+ }, undefined, location)
+ } else {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
+ }
+ return _createRoute(null, location)
+ }
+ }
+
+ function alias (
+ record,
+ location,
+ matchAs
+ ) {
+ var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
+ var aliasedMatch = match({
+ _normalized: true,
+ path: aliasedPath
+ });
+ if (aliasedMatch) {
+ var matched = aliasedMatch.matched;
+ var aliasedRecord = matched[matched.length - 1];
+ location.params = aliasedMatch.params;
+ return _createRoute(aliasedRecord, location)
+ }
+ return _createRoute(null, location)
+ }
+
+ function _createRoute (
+ record,
+ location,
+ redirectedFrom
+ ) {
+ if (record && record.redirect) {
+ return redirect(record, redirectedFrom || location)
+ }
+ if (record && record.matchAs) {
+ return alias(record, location, record.matchAs)
+ }
+ return createRoute(record, location, redirectedFrom, router)
+ }
+
+ return {
+ match: match,
+ addRoutes: addRoutes
+ }
+}
+
+function matchRoute (
+ regex,
+ path,
+ params
+) {
+ var m = path.match(regex);
+
+ if (!m) {
+ return false
+ } else if (!params) {
+ return true
+ }
+
+ for (var i = 1, len = m.length; i < len; ++i) {
+ var key = regex.keys[i - 1];
+ var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
+ if (key) {
+ // Fix #1994: using * with props: true generates a param named 0
+ params[key.name || 'pathMatch'] = val;
+ }
+ }
+
+ return true
+}
+
+function resolveRecordPath (path, record) {
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
+}
+
+/* */
+
+// use User Timing api (if present) for more accurate key precision
+var Time =
+ inBrowser && window.performance && window.performance.now
+ ? window.performance
+ : Date;
+
+function genStateKey () {
+ return Time.now().toFixed(3)
+}
+
+var _key = genStateKey();
+
+function getStateKey () {
+ return _key
+}
+
+function setStateKey (key) {
+ return (_key = key)
+}
+
+/* */
+
+var positionStore = Object.create(null);
+
+function setupScroll () {
+ // Fix for #1585 for Firefox
+ // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
+ // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
+ // window.location.protocol + '//' + window.location.host
+ // location.host contains the port and location.hostname doesn't
+ var protocolAndPath = window.location.protocol + '//' + window.location.host;
+ var absolutePath = window.location.href.replace(protocolAndPath, '');
+ window.history.replaceState({ key: getStateKey() }, '', absolutePath);
+ window.addEventListener('popstate', function (e) {
+ saveScrollPosition();
+ if (e.state && e.state.key) {
+ setStateKey(e.state.key);
+ }
+ });
+}
+
+function handleScroll (
+ router,
+ to,
+ from,
+ isPop
+) {
+ if (!router.app) {
+ return
+ }
+
+ var behavior = router.options.scrollBehavior;
+ if (!behavior) {
+ return
+ }
+
+ if (process.env.NODE_ENV !== 'production') {
+ assert(typeof behavior === 'function', "scrollBehavior must be a function");
+ }
+
+ // wait until re-render finishes before scrolling
+ router.app.$nextTick(function () {
+ var position = getScrollPosition();
+ var shouldScroll = behavior.call(
+ router,
+ to,
+ from,
+ isPop ? position : null
+ );
+
+ if (!shouldScroll) {
+ return
+ }
+
+ if (typeof shouldScroll.then === 'function') {
+ shouldScroll
+ .then(function (shouldScroll) {
+ scrollToPosition((shouldScroll), position);
+ })
+ .catch(function (err) {
+ if (process.env.NODE_ENV !== 'production') {
+ assert(false, err.toString());
+ }
+ });
+ } else {
+ scrollToPosition(shouldScroll, position);
+ }
+ });
+}
+
+function saveScrollPosition () {
+ var key = getStateKey();
+ if (key) {
+ positionStore[key] = {
+ x: window.pageXOffset,
+ y: window.pageYOffset
+ };
+ }
+}
+
+function getScrollPosition () {
+ var key = getStateKey();
+ if (key) {
+ return positionStore[key]
+ }
+}
+
+function getElementPosition (el, offset) {
+ var docEl = document.documentElement;
+ var docRect = docEl.getBoundingClientRect();
+ var elRect = el.getBoundingClientRect();
+ return {
+ x: elRect.left - docRect.left - offset.x,
+ y: elRect.top - docRect.top - offset.y
+ }
+}
+
+function isValidPosition (obj) {
+ return isNumber(obj.x) || isNumber(obj.y)
+}
+
+function normalizePosition (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : window.pageXOffset,
+ y: isNumber(obj.y) ? obj.y : window.pageYOffset
+ }
+}
+
+function normalizeOffset (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : 0,
+ y: isNumber(obj.y) ? obj.y : 0
+ }
+}
+
+function isNumber (v) {
+ return typeof v === 'number'
+}
+
+var hashStartsWithNumberRE = /^#\d/;
+
+function scrollToPosition (shouldScroll, position) {
+ var isObject = typeof shouldScroll === 'object';
+ if (isObject && typeof shouldScroll.selector === 'string') {
+ // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
+ // but at the same time, it doesn't make much sense to select an element with an id and an extra selector
+ var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
+ ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
+ : document.querySelector(shouldScroll.selector);
+
+ if (el) {
+ var offset =
+ shouldScroll.offset && typeof shouldScroll.offset === 'object'
+ ? shouldScroll.offset
+ : {};
+ offset = normalizeOffset(offset);
+ position = getElementPosition(el, offset);
+ } else if (isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+ } else if (isObject && isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+
+ if (position) {
+ window.scrollTo(position.x, position.y);
+ }
+}
+
+/* */
+
+var supportsPushState =
+ inBrowser &&
+ (function () {
+ var ua = window.navigator.userAgent;
+
+ if (
+ (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
+ ua.indexOf('Mobile Safari') !== -1 &&
+ ua.indexOf('Chrome') === -1 &&
+ ua.indexOf('Windows Phone') === -1
+ ) {
+ return false
+ }
+
+ return window.history && 'pushState' in window.history
+ })();
+
+function pushState (url, replace) {
+ saveScrollPosition();
+ // try...catch the pushState call to get around Safari
+ // DOM Exception 18 where it limits to 100 pushState calls
+ var history = window.history;
+ try {
+ if (replace) {
+ history.replaceState({ key: getStateKey() }, '', url);
+ } else {
+ history.pushState({ key: setStateKey(genStateKey()) }, '', url);
+ }
+ } catch (e) {
+ window.location[replace ? 'replace' : 'assign'](url);
+ }
+}
+
+function replaceState (url) {
+ pushState(url, true);
+}
+
+/* */
+
+function runQueue (queue, fn, cb) {
+ var step = function (index) {
+ if (index >= queue.length) {
+ cb();
+ } else {
+ if (queue[index]) {
+ fn(queue[index], function () {
+ step(index + 1);
+ });
+ } else {
+ step(index + 1);
+ }
+ }
+ };
+ step(0);
+}
+
+/* */
+
+function resolveAsyncComponents (matched) {
+ return function (to, from, next) {
+ var hasAsync = false;
+ var pending = 0;
+ var error = null;
+
+ flatMapComponents(matched, function (def, _, match, key) {
+ // if it's a function and doesn't have cid attached,
+ // assume it's an async component resolve function.
+ // we are not using Vue's default async resolving mechanism because
+ // we want to halt the navigation until the incoming component has been
+ // resolved.
+ if (typeof def === 'function' && def.cid === undefined) {
+ hasAsync = true;
+ pending++;
+
+ var resolve = once(function (resolvedDef) {
+ if (isESModule(resolvedDef)) {
+ resolvedDef = resolvedDef.default;
+ }
+ // save resolved on async factory in case it's used elsewhere
+ def.resolved = typeof resolvedDef === 'function'
+ ? resolvedDef
+ : _Vue.extend(resolvedDef);
+ match.components[key] = resolvedDef;
+ pending--;
+ if (pending <= 0) {
+ next();
+ }
+ });
+
+ var reject = once(function (reason) {
+ var msg = "Failed to resolve async component " + key + ": " + reason;
+ process.env.NODE_ENV !== 'production' && warn(false, msg);
+ if (!error) {
+ error = isError(reason)
+ ? reason
+ : new Error(msg);
+ next(error);
+ }
+ });
+
+ var res;
+ try {
+ res = def(resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ if (res) {
+ if (typeof res.then === 'function') {
+ res.then(resolve, reject);
+ } else {
+ // new syntax in Vue 2.3
+ var comp = res.component;
+ if (comp && typeof comp.then === 'function') {
+ comp.then(resolve, reject);
+ }
+ }
+ }
+ }
+ });
+
+ if (!hasAsync) { next(); }
+ }
+}
+
+function flatMapComponents (
+ matched,
+ fn
+) {
+ return flatten(matched.map(function (m) {
+ return Object.keys(m.components).map(function (key) { return fn(
+ m.components[key],
+ m.instances[key],
+ m, key
+ ); })
+ }))
+}
+
+function flatten (arr) {
+ return Array.prototype.concat.apply([], arr)
+}
+
+var hasSymbol =
+ typeof Symbol === 'function' &&
+ typeof Symbol.toStringTag === 'symbol';
+
+function isESModule (obj) {
+ return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
+}
+
+// in Webpack 2, require.ensure now also returns a Promise
+// so the resolve/reject functions may get called an extra time
+// if the user uses an arrow function shorthand that happens to
+// return that Promise.
+function once (fn) {
+ var called = false;
+ return function () {
+ var args = [], len = arguments.length;
+ while ( len-- ) args[ len ] = arguments[ len ];
+
+ if (called) { return }
+ called = true;
+ return fn.apply(this, args)
+ }
+}
+
+var NavigationDuplicated = /*@__PURE__*/(function (Error) {
+ function NavigationDuplicated (normalizedLocation) {
+ Error.call(this);
+ this.name = this._name = 'NavigationDuplicated';
+ // passing the message to super() doesn't seem to work in the transpiled version
+ this.message = "Navigating to current location (\"" + (normalizedLocation.fullPath) + "\") is not allowed";
+ // add a stack property so services like Sentry can correctly display it
+ Object.defineProperty(this, 'stack', {
+ value: new Error().stack,
+ writable: true,
+ configurable: true
+ });
+ // we could also have used
+ // Error.captureStackTrace(this, this.constructor)
+ // but it only exists on node and chrome
+ }
+
+ if ( Error ) NavigationDuplicated.__proto__ = Error;
+ NavigationDuplicated.prototype = Object.create( Error && Error.prototype );
+ NavigationDuplicated.prototype.constructor = NavigationDuplicated;
+
+ return NavigationDuplicated;
+}(Error));
+
+// support IE9
+NavigationDuplicated._name = 'NavigationDuplicated';
+
+/* */
+
+var History = function History (router, base) {
+ this.router = router;
+ this.base = normalizeBase(base);
+ // start with a route object that stands for "nowhere"
+ this.current = START;
+ this.pending = null;
+ this.ready = false;
+ this.readyCbs = [];
+ this.readyErrorCbs = [];
+ this.errorCbs = [];
+};
+
+History.prototype.listen = function listen (cb) {
+ this.cb = cb;
+};
+
+History.prototype.onReady = function onReady (cb, errorCb) {
+ if (this.ready) {
+ cb();
+ } else {
+ this.readyCbs.push(cb);
+ if (errorCb) {
+ this.readyErrorCbs.push(errorCb);
+ }
+ }
+};
+
+History.prototype.onError = function onError (errorCb) {
+ this.errorCbs.push(errorCb);
+};
+
+History.prototype.transitionTo = function transitionTo (
+ location,
+ onComplete,
+ onAbort
+) {
+ var this$1 = this;
+
+ var route = this.router.match(location, this.current);
+ this.confirmTransition(
+ route,
+ function () {
+ this$1.updateRoute(route);
+ onComplete && onComplete(route);
+ this$1.ensureURL();
+
+ // fire ready cbs once
+ if (!this$1.ready) {
+ this$1.ready = true;
+ this$1.readyCbs.forEach(function (cb) {
+ cb(route);
+ });
+ }
+ },
+ function (err) {
+ if (onAbort) {
+ onAbort(err);
+ }
+ if (err && !this$1.ready) {
+ this$1.ready = true;
+ this$1.readyErrorCbs.forEach(function (cb) {
+ cb(err);
+ });
+ }
+ }
+ );
+};
+
+History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
+ var this$1 = this;
+
+ var current = this.current;
+ var abort = function (err) {
+ // after merging https://github.com/vuejs/vue-router/pull/2771 we
+ // When the user navigates through history through back/forward buttons
+ // we do not want to throw the error. We only throw it if directly calling
+ // push/replace. That's why it's not included in isError
+ if (!isExtendedError(NavigationDuplicated, err) && isError(err)) {
+ if (this$1.errorCbs.length) {
+ this$1.errorCbs.forEach(function (cb) {
+ cb(err);
+ });
+ } else {
+ warn(false, 'uncaught error during route navigation:');
+ console.error(err);
+ }
+ }
+ onAbort && onAbort(err);
+ };
+ if (
+ isSameRoute(route, current) &&
+ // in the case the route map has been dynamically appended to
+ route.matched.length === current.matched.length
+ ) {
+ this.ensureURL();
+ return abort(new NavigationDuplicated(route))
+ }
+
+ var ref = resolveQueue(
+ this.current.matched,
+ route.matched
+ );
+ var updated = ref.updated;
+ var deactivated = ref.deactivated;
+ var activated = ref.activated;
+
+ var queue = [].concat(
+ // in-component leave guards
+ extractLeaveGuards(deactivated),
+ // global before hooks
+ this.router.beforeHooks,
+ // in-component update hooks
+ extractUpdateHooks(updated),
+ // in-config enter guards
+ activated.map(function (m) { return m.beforeEnter; }),
+ // async components
+ resolveAsyncComponents(activated)
+ );
+
+ this.pending = route;
+ var iterator = function (hook, next) {
+ if (this$1.pending !== route) {
+ return abort()
+ }
+ try {
+ hook(route, current, function (to) {
+ if (to === false || isError(to)) {
+ // next(false) -> abort navigation, ensure current URL
+ this$1.ensureURL(true);
+ abort(to);
+ } else if (
+ typeof to === 'string' ||
+ (typeof to === 'object' &&
+ (typeof to.path === 'string' || typeof to.name === 'string'))
+ ) {
+ // next('/') or next({ path: '/' }) -> redirect
+ abort();
+ if (typeof to === 'object' && to.replace) {
+ this$1.replace(to);
+ } else {
+ this$1.push(to);
+ }
+ } else {
+ // confirm transition and pass on the value
+ next(to);
+ }
+ });
+ } catch (e) {
+ abort(e);
+ }
+ };
+
+ runQueue(queue, iterator, function () {
+ var postEnterCbs = [];
+ var isValid = function () { return this$1.current === route; };
+ // wait until async components are resolved before
+ // extracting in-component enter guards
+ var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
+ var queue = enterGuards.concat(this$1.router.resolveHooks);
+ runQueue(queue, iterator, function () {
+ if (this$1.pending !== route) {
+ return abort()
+ }
+ this$1.pending = null;
+ onComplete(route);
+ if (this$1.router.app) {
+ this$1.router.app.$nextTick(function () {
+ postEnterCbs.forEach(function (cb) {
+ cb();
+ });
+ });
+ }
+ });
+ });
+};
+
+History.prototype.updateRoute = function updateRoute (route) {
+ var prev = this.current;
+ this.current = route;
+ this.cb && this.cb(route);
+ this.router.afterHooks.forEach(function (hook) {
+ hook && hook(route, prev);
+ });
+};
+
+function normalizeBase (base) {
+ if (!base) {
+ if (inBrowser) {
+ // respect tag
+ var baseEl = document.querySelector('base');
+ base = (baseEl && baseEl.getAttribute('href')) || '/';
+ // strip full URL origin
+ base = base.replace(/^https?:\/\/[^\/]+/, '');
+ } else {
+ base = '/';
+ }
+ }
+ // make sure there's the starting slash
+ if (base.charAt(0) !== '/') {
+ base = '/' + base;
+ }
+ // remove trailing slash
+ return base.replace(/\/$/, '')
+}
+
+function resolveQueue (
+ current,
+ next
+) {
+ var i;
+ var max = Math.max(current.length, next.length);
+ for (i = 0; i < max; i++) {
+ if (current[i] !== next[i]) {
+ break
+ }
+ }
+ return {
+ updated: next.slice(0, i),
+ activated: next.slice(i),
+ deactivated: current.slice(i)
+ }
+}
+
+function extractGuards (
+ records,
+ name,
+ bind,
+ reverse
+) {
+ var guards = flatMapComponents(records, function (def, instance, match, key) {
+ var guard = extractGuard(def, name);
+ if (guard) {
+ return Array.isArray(guard)
+ ? guard.map(function (guard) { return bind(guard, instance, match, key); })
+ : bind(guard, instance, match, key)
+ }
+ });
+ return flatten(reverse ? guards.reverse() : guards)
+}
+
+function extractGuard (
+ def,
+ key
+) {
+ if (typeof def !== 'function') {
+ // extend now so that global mixins are applied.
+ def = _Vue.extend(def);
+ }
+ return def.options[key]
+}
+
+function extractLeaveGuards (deactivated) {
+ return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
+}
+
+function extractUpdateHooks (updated) {
+ return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
+}
+
+function bindGuard (guard, instance) {
+ if (instance) {
+ return function boundRouteGuard () {
+ return guard.apply(instance, arguments)
+ }
+ }
+}
+
+function extractEnterGuards (
+ activated,
+ cbs,
+ isValid
+) {
+ return extractGuards(
+ activated,
+ 'beforeRouteEnter',
+ function (guard, _, match, key) {
+ return bindEnterGuard(guard, match, key, cbs, isValid)
+ }
+ )
+}
+
+function bindEnterGuard (
+ guard,
+ match,
+ key,
+ cbs,
+ isValid
+) {
+ return function routeEnterGuard (to, from, next) {
+ return guard(to, from, function (cb) {
+ if (typeof cb === 'function') {
+ cbs.push(function () {
+ // #750
+ // if a router-view is wrapped with an out-in transition,
+ // the instance may not have been registered at this time.
+ // we will need to poll for registration until current route
+ // is no longer valid.
+ poll(cb, match.instances, key, isValid);
+ });
+ }
+ next(cb);
+ })
+ }
+}
+
+function poll (
+ cb, // somehow flow cannot infer this is a function
+ instances,
+ key,
+ isValid
+) {
+ if (
+ instances[key] &&
+ !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
+ ) {
+ cb(instances[key]);
+ } else if (isValid()) {
+ setTimeout(function () {
+ poll(cb, instances, key, isValid);
+ }, 16);
+ }
+}
+
+/* */
+
+var HTML5History = /*@__PURE__*/(function (History) {
+ function HTML5History (router, base) {
+ var this$1 = this;
+
+ History.call(this, router, base);
+
+ var expectScroll = router.options.scrollBehavior;
+ var supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ var initLocation = getLocation(this.base);
+ window.addEventListener('popstate', function (e) {
+ var current = this$1.current;
+
+ // Avoiding first `popstate` event dispatched in some browsers but first
+ // history route not updated since async guard at the same time.
+ var location = getLocation(this$1.base);
+ if (this$1.current === START && location === initLocation) {
+ return
+ }
+
+ this$1.transitionTo(location, function (route) {
+ if (supportsScroll) {
+ handleScroll(router, route, current, true);
+ }
+ });
+ });
+ }
+
+ if ( History ) HTML5History.__proto__ = History;
+ HTML5History.prototype = Object.create( History && History.prototype );
+ HTML5History.prototype.constructor = HTML5History;
+
+ HTML5History.prototype.go = function go (n) {
+ window.history.go(n);
+ };
+
+ HTML5History.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(location, function (route) {
+ pushState(cleanPath(this$1.base + route.fullPath));
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ };
+
+ HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(location, function (route) {
+ replaceState(cleanPath(this$1.base + route.fullPath));
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ };
+
+ HTML5History.prototype.ensureURL = function ensureURL (push) {
+ if (getLocation(this.base) !== this.current.fullPath) {
+ var current = cleanPath(this.base + this.current.fullPath);
+ push ? pushState(current) : replaceState(current);
+ }
+ };
+
+ HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
+ return getLocation(this.base)
+ };
+
+ return HTML5History;
+}(History));
+
+function getLocation (base) {
+ var path = decodeURI(window.location.pathname);
+ if (base && path.indexOf(base) === 0) {
+ path = path.slice(base.length);
+ }
+ return (path || '/') + window.location.search + window.location.hash
+}
+
+/* */
+
+var HashHistory = /*@__PURE__*/(function (History) {
+ function HashHistory (router, base, fallback) {
+ History.call(this, router, base);
+ // check history fallback deeplinking
+ if (fallback && checkFallback(this.base)) {
+ return
+ }
+ ensureSlash();
+ }
+
+ if ( History ) HashHistory.__proto__ = History;
+ HashHistory.prototype = Object.create( History && History.prototype );
+ HashHistory.prototype.constructor = HashHistory;
+
+ // this is delayed until the app mounts
+ // to avoid the hashchange listener being fired too early
+ HashHistory.prototype.setupListeners = function setupListeners () {
+ var this$1 = this;
+
+ var router = this.router;
+ var expectScroll = router.options.scrollBehavior;
+ var supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ window.addEventListener(
+ supportsPushState ? 'popstate' : 'hashchange',
+ function () {
+ var current = this$1.current;
+ if (!ensureSlash()) {
+ return
+ }
+ this$1.transitionTo(getHash(), function (route) {
+ if (supportsScroll) {
+ handleScroll(this$1.router, route, current, true);
+ }
+ if (!supportsPushState) {
+ replaceHash(route.fullPath);
+ }
+ });
+ }
+ );
+ };
+
+ HashHistory.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(
+ location,
+ function (route) {
+ pushHash(route.fullPath);
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(
+ location,
+ function (route) {
+ replaceHash(route.fullPath);
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ HashHistory.prototype.go = function go (n) {
+ window.history.go(n);
+ };
+
+ HashHistory.prototype.ensureURL = function ensureURL (push) {
+ var current = this.current.fullPath;
+ if (getHash() !== current) {
+ push ? pushHash(current) : replaceHash(current);
+ }
+ };
+
+ HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+ return getHash()
+ };
+
+ return HashHistory;
+}(History));
+
+function checkFallback (base) {
+ var location = getLocation(base);
+ if (!/^\/#/.test(location)) {
+ window.location.replace(cleanPath(base + '/#' + location));
+ return true
+ }
+}
+
+function ensureSlash () {
+ var path = getHash();
+ if (path.charAt(0) === '/') {
+ return true
+ }
+ replaceHash('/' + path);
+ return false
+}
+
+function getHash () {
+ // We can't use window.location.hash here because it's not
+ // consistent across browsers - Firefox will pre-decode it!
+ var href = window.location.href;
+ var index = href.indexOf('#');
+ // empty path
+ if (index < 0) { return '' }
+
+ href = href.slice(index + 1);
+ // decode the hash but not the search or hash
+ // as search(query) is already decoded
+ // https://github.com/vuejs/vue-router/issues/2708
+ var searchIndex = href.indexOf('?');
+ if (searchIndex < 0) {
+ var hashIndex = href.indexOf('#');
+ if (hashIndex > -1) {
+ href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex);
+ } else { href = decodeURI(href); }
+ } else {
+ if (searchIndex > -1) {
+ href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex);
+ }
+ }
+
+ return href
+}
+
+function getUrl (path) {
+ var href = window.location.href;
+ var i = href.indexOf('#');
+ var base = i >= 0 ? href.slice(0, i) : href;
+ return (base + "#" + path)
+}
+
+function pushHash (path) {
+ if (supportsPushState) {
+ pushState(getUrl(path));
+ } else {
+ window.location.hash = path;
+ }
+}
+
+function replaceHash (path) {
+ if (supportsPushState) {
+ replaceState(getUrl(path));
+ } else {
+ window.location.replace(getUrl(path));
+ }
+}
+
+/* */
+
+var AbstractHistory = /*@__PURE__*/(function (History) {
+ function AbstractHistory (router, base) {
+ History.call(this, router, base);
+ this.stack = [];
+ this.index = -1;
+ }
+
+ if ( History ) AbstractHistory.__proto__ = History;
+ AbstractHistory.prototype = Object.create( History && History.prototype );
+ AbstractHistory.prototype.constructor = AbstractHistory;
+
+ AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ this.transitionTo(
+ location,
+ function (route) {
+ this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
+ this$1.index++;
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ this.transitionTo(
+ location,
+ function (route) {
+ this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ AbstractHistory.prototype.go = function go (n) {
+ var this$1 = this;
+
+ var targetIndex = this.index + n;
+ if (targetIndex < 0 || targetIndex >= this.stack.length) {
+ return
+ }
+ var route = this.stack[targetIndex];
+ this.confirmTransition(
+ route,
+ function () {
+ this$1.index = targetIndex;
+ this$1.updateRoute(route);
+ },
+ function (err) {
+ if (isExtendedError(NavigationDuplicated, err)) {
+ this$1.index = targetIndex;
+ }
+ }
+ );
+ };
+
+ AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+ var current = this.stack[this.stack.length - 1];
+ return current ? current.fullPath : '/'
+ };
+
+ AbstractHistory.prototype.ensureURL = function ensureURL () {
+ // noop
+ };
+
+ return AbstractHistory;
+}(History));
+
+/* */
+
+
+
+var VueRouter = function VueRouter (options) {
+ if ( options === void 0 ) options = {};
+
+ this.app = null;
+ this.apps = [];
+ this.options = options;
+ this.beforeHooks = [];
+ this.resolveHooks = [];
+ this.afterHooks = [];
+ this.matcher = createMatcher(options.routes || [], this);
+
+ var mode = options.mode || 'hash';
+ this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
+ if (this.fallback) {
+ mode = 'hash';
+ }
+ if (!inBrowser) {
+ mode = 'abstract';
+ }
+ this.mode = mode;
+
+ switch (mode) {
+ case 'history':
+ this.history = new HTML5History(this, options.base);
+ break
+ case 'hash':
+ this.history = new HashHistory(this, options.base, this.fallback);
+ break
+ case 'abstract':
+ this.history = new AbstractHistory(this, options.base);
+ break
+ default:
+ if (process.env.NODE_ENV !== 'production') {
+ assert(false, ("invalid mode: " + mode));
+ }
+ }
+};
+
+var prototypeAccessors = { currentRoute: { configurable: true } };
+
+VueRouter.prototype.match = function match (
+ raw,
+ current,
+ redirectedFrom
+) {
+ return this.matcher.match(raw, current, redirectedFrom)
+};
+
+prototypeAccessors.currentRoute.get = function () {
+ return this.history && this.history.current
+};
+
+VueRouter.prototype.init = function init (app /* Vue component instance */) {
+ var this$1 = this;
+
+ process.env.NODE_ENV !== 'production' && assert(
+ install.installed,
+ "not installed. Make sure to call `Vue.use(VueRouter)` " +
+ "before creating root instance."
+ );
+
+ this.apps.push(app);
+
+ // set up app destroyed handler
+ // https://github.com/vuejs/vue-router/issues/2639
+ app.$once('hook:destroyed', function () {
+ // clean out app from this.apps array once destroyed
+ var index = this$1.apps.indexOf(app);
+ if (index > -1) { this$1.apps.splice(index, 1); }
+ // ensure we still have a main app or null if no apps
+ // we do not release the router so it can be reused
+ if (this$1.app === app) { this$1.app = this$1.apps[0] || null; }
+ });
+
+ // main app previously initialized
+ // return as we don't need to set up new history listener
+ if (this.app) {
+ return
+ }
+
+ this.app = app;
+
+ var history = this.history;
+
+ if (history instanceof HTML5History) {
+ history.transitionTo(history.getCurrentLocation());
+ } else if (history instanceof HashHistory) {
+ var setupHashListener = function () {
+ history.setupListeners();
+ };
+ history.transitionTo(
+ history.getCurrentLocation(),
+ setupHashListener,
+ setupHashListener
+ );
+ }
+
+ history.listen(function (route) {
+ this$1.apps.forEach(function (app) {
+ app._route = route;
+ });
+ });
+};
+
+VueRouter.prototype.beforeEach = function beforeEach (fn) {
+ return registerHook(this.beforeHooks, fn)
+};
+
+VueRouter.prototype.beforeResolve = function beforeResolve (fn) {
+ return registerHook(this.resolveHooks, fn)
+};
+
+VueRouter.prototype.afterEach = function afterEach (fn) {
+ return registerHook(this.afterHooks, fn)
+};
+
+VueRouter.prototype.onReady = function onReady (cb, errorCb) {
+ this.history.onReady(cb, errorCb);
+};
+
+VueRouter.prototype.onError = function onError (errorCb) {
+ this.history.onError(errorCb);
+};
+
+VueRouter.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise(function (resolve, reject) {
+ this$1.history.push(location, resolve, reject);
+ })
+ } else {
+ this.history.push(location, onComplete, onAbort);
+ }
+};
+
+VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise(function (resolve, reject) {
+ this$1.history.replace(location, resolve, reject);
+ })
+ } else {
+ this.history.replace(location, onComplete, onAbort);
+ }
+};
+
+VueRouter.prototype.go = function go (n) {
+ this.history.go(n);
+};
+
+VueRouter.prototype.back = function back () {
+ this.go(-1);
+};
+
+VueRouter.prototype.forward = function forward () {
+ this.go(1);
+};
+
+VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
+ var route = to
+ ? to.matched
+ ? to
+ : this.resolve(to).route
+ : this.currentRoute;
+ if (!route) {
+ return []
+ }
+ return [].concat.apply([], route.matched.map(function (m) {
+ return Object.keys(m.components).map(function (key) {
+ return m.components[key]
+ })
+ }))
+};
+
+VueRouter.prototype.resolve = function resolve (
+ to,
+ current,
+ append
+) {
+ current = current || this.history.current;
+ var location = normalizeLocation(
+ to,
+ current,
+ append,
+ this
+ );
+ var route = this.match(location, current);
+ var fullPath = route.redirectedFrom || route.fullPath;
+ var base = this.history.base;
+ var href = createHref(base, fullPath, this.mode);
+ return {
+ location: location,
+ route: route,
+ href: href,
+ // for backwards compat
+ normalizedTo: location,
+ resolved: route
+ }
+};
+
+VueRouter.prototype.addRoutes = function addRoutes (routes) {
+ this.matcher.addRoutes(routes);
+ if (this.history.current !== START) {
+ this.history.transitionTo(this.history.getCurrentLocation());
+ }
+};
+
+Object.defineProperties( VueRouter.prototype, prototypeAccessors );
+
+function registerHook (list, fn) {
+ list.push(fn);
+ return function () {
+ var i = list.indexOf(fn);
+ if (i > -1) { list.splice(i, 1); }
+ }
+}
+
+function createHref (base, fullPath, mode) {
+ var path = mode === 'hash' ? '#' + fullPath : fullPath;
+ return base ? cleanPath(base + '/' + path) : path
+}
+
+VueRouter.install = install;
+VueRouter.version = '3.1.3';
+
+if (inBrowser && window.Vue) {
+ window.Vue.use(VueRouter);
+}
+
+module.exports = VueRouter;
diff --git a/node_modules/vue-router/dist/vue-router.esm.browser.js b/node_modules/vue-router/dist/vue-router.esm.browser.js
new file mode 100644
index 0000000..4bb3572
--- /dev/null
+++ b/node_modules/vue-router/dist/vue-router.esm.browser.js
@@ -0,0 +1,2834 @@
+/*!
+ * vue-router v3.1.3
+ * (c) 2019 Evan You
+ * @license MIT
+ */
+/* */
+
+function assert (condition, message) {
+ if (!condition) {
+ throw new Error(`[vue-router] ${message}`)
+ }
+}
+
+function warn (condition, message) {
+ if ( !condition) {
+ typeof console !== 'undefined' && console.warn(`[vue-router] ${message}`);
+ }
+}
+
+function isError (err) {
+ return Object.prototype.toString.call(err).indexOf('Error') > -1
+}
+
+function isExtendedError (constructor, err) {
+ return (
+ err instanceof constructor ||
+ // _name is to support IE9 too
+ (err && (err.name === constructor.name || err._name === constructor._name))
+ )
+}
+
+function extend (a, b) {
+ for (const key in b) {
+ a[key] = b[key];
+ }
+ return a
+}
+
+var View = {
+ name: 'RouterView',
+ functional: true,
+ props: {
+ name: {
+ type: String,
+ default: 'default'
+ }
+ },
+ render (_, { props, children, parent, data }) {
+ // used by devtools to display a router-view badge
+ data.routerView = true;
+
+ // directly use parent context's createElement() function
+ // so that components rendered by router-view can resolve named slots
+ const h = parent.$createElement;
+ const name = props.name;
+ const route = parent.$route;
+ const cache = parent._routerViewCache || (parent._routerViewCache = {});
+
+ // determine current view depth, also check to see if the tree
+ // has been toggled inactive but kept-alive.
+ let depth = 0;
+ let inactive = false;
+ while (parent && parent._routerRoot !== parent) {
+ const vnodeData = parent.$vnode && parent.$vnode.data;
+ if (vnodeData) {
+ if (vnodeData.routerView) {
+ depth++;
+ }
+ if (vnodeData.keepAlive && parent._inactive) {
+ inactive = true;
+ }
+ }
+ parent = parent.$parent;
+ }
+ data.routerViewDepth = depth;
+
+ // render previous view if the tree is inactive and kept-alive
+ if (inactive) {
+ return h(cache[name], data, children)
+ }
+
+ const matched = route.matched[depth];
+ // render empty node if no matched route
+ if (!matched) {
+ cache[name] = null;
+ return h()
+ }
+
+ const component = cache[name] = matched.components[name];
+
+ // attach instance registration hook
+ // this will be called in the instance's injected lifecycle hooks
+ data.registerRouteInstance = (vm, val) => {
+ // val could be undefined for unregistration
+ const current = matched.instances[name];
+ if (
+ (val && current !== vm) ||
+ (!val && current === vm)
+ ) {
+ matched.instances[name] = val;
+ }
+ }
+
+ // also register instance in prepatch hook
+ // in case the same component instance is reused across different routes
+ ;(data.hook || (data.hook = {})).prepatch = (_, vnode) => {
+ matched.instances[name] = vnode.componentInstance;
+ };
+
+ // register instance in init hook
+ // in case kept-alive component be actived when routes changed
+ data.hook.init = (vnode) => {
+ if (vnode.data.keepAlive &&
+ vnode.componentInstance &&
+ vnode.componentInstance !== matched.instances[name]
+ ) {
+ matched.instances[name] = vnode.componentInstance;
+ }
+ };
+
+ // resolve props
+ let propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
+ if (propsToPass) {
+ // clone to prevent mutation
+ propsToPass = data.props = extend({}, propsToPass);
+ // pass non-declared props as attrs
+ const attrs = data.attrs = data.attrs || {};
+ for (const key in propsToPass) {
+ if (!component.props || !(key in component.props)) {
+ attrs[key] = propsToPass[key];
+ delete propsToPass[key];
+ }
+ }
+ }
+
+ return h(component, data, children)
+ }
+};
+
+function resolveProps (route, config) {
+ switch (typeof config) {
+ case 'undefined':
+ return
+ case 'object':
+ return config
+ case 'function':
+ return config(route)
+ case 'boolean':
+ return config ? route.params : undefined
+ default:
+ {
+ warn(
+ false,
+ `props in "${route.path}" is a ${typeof config}, ` +
+ `expecting an object, function or boolean.`
+ );
+ }
+ }
+}
+
+/* */
+
+const encodeReserveRE = /[!'()*]/g;
+const encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16);
+const commaRE = /%2C/g;
+
+// fixed encodeURIComponent which is more conformant to RFC3986:
+// - escapes [!'()*]
+// - preserve commas
+const encode = str => encodeURIComponent(str)
+ .replace(encodeReserveRE, encodeReserveReplacer)
+ .replace(commaRE, ',');
+
+const decode = decodeURIComponent;
+
+function resolveQuery (
+ query,
+ extraQuery = {},
+ _parseQuery
+) {
+ const parse = _parseQuery || parseQuery;
+ let parsedQuery;
+ try {
+ parsedQuery = parse(query || '');
+ } catch (e) {
+ warn(false, e.message);
+ parsedQuery = {};
+ }
+ for (const key in extraQuery) {
+ parsedQuery[key] = extraQuery[key];
+ }
+ return parsedQuery
+}
+
+function parseQuery (query) {
+ const res = {};
+
+ query = query.trim().replace(/^(\?|#|&)/, '');
+
+ if (!query) {
+ return res
+ }
+
+ query.split('&').forEach(param => {
+ const parts = param.replace(/\+/g, ' ').split('=');
+ const key = decode(parts.shift());
+ const val = parts.length > 0
+ ? decode(parts.join('='))
+ : null;
+
+ if (res[key] === undefined) {
+ res[key] = val;
+ } else if (Array.isArray(res[key])) {
+ res[key].push(val);
+ } else {
+ res[key] = [res[key], val];
+ }
+ });
+
+ return res
+}
+
+function stringifyQuery (obj) {
+ const res = obj ? Object.keys(obj).map(key => {
+ const val = obj[key];
+
+ if (val === undefined) {
+ return ''
+ }
+
+ if (val === null) {
+ return encode(key)
+ }
+
+ if (Array.isArray(val)) {
+ const result = [];
+ val.forEach(val2 => {
+ if (val2 === undefined) {
+ return
+ }
+ if (val2 === null) {
+ result.push(encode(key));
+ } else {
+ result.push(encode(key) + '=' + encode(val2));
+ }
+ });
+ return result.join('&')
+ }
+
+ return encode(key) + '=' + encode(val)
+ }).filter(x => x.length > 0).join('&') : null;
+ return res ? `?${res}` : ''
+}
+
+/* */
+
+const trailingSlashRE = /\/?$/;
+
+function createRoute (
+ record,
+ location,
+ redirectedFrom,
+ router
+) {
+ const stringifyQuery = router && router.options.stringifyQuery;
+
+ let query = location.query || {};
+ try {
+ query = clone(query);
+ } catch (e) {}
+
+ const route = {
+ name: location.name || (record && record.name),
+ meta: (record && record.meta) || {},
+ path: location.path || '/',
+ hash: location.hash || '',
+ query,
+ params: location.params || {},
+ fullPath: getFullPath(location, stringifyQuery),
+ matched: record ? formatMatch(record) : []
+ };
+ if (redirectedFrom) {
+ route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);
+ }
+ return Object.freeze(route)
+}
+
+function clone (value) {
+ if (Array.isArray(value)) {
+ return value.map(clone)
+ } else if (value && typeof value === 'object') {
+ const res = {};
+ for (const key in value) {
+ res[key] = clone(value[key]);
+ }
+ return res
+ } else {
+ return value
+ }
+}
+
+// the starting route that represents the initial state
+const START = createRoute(null, {
+ path: '/'
+});
+
+function formatMatch (record) {
+ const res = [];
+ while (record) {
+ res.unshift(record);
+ record = record.parent;
+ }
+ return res
+}
+
+function getFullPath (
+ { path, query = {}, hash = '' },
+ _stringifyQuery
+) {
+ const stringify = _stringifyQuery || stringifyQuery;
+ return (path || '/') + stringify(query) + hash
+}
+
+function isSameRoute (a, b) {
+ if (b === START) {
+ return a === b
+ } else if (!b) {
+ return false
+ } else if (a.path && b.path) {
+ return (
+ a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query)
+ )
+ } else if (a.name && b.name) {
+ return (
+ a.name === b.name &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query) &&
+ isObjectEqual(a.params, b.params)
+ )
+ } else {
+ return false
+ }
+}
+
+function isObjectEqual (a = {}, b = {}) {
+ // handle null value #1566
+ if (!a || !b) return a === b
+ const aKeys = Object.keys(a);
+ const bKeys = Object.keys(b);
+ if (aKeys.length !== bKeys.length) {
+ return false
+ }
+ return aKeys.every(key => {
+ const aVal = a[key];
+ const bVal = b[key];
+ // check nested equality
+ if (typeof aVal === 'object' && typeof bVal === 'object') {
+ return isObjectEqual(aVal, bVal)
+ }
+ return String(aVal) === String(bVal)
+ })
+}
+
+function isIncludedRoute (current, target) {
+ return (
+ current.path.replace(trailingSlashRE, '/').indexOf(
+ target.path.replace(trailingSlashRE, '/')
+ ) === 0 &&
+ (!target.hash || current.hash === target.hash) &&
+ queryIncludes(current.query, target.query)
+ )
+}
+
+function queryIncludes (current, target) {
+ for (const key in target) {
+ if (!(key in current)) {
+ return false
+ }
+ }
+ return true
+}
+
+/* */
+
+function resolvePath (
+ relative,
+ base,
+ append
+) {
+ const firstChar = relative.charAt(0);
+ if (firstChar === '/') {
+ return relative
+ }
+
+ if (firstChar === '?' || firstChar === '#') {
+ return base + relative
+ }
+
+ const stack = base.split('/');
+
+ // remove trailing segment if:
+ // - not appending
+ // - appending to trailing slash (last segment is empty)
+ if (!append || !stack[stack.length - 1]) {
+ stack.pop();
+ }
+
+ // resolve relative path
+ const segments = relative.replace(/^\//, '').split('/');
+ for (let i = 0; i < segments.length; i++) {
+ const segment = segments[i];
+ if (segment === '..') {
+ stack.pop();
+ } else if (segment !== '.') {
+ stack.push(segment);
+ }
+ }
+
+ // ensure leading slash
+ if (stack[0] !== '') {
+ stack.unshift('');
+ }
+
+ return stack.join('/')
+}
+
+function parsePath (path) {
+ let hash = '';
+ let query = '';
+
+ const hashIndex = path.indexOf('#');
+ if (hashIndex >= 0) {
+ hash = path.slice(hashIndex);
+ path = path.slice(0, hashIndex);
+ }
+
+ const queryIndex = path.indexOf('?');
+ if (queryIndex >= 0) {
+ query = path.slice(queryIndex + 1);
+ path = path.slice(0, queryIndex);
+ }
+
+ return {
+ path,
+ query,
+ hash
+ }
+}
+
+function cleanPath (path) {
+ return path.replace(/\/\//g, '/')
+}
+
+var isarray = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Expose `pathToRegexp`.
+ */
+var pathToRegexp_1 = pathToRegexp;
+var parse_1 = parse;
+var compile_1 = compile;
+var tokensToFunction_1 = tokensToFunction;
+var tokensToRegExp_1 = tokensToRegExp;
+
+/**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+var PATH_REGEXP = new RegExp([
+ // Match escaped characters that would otherwise appear in future matches.
+ // This allows the user to escape special characters that won't transform.
+ '(\\\\.)',
+ // Match Express-style parameters and un-named parameters with a prefix
+ // and optional suffixes. Matches appear as:
+ //
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
+].join('|'), 'g');
+
+/**
+ * Parse a string for the raw tokens.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!Array}
+ */
+function parse (str, options) {
+ var tokens = [];
+ var key = 0;
+ var index = 0;
+ var path = '';
+ var defaultDelimiter = options && options.delimiter || '/';
+ var res;
+
+ while ((res = PATH_REGEXP.exec(str)) != null) {
+ var m = res[0];
+ var escaped = res[1];
+ var offset = res.index;
+ path += str.slice(index, offset);
+ index = offset + m.length;
+
+ // Ignore already escaped sequences.
+ if (escaped) {
+ path += escaped[1];
+ continue
+ }
+
+ var next = str[index];
+ var prefix = res[2];
+ var name = res[3];
+ var capture = res[4];
+ var group = res[5];
+ var modifier = res[6];
+ var asterisk = res[7];
+
+ // Push the current path onto the tokens.
+ if (path) {
+ tokens.push(path);
+ path = '';
+ }
+
+ var partial = prefix != null && next != null && next !== prefix;
+ var repeat = modifier === '+' || modifier === '*';
+ var optional = modifier === '?' || modifier === '*';
+ var delimiter = res[2] || defaultDelimiter;
+ var pattern = capture || group;
+
+ tokens.push({
+ name: name || key++,
+ prefix: prefix || '',
+ delimiter: delimiter,
+ optional: optional,
+ repeat: repeat,
+ partial: partial,
+ asterisk: !!asterisk,
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
+ });
+ }
+
+ // Match any characters still remaining.
+ if (index < str.length) {
+ path += str.substr(index);
+ }
+
+ // If the path exists, push it onto the end.
+ if (path) {
+ tokens.push(path);
+ }
+
+ return tokens
+}
+
+/**
+ * Compile a string to a template function for the path.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!function(Object=, Object=)}
+ */
+function compile (str, options) {
+ return tokensToFunction(parse(str, options))
+}
+
+/**
+ * Prettier encoding of URI path segments.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeURIComponentPretty (str) {
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeAsterisk (str) {
+ return encodeURI(str).replace(/[?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Expose a method for transforming tokens into the path function.
+ */
+function tokensToFunction (tokens) {
+ // Compile all the tokens into regexps.
+ var matches = new Array(tokens.length);
+
+ // Compile all the patterns before compilation.
+ for (var i = 0; i < tokens.length; i++) {
+ if (typeof tokens[i] === 'object') {
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
+ }
+ }
+
+ return function (obj, opts) {
+ var path = '';
+ var data = obj || {};
+ var options = opts || {};
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
+
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ path += token;
+
+ continue
+ }
+
+ var value = data[token.name];
+ var segment;
+
+ if (value == null) {
+ if (token.optional) {
+ // Prepend partial segment prefixes.
+ if (token.partial) {
+ path += token.prefix;
+ }
+
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to be defined')
+ }
+ }
+
+ if (isarray(value)) {
+ if (!token.repeat) {
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
+ }
+
+ if (value.length === 0) {
+ if (token.optional) {
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
+ }
+ }
+
+ for (var j = 0; j < value.length; j++) {
+ segment = encode(value[j]);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
+ }
+
+ path += (j === 0 ? token.prefix : token.delimiter) + segment;
+ }
+
+ continue
+ }
+
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
+ }
+
+ path += token.prefix + segment;
+ }
+
+ return path
+ }
+}
+
+/**
+ * Escape a regular expression string.
+ *
+ * @param {string} str
+ * @return {string}
+ */
+function escapeString (str) {
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
+}
+
+/**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param {string} group
+ * @return {string}
+ */
+function escapeGroup (group) {
+ return group.replace(/([=!:$\/()])/g, '\\$1')
+}
+
+/**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param {!RegExp} re
+ * @param {Array} keys
+ * @return {!RegExp}
+ */
+function attachKeys (re, keys) {
+ re.keys = keys;
+ return re
+}
+
+/**
+ * Get the flags for a regexp from the options.
+ *
+ * @param {Object} options
+ * @return {string}
+ */
+function flags (options) {
+ return options.sensitive ? '' : 'i'
+}
+
+/**
+ * Pull out keys from a regexp.
+ *
+ * @param {!RegExp} path
+ * @param {!Array} keys
+ * @return {!RegExp}
+ */
+function regexpToRegexp (path, keys) {
+ // Use a negative lookahead to match only capturing groups.
+ var groups = path.source.match(/\((?!\?)/g);
+
+ if (groups) {
+ for (var i = 0; i < groups.length; i++) {
+ keys.push({
+ name: i,
+ prefix: null,
+ delimiter: null,
+ optional: false,
+ repeat: false,
+ partial: false,
+ asterisk: false,
+ pattern: null
+ });
+ }
+ }
+
+ return attachKeys(path, keys)
+}
+
+/**
+ * Transform an array into a regexp.
+ *
+ * @param {!Array} path
+ * @param {Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function arrayToRegexp (path, keys, options) {
+ var parts = [];
+
+ for (var i = 0; i < path.length; i++) {
+ parts.push(pathToRegexp(path[i], keys, options).source);
+ }
+
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
+
+ return attachKeys(regexp, keys)
+}
+
+/**
+ * Create a path regexp from string input.
+ *
+ * @param {string} path
+ * @param {!Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function stringToRegexp (path, keys, options) {
+ return tokensToRegExp(parse(path, options), keys, options)
+}
+
+/**
+ * Expose a function for taking tokens and returning a RegExp.
+ *
+ * @param {!Array} tokens
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function tokensToRegExp (tokens, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ var strict = options.strict;
+ var end = options.end !== false;
+ var route = '';
+
+ // Iterate over the tokens and create our regexp string.
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ route += escapeString(token);
+ } else {
+ var prefix = escapeString(token.prefix);
+ var capture = '(?:' + token.pattern + ')';
+
+ keys.push(token);
+
+ if (token.repeat) {
+ capture += '(?:' + prefix + capture + ')*';
+ }
+
+ if (token.optional) {
+ if (!token.partial) {
+ capture = '(?:' + prefix + '(' + capture + '))?';
+ } else {
+ capture = prefix + '(' + capture + ')?';
+ }
+ } else {
+ capture = prefix + '(' + capture + ')';
+ }
+
+ route += capture;
+ }
+ }
+
+ var delimiter = escapeString(options.delimiter || '/');
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
+
+ // In non-strict mode we allow a slash at the end of match. If the path to
+ // match already ends with a slash, we remove it for consistency. The slash
+ // is valid at the end of a path match, not in the middle. This is important
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
+ if (!strict) {
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
+ }
+
+ if (end) {
+ route += '$';
+ } else {
+ // In non-ending mode, we need the capturing groups to match as much as
+ // possible by using a positive lookahead to the end or next path segment.
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
+ }
+
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
+}
+
+/**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param {(string|RegExp|Array)} path
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function pathToRegexp (path, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ if (path instanceof RegExp) {
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
+ }
+
+ if (isarray(path)) {
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
+ }
+
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
+}
+pathToRegexp_1.parse = parse_1;
+pathToRegexp_1.compile = compile_1;
+pathToRegexp_1.tokensToFunction = tokensToFunction_1;
+pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
+
+/* */
+
+// $flow-disable-line
+const regexpCompileCache = Object.create(null);
+
+function fillParams (
+ path,
+ params,
+ routeMsg
+) {
+ params = params || {};
+ try {
+ const filler =
+ regexpCompileCache[path] ||
+ (regexpCompileCache[path] = pathToRegexp_1.compile(path));
+
+ // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
+ if (params.pathMatch) params[0] = params.pathMatch;
+
+ return filler(params, { pretty: true })
+ } catch (e) {
+ {
+ warn(false, `missing param for ${routeMsg}: ${e.message}`);
+ }
+ return ''
+ } finally {
+ // delete the 0 if it was added
+ delete params[0];
+ }
+}
+
+/* */
+
+function normalizeLocation (
+ raw,
+ current,
+ append,
+ router
+) {
+ let next = typeof raw === 'string' ? { path: raw } : raw;
+ // named target
+ if (next._normalized) {
+ return next
+ } else if (next.name) {
+ return extend({}, raw)
+ }
+
+ // relative params
+ if (!next.path && next.params && current) {
+ next = extend({}, next);
+ next._normalized = true;
+ const params = extend(extend({}, current.params), next.params);
+ if (current.name) {
+ next.name = current.name;
+ next.params = params;
+ } else if (current.matched.length) {
+ const rawPath = current.matched[current.matched.length - 1].path;
+ next.path = fillParams(rawPath, params, `path ${current.path}`);
+ } else {
+ warn(false, `relative params navigation requires a current route.`);
+ }
+ return next
+ }
+
+ const parsedPath = parsePath(next.path || '');
+ const basePath = (current && current.path) || '/';
+ const path = parsedPath.path
+ ? resolvePath(parsedPath.path, basePath, append || next.append)
+ : basePath;
+
+ const query = resolveQuery(
+ parsedPath.query,
+ next.query,
+ router && router.options.parseQuery
+ );
+
+ let hash = next.hash || parsedPath.hash;
+ if (hash && hash.charAt(0) !== '#') {
+ hash = `#${hash}`;
+ }
+
+ return {
+ _normalized: true,
+ path,
+ query,
+ hash
+ }
+}
+
+/* */
+
+// work around weird flow bug
+const toTypes = [String, Object];
+const eventTypes = [String, Array];
+
+const noop = () => {};
+
+var Link = {
+ name: 'RouterLink',
+ props: {
+ to: {
+ type: toTypes,
+ required: true
+ },
+ tag: {
+ type: String,
+ default: 'a'
+ },
+ exact: Boolean,
+ append: Boolean,
+ replace: Boolean,
+ activeClass: String,
+ exactActiveClass: String,
+ event: {
+ type: eventTypes,
+ default: 'click'
+ }
+ },
+ render (h) {
+ const router = this.$router;
+ const current = this.$route;
+ const { location, route, href } = router.resolve(
+ this.to,
+ current,
+ this.append
+ );
+
+ const classes = {};
+ const globalActiveClass = router.options.linkActiveClass;
+ const globalExactActiveClass = router.options.linkExactActiveClass;
+ // Support global empty active class
+ const activeClassFallback =
+ globalActiveClass == null ? 'router-link-active' : globalActiveClass;
+ const exactActiveClassFallback =
+ globalExactActiveClass == null
+ ? 'router-link-exact-active'
+ : globalExactActiveClass;
+ const activeClass =
+ this.activeClass == null ? activeClassFallback : this.activeClass;
+ const exactActiveClass =
+ this.exactActiveClass == null
+ ? exactActiveClassFallback
+ : this.exactActiveClass;
+
+ const compareTarget = route.redirectedFrom
+ ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)
+ : route;
+
+ classes[exactActiveClass] = isSameRoute(current, compareTarget);
+ classes[activeClass] = this.exact
+ ? classes[exactActiveClass]
+ : isIncludedRoute(current, compareTarget);
+
+ const handler = e => {
+ if (guardEvent(e)) {
+ if (this.replace) {
+ router.replace(location, noop);
+ } else {
+ router.push(location, noop);
+ }
+ }
+ };
+
+ const on = { click: guardEvent };
+ if (Array.isArray(this.event)) {
+ this.event.forEach(e => {
+ on[e] = handler;
+ });
+ } else {
+ on[this.event] = handler;
+ }
+
+ const data = { class: classes };
+
+ const scopedSlot =
+ !this.$scopedSlots.$hasNormal &&
+ this.$scopedSlots.default &&
+ this.$scopedSlots.default({
+ href,
+ route,
+ navigate: handler,
+ isActive: classes[activeClass],
+ isExactActive: classes[exactActiveClass]
+ });
+
+ if (scopedSlot) {
+ if (scopedSlot.length === 1) {
+ return scopedSlot[0]
+ } else if (scopedSlot.length > 1 || !scopedSlot.length) {
+ {
+ warn(
+ false,
+ `RouterLink with to="${
+ this.props.to
+ }" is trying to use a scoped slot but it didn't provide exactly one child.`
+ );
+ }
+ return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)
+ }
+ }
+
+ if (this.tag === 'a') {
+ data.on = on;
+ data.attrs = { href };
+ } else {
+ // find the first child and apply listener and href
+ const a = findAnchor(this.$slots.default);
+ if (a) {
+ // in case the is a static node
+ a.isStatic = false;
+ const aData = (a.data = extend({}, a.data));
+ aData.on = aData.on || {};
+ // transform existing events in both objects into arrays so we can push later
+ for (const event in aData.on) {
+ const handler = aData.on[event];
+ if (event in on) {
+ aData.on[event] = Array.isArray(handler) ? handler : [handler];
+ }
+ }
+ // append new listeners for router-link
+ for (const event in on) {
+ if (event in aData.on) {
+ // on[event] is always a function
+ aData.on[event].push(on[event]);
+ } else {
+ aData.on[event] = handler;
+ }
+ }
+
+ const aAttrs = (a.data.attrs = extend({}, a.data.attrs));
+ aAttrs.href = href;
+ } else {
+ // doesn't have child, apply listener to self
+ data.on = on;
+ }
+ }
+
+ return h(this.tag, data, this.$slots.default)
+ }
+};
+
+function guardEvent (e) {
+ // don't redirect with control keys
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return
+ // don't redirect when preventDefault called
+ if (e.defaultPrevented) return
+ // don't redirect on right click
+ if (e.button !== undefined && e.button !== 0) return
+ // don't redirect if `target="_blank"`
+ if (e.currentTarget && e.currentTarget.getAttribute) {
+ const target = e.currentTarget.getAttribute('target');
+ if (/\b_blank\b/i.test(target)) return
+ }
+ // this may be a Weex event which doesn't have this method
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ return true
+}
+
+function findAnchor (children) {
+ if (children) {
+ let child;
+ for (let i = 0; i < children.length; i++) {
+ child = children[i];
+ if (child.tag === 'a') {
+ return child
+ }
+ if (child.children && (child = findAnchor(child.children))) {
+ return child
+ }
+ }
+ }
+}
+
+let _Vue;
+
+function install (Vue) {
+ if (install.installed && _Vue === Vue) return
+ install.installed = true;
+
+ _Vue = Vue;
+
+ const isDef = v => v !== undefined;
+
+ const registerInstance = (vm, callVal) => {
+ let i = vm.$options._parentVnode;
+ if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
+ i(vm, callVal);
+ }
+ };
+
+ Vue.mixin({
+ beforeCreate () {
+ if (isDef(this.$options.router)) {
+ this._routerRoot = this;
+ this._router = this.$options.router;
+ this._router.init(this);
+ Vue.util.defineReactive(this, '_route', this._router.history.current);
+ } else {
+ this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
+ }
+ registerInstance(this, this);
+ },
+ destroyed () {
+ registerInstance(this);
+ }
+ });
+
+ Object.defineProperty(Vue.prototype, '$router', {
+ get () { return this._routerRoot._router }
+ });
+
+ Object.defineProperty(Vue.prototype, '$route', {
+ get () { return this._routerRoot._route }
+ });
+
+ Vue.component('RouterView', View);
+ Vue.component('RouterLink', Link);
+
+ const strats = Vue.config.optionMergeStrategies;
+ // use the same hook merging strategy for route hooks
+ strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
+}
+
+/* */
+
+const inBrowser = typeof window !== 'undefined';
+
+/* */
+
+function createRouteMap (
+ routes,
+ oldPathList,
+ oldPathMap,
+ oldNameMap
+) {
+ // the path list is used to control path matching priority
+ const pathList = oldPathList || [];
+ // $flow-disable-line
+ const pathMap = oldPathMap || Object.create(null);
+ // $flow-disable-line
+ const nameMap = oldNameMap || Object.create(null);
+
+ routes.forEach(route => {
+ addRouteRecord(pathList, pathMap, nameMap, route);
+ });
+
+ // ensure wildcard routes are always at the end
+ for (let i = 0, l = pathList.length; i < l; i++) {
+ if (pathList[i] === '*') {
+ pathList.push(pathList.splice(i, 1)[0]);
+ l--;
+ i--;
+ }
+ }
+
+ {
+ // warn if routes do not include leading slashes
+ const found = pathList
+ // check for missing leading slash
+ .filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/');
+
+ if (found.length > 0) {
+ const pathNames = found.map(path => `- ${path}`).join('\n');
+ warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \n${pathNames}`);
+ }
+ }
+
+ return {
+ pathList,
+ pathMap,
+ nameMap
+ }
+}
+
+function addRouteRecord (
+ pathList,
+ pathMap,
+ nameMap,
+ route,
+ parent,
+ matchAs
+) {
+ const { path, name } = route;
+ {
+ assert(path != null, `"path" is required in a route configuration.`);
+ assert(
+ typeof route.component !== 'string',
+ `route config "component" for path: ${String(
+ path || name
+ )} cannot be a ` + `string id. Use an actual component instead.`
+ );
+ }
+
+ const pathToRegexpOptions =
+ route.pathToRegexpOptions || {};
+ const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);
+
+ if (typeof route.caseSensitive === 'boolean') {
+ pathToRegexpOptions.sensitive = route.caseSensitive;
+ }
+
+ const record = {
+ path: normalizedPath,
+ regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
+ components: route.components || { default: route.component },
+ instances: {},
+ name,
+ parent,
+ matchAs,
+ redirect: route.redirect,
+ beforeEnter: route.beforeEnter,
+ meta: route.meta || {},
+ props:
+ route.props == null
+ ? {}
+ : route.components
+ ? route.props
+ : { default: route.props }
+ };
+
+ if (route.children) {
+ // Warn if route is named, does not redirect and has a default child route.
+ // If users navigate to this route by name, the default child will
+ // not be rendered (GH Issue #629)
+ {
+ if (
+ route.name &&
+ !route.redirect &&
+ route.children.some(child => /^\/?$/.test(child.path))
+ ) {
+ warn(
+ false,
+ `Named Route '${route.name}' has a default child route. ` +
+ `When navigating to this named route (:to="{name: '${
+ route.name
+ }'"), ` +
+ `the default child route will not be rendered. Remove the name from ` +
+ `this route and use the name of the default child route for named ` +
+ `links instead.`
+ );
+ }
+ }
+ route.children.forEach(child => {
+ const childMatchAs = matchAs
+ ? cleanPath(`${matchAs}/${child.path}`)
+ : undefined;
+ addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
+ });
+ }
+
+ if (!pathMap[record.path]) {
+ pathList.push(record.path);
+ pathMap[record.path] = record;
+ }
+
+ if (route.alias !== undefined) {
+ const aliases = Array.isArray(route.alias) ? route.alias : [route.alias];
+ for (let i = 0; i < aliases.length; ++i) {
+ const alias = aliases[i];
+ if ( alias === path) {
+ warn(
+ false,
+ `Found an alias with the same value as the path: "${path}". You have to remove that alias. It will be ignored in development.`
+ );
+ // skip in dev to make it work
+ continue
+ }
+
+ const aliasRoute = {
+ path: alias,
+ children: route.children
+ };
+ addRouteRecord(
+ pathList,
+ pathMap,
+ nameMap,
+ aliasRoute,
+ parent,
+ record.path || '/' // matchAs
+ );
+ }
+ }
+
+ if (name) {
+ if (!nameMap[name]) {
+ nameMap[name] = record;
+ } else if ( !matchAs) {
+ warn(
+ false,
+ `Duplicate named routes definition: ` +
+ `{ name: "${name}", path: "${record.path}" }`
+ );
+ }
+ }
+}
+
+function compileRouteRegex (
+ path,
+ pathToRegexpOptions
+) {
+ const regex = pathToRegexp_1(path, [], pathToRegexpOptions);
+ {
+ const keys = Object.create(null);
+ regex.keys.forEach(key => {
+ warn(
+ !keys[key.name],
+ `Duplicate param keys in route with path: "${path}"`
+ );
+ keys[key.name] = true;
+ });
+ }
+ return regex
+}
+
+function normalizePath (
+ path,
+ parent,
+ strict
+) {
+ if (!strict) path = path.replace(/\/$/, '');
+ if (path[0] === '/') return path
+ if (parent == null) return path
+ return cleanPath(`${parent.path}/${path}`)
+}
+
+/* */
+
+
+
+function createMatcher (
+ routes,
+ router
+) {
+ const { pathList, pathMap, nameMap } = createRouteMap(routes);
+
+ function addRoutes (routes) {
+ createRouteMap(routes, pathList, pathMap, nameMap);
+ }
+
+ function match (
+ raw,
+ currentRoute,
+ redirectedFrom
+ ) {
+ const location = normalizeLocation(raw, currentRoute, false, router);
+ const { name } = location;
+
+ if (name) {
+ const record = nameMap[name];
+ {
+ warn(record, `Route with name '${name}' does not exist`);
+ }
+ if (!record) return _createRoute(null, location)
+ const paramNames = record.regex.keys
+ .filter(key => !key.optional)
+ .map(key => key.name);
+
+ if (typeof location.params !== 'object') {
+ location.params = {};
+ }
+
+ if (currentRoute && typeof currentRoute.params === 'object') {
+ for (const key in currentRoute.params) {
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
+ location.params[key] = currentRoute.params[key];
+ }
+ }
+ }
+
+ location.path = fillParams(record.path, location.params, `named route "${name}"`);
+ return _createRoute(record, location, redirectedFrom)
+ } else if (location.path) {
+ location.params = {};
+ for (let i = 0; i < pathList.length; i++) {
+ const path = pathList[i];
+ const record = pathMap[path];
+ if (matchRoute(record.regex, location.path, location.params)) {
+ return _createRoute(record, location, redirectedFrom)
+ }
+ }
+ }
+ // no match
+ return _createRoute(null, location)
+ }
+
+ function redirect (
+ record,
+ location
+ ) {
+ const originalRedirect = record.redirect;
+ let redirect = typeof originalRedirect === 'function'
+ ? originalRedirect(createRoute(record, location, null, router))
+ : originalRedirect;
+
+ if (typeof redirect === 'string') {
+ redirect = { path: redirect };
+ }
+
+ if (!redirect || typeof redirect !== 'object') {
+ {
+ warn(
+ false, `invalid redirect option: ${JSON.stringify(redirect)}`
+ );
+ }
+ return _createRoute(null, location)
+ }
+
+ const re = redirect;
+ const { name, path } = re;
+ let { query, hash, params } = location;
+ query = re.hasOwnProperty('query') ? re.query : query;
+ hash = re.hasOwnProperty('hash') ? re.hash : hash;
+ params = re.hasOwnProperty('params') ? re.params : params;
+
+ if (name) {
+ // resolved named direct
+ const targetRecord = nameMap[name];
+ {
+ assert(targetRecord, `redirect failed: named route "${name}" not found.`);
+ }
+ return match({
+ _normalized: true,
+ name,
+ query,
+ hash,
+ params
+ }, undefined, location)
+ } else if (path) {
+ // 1. resolve relative redirect
+ const rawPath = resolveRecordPath(path, record);
+ // 2. resolve params
+ const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`);
+ // 3. rematch with existing query and hash
+ return match({
+ _normalized: true,
+ path: resolvedPath,
+ query,
+ hash
+ }, undefined, location)
+ } else {
+ {
+ warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`);
+ }
+ return _createRoute(null, location)
+ }
+ }
+
+ function alias (
+ record,
+ location,
+ matchAs
+ ) {
+ const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`);
+ const aliasedMatch = match({
+ _normalized: true,
+ path: aliasedPath
+ });
+ if (aliasedMatch) {
+ const matched = aliasedMatch.matched;
+ const aliasedRecord = matched[matched.length - 1];
+ location.params = aliasedMatch.params;
+ return _createRoute(aliasedRecord, location)
+ }
+ return _createRoute(null, location)
+ }
+
+ function _createRoute (
+ record,
+ location,
+ redirectedFrom
+ ) {
+ if (record && record.redirect) {
+ return redirect(record, redirectedFrom || location)
+ }
+ if (record && record.matchAs) {
+ return alias(record, location, record.matchAs)
+ }
+ return createRoute(record, location, redirectedFrom, router)
+ }
+
+ return {
+ match,
+ addRoutes
+ }
+}
+
+function matchRoute (
+ regex,
+ path,
+ params
+) {
+ const m = path.match(regex);
+
+ if (!m) {
+ return false
+ } else if (!params) {
+ return true
+ }
+
+ for (let i = 1, len = m.length; i < len; ++i) {
+ const key = regex.keys[i - 1];
+ const val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
+ if (key) {
+ // Fix #1994: using * with props: true generates a param named 0
+ params[key.name || 'pathMatch'] = val;
+ }
+ }
+
+ return true
+}
+
+function resolveRecordPath (path, record) {
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
+}
+
+/* */
+
+// use User Timing api (if present) for more accurate key precision
+const Time =
+ inBrowser && window.performance && window.performance.now
+ ? window.performance
+ : Date;
+
+function genStateKey () {
+ return Time.now().toFixed(3)
+}
+
+let _key = genStateKey();
+
+function getStateKey () {
+ return _key
+}
+
+function setStateKey (key) {
+ return (_key = key)
+}
+
+/* */
+
+const positionStore = Object.create(null);
+
+function setupScroll () {
+ // Fix for #1585 for Firefox
+ // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
+ // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
+ // window.location.protocol + '//' + window.location.host
+ // location.host contains the port and location.hostname doesn't
+ const protocolAndPath = window.location.protocol + '//' + window.location.host;
+ const absolutePath = window.location.href.replace(protocolAndPath, '');
+ window.history.replaceState({ key: getStateKey() }, '', absolutePath);
+ window.addEventListener('popstate', e => {
+ saveScrollPosition();
+ if (e.state && e.state.key) {
+ setStateKey(e.state.key);
+ }
+ });
+}
+
+function handleScroll (
+ router,
+ to,
+ from,
+ isPop
+) {
+ if (!router.app) {
+ return
+ }
+
+ const behavior = router.options.scrollBehavior;
+ if (!behavior) {
+ return
+ }
+
+ {
+ assert(typeof behavior === 'function', `scrollBehavior must be a function`);
+ }
+
+ // wait until re-render finishes before scrolling
+ router.app.$nextTick(() => {
+ const position = getScrollPosition();
+ const shouldScroll = behavior.call(
+ router,
+ to,
+ from,
+ isPop ? position : null
+ );
+
+ if (!shouldScroll) {
+ return
+ }
+
+ if (typeof shouldScroll.then === 'function') {
+ shouldScroll
+ .then(shouldScroll => {
+ scrollToPosition((shouldScroll), position);
+ })
+ .catch(err => {
+ {
+ assert(false, err.toString());
+ }
+ });
+ } else {
+ scrollToPosition(shouldScroll, position);
+ }
+ });
+}
+
+function saveScrollPosition () {
+ const key = getStateKey();
+ if (key) {
+ positionStore[key] = {
+ x: window.pageXOffset,
+ y: window.pageYOffset
+ };
+ }
+}
+
+function getScrollPosition () {
+ const key = getStateKey();
+ if (key) {
+ return positionStore[key]
+ }
+}
+
+function getElementPosition (el, offset) {
+ const docEl = document.documentElement;
+ const docRect = docEl.getBoundingClientRect();
+ const elRect = el.getBoundingClientRect();
+ return {
+ x: elRect.left - docRect.left - offset.x,
+ y: elRect.top - docRect.top - offset.y
+ }
+}
+
+function isValidPosition (obj) {
+ return isNumber(obj.x) || isNumber(obj.y)
+}
+
+function normalizePosition (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : window.pageXOffset,
+ y: isNumber(obj.y) ? obj.y : window.pageYOffset
+ }
+}
+
+function normalizeOffset (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : 0,
+ y: isNumber(obj.y) ? obj.y : 0
+ }
+}
+
+function isNumber (v) {
+ return typeof v === 'number'
+}
+
+const hashStartsWithNumberRE = /^#\d/;
+
+function scrollToPosition (shouldScroll, position) {
+ const isObject = typeof shouldScroll === 'object';
+ if (isObject && typeof shouldScroll.selector === 'string') {
+ // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
+ // but at the same time, it doesn't make much sense to select an element with an id and an extra selector
+ const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
+ ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
+ : document.querySelector(shouldScroll.selector);
+
+ if (el) {
+ let offset =
+ shouldScroll.offset && typeof shouldScroll.offset === 'object'
+ ? shouldScroll.offset
+ : {};
+ offset = normalizeOffset(offset);
+ position = getElementPosition(el, offset);
+ } else if (isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+ } else if (isObject && isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+
+ if (position) {
+ window.scrollTo(position.x, position.y);
+ }
+}
+
+/* */
+
+const supportsPushState =
+ inBrowser &&
+ (function () {
+ const ua = window.navigator.userAgent;
+
+ if (
+ (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
+ ua.indexOf('Mobile Safari') !== -1 &&
+ ua.indexOf('Chrome') === -1 &&
+ ua.indexOf('Windows Phone') === -1
+ ) {
+ return false
+ }
+
+ return window.history && 'pushState' in window.history
+ })();
+
+function pushState (url, replace) {
+ saveScrollPosition();
+ // try...catch the pushState call to get around Safari
+ // DOM Exception 18 where it limits to 100 pushState calls
+ const history = window.history;
+ try {
+ if (replace) {
+ history.replaceState({ key: getStateKey() }, '', url);
+ } else {
+ history.pushState({ key: setStateKey(genStateKey()) }, '', url);
+ }
+ } catch (e) {
+ window.location[replace ? 'replace' : 'assign'](url);
+ }
+}
+
+function replaceState (url) {
+ pushState(url, true);
+}
+
+/* */
+
+function runQueue (queue, fn, cb) {
+ const step = index => {
+ if (index >= queue.length) {
+ cb();
+ } else {
+ if (queue[index]) {
+ fn(queue[index], () => {
+ step(index + 1);
+ });
+ } else {
+ step(index + 1);
+ }
+ }
+ };
+ step(0);
+}
+
+/* */
+
+function resolveAsyncComponents (matched) {
+ return (to, from, next) => {
+ let hasAsync = false;
+ let pending = 0;
+ let error = null;
+
+ flatMapComponents(matched, (def, _, match, key) => {
+ // if it's a function and doesn't have cid attached,
+ // assume it's an async component resolve function.
+ // we are not using Vue's default async resolving mechanism because
+ // we want to halt the navigation until the incoming component has been
+ // resolved.
+ if (typeof def === 'function' && def.cid === undefined) {
+ hasAsync = true;
+ pending++;
+
+ const resolve = once(resolvedDef => {
+ if (isESModule(resolvedDef)) {
+ resolvedDef = resolvedDef.default;
+ }
+ // save resolved on async factory in case it's used elsewhere
+ def.resolved = typeof resolvedDef === 'function'
+ ? resolvedDef
+ : _Vue.extend(resolvedDef);
+ match.components[key] = resolvedDef;
+ pending--;
+ if (pending <= 0) {
+ next();
+ }
+ });
+
+ const reject = once(reason => {
+ const msg = `Failed to resolve async component ${key}: ${reason}`;
+ warn(false, msg);
+ if (!error) {
+ error = isError(reason)
+ ? reason
+ : new Error(msg);
+ next(error);
+ }
+ });
+
+ let res;
+ try {
+ res = def(resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ if (res) {
+ if (typeof res.then === 'function') {
+ res.then(resolve, reject);
+ } else {
+ // new syntax in Vue 2.3
+ const comp = res.component;
+ if (comp && typeof comp.then === 'function') {
+ comp.then(resolve, reject);
+ }
+ }
+ }
+ }
+ });
+
+ if (!hasAsync) next();
+ }
+}
+
+function flatMapComponents (
+ matched,
+ fn
+) {
+ return flatten(matched.map(m => {
+ return Object.keys(m.components).map(key => fn(
+ m.components[key],
+ m.instances[key],
+ m, key
+ ))
+ }))
+}
+
+function flatten (arr) {
+ return Array.prototype.concat.apply([], arr)
+}
+
+const hasSymbol =
+ typeof Symbol === 'function' &&
+ typeof Symbol.toStringTag === 'symbol';
+
+function isESModule (obj) {
+ return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
+}
+
+// in Webpack 2, require.ensure now also returns a Promise
+// so the resolve/reject functions may get called an extra time
+// if the user uses an arrow function shorthand that happens to
+// return that Promise.
+function once (fn) {
+ let called = false;
+ return function (...args) {
+ if (called) return
+ called = true;
+ return fn.apply(this, args)
+ }
+}
+
+class NavigationDuplicated extends Error {
+ constructor (normalizedLocation) {
+ super();
+ this.name = this._name = 'NavigationDuplicated';
+ // passing the message to super() doesn't seem to work in the transpiled version
+ this.message = `Navigating to current location ("${
+ normalizedLocation.fullPath
+ }") is not allowed`;
+ // add a stack property so services like Sentry can correctly display it
+ Object.defineProperty(this, 'stack', {
+ value: new Error().stack,
+ writable: true,
+ configurable: true
+ });
+ // we could also have used
+ // Error.captureStackTrace(this, this.constructor)
+ // but it only exists on node and chrome
+ }
+}
+
+// support IE9
+NavigationDuplicated._name = 'NavigationDuplicated';
+
+/* */
+
+class History {
+
+
+
+
+
+
+
+
+
+
+ // implemented by sub-classes
+
+
+
+
+
+
+ constructor (router, base) {
+ this.router = router;
+ this.base = normalizeBase(base);
+ // start with a route object that stands for "nowhere"
+ this.current = START;
+ this.pending = null;
+ this.ready = false;
+ this.readyCbs = [];
+ this.readyErrorCbs = [];
+ this.errorCbs = [];
+ }
+
+ listen (cb) {
+ this.cb = cb;
+ }
+
+ onReady (cb, errorCb) {
+ if (this.ready) {
+ cb();
+ } else {
+ this.readyCbs.push(cb);
+ if (errorCb) {
+ this.readyErrorCbs.push(errorCb);
+ }
+ }
+ }
+
+ onError (errorCb) {
+ this.errorCbs.push(errorCb);
+ }
+
+ transitionTo (
+ location,
+ onComplete,
+ onAbort
+ ) {
+ const route = this.router.match(location, this.current);
+ this.confirmTransition(
+ route,
+ () => {
+ this.updateRoute(route);
+ onComplete && onComplete(route);
+ this.ensureURL();
+
+ // fire ready cbs once
+ if (!this.ready) {
+ this.ready = true;
+ this.readyCbs.forEach(cb => {
+ cb(route);
+ });
+ }
+ },
+ err => {
+ if (onAbort) {
+ onAbort(err);
+ }
+ if (err && !this.ready) {
+ this.ready = true;
+ this.readyErrorCbs.forEach(cb => {
+ cb(err);
+ });
+ }
+ }
+ );
+ }
+
+ confirmTransition (route, onComplete, onAbort) {
+ const current = this.current;
+ const abort = err => {
+ // after merging https://github.com/vuejs/vue-router/pull/2771 we
+ // When the user navigates through history through back/forward buttons
+ // we do not want to throw the error. We only throw it if directly calling
+ // push/replace. That's why it's not included in isError
+ if (!isExtendedError(NavigationDuplicated, err) && isError(err)) {
+ if (this.errorCbs.length) {
+ this.errorCbs.forEach(cb => {
+ cb(err);
+ });
+ } else {
+ warn(false, 'uncaught error during route navigation:');
+ console.error(err);
+ }
+ }
+ onAbort && onAbort(err);
+ };
+ if (
+ isSameRoute(route, current) &&
+ // in the case the route map has been dynamically appended to
+ route.matched.length === current.matched.length
+ ) {
+ this.ensureURL();
+ return abort(new NavigationDuplicated(route))
+ }
+
+ const { updated, deactivated, activated } = resolveQueue(
+ this.current.matched,
+ route.matched
+ );
+
+ const queue = [].concat(
+ // in-component leave guards
+ extractLeaveGuards(deactivated),
+ // global before hooks
+ this.router.beforeHooks,
+ // in-component update hooks
+ extractUpdateHooks(updated),
+ // in-config enter guards
+ activated.map(m => m.beforeEnter),
+ // async components
+ resolveAsyncComponents(activated)
+ );
+
+ this.pending = route;
+ const iterator = (hook, next) => {
+ if (this.pending !== route) {
+ return abort()
+ }
+ try {
+ hook(route, current, (to) => {
+ if (to === false || isError(to)) {
+ // next(false) -> abort navigation, ensure current URL
+ this.ensureURL(true);
+ abort(to);
+ } else if (
+ typeof to === 'string' ||
+ (typeof to === 'object' &&
+ (typeof to.path === 'string' || typeof to.name === 'string'))
+ ) {
+ // next('/') or next({ path: '/' }) -> redirect
+ abort();
+ if (typeof to === 'object' && to.replace) {
+ this.replace(to);
+ } else {
+ this.push(to);
+ }
+ } else {
+ // confirm transition and pass on the value
+ next(to);
+ }
+ });
+ } catch (e) {
+ abort(e);
+ }
+ };
+
+ runQueue(queue, iterator, () => {
+ const postEnterCbs = [];
+ const isValid = () => this.current === route;
+ // wait until async components are resolved before
+ // extracting in-component enter guards
+ const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
+ const queue = enterGuards.concat(this.router.resolveHooks);
+ runQueue(queue, iterator, () => {
+ if (this.pending !== route) {
+ return abort()
+ }
+ this.pending = null;
+ onComplete(route);
+ if (this.router.app) {
+ this.router.app.$nextTick(() => {
+ postEnterCbs.forEach(cb => {
+ cb();
+ });
+ });
+ }
+ });
+ });
+ }
+
+ updateRoute (route) {
+ const prev = this.current;
+ this.current = route;
+ this.cb && this.cb(route);
+ this.router.afterHooks.forEach(hook => {
+ hook && hook(route, prev);
+ });
+ }
+}
+
+function normalizeBase (base) {
+ if (!base) {
+ if (inBrowser) {
+ // respect tag
+ const baseEl = document.querySelector('base');
+ base = (baseEl && baseEl.getAttribute('href')) || '/';
+ // strip full URL origin
+ base = base.replace(/^https?:\/\/[^\/]+/, '');
+ } else {
+ base = '/';
+ }
+ }
+ // make sure there's the starting slash
+ if (base.charAt(0) !== '/') {
+ base = '/' + base;
+ }
+ // remove trailing slash
+ return base.replace(/\/$/, '')
+}
+
+function resolveQueue (
+ current,
+ next
+) {
+ let i;
+ const max = Math.max(current.length, next.length);
+ for (i = 0; i < max; i++) {
+ if (current[i] !== next[i]) {
+ break
+ }
+ }
+ return {
+ updated: next.slice(0, i),
+ activated: next.slice(i),
+ deactivated: current.slice(i)
+ }
+}
+
+function extractGuards (
+ records,
+ name,
+ bind,
+ reverse
+) {
+ const guards = flatMapComponents(records, (def, instance, match, key) => {
+ const guard = extractGuard(def, name);
+ if (guard) {
+ return Array.isArray(guard)
+ ? guard.map(guard => bind(guard, instance, match, key))
+ : bind(guard, instance, match, key)
+ }
+ });
+ return flatten(reverse ? guards.reverse() : guards)
+}
+
+function extractGuard (
+ def,
+ key
+) {
+ if (typeof def !== 'function') {
+ // extend now so that global mixins are applied.
+ def = _Vue.extend(def);
+ }
+ return def.options[key]
+}
+
+function extractLeaveGuards (deactivated) {
+ return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
+}
+
+function extractUpdateHooks (updated) {
+ return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
+}
+
+function bindGuard (guard, instance) {
+ if (instance) {
+ return function boundRouteGuard () {
+ return guard.apply(instance, arguments)
+ }
+ }
+}
+
+function extractEnterGuards (
+ activated,
+ cbs,
+ isValid
+) {
+ return extractGuards(
+ activated,
+ 'beforeRouteEnter',
+ (guard, _, match, key) => {
+ return bindEnterGuard(guard, match, key, cbs, isValid)
+ }
+ )
+}
+
+function bindEnterGuard (
+ guard,
+ match,
+ key,
+ cbs,
+ isValid
+) {
+ return function routeEnterGuard (to, from, next) {
+ return guard(to, from, cb => {
+ if (typeof cb === 'function') {
+ cbs.push(() => {
+ // #750
+ // if a router-view is wrapped with an out-in transition,
+ // the instance may not have been registered at this time.
+ // we will need to poll for registration until current route
+ // is no longer valid.
+ poll(cb, match.instances, key, isValid);
+ });
+ }
+ next(cb);
+ })
+ }
+}
+
+function poll (
+ cb, // somehow flow cannot infer this is a function
+ instances,
+ key,
+ isValid
+) {
+ if (
+ instances[key] &&
+ !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
+ ) {
+ cb(instances[key]);
+ } else if (isValid()) {
+ setTimeout(() => {
+ poll(cb, instances, key, isValid);
+ }, 16);
+ }
+}
+
+/* */
+
+class HTML5History extends History {
+ constructor (router, base) {
+ super(router, base);
+
+ const expectScroll = router.options.scrollBehavior;
+ const supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ const initLocation = getLocation(this.base);
+ window.addEventListener('popstate', e => {
+ const current = this.current;
+
+ // Avoiding first `popstate` event dispatched in some browsers but first
+ // history route not updated since async guard at the same time.
+ const location = getLocation(this.base);
+ if (this.current === START && location === initLocation) {
+ return
+ }
+
+ this.transitionTo(location, route => {
+ if (supportsScroll) {
+ handleScroll(router, route, current, true);
+ }
+ });
+ });
+ }
+
+ go (n) {
+ window.history.go(n);
+ }
+
+ push (location, onComplete, onAbort) {
+ const { current: fromRoute } = this;
+ this.transitionTo(location, route => {
+ pushState(cleanPath(this.base + route.fullPath));
+ handleScroll(this.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ }
+
+ replace (location, onComplete, onAbort) {
+ const { current: fromRoute } = this;
+ this.transitionTo(location, route => {
+ replaceState(cleanPath(this.base + route.fullPath));
+ handleScroll(this.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ }
+
+ ensureURL (push) {
+ if (getLocation(this.base) !== this.current.fullPath) {
+ const current = cleanPath(this.base + this.current.fullPath);
+ push ? pushState(current) : replaceState(current);
+ }
+ }
+
+ getCurrentLocation () {
+ return getLocation(this.base)
+ }
+}
+
+function getLocation (base) {
+ let path = decodeURI(window.location.pathname);
+ if (base && path.indexOf(base) === 0) {
+ path = path.slice(base.length);
+ }
+ return (path || '/') + window.location.search + window.location.hash
+}
+
+/* */
+
+class HashHistory extends History {
+ constructor (router, base, fallback) {
+ super(router, base);
+ // check history fallback deeplinking
+ if (fallback && checkFallback(this.base)) {
+ return
+ }
+ ensureSlash();
+ }
+
+ // this is delayed until the app mounts
+ // to avoid the hashchange listener being fired too early
+ setupListeners () {
+ const router = this.router;
+ const expectScroll = router.options.scrollBehavior;
+ const supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ window.addEventListener(
+ supportsPushState ? 'popstate' : 'hashchange',
+ () => {
+ const current = this.current;
+ if (!ensureSlash()) {
+ return
+ }
+ this.transitionTo(getHash(), route => {
+ if (supportsScroll) {
+ handleScroll(this.router, route, current, true);
+ }
+ if (!supportsPushState) {
+ replaceHash(route.fullPath);
+ }
+ });
+ }
+ );
+ }
+
+ push (location, onComplete, onAbort) {
+ const { current: fromRoute } = this;
+ this.transitionTo(
+ location,
+ route => {
+ pushHash(route.fullPath);
+ handleScroll(this.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ }
+
+ replace (location, onComplete, onAbort) {
+ const { current: fromRoute } = this;
+ this.transitionTo(
+ location,
+ route => {
+ replaceHash(route.fullPath);
+ handleScroll(this.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ }
+
+ go (n) {
+ window.history.go(n);
+ }
+
+ ensureURL (push) {
+ const current = this.current.fullPath;
+ if (getHash() !== current) {
+ push ? pushHash(current) : replaceHash(current);
+ }
+ }
+
+ getCurrentLocation () {
+ return getHash()
+ }
+}
+
+function checkFallback (base) {
+ const location = getLocation(base);
+ if (!/^\/#/.test(location)) {
+ window.location.replace(cleanPath(base + '/#' + location));
+ return true
+ }
+}
+
+function ensureSlash () {
+ const path = getHash();
+ if (path.charAt(0) === '/') {
+ return true
+ }
+ replaceHash('/' + path);
+ return false
+}
+
+function getHash () {
+ // We can't use window.location.hash here because it's not
+ // consistent across browsers - Firefox will pre-decode it!
+ let href = window.location.href;
+ const index = href.indexOf('#');
+ // empty path
+ if (index < 0) return ''
+
+ href = href.slice(index + 1);
+ // decode the hash but not the search or hash
+ // as search(query) is already decoded
+ // https://github.com/vuejs/vue-router/issues/2708
+ const searchIndex = href.indexOf('?');
+ if (searchIndex < 0) {
+ const hashIndex = href.indexOf('#');
+ if (hashIndex > -1) {
+ href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex);
+ } else href = decodeURI(href);
+ } else {
+ if (searchIndex > -1) {
+ href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex);
+ }
+ }
+
+ return href
+}
+
+function getUrl (path) {
+ const href = window.location.href;
+ const i = href.indexOf('#');
+ const base = i >= 0 ? href.slice(0, i) : href;
+ return `${base}#${path}`
+}
+
+function pushHash (path) {
+ if (supportsPushState) {
+ pushState(getUrl(path));
+ } else {
+ window.location.hash = path;
+ }
+}
+
+function replaceHash (path) {
+ if (supportsPushState) {
+ replaceState(getUrl(path));
+ } else {
+ window.location.replace(getUrl(path));
+ }
+}
+
+/* */
+
+class AbstractHistory extends History {
+
+
+
+ constructor (router, base) {
+ super(router, base);
+ this.stack = [];
+ this.index = -1;
+ }
+
+ push (location, onComplete, onAbort) {
+ this.transitionTo(
+ location,
+ route => {
+ this.stack = this.stack.slice(0, this.index + 1).concat(route);
+ this.index++;
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ }
+
+ replace (location, onComplete, onAbort) {
+ this.transitionTo(
+ location,
+ route => {
+ this.stack = this.stack.slice(0, this.index).concat(route);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ }
+
+ go (n) {
+ const targetIndex = this.index + n;
+ if (targetIndex < 0 || targetIndex >= this.stack.length) {
+ return
+ }
+ const route = this.stack[targetIndex];
+ this.confirmTransition(
+ route,
+ () => {
+ this.index = targetIndex;
+ this.updateRoute(route);
+ },
+ err => {
+ if (isExtendedError(NavigationDuplicated, err)) {
+ this.index = targetIndex;
+ }
+ }
+ );
+ }
+
+ getCurrentLocation () {
+ const current = this.stack[this.stack.length - 1];
+ return current ? current.fullPath : '/'
+ }
+
+ ensureURL () {
+ // noop
+ }
+}
+
+/* */
+
+
+
+class VueRouter {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ constructor (options = {}) {
+ this.app = null;
+ this.apps = [];
+ this.options = options;
+ this.beforeHooks = [];
+ this.resolveHooks = [];
+ this.afterHooks = [];
+ this.matcher = createMatcher(options.routes || [], this);
+
+ let mode = options.mode || 'hash';
+ this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
+ if (this.fallback) {
+ mode = 'hash';
+ }
+ if (!inBrowser) {
+ mode = 'abstract';
+ }
+ this.mode = mode;
+
+ switch (mode) {
+ case 'history':
+ this.history = new HTML5History(this, options.base);
+ break
+ case 'hash':
+ this.history = new HashHistory(this, options.base, this.fallback);
+ break
+ case 'abstract':
+ this.history = new AbstractHistory(this, options.base);
+ break
+ default:
+ {
+ assert(false, `invalid mode: ${mode}`);
+ }
+ }
+ }
+
+ match (
+ raw,
+ current,
+ redirectedFrom
+ ) {
+ return this.matcher.match(raw, current, redirectedFrom)
+ }
+
+ get currentRoute () {
+ return this.history && this.history.current
+ }
+
+ init (app /* Vue component instance */) {
+ assert(
+ install.installed,
+ `not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
+ `before creating root instance.`
+ );
+
+ this.apps.push(app);
+
+ // set up app destroyed handler
+ // https://github.com/vuejs/vue-router/issues/2639
+ app.$once('hook:destroyed', () => {
+ // clean out app from this.apps array once destroyed
+ const index = this.apps.indexOf(app);
+ if (index > -1) this.apps.splice(index, 1);
+ // ensure we still have a main app or null if no apps
+ // we do not release the router so it can be reused
+ if (this.app === app) this.app = this.apps[0] || null;
+ });
+
+ // main app previously initialized
+ // return as we don't need to set up new history listener
+ if (this.app) {
+ return
+ }
+
+ this.app = app;
+
+ const history = this.history;
+
+ if (history instanceof HTML5History) {
+ history.transitionTo(history.getCurrentLocation());
+ } else if (history instanceof HashHistory) {
+ const setupHashListener = () => {
+ history.setupListeners();
+ };
+ history.transitionTo(
+ history.getCurrentLocation(),
+ setupHashListener,
+ setupHashListener
+ );
+ }
+
+ history.listen(route => {
+ this.apps.forEach((app) => {
+ app._route = route;
+ });
+ });
+ }
+
+ beforeEach (fn) {
+ return registerHook(this.beforeHooks, fn)
+ }
+
+ beforeResolve (fn) {
+ return registerHook(this.resolveHooks, fn)
+ }
+
+ afterEach (fn) {
+ return registerHook(this.afterHooks, fn)
+ }
+
+ onReady (cb, errorCb) {
+ this.history.onReady(cb, errorCb);
+ }
+
+ onError (errorCb) {
+ this.history.onError(errorCb);
+ }
+
+ push (location, onComplete, onAbort) {
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise((resolve, reject) => {
+ this.history.push(location, resolve, reject);
+ })
+ } else {
+ this.history.push(location, onComplete, onAbort);
+ }
+ }
+
+ replace (location, onComplete, onAbort) {
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise((resolve, reject) => {
+ this.history.replace(location, resolve, reject);
+ })
+ } else {
+ this.history.replace(location, onComplete, onAbort);
+ }
+ }
+
+ go (n) {
+ this.history.go(n);
+ }
+
+ back () {
+ this.go(-1);
+ }
+
+ forward () {
+ this.go(1);
+ }
+
+ getMatchedComponents (to) {
+ const route = to
+ ? to.matched
+ ? to
+ : this.resolve(to).route
+ : this.currentRoute;
+ if (!route) {
+ return []
+ }
+ return [].concat.apply([], route.matched.map(m => {
+ return Object.keys(m.components).map(key => {
+ return m.components[key]
+ })
+ }))
+ }
+
+ resolve (
+ to,
+ current,
+ append
+ ) {
+ current = current || this.history.current;
+ const location = normalizeLocation(
+ to,
+ current,
+ append,
+ this
+ );
+ const route = this.match(location, current);
+ const fullPath = route.redirectedFrom || route.fullPath;
+ const base = this.history.base;
+ const href = createHref(base, fullPath, this.mode);
+ return {
+ location,
+ route,
+ href,
+ // for backwards compat
+ normalizedTo: location,
+ resolved: route
+ }
+ }
+
+ addRoutes (routes) {
+ this.matcher.addRoutes(routes);
+ if (this.history.current !== START) {
+ this.history.transitionTo(this.history.getCurrentLocation());
+ }
+ }
+}
+
+function registerHook (list, fn) {
+ list.push(fn);
+ return () => {
+ const i = list.indexOf(fn);
+ if (i > -1) list.splice(i, 1);
+ }
+}
+
+function createHref (base, fullPath, mode) {
+ var path = mode === 'hash' ? '#' + fullPath : fullPath;
+ return base ? cleanPath(base + '/' + path) : path
+}
+
+VueRouter.install = install;
+VueRouter.version = '3.1.3';
+
+if (inBrowser && window.Vue) {
+ window.Vue.use(VueRouter);
+}
+
+export default VueRouter;
diff --git a/node_modules/vue-router/dist/vue-router.esm.browser.min.js b/node_modules/vue-router/dist/vue-router.esm.browser.min.js
new file mode 100644
index 0000000..c681a91
--- /dev/null
+++ b/node_modules/vue-router/dist/vue-router.esm.browser.min.js
@@ -0,0 +1,6 @@
+/*!
+ * vue-router v3.1.3
+ * (c) 2019 Evan You
+ * @license MIT
+ */
+function t(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function e(t,e){return e instanceof t||e&&(e.name===t.name||e._name===t._name)}function n(t,e){for(const n in e)t[n]=e[n];return t}var r={name:"RouterView",functional:!0,props:{name:{type:String,default:"default"}},render(t,{props:e,children:r,parent:o,data:i}){i.routerView=!0;const s=o.$createElement,a=e.name,c=o.$route,u=o._routerViewCache||(o._routerViewCache={});let h=0,p=!1;for(;o&&o._routerRoot!==o;){const t=o.$vnode&&o.$vnode.data;t&&(t.routerView&&h++,t.keepAlive&&o._inactive&&(p=!0)),o=o.$parent}if(i.routerViewDepth=h,p)return s(u[a],i,r);const l=c.matched[h];if(!l)return u[a]=null,s();const f=u[a]=l.components[a];i.registerRouteInstance=(t,e)=>{const n=l.instances[a];(e&&n!==t||!e&&n===t)&&(l.instances[a]=e)},(i.hook||(i.hook={})).prepatch=(t,e)=>{l.instances[a]=e.componentInstance},i.hook.init=t=>{t.data.keepAlive&&t.componentInstance&&t.componentInstance!==l.instances[a]&&(l.instances[a]=t.componentInstance)};let d=i.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0}}(c,l.props&&l.props[a]);if(d){d=i.props=n({},d);const t=i.attrs=i.attrs||{};for(const e in d)f.props&&e in f.props||(t[e]=d[e],delete d[e])}return s(f,i,r)}};const o=/[!'()*]/g,i=t=>"%"+t.charCodeAt(0).toString(16),s=/%2C/g,a=t=>encodeURIComponent(t).replace(o,i).replace(s,","),c=decodeURIComponent;function u(t){const e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(t=>{const n=t.replace(/\+/g," ").split("="),r=c(n.shift()),o=n.length>0?c(n.join("=")):null;void 0===e[r]?e[r]=o:Array.isArray(e[r])?e[r].push(o):e[r]=[e[r],o]}),e):e}function h(t){const e=t?Object.keys(t).map(e=>{const n=t[e];if(void 0===n)return"";if(null===n)return a(e);if(Array.isArray(n)){const t=[];return n.forEach(n=>{void 0!==n&&(null===n?t.push(a(e)):t.push(a(e)+"="+a(n)))}),t.join("&")}return a(e)+"="+a(n)}).filter(t=>t.length>0).join("&"):null;return e?`?${e}`:""}const p=/\/?$/;function l(t,e,n,r){const o=r&&r.options.stringifyQuery;let i=e.query||{};try{i=f(i)}catch(t){}const s={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:m(e,o),matched:t?y(t):[]};return n&&(s.redirectedFrom=m(n,o)),Object.freeze(s)}function f(t){if(Array.isArray(t))return t.map(f);if(t&&"object"==typeof t){const e={};for(const n in t)e[n]=f(t[n]);return e}return t}const d=l(null,{path:"/"});function y(t){const e=[];for(;t;)e.unshift(t),t=t.parent;return e}function m({path:t,query:e={},hash:n=""},r){return(t||"/")+(r||h)(e)+n}function g(t,e){return e===d?t===e:!!e&&(t.path&&e.path?t.path.replace(p,"")===e.path.replace(p,"")&&t.hash===e.hash&&w(t.query,e.query):!(!t.name||!e.name)&&(t.name===e.name&&t.hash===e.hash&&w(t.query,e.query)&&w(t.params,e.params)))}function w(t={},e={}){if(!t||!e)return t===e;const n=Object.keys(t),r=Object.keys(e);return n.length===r.length&&n.every(n=>{const r=t[n],o=e[n];return"object"==typeof r&&"object"==typeof o?w(r,o):String(r)===String(o)})}function b(t,e,n){const r=t.charAt(0);if("/"===r)return t;if("?"===r||"#"===r)return e+t;const o=e.split("/");n&&o[o.length-1]||o.pop();const i=t.replace(/^\//,"").split("/");for(let t=0;t=0&&(e=t.slice(r),t=t.slice(0,r));const o=t.indexOf("?");return o>=0&&(n=t.slice(o+1),t=t.slice(0,o)),{path:t,query:n,hash:e}}(i.path||""),a=e&&e.path||"/",c=s.path?b(s.path,a,r||i.append):a,h=function(t,e={},n){const r=n||u;let o;try{o=r(t||"")}catch(t){o={}}for(const t in e)o[t]=e[t];return o}(s.query,i.query,o&&o.options.parseQuery);let p=i.hash||s.hash;return p&&"#"!==p.charAt(0)&&(p=`#${p}`),{_normalized:!0,path:c,query:h,hash:p}}const V=[String,Object],H=[String,Array],z=()=>{};var D={name:"RouterLink",props:{to:{type:V,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:H,default:"click"}},render(t){const e=this.$router,r=this.$route,{location:o,route:i,href:s}=e.resolve(this.to,r,this.append),a={},c=e.options.linkActiveClass,u=e.options.linkExactActiveClass,h=null==c?"router-link-active":c,f=null==u?"router-link-exact-active":u,d=null==this.activeClass?h:this.activeClass,y=null==this.exactActiveClass?f:this.exactActiveClass,m=i.redirectedFrom?l(null,B(i.redirectedFrom),null,e):i;a[y]=g(r,m),a[d]=this.exact?a[y]:function(t,e){return 0===t.path.replace(p,"/").indexOf(e.path.replace(p,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(const n in e)if(!(n in t))return!1;return!0}(t.query,e.query)}(r,m);const w=t=>{F(t)&&(this.replace?e.replace(o,z):e.push(o,z))},b={click:F};Array.isArray(this.event)?this.event.forEach(t=>{b[t]=w}):b[this.event]=w;const v={class:a},x=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:s,route:i,navigate:w,isActive:a[d],isExactActive:a[y]});if(x){if(1===x.length)return x[0];if(x.length>1||!x.length)return 0===x.length?t():t("span",{},x)}if("a"===this.tag)v.on=b,v.attrs={href:s};else{const t=function t(e){if(e){let n;for(let r=0;r{!function t(e,n,r,o,i,s){const{path:a,name:c}=o;const u=o.pathToRegexpOptions||{};const h=function(t,e,n){n||(t=t.replace(/\/$/,""));return"/"===t[0]?t:null==e?t:v(`${e.path}/${t}`)}(a,i,u.strict);"boolean"==typeof o.caseSensitive&&(u.sensitive=o.caseSensitive);const p={path:h,regex:Q(h,u),components:o.components||{default:o.component},instances:{},name:c,parent:i,matchAs:s,redirect:o.redirect,beforeEnter:o.beforeEnter,meta:o.meta||{},props:null==o.props?{}:o.components?o.props:{default:o.props}};o.children&&o.children.forEach(o=>{const i=s?v(`${s}/${o.path}`):void 0;t(e,n,r,o,p,i)});n[p.path]||(e.push(p.path),n[p.path]=p);if(void 0!==o.alias){const s=Array.isArray(o.alias)?o.alias:[o.alias];for(let a=0;a!t.optional).map(t=>t.name);if("object"!=typeof c.params&&(c.params={}),i&&"object"==typeof i.params)for(const t in i.params)!(t in c.params)&&e.indexOf(t)>-1&&(c.params[t]=i.params[t]);return c.path=M(t.path,c.params),a(t,c,s)}if(c.path){c.params={};for(let t=0;t{it(),t.state&&t.state.key&&et(t.state.key)})}function ot(t,e,n,r){if(!t.app)return;const o=t.options.scrollBehavior;o&&t.app.$nextTick(()=>{const i=function(){const t=tt();if(t)return nt[t]}(),s=o.call(t,e,n,r?i:null);s&&("function"==typeof s.then?s.then(t=>{ht(t,i)}).catch(t=>{}):ht(s,i))})}function it(){const t=tt();t&&(nt[t]={x:window.pageXOffset,y:window.pageYOffset})}function st(t){return ct(t.x)||ct(t.y)}function at(t){return{x:ct(t.x)?t.x:window.pageXOffset,y:ct(t.y)?t.y:window.pageYOffset}}function ct(t){return"number"==typeof t}const ut=/^#\d/;function ht(t,e){const n="object"==typeof t;if(n&&"string"==typeof t.selector){const n=ut.test(t.selector)?document.getElementById(t.selector.slice(1)):document.querySelector(t.selector);if(n){let o=t.offset&&"object"==typeof t.offset?t.offset:{};e=function(t,e){const n=document.documentElement.getBoundingClientRect(),r=t.getBoundingClientRect();return{x:r.left-n.left-e.x,y:r.top-n.top-e.y}}(n,o={x:ct((r=o).x)?r.x:0,y:ct(r.y)?r.y:0})}else st(t)&&(e=at(t))}else n&&st(t)&&(e=at(t));var r;e&&window.scrollTo(e.x,e.y)}const pt=K&&function(){const t=window.navigator.userAgent;return(-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&(window.history&&"pushState"in window.history)}();function lt(t,e){it();const n=window.history;try{e?n.replaceState({key:tt()},"",t):n.pushState({key:et(G())},"",t)}catch(n){window.location[e?"replace":"assign"](t)}}function ft(t){lt(t,!0)}function dt(t,e,n){const r=o=>{o>=t.length?n():t[o]?e(t[o],()=>{r(o+1)}):r(o+1)};r(0)}function yt(e){return(n,r,o)=>{let i=!1,s=0,a=null;mt(e,(e,n,r,c)=>{if("function"==typeof e&&void 0===e.cid){i=!0,s++;const n=bt(t=>{(function(t){return t.__esModule||wt&&"Module"===t[Symbol.toStringTag]})(t)&&(t=t.default),e.resolved="function"==typeof t?t:N.extend(t),r.components[c]=t,--s<=0&&o()}),u=bt(e=>{const n=`Failed to resolve async component ${c}: ${e}`;a||(a=t(e)?e:new Error(n),o(a))});let h;try{h=e(n,u)}catch(t){u(t)}if(h)if("function"==typeof h.then)h.then(n,u);else{const t=h.component;t&&"function"==typeof t.then&&t.then(n,u)}}}),i||o()}}function mt(t,e){return gt(t.map(t=>Object.keys(t.components).map(n=>e(t.components[n],t.instances[n],t,n))))}function gt(t){return Array.prototype.concat.apply([],t)}const wt="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function bt(t){let e=!1;return function(...n){if(!e)return e=!0,t.apply(this,n)}}class vt extends Error{constructor(t){super(),this.name=this._name="NavigationDuplicated",this.message=`Navigating to current location ("${t.fullPath}") is not allowed`,Object.defineProperty(this,"stack",{value:(new Error).stack,writable:!0,configurable:!0})}}vt._name="NavigationDuplicated";class xt{constructor(t,e){this.router=t,this.base=function(t){if(!t)if(K){const e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";"/"!==t.charAt(0)&&(t="/"+t);return t.replace(/\/$/,"")}(e),this.current=d,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]}listen(t){this.cb=t}onReady(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))}onError(t){this.errorCbs.push(t)}transitionTo(t,e,n){const r=this.router.match(t,this.current);this.confirmTransition(r,()=>{this.updateRoute(r),e&&e(r),this.ensureURL(),this.ready||(this.ready=!0,this.readyCbs.forEach(t=>{t(r)}))},t=>{n&&n(t),t&&!this.ready&&(this.ready=!0,this.readyErrorCbs.forEach(e=>{e(t)}))})}confirmTransition(n,r,o){const i=this.current,s=n=>{!e(vt,n)&&t(n)&&(this.errorCbs.length?this.errorCbs.forEach(t=>{t(n)}):console.error(n)),o&&o(n)};if(g(n,i)&&n.matched.length===i.matched.length)return this.ensureURL(),s(new vt(n));const{updated:a,deactivated:c,activated:u}=function(t,e){let n;const r=Math.max(t.length,e.length);for(n=0;nt.beforeEnter),yt(u));this.pending=n;const p=(e,r)=>{if(this.pending!==n)return s();try{e(n,i,e=>{!1===e||t(e)?(this.ensureURL(!0),s(e)):"string"==typeof e||"object"==typeof e&&("string"==typeof e.path||"string"==typeof e.name)?(s(),"object"==typeof e&&e.replace?this.replace(e):this.push(e)):r(e)})}catch(t){s(t)}};dt(h,p,()=>{const t=[];dt(function(t,e,n){return kt(t,"beforeRouteEnter",(t,r,o,i)=>(function(t,e,n,r,o){return function(i,s,a){return t(i,s,t=>{"function"==typeof t&&r.push(()=>{!function t(e,n,r,o){n[r]&&!n[r]._isBeingDestroyed?e(n[r]):o()&&setTimeout(()=>{t(e,n,r,o)},16)}(t,e.instances,n,o)}),a(t)})}})(t,o,i,e,n))}(u,t,()=>this.current===n).concat(this.router.resolveHooks),p,()=>{if(this.pending!==n)return s();this.pending=null,r(n),this.router.app&&this.router.app.$nextTick(()=>{t.forEach(t=>{t()})})})})}updateRoute(t){const e=this.current;this.current=t,this.cb&&this.cb(t),this.router.afterHooks.forEach(n=>{n&&n(t,e)})}}function kt(t,e,n,r){const o=mt(t,(t,r,o,i)=>{const s=function(t,e){"function"!=typeof t&&(t=N.extend(t));return t.options[e]}(t,e);if(s)return Array.isArray(s)?s.map(t=>n(t,r,o,i)):n(s,r,o,i)});return gt(r?o.reverse():o)}function Rt(t,e){if(e)return function(){return t.apply(e,arguments)}}class Et extends xt{constructor(t,e){super(t,e);const n=t.options.scrollBehavior,r=pt&&n;r&&rt();const o=At(this.base);window.addEventListener("popstate",e=>{const n=this.current,i=At(this.base);this.current===d&&i===o||this.transitionTo(i,e=>{r&&ot(t,e,n,!0)})})}go(t){window.history.go(t)}push(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{lt(v(this.base+t.fullPath)),ot(this.router,t,r,!1),e&&e(t)},n)}replace(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{ft(v(this.base+t.fullPath)),ot(this.router,t,r,!1),e&&e(t)},n)}ensureURL(t){if(At(this.base)!==this.current.fullPath){const e=v(this.base+this.current.fullPath);t?lt(e):ft(e)}}getCurrentLocation(){return At(this.base)}}function At(t){let e=decodeURI(window.location.pathname);return t&&0===e.indexOf(t)&&(e=e.slice(t.length)),(e||"/")+window.location.search+window.location.hash}class $t extends xt{constructor(t,e,n){super(t,e),n&&function(t){const e=At(t);if(!/^\/#/.test(e))return window.location.replace(v(t+"/#"+e)),!0}(this.base)||Ot()}setupListeners(){const t=this.router.options.scrollBehavior,e=pt&&t;e&&rt(),window.addEventListener(pt?"popstate":"hashchange",()=>{const t=this.current;Ot()&&this.transitionTo(Ct(),n=>{e&&ot(this.router,n,t,!0),pt||Tt(n.fullPath)})})}push(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{St(t.fullPath),ot(this.router,t,r,!1),e&&e(t)},n)}replace(t,e,n){const{current:r}=this;this.transitionTo(t,t=>{Tt(t.fullPath),ot(this.router,t,r,!1),e&&e(t)},n)}go(t){window.history.go(t)}ensureURL(t){const e=this.current.fullPath;Ct()!==e&&(t?St(e):Tt(e))}getCurrentLocation(){return Ct()}}function Ot(){const t=Ct();return"/"===t.charAt(0)||(Tt("/"+t),!1)}function Ct(){let t=window.location.href;const e=t.indexOf("#");if(e<0)return"";const n=(t=t.slice(e+1)).indexOf("?");if(n<0){const e=t.indexOf("#");t=e>-1?decodeURI(t.slice(0,e))+t.slice(e):decodeURI(t)}else n>-1&&(t=decodeURI(t.slice(0,n))+t.slice(n));return t}function jt(t){const e=window.location.href,n=e.indexOf("#");return`${n>=0?e.slice(0,n):e}#${t}`}function St(t){pt?lt(jt(t)):window.location.hash=t}function Tt(t){pt?ft(jt(t)):window.location.replace(jt(t))}class _t extends xt{constructor(t,e){super(t,e),this.stack=[],this.index=-1}push(t,e,n){this.transitionTo(t,t=>{this.stack=this.stack.slice(0,this.index+1).concat(t),this.index++,e&&e(t)},n)}replace(t,e,n){this.transitionTo(t,t=>{this.stack=this.stack.slice(0,this.index).concat(t),e&&e(t)},n)}go(t){const n=this.index+t;if(n<0||n>=this.stack.length)return;const r=this.stack[n];this.confirmTransition(r,()=>{this.index=n,this.updateRoute(r)},t=>{e(vt,t)&&(this.index=n)})}getCurrentLocation(){const t=this.stack[this.stack.length-1];return t?t.fullPath:"/"}ensureURL(){}}class Pt{constructor(t={}){this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=X(t.routes||[],this);let e=t.mode||"hash";switch(this.fallback="history"===e&&!pt&&!1!==t.fallback,this.fallback&&(e="hash"),K||(e="abstract"),this.mode=e,e){case"history":this.history=new Et(this,t.base);break;case"hash":this.history=new $t(this,t.base,this.fallback);break;case"abstract":this.history=new _t(this,t.base)}}match(t,e,n){return this.matcher.match(t,e,n)}get currentRoute(){return this.history&&this.history.current}init(t){if(this.apps.push(t),t.$once("hook:destroyed",()=>{const e=this.apps.indexOf(t);e>-1&&this.apps.splice(e,1),this.app===t&&(this.app=this.apps[0]||null)}),this.app)return;this.app=t;const e=this.history;if(e instanceof Et)e.transitionTo(e.getCurrentLocation());else if(e instanceof $t){const t=()=>{e.setupListeners()};e.transitionTo(e.getCurrentLocation(),t,t)}e.listen(t=>{this.apps.forEach(e=>{e._route=t})})}beforeEach(t){return Lt(this.beforeHooks,t)}beforeResolve(t){return Lt(this.resolveHooks,t)}afterEach(t){return Lt(this.afterHooks,t)}onReady(t,e){this.history.onReady(t,e)}onError(t){this.history.onError(t)}push(t,e,n){if(!e&&!n&&"undefined"!=typeof Promise)return new Promise((e,n)=>{this.history.push(t,e,n)});this.history.push(t,e,n)}replace(t,e,n){if(!e&&!n&&"undefined"!=typeof Promise)return new Promise((e,n)=>{this.history.replace(t,e,n)});this.history.replace(t,e,n)}go(t){this.history.go(t)}back(){this.go(-1)}forward(){this.go(1)}getMatchedComponents(t){const e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(t=>Object.keys(t.components).map(e=>t.components[e]))):[]}resolve(t,e,n){const r=B(t,e=e||this.history.current,n,this),o=this.match(r,e),i=o.redirectedFrom||o.fullPath;return{location:r,route:o,href:function(t,e,n){var r="hash"===n?"#"+e:e;return t?v(t+"/"+r):r}(this.history.base,i,this.mode),normalizedTo:r,resolved:o}}addRoutes(t){this.matcher.addRoutes(t),this.history.current!==d&&this.history.transitionTo(this.history.getCurrentLocation())}}function Lt(t,e){return t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)}}Pt.install=function t(e){if(t.installed&&N===e)return;t.installed=!0,N=e;const n=t=>void 0!==t,o=(t,e)=>{let r=t.$options._parentVnode;n(r)&&n(r=r.data)&&n(r=r.registerRouteInstance)&&r(t,e)};e.mixin({beforeCreate(){n(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),e.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,o(this,this)},destroyed(){o(this)}}),Object.defineProperty(e.prototype,"$router",{get(){return this._routerRoot._router}}),Object.defineProperty(e.prototype,"$route",{get(){return this._routerRoot._route}}),e.component("RouterView",r),e.component("RouterLink",D);const i=e.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created},Pt.version="3.1.3",K&&window.Vue&&window.Vue.use(Pt);export default Pt;
\ No newline at end of file
diff --git a/node_modules/vue-router/dist/vue-router.esm.js b/node_modules/vue-router/dist/vue-router.esm.js
new file mode 100644
index 0000000..39056e6
--- /dev/null
+++ b/node_modules/vue-router/dist/vue-router.esm.js
@@ -0,0 +1,2882 @@
+/*!
+ * vue-router v3.1.3
+ * (c) 2019 Evan You
+ * @license MIT
+ */
+/* */
+
+function assert (condition, message) {
+ if (!condition) {
+ throw new Error(("[vue-router] " + message))
+ }
+}
+
+function warn (condition, message) {
+ if (process.env.NODE_ENV !== 'production' && !condition) {
+ typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
+ }
+}
+
+function isError (err) {
+ return Object.prototype.toString.call(err).indexOf('Error') > -1
+}
+
+function isExtendedError (constructor, err) {
+ return (
+ err instanceof constructor ||
+ // _name is to support IE9 too
+ (err && (err.name === constructor.name || err._name === constructor._name))
+ )
+}
+
+function extend (a, b) {
+ for (var key in b) {
+ a[key] = b[key];
+ }
+ return a
+}
+
+var View = {
+ name: 'RouterView',
+ functional: true,
+ props: {
+ name: {
+ type: String,
+ default: 'default'
+ }
+ },
+ render: function render (_, ref) {
+ var props = ref.props;
+ var children = ref.children;
+ var parent = ref.parent;
+ var data = ref.data;
+
+ // used by devtools to display a router-view badge
+ data.routerView = true;
+
+ // directly use parent context's createElement() function
+ // so that components rendered by router-view can resolve named slots
+ var h = parent.$createElement;
+ var name = props.name;
+ var route = parent.$route;
+ var cache = parent._routerViewCache || (parent._routerViewCache = {});
+
+ // determine current view depth, also check to see if the tree
+ // has been toggled inactive but kept-alive.
+ var depth = 0;
+ var inactive = false;
+ while (parent && parent._routerRoot !== parent) {
+ var vnodeData = parent.$vnode && parent.$vnode.data;
+ if (vnodeData) {
+ if (vnodeData.routerView) {
+ depth++;
+ }
+ if (vnodeData.keepAlive && parent._inactive) {
+ inactive = true;
+ }
+ }
+ parent = parent.$parent;
+ }
+ data.routerViewDepth = depth;
+
+ // render previous view if the tree is inactive and kept-alive
+ if (inactive) {
+ return h(cache[name], data, children)
+ }
+
+ var matched = route.matched[depth];
+ // render empty node if no matched route
+ if (!matched) {
+ cache[name] = null;
+ return h()
+ }
+
+ var component = cache[name] = matched.components[name];
+
+ // attach instance registration hook
+ // this will be called in the instance's injected lifecycle hooks
+ data.registerRouteInstance = function (vm, val) {
+ // val could be undefined for unregistration
+ var current = matched.instances[name];
+ if (
+ (val && current !== vm) ||
+ (!val && current === vm)
+ ) {
+ matched.instances[name] = val;
+ }
+ }
+
+ // also register instance in prepatch hook
+ // in case the same component instance is reused across different routes
+ ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
+ matched.instances[name] = vnode.componentInstance;
+ };
+
+ // register instance in init hook
+ // in case kept-alive component be actived when routes changed
+ data.hook.init = function (vnode) {
+ if (vnode.data.keepAlive &&
+ vnode.componentInstance &&
+ vnode.componentInstance !== matched.instances[name]
+ ) {
+ matched.instances[name] = vnode.componentInstance;
+ }
+ };
+
+ // resolve props
+ var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
+ if (propsToPass) {
+ // clone to prevent mutation
+ propsToPass = data.props = extend({}, propsToPass);
+ // pass non-declared props as attrs
+ var attrs = data.attrs = data.attrs || {};
+ for (var key in propsToPass) {
+ if (!component.props || !(key in component.props)) {
+ attrs[key] = propsToPass[key];
+ delete propsToPass[key];
+ }
+ }
+ }
+
+ return h(component, data, children)
+ }
+};
+
+function resolveProps (route, config) {
+ switch (typeof config) {
+ case 'undefined':
+ return
+ case 'object':
+ return config
+ case 'function':
+ return config(route)
+ case 'boolean':
+ return config ? route.params : undefined
+ default:
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false,
+ "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " +
+ "expecting an object, function or boolean."
+ );
+ }
+ }
+}
+
+/* */
+
+var encodeReserveRE = /[!'()*]/g;
+var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
+var commaRE = /%2C/g;
+
+// fixed encodeURIComponent which is more conformant to RFC3986:
+// - escapes [!'()*]
+// - preserve commas
+var encode = function (str) { return encodeURIComponent(str)
+ .replace(encodeReserveRE, encodeReserveReplacer)
+ .replace(commaRE, ','); };
+
+var decode = decodeURIComponent;
+
+function resolveQuery (
+ query,
+ extraQuery,
+ _parseQuery
+) {
+ if ( extraQuery === void 0 ) extraQuery = {};
+
+ var parse = _parseQuery || parseQuery;
+ var parsedQuery;
+ try {
+ parsedQuery = parse(query || '');
+ } catch (e) {
+ process.env.NODE_ENV !== 'production' && warn(false, e.message);
+ parsedQuery = {};
+ }
+ for (var key in extraQuery) {
+ parsedQuery[key] = extraQuery[key];
+ }
+ return parsedQuery
+}
+
+function parseQuery (query) {
+ var res = {};
+
+ query = query.trim().replace(/^(\?|#|&)/, '');
+
+ if (!query) {
+ return res
+ }
+
+ query.split('&').forEach(function (param) {
+ var parts = param.replace(/\+/g, ' ').split('=');
+ var key = decode(parts.shift());
+ var val = parts.length > 0
+ ? decode(parts.join('='))
+ : null;
+
+ if (res[key] === undefined) {
+ res[key] = val;
+ } else if (Array.isArray(res[key])) {
+ res[key].push(val);
+ } else {
+ res[key] = [res[key], val];
+ }
+ });
+
+ return res
+}
+
+function stringifyQuery (obj) {
+ var res = obj ? Object.keys(obj).map(function (key) {
+ var val = obj[key];
+
+ if (val === undefined) {
+ return ''
+ }
+
+ if (val === null) {
+ return encode(key)
+ }
+
+ if (Array.isArray(val)) {
+ var result = [];
+ val.forEach(function (val2) {
+ if (val2 === undefined) {
+ return
+ }
+ if (val2 === null) {
+ result.push(encode(key));
+ } else {
+ result.push(encode(key) + '=' + encode(val2));
+ }
+ });
+ return result.join('&')
+ }
+
+ return encode(key) + '=' + encode(val)
+ }).filter(function (x) { return x.length > 0; }).join('&') : null;
+ return res ? ("?" + res) : ''
+}
+
+/* */
+
+var trailingSlashRE = /\/?$/;
+
+function createRoute (
+ record,
+ location,
+ redirectedFrom,
+ router
+) {
+ var stringifyQuery = router && router.options.stringifyQuery;
+
+ var query = location.query || {};
+ try {
+ query = clone(query);
+ } catch (e) {}
+
+ var route = {
+ name: location.name || (record && record.name),
+ meta: (record && record.meta) || {},
+ path: location.path || '/',
+ hash: location.hash || '',
+ query: query,
+ params: location.params || {},
+ fullPath: getFullPath(location, stringifyQuery),
+ matched: record ? formatMatch(record) : []
+ };
+ if (redirectedFrom) {
+ route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);
+ }
+ return Object.freeze(route)
+}
+
+function clone (value) {
+ if (Array.isArray(value)) {
+ return value.map(clone)
+ } else if (value && typeof value === 'object') {
+ var res = {};
+ for (var key in value) {
+ res[key] = clone(value[key]);
+ }
+ return res
+ } else {
+ return value
+ }
+}
+
+// the starting route that represents the initial state
+var START = createRoute(null, {
+ path: '/'
+});
+
+function formatMatch (record) {
+ var res = [];
+ while (record) {
+ res.unshift(record);
+ record = record.parent;
+ }
+ return res
+}
+
+function getFullPath (
+ ref,
+ _stringifyQuery
+) {
+ var path = ref.path;
+ var query = ref.query; if ( query === void 0 ) query = {};
+ var hash = ref.hash; if ( hash === void 0 ) hash = '';
+
+ var stringify = _stringifyQuery || stringifyQuery;
+ return (path || '/') + stringify(query) + hash
+}
+
+function isSameRoute (a, b) {
+ if (b === START) {
+ return a === b
+ } else if (!b) {
+ return false
+ } else if (a.path && b.path) {
+ return (
+ a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query)
+ )
+ } else if (a.name && b.name) {
+ return (
+ a.name === b.name &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query) &&
+ isObjectEqual(a.params, b.params)
+ )
+ } else {
+ return false
+ }
+}
+
+function isObjectEqual (a, b) {
+ if ( a === void 0 ) a = {};
+ if ( b === void 0 ) b = {};
+
+ // handle null value #1566
+ if (!a || !b) { return a === b }
+ var aKeys = Object.keys(a);
+ var bKeys = Object.keys(b);
+ if (aKeys.length !== bKeys.length) {
+ return false
+ }
+ return aKeys.every(function (key) {
+ var aVal = a[key];
+ var bVal = b[key];
+ // check nested equality
+ if (typeof aVal === 'object' && typeof bVal === 'object') {
+ return isObjectEqual(aVal, bVal)
+ }
+ return String(aVal) === String(bVal)
+ })
+}
+
+function isIncludedRoute (current, target) {
+ return (
+ current.path.replace(trailingSlashRE, '/').indexOf(
+ target.path.replace(trailingSlashRE, '/')
+ ) === 0 &&
+ (!target.hash || current.hash === target.hash) &&
+ queryIncludes(current.query, target.query)
+ )
+}
+
+function queryIncludes (current, target) {
+ for (var key in target) {
+ if (!(key in current)) {
+ return false
+ }
+ }
+ return true
+}
+
+/* */
+
+function resolvePath (
+ relative,
+ base,
+ append
+) {
+ var firstChar = relative.charAt(0);
+ if (firstChar === '/') {
+ return relative
+ }
+
+ if (firstChar === '?' || firstChar === '#') {
+ return base + relative
+ }
+
+ var stack = base.split('/');
+
+ // remove trailing segment if:
+ // - not appending
+ // - appending to trailing slash (last segment is empty)
+ if (!append || !stack[stack.length - 1]) {
+ stack.pop();
+ }
+
+ // resolve relative path
+ var segments = relative.replace(/^\//, '').split('/');
+ for (var i = 0; i < segments.length; i++) {
+ var segment = segments[i];
+ if (segment === '..') {
+ stack.pop();
+ } else if (segment !== '.') {
+ stack.push(segment);
+ }
+ }
+
+ // ensure leading slash
+ if (stack[0] !== '') {
+ stack.unshift('');
+ }
+
+ return stack.join('/')
+}
+
+function parsePath (path) {
+ var hash = '';
+ var query = '';
+
+ var hashIndex = path.indexOf('#');
+ if (hashIndex >= 0) {
+ hash = path.slice(hashIndex);
+ path = path.slice(0, hashIndex);
+ }
+
+ var queryIndex = path.indexOf('?');
+ if (queryIndex >= 0) {
+ query = path.slice(queryIndex + 1);
+ path = path.slice(0, queryIndex);
+ }
+
+ return {
+ path: path,
+ query: query,
+ hash: hash
+ }
+}
+
+function cleanPath (path) {
+ return path.replace(/\/\//g, '/')
+}
+
+var isarray = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]';
+};
+
+/**
+ * Expose `pathToRegexp`.
+ */
+var pathToRegexp_1 = pathToRegexp;
+var parse_1 = parse;
+var compile_1 = compile;
+var tokensToFunction_1 = tokensToFunction;
+var tokensToRegExp_1 = tokensToRegExp;
+
+/**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+var PATH_REGEXP = new RegExp([
+ // Match escaped characters that would otherwise appear in future matches.
+ // This allows the user to escape special characters that won't transform.
+ '(\\\\.)',
+ // Match Express-style parameters and un-named parameters with a prefix
+ // and optional suffixes. Matches appear as:
+ //
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
+].join('|'), 'g');
+
+/**
+ * Parse a string for the raw tokens.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!Array}
+ */
+function parse (str, options) {
+ var tokens = [];
+ var key = 0;
+ var index = 0;
+ var path = '';
+ var defaultDelimiter = options && options.delimiter || '/';
+ var res;
+
+ while ((res = PATH_REGEXP.exec(str)) != null) {
+ var m = res[0];
+ var escaped = res[1];
+ var offset = res.index;
+ path += str.slice(index, offset);
+ index = offset + m.length;
+
+ // Ignore already escaped sequences.
+ if (escaped) {
+ path += escaped[1];
+ continue
+ }
+
+ var next = str[index];
+ var prefix = res[2];
+ var name = res[3];
+ var capture = res[4];
+ var group = res[5];
+ var modifier = res[6];
+ var asterisk = res[7];
+
+ // Push the current path onto the tokens.
+ if (path) {
+ tokens.push(path);
+ path = '';
+ }
+
+ var partial = prefix != null && next != null && next !== prefix;
+ var repeat = modifier === '+' || modifier === '*';
+ var optional = modifier === '?' || modifier === '*';
+ var delimiter = res[2] || defaultDelimiter;
+ var pattern = capture || group;
+
+ tokens.push({
+ name: name || key++,
+ prefix: prefix || '',
+ delimiter: delimiter,
+ optional: optional,
+ repeat: repeat,
+ partial: partial,
+ asterisk: !!asterisk,
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
+ });
+ }
+
+ // Match any characters still remaining.
+ if (index < str.length) {
+ path += str.substr(index);
+ }
+
+ // If the path exists, push it onto the end.
+ if (path) {
+ tokens.push(path);
+ }
+
+ return tokens
+}
+
+/**
+ * Compile a string to a template function for the path.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!function(Object=, Object=)}
+ */
+function compile (str, options) {
+ return tokensToFunction(parse(str, options))
+}
+
+/**
+ * Prettier encoding of URI path segments.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeURIComponentPretty (str) {
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeAsterisk (str) {
+ return encodeURI(str).replace(/[?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Expose a method for transforming tokens into the path function.
+ */
+function tokensToFunction (tokens) {
+ // Compile all the tokens into regexps.
+ var matches = new Array(tokens.length);
+
+ // Compile all the patterns before compilation.
+ for (var i = 0; i < tokens.length; i++) {
+ if (typeof tokens[i] === 'object') {
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
+ }
+ }
+
+ return function (obj, opts) {
+ var path = '';
+ var data = obj || {};
+ var options = opts || {};
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
+
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ path += token;
+
+ continue
+ }
+
+ var value = data[token.name];
+ var segment;
+
+ if (value == null) {
+ if (token.optional) {
+ // Prepend partial segment prefixes.
+ if (token.partial) {
+ path += token.prefix;
+ }
+
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to be defined')
+ }
+ }
+
+ if (isarray(value)) {
+ if (!token.repeat) {
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
+ }
+
+ if (value.length === 0) {
+ if (token.optional) {
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
+ }
+ }
+
+ for (var j = 0; j < value.length; j++) {
+ segment = encode(value[j]);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
+ }
+
+ path += (j === 0 ? token.prefix : token.delimiter) + segment;
+ }
+
+ continue
+ }
+
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
+ }
+
+ path += token.prefix + segment;
+ }
+
+ return path
+ }
+}
+
+/**
+ * Escape a regular expression string.
+ *
+ * @param {string} str
+ * @return {string}
+ */
+function escapeString (str) {
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
+}
+
+/**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param {string} group
+ * @return {string}
+ */
+function escapeGroup (group) {
+ return group.replace(/([=!:$\/()])/g, '\\$1')
+}
+
+/**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param {!RegExp} re
+ * @param {Array} keys
+ * @return {!RegExp}
+ */
+function attachKeys (re, keys) {
+ re.keys = keys;
+ return re
+}
+
+/**
+ * Get the flags for a regexp from the options.
+ *
+ * @param {Object} options
+ * @return {string}
+ */
+function flags (options) {
+ return options.sensitive ? '' : 'i'
+}
+
+/**
+ * Pull out keys from a regexp.
+ *
+ * @param {!RegExp} path
+ * @param {!Array} keys
+ * @return {!RegExp}
+ */
+function regexpToRegexp (path, keys) {
+ // Use a negative lookahead to match only capturing groups.
+ var groups = path.source.match(/\((?!\?)/g);
+
+ if (groups) {
+ for (var i = 0; i < groups.length; i++) {
+ keys.push({
+ name: i,
+ prefix: null,
+ delimiter: null,
+ optional: false,
+ repeat: false,
+ partial: false,
+ asterisk: false,
+ pattern: null
+ });
+ }
+ }
+
+ return attachKeys(path, keys)
+}
+
+/**
+ * Transform an array into a regexp.
+ *
+ * @param {!Array} path
+ * @param {Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function arrayToRegexp (path, keys, options) {
+ var parts = [];
+
+ for (var i = 0; i < path.length; i++) {
+ parts.push(pathToRegexp(path[i], keys, options).source);
+ }
+
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
+
+ return attachKeys(regexp, keys)
+}
+
+/**
+ * Create a path regexp from string input.
+ *
+ * @param {string} path
+ * @param {!Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function stringToRegexp (path, keys, options) {
+ return tokensToRegExp(parse(path, options), keys, options)
+}
+
+/**
+ * Expose a function for taking tokens and returning a RegExp.
+ *
+ * @param {!Array} tokens
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function tokensToRegExp (tokens, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ var strict = options.strict;
+ var end = options.end !== false;
+ var route = '';
+
+ // Iterate over the tokens and create our regexp string.
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ route += escapeString(token);
+ } else {
+ var prefix = escapeString(token.prefix);
+ var capture = '(?:' + token.pattern + ')';
+
+ keys.push(token);
+
+ if (token.repeat) {
+ capture += '(?:' + prefix + capture + ')*';
+ }
+
+ if (token.optional) {
+ if (!token.partial) {
+ capture = '(?:' + prefix + '(' + capture + '))?';
+ } else {
+ capture = prefix + '(' + capture + ')?';
+ }
+ } else {
+ capture = prefix + '(' + capture + ')';
+ }
+
+ route += capture;
+ }
+ }
+
+ var delimiter = escapeString(options.delimiter || '/');
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
+
+ // In non-strict mode we allow a slash at the end of match. If the path to
+ // match already ends with a slash, we remove it for consistency. The slash
+ // is valid at the end of a path match, not in the middle. This is important
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
+ if (!strict) {
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
+ }
+
+ if (end) {
+ route += '$';
+ } else {
+ // In non-ending mode, we need the capturing groups to match as much as
+ // possible by using a positive lookahead to the end or next path segment.
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
+ }
+
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
+}
+
+/**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param {(string|RegExp|Array)} path
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function pathToRegexp (path, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ if (path instanceof RegExp) {
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
+ }
+
+ if (isarray(path)) {
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
+ }
+
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
+}
+pathToRegexp_1.parse = parse_1;
+pathToRegexp_1.compile = compile_1;
+pathToRegexp_1.tokensToFunction = tokensToFunction_1;
+pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
+
+/* */
+
+// $flow-disable-line
+var regexpCompileCache = Object.create(null);
+
+function fillParams (
+ path,
+ params,
+ routeMsg
+) {
+ params = params || {};
+ try {
+ var filler =
+ regexpCompileCache[path] ||
+ (regexpCompileCache[path] = pathToRegexp_1.compile(path));
+
+ // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
+ if (params.pathMatch) { params[0] = params.pathMatch; }
+
+ return filler(params, { pretty: true })
+ } catch (e) {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
+ }
+ return ''
+ } finally {
+ // delete the 0 if it was added
+ delete params[0];
+ }
+}
+
+/* */
+
+function normalizeLocation (
+ raw,
+ current,
+ append,
+ router
+) {
+ var next = typeof raw === 'string' ? { path: raw } : raw;
+ // named target
+ if (next._normalized) {
+ return next
+ } else if (next.name) {
+ return extend({}, raw)
+ }
+
+ // relative params
+ if (!next.path && next.params && current) {
+ next = extend({}, next);
+ next._normalized = true;
+ var params = extend(extend({}, current.params), next.params);
+ if (current.name) {
+ next.name = current.name;
+ next.params = params;
+ } else if (current.matched.length) {
+ var rawPath = current.matched[current.matched.length - 1].path;
+ next.path = fillParams(rawPath, params, ("path " + (current.path)));
+ } else if (process.env.NODE_ENV !== 'production') {
+ warn(false, "relative params navigation requires a current route.");
+ }
+ return next
+ }
+
+ var parsedPath = parsePath(next.path || '');
+ var basePath = (current && current.path) || '/';
+ var path = parsedPath.path
+ ? resolvePath(parsedPath.path, basePath, append || next.append)
+ : basePath;
+
+ var query = resolveQuery(
+ parsedPath.query,
+ next.query,
+ router && router.options.parseQuery
+ );
+
+ var hash = next.hash || parsedPath.hash;
+ if (hash && hash.charAt(0) !== '#') {
+ hash = "#" + hash;
+ }
+
+ return {
+ _normalized: true,
+ path: path,
+ query: query,
+ hash: hash
+ }
+}
+
+/* */
+
+// work around weird flow bug
+var toTypes = [String, Object];
+var eventTypes = [String, Array];
+
+var noop = function () {};
+
+var Link = {
+ name: 'RouterLink',
+ props: {
+ to: {
+ type: toTypes,
+ required: true
+ },
+ tag: {
+ type: String,
+ default: 'a'
+ },
+ exact: Boolean,
+ append: Boolean,
+ replace: Boolean,
+ activeClass: String,
+ exactActiveClass: String,
+ event: {
+ type: eventTypes,
+ default: 'click'
+ }
+ },
+ render: function render (h) {
+ var this$1 = this;
+
+ var router = this.$router;
+ var current = this.$route;
+ var ref = router.resolve(
+ this.to,
+ current,
+ this.append
+ );
+ var location = ref.location;
+ var route = ref.route;
+ var href = ref.href;
+
+ var classes = {};
+ var globalActiveClass = router.options.linkActiveClass;
+ var globalExactActiveClass = router.options.linkExactActiveClass;
+ // Support global empty active class
+ var activeClassFallback =
+ globalActiveClass == null ? 'router-link-active' : globalActiveClass;
+ var exactActiveClassFallback =
+ globalExactActiveClass == null
+ ? 'router-link-exact-active'
+ : globalExactActiveClass;
+ var activeClass =
+ this.activeClass == null ? activeClassFallback : this.activeClass;
+ var exactActiveClass =
+ this.exactActiveClass == null
+ ? exactActiveClassFallback
+ : this.exactActiveClass;
+
+ var compareTarget = route.redirectedFrom
+ ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)
+ : route;
+
+ classes[exactActiveClass] = isSameRoute(current, compareTarget);
+ classes[activeClass] = this.exact
+ ? classes[exactActiveClass]
+ : isIncludedRoute(current, compareTarget);
+
+ var handler = function (e) {
+ if (guardEvent(e)) {
+ if (this$1.replace) {
+ router.replace(location, noop);
+ } else {
+ router.push(location, noop);
+ }
+ }
+ };
+
+ var on = { click: guardEvent };
+ if (Array.isArray(this.event)) {
+ this.event.forEach(function (e) {
+ on[e] = handler;
+ });
+ } else {
+ on[this.event] = handler;
+ }
+
+ var data = { class: classes };
+
+ var scopedSlot =
+ !this.$scopedSlots.$hasNormal &&
+ this.$scopedSlots.default &&
+ this.$scopedSlots.default({
+ href: href,
+ route: route,
+ navigate: handler,
+ isActive: classes[activeClass],
+ isExactActive: classes[exactActiveClass]
+ });
+
+ if (scopedSlot) {
+ if (scopedSlot.length === 1) {
+ return scopedSlot[0]
+ } else if (scopedSlot.length > 1 || !scopedSlot.length) {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false,
+ ("RouterLink with to=\"" + (this.props.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child.")
+ );
+ }
+ return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)
+ }
+ }
+
+ if (this.tag === 'a') {
+ data.on = on;
+ data.attrs = { href: href };
+ } else {
+ // find the first child and apply listener and href
+ var a = findAnchor(this.$slots.default);
+ if (a) {
+ // in case the is a static node
+ a.isStatic = false;
+ var aData = (a.data = extend({}, a.data));
+ aData.on = aData.on || {};
+ // transform existing events in both objects into arrays so we can push later
+ for (var event in aData.on) {
+ var handler$1 = aData.on[event];
+ if (event in on) {
+ aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];
+ }
+ }
+ // append new listeners for router-link
+ for (var event$1 in on) {
+ if (event$1 in aData.on) {
+ // on[event] is always a function
+ aData.on[event$1].push(on[event$1]);
+ } else {
+ aData.on[event$1] = handler;
+ }
+ }
+
+ var aAttrs = (a.data.attrs = extend({}, a.data.attrs));
+ aAttrs.href = href;
+ } else {
+ // doesn't have child, apply listener to self
+ data.on = on;
+ }
+ }
+
+ return h(this.tag, data, this.$slots.default)
+ }
+};
+
+function guardEvent (e) {
+ // don't redirect with control keys
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
+ // don't redirect when preventDefault called
+ if (e.defaultPrevented) { return }
+ // don't redirect on right click
+ if (e.button !== undefined && e.button !== 0) { return }
+ // don't redirect if `target="_blank"`
+ if (e.currentTarget && e.currentTarget.getAttribute) {
+ var target = e.currentTarget.getAttribute('target');
+ if (/\b_blank\b/i.test(target)) { return }
+ }
+ // this may be a Weex event which doesn't have this method
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ return true
+}
+
+function findAnchor (children) {
+ if (children) {
+ var child;
+ for (var i = 0; i < children.length; i++) {
+ child = children[i];
+ if (child.tag === 'a') {
+ return child
+ }
+ if (child.children && (child = findAnchor(child.children))) {
+ return child
+ }
+ }
+ }
+}
+
+var _Vue;
+
+function install (Vue) {
+ if (install.installed && _Vue === Vue) { return }
+ install.installed = true;
+
+ _Vue = Vue;
+
+ var isDef = function (v) { return v !== undefined; };
+
+ var registerInstance = function (vm, callVal) {
+ var i = vm.$options._parentVnode;
+ if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
+ i(vm, callVal);
+ }
+ };
+
+ Vue.mixin({
+ beforeCreate: function beforeCreate () {
+ if (isDef(this.$options.router)) {
+ this._routerRoot = this;
+ this._router = this.$options.router;
+ this._router.init(this);
+ Vue.util.defineReactive(this, '_route', this._router.history.current);
+ } else {
+ this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
+ }
+ registerInstance(this, this);
+ },
+ destroyed: function destroyed () {
+ registerInstance(this);
+ }
+ });
+
+ Object.defineProperty(Vue.prototype, '$router', {
+ get: function get () { return this._routerRoot._router }
+ });
+
+ Object.defineProperty(Vue.prototype, '$route', {
+ get: function get () { return this._routerRoot._route }
+ });
+
+ Vue.component('RouterView', View);
+ Vue.component('RouterLink', Link);
+
+ var strats = Vue.config.optionMergeStrategies;
+ // use the same hook merging strategy for route hooks
+ strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
+}
+
+/* */
+
+var inBrowser = typeof window !== 'undefined';
+
+/* */
+
+function createRouteMap (
+ routes,
+ oldPathList,
+ oldPathMap,
+ oldNameMap
+) {
+ // the path list is used to control path matching priority
+ var pathList = oldPathList || [];
+ // $flow-disable-line
+ var pathMap = oldPathMap || Object.create(null);
+ // $flow-disable-line
+ var nameMap = oldNameMap || Object.create(null);
+
+ routes.forEach(function (route) {
+ addRouteRecord(pathList, pathMap, nameMap, route);
+ });
+
+ // ensure wildcard routes are always at the end
+ for (var i = 0, l = pathList.length; i < l; i++) {
+ if (pathList[i] === '*') {
+ pathList.push(pathList.splice(i, 1)[0]);
+ l--;
+ i--;
+ }
+ }
+
+ if (process.env.NODE_ENV === 'development') {
+ // warn if routes do not include leading slashes
+ var found = pathList
+ // check for missing leading slash
+ .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });
+
+ if (found.length > 0) {
+ var pathNames = found.map(function (path) { return ("- " + path); }).join('\n');
+ warn(false, ("Non-nested routes must include a leading slash character. Fix the following routes: \n" + pathNames));
+ }
+ }
+
+ return {
+ pathList: pathList,
+ pathMap: pathMap,
+ nameMap: nameMap
+ }
+}
+
+function addRouteRecord (
+ pathList,
+ pathMap,
+ nameMap,
+ route,
+ parent,
+ matchAs
+) {
+ var path = route.path;
+ var name = route.name;
+ if (process.env.NODE_ENV !== 'production') {
+ assert(path != null, "\"path\" is required in a route configuration.");
+ assert(
+ typeof route.component !== 'string',
+ "route config \"component\" for path: " + (String(
+ path || name
+ )) + " cannot be a " + "string id. Use an actual component instead."
+ );
+ }
+
+ var pathToRegexpOptions =
+ route.pathToRegexpOptions || {};
+ var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);
+
+ if (typeof route.caseSensitive === 'boolean') {
+ pathToRegexpOptions.sensitive = route.caseSensitive;
+ }
+
+ var record = {
+ path: normalizedPath,
+ regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
+ components: route.components || { default: route.component },
+ instances: {},
+ name: name,
+ parent: parent,
+ matchAs: matchAs,
+ redirect: route.redirect,
+ beforeEnter: route.beforeEnter,
+ meta: route.meta || {},
+ props:
+ route.props == null
+ ? {}
+ : route.components
+ ? route.props
+ : { default: route.props }
+ };
+
+ if (route.children) {
+ // Warn if route is named, does not redirect and has a default child route.
+ // If users navigate to this route by name, the default child will
+ // not be rendered (GH Issue #629)
+ if (process.env.NODE_ENV !== 'production') {
+ if (
+ route.name &&
+ !route.redirect &&
+ route.children.some(function (child) { return /^\/?$/.test(child.path); })
+ ) {
+ warn(
+ false,
+ "Named Route '" + (route.name) + "' has a default child route. " +
+ "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
+ "the default child route will not be rendered. Remove the name from " +
+ "this route and use the name of the default child route for named " +
+ "links instead."
+ );
+ }
+ }
+ route.children.forEach(function (child) {
+ var childMatchAs = matchAs
+ ? cleanPath((matchAs + "/" + (child.path)))
+ : undefined;
+ addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
+ });
+ }
+
+ if (!pathMap[record.path]) {
+ pathList.push(record.path);
+ pathMap[record.path] = record;
+ }
+
+ if (route.alias !== undefined) {
+ var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];
+ for (var i = 0; i < aliases.length; ++i) {
+ var alias = aliases[i];
+ if (process.env.NODE_ENV !== 'production' && alias === path) {
+ warn(
+ false,
+ ("Found an alias with the same value as the path: \"" + path + "\". You have to remove that alias. It will be ignored in development.")
+ );
+ // skip in dev to make it work
+ continue
+ }
+
+ var aliasRoute = {
+ path: alias,
+ children: route.children
+ };
+ addRouteRecord(
+ pathList,
+ pathMap,
+ nameMap,
+ aliasRoute,
+ parent,
+ record.path || '/' // matchAs
+ );
+ }
+ }
+
+ if (name) {
+ if (!nameMap[name]) {
+ nameMap[name] = record;
+ } else if (process.env.NODE_ENV !== 'production' && !matchAs) {
+ warn(
+ false,
+ "Duplicate named routes definition: " +
+ "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
+ );
+ }
+ }
+}
+
+function compileRouteRegex (
+ path,
+ pathToRegexpOptions
+) {
+ var regex = pathToRegexp_1(path, [], pathToRegexpOptions);
+ if (process.env.NODE_ENV !== 'production') {
+ var keys = Object.create(null);
+ regex.keys.forEach(function (key) {
+ warn(
+ !keys[key.name],
+ ("Duplicate param keys in route with path: \"" + path + "\"")
+ );
+ keys[key.name] = true;
+ });
+ }
+ return regex
+}
+
+function normalizePath (
+ path,
+ parent,
+ strict
+) {
+ if (!strict) { path = path.replace(/\/$/, ''); }
+ if (path[0] === '/') { return path }
+ if (parent == null) { return path }
+ return cleanPath(((parent.path) + "/" + path))
+}
+
+/* */
+
+
+
+function createMatcher (
+ routes,
+ router
+) {
+ var ref = createRouteMap(routes);
+ var pathList = ref.pathList;
+ var pathMap = ref.pathMap;
+ var nameMap = ref.nameMap;
+
+ function addRoutes (routes) {
+ createRouteMap(routes, pathList, pathMap, nameMap);
+ }
+
+ function match (
+ raw,
+ currentRoute,
+ redirectedFrom
+ ) {
+ var location = normalizeLocation(raw, currentRoute, false, router);
+ var name = location.name;
+
+ if (name) {
+ var record = nameMap[name];
+ if (process.env.NODE_ENV !== 'production') {
+ warn(record, ("Route with name '" + name + "' does not exist"));
+ }
+ if (!record) { return _createRoute(null, location) }
+ var paramNames = record.regex.keys
+ .filter(function (key) { return !key.optional; })
+ .map(function (key) { return key.name; });
+
+ if (typeof location.params !== 'object') {
+ location.params = {};
+ }
+
+ if (currentRoute && typeof currentRoute.params === 'object') {
+ for (var key in currentRoute.params) {
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
+ location.params[key] = currentRoute.params[key];
+ }
+ }
+ }
+
+ location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
+ return _createRoute(record, location, redirectedFrom)
+ } else if (location.path) {
+ location.params = {};
+ for (var i = 0; i < pathList.length; i++) {
+ var path = pathList[i];
+ var record$1 = pathMap[path];
+ if (matchRoute(record$1.regex, location.path, location.params)) {
+ return _createRoute(record$1, location, redirectedFrom)
+ }
+ }
+ }
+ // no match
+ return _createRoute(null, location)
+ }
+
+ function redirect (
+ record,
+ location
+ ) {
+ var originalRedirect = record.redirect;
+ var redirect = typeof originalRedirect === 'function'
+ ? originalRedirect(createRoute(record, location, null, router))
+ : originalRedirect;
+
+ if (typeof redirect === 'string') {
+ redirect = { path: redirect };
+ }
+
+ if (!redirect || typeof redirect !== 'object') {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false, ("invalid redirect option: " + (JSON.stringify(redirect)))
+ );
+ }
+ return _createRoute(null, location)
+ }
+
+ var re = redirect;
+ var name = re.name;
+ var path = re.path;
+ var query = location.query;
+ var hash = location.hash;
+ var params = location.params;
+ query = re.hasOwnProperty('query') ? re.query : query;
+ hash = re.hasOwnProperty('hash') ? re.hash : hash;
+ params = re.hasOwnProperty('params') ? re.params : params;
+
+ if (name) {
+ // resolved named direct
+ var targetRecord = nameMap[name];
+ if (process.env.NODE_ENV !== 'production') {
+ assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
+ }
+ return match({
+ _normalized: true,
+ name: name,
+ query: query,
+ hash: hash,
+ params: params
+ }, undefined, location)
+ } else if (path) {
+ // 1. resolve relative redirect
+ var rawPath = resolveRecordPath(path, record);
+ // 2. resolve params
+ var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
+ // 3. rematch with existing query and hash
+ return match({
+ _normalized: true,
+ path: resolvedPath,
+ query: query,
+ hash: hash
+ }, undefined, location)
+ } else {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
+ }
+ return _createRoute(null, location)
+ }
+ }
+
+ function alias (
+ record,
+ location,
+ matchAs
+ ) {
+ var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
+ var aliasedMatch = match({
+ _normalized: true,
+ path: aliasedPath
+ });
+ if (aliasedMatch) {
+ var matched = aliasedMatch.matched;
+ var aliasedRecord = matched[matched.length - 1];
+ location.params = aliasedMatch.params;
+ return _createRoute(aliasedRecord, location)
+ }
+ return _createRoute(null, location)
+ }
+
+ function _createRoute (
+ record,
+ location,
+ redirectedFrom
+ ) {
+ if (record && record.redirect) {
+ return redirect(record, redirectedFrom || location)
+ }
+ if (record && record.matchAs) {
+ return alias(record, location, record.matchAs)
+ }
+ return createRoute(record, location, redirectedFrom, router)
+ }
+
+ return {
+ match: match,
+ addRoutes: addRoutes
+ }
+}
+
+function matchRoute (
+ regex,
+ path,
+ params
+) {
+ var m = path.match(regex);
+
+ if (!m) {
+ return false
+ } else if (!params) {
+ return true
+ }
+
+ for (var i = 1, len = m.length; i < len; ++i) {
+ var key = regex.keys[i - 1];
+ var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
+ if (key) {
+ // Fix #1994: using * with props: true generates a param named 0
+ params[key.name || 'pathMatch'] = val;
+ }
+ }
+
+ return true
+}
+
+function resolveRecordPath (path, record) {
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
+}
+
+/* */
+
+// use User Timing api (if present) for more accurate key precision
+var Time =
+ inBrowser && window.performance && window.performance.now
+ ? window.performance
+ : Date;
+
+function genStateKey () {
+ return Time.now().toFixed(3)
+}
+
+var _key = genStateKey();
+
+function getStateKey () {
+ return _key
+}
+
+function setStateKey (key) {
+ return (_key = key)
+}
+
+/* */
+
+var positionStore = Object.create(null);
+
+function setupScroll () {
+ // Fix for #1585 for Firefox
+ // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
+ // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
+ // window.location.protocol + '//' + window.location.host
+ // location.host contains the port and location.hostname doesn't
+ var protocolAndPath = window.location.protocol + '//' + window.location.host;
+ var absolutePath = window.location.href.replace(protocolAndPath, '');
+ window.history.replaceState({ key: getStateKey() }, '', absolutePath);
+ window.addEventListener('popstate', function (e) {
+ saveScrollPosition();
+ if (e.state && e.state.key) {
+ setStateKey(e.state.key);
+ }
+ });
+}
+
+function handleScroll (
+ router,
+ to,
+ from,
+ isPop
+) {
+ if (!router.app) {
+ return
+ }
+
+ var behavior = router.options.scrollBehavior;
+ if (!behavior) {
+ return
+ }
+
+ if (process.env.NODE_ENV !== 'production') {
+ assert(typeof behavior === 'function', "scrollBehavior must be a function");
+ }
+
+ // wait until re-render finishes before scrolling
+ router.app.$nextTick(function () {
+ var position = getScrollPosition();
+ var shouldScroll = behavior.call(
+ router,
+ to,
+ from,
+ isPop ? position : null
+ );
+
+ if (!shouldScroll) {
+ return
+ }
+
+ if (typeof shouldScroll.then === 'function') {
+ shouldScroll
+ .then(function (shouldScroll) {
+ scrollToPosition((shouldScroll), position);
+ })
+ .catch(function (err) {
+ if (process.env.NODE_ENV !== 'production') {
+ assert(false, err.toString());
+ }
+ });
+ } else {
+ scrollToPosition(shouldScroll, position);
+ }
+ });
+}
+
+function saveScrollPosition () {
+ var key = getStateKey();
+ if (key) {
+ positionStore[key] = {
+ x: window.pageXOffset,
+ y: window.pageYOffset
+ };
+ }
+}
+
+function getScrollPosition () {
+ var key = getStateKey();
+ if (key) {
+ return positionStore[key]
+ }
+}
+
+function getElementPosition (el, offset) {
+ var docEl = document.documentElement;
+ var docRect = docEl.getBoundingClientRect();
+ var elRect = el.getBoundingClientRect();
+ return {
+ x: elRect.left - docRect.left - offset.x,
+ y: elRect.top - docRect.top - offset.y
+ }
+}
+
+function isValidPosition (obj) {
+ return isNumber(obj.x) || isNumber(obj.y)
+}
+
+function normalizePosition (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : window.pageXOffset,
+ y: isNumber(obj.y) ? obj.y : window.pageYOffset
+ }
+}
+
+function normalizeOffset (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : 0,
+ y: isNumber(obj.y) ? obj.y : 0
+ }
+}
+
+function isNumber (v) {
+ return typeof v === 'number'
+}
+
+var hashStartsWithNumberRE = /^#\d/;
+
+function scrollToPosition (shouldScroll, position) {
+ var isObject = typeof shouldScroll === 'object';
+ if (isObject && typeof shouldScroll.selector === 'string') {
+ // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
+ // but at the same time, it doesn't make much sense to select an element with an id and an extra selector
+ var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
+ ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
+ : document.querySelector(shouldScroll.selector);
+
+ if (el) {
+ var offset =
+ shouldScroll.offset && typeof shouldScroll.offset === 'object'
+ ? shouldScroll.offset
+ : {};
+ offset = normalizeOffset(offset);
+ position = getElementPosition(el, offset);
+ } else if (isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+ } else if (isObject && isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+
+ if (position) {
+ window.scrollTo(position.x, position.y);
+ }
+}
+
+/* */
+
+var supportsPushState =
+ inBrowser &&
+ (function () {
+ var ua = window.navigator.userAgent;
+
+ if (
+ (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
+ ua.indexOf('Mobile Safari') !== -1 &&
+ ua.indexOf('Chrome') === -1 &&
+ ua.indexOf('Windows Phone') === -1
+ ) {
+ return false
+ }
+
+ return window.history && 'pushState' in window.history
+ })();
+
+function pushState (url, replace) {
+ saveScrollPosition();
+ // try...catch the pushState call to get around Safari
+ // DOM Exception 18 where it limits to 100 pushState calls
+ var history = window.history;
+ try {
+ if (replace) {
+ history.replaceState({ key: getStateKey() }, '', url);
+ } else {
+ history.pushState({ key: setStateKey(genStateKey()) }, '', url);
+ }
+ } catch (e) {
+ window.location[replace ? 'replace' : 'assign'](url);
+ }
+}
+
+function replaceState (url) {
+ pushState(url, true);
+}
+
+/* */
+
+function runQueue (queue, fn, cb) {
+ var step = function (index) {
+ if (index >= queue.length) {
+ cb();
+ } else {
+ if (queue[index]) {
+ fn(queue[index], function () {
+ step(index + 1);
+ });
+ } else {
+ step(index + 1);
+ }
+ }
+ };
+ step(0);
+}
+
+/* */
+
+function resolveAsyncComponents (matched) {
+ return function (to, from, next) {
+ var hasAsync = false;
+ var pending = 0;
+ var error = null;
+
+ flatMapComponents(matched, function (def, _, match, key) {
+ // if it's a function and doesn't have cid attached,
+ // assume it's an async component resolve function.
+ // we are not using Vue's default async resolving mechanism because
+ // we want to halt the navigation until the incoming component has been
+ // resolved.
+ if (typeof def === 'function' && def.cid === undefined) {
+ hasAsync = true;
+ pending++;
+
+ var resolve = once(function (resolvedDef) {
+ if (isESModule(resolvedDef)) {
+ resolvedDef = resolvedDef.default;
+ }
+ // save resolved on async factory in case it's used elsewhere
+ def.resolved = typeof resolvedDef === 'function'
+ ? resolvedDef
+ : _Vue.extend(resolvedDef);
+ match.components[key] = resolvedDef;
+ pending--;
+ if (pending <= 0) {
+ next();
+ }
+ });
+
+ var reject = once(function (reason) {
+ var msg = "Failed to resolve async component " + key + ": " + reason;
+ process.env.NODE_ENV !== 'production' && warn(false, msg);
+ if (!error) {
+ error = isError(reason)
+ ? reason
+ : new Error(msg);
+ next(error);
+ }
+ });
+
+ var res;
+ try {
+ res = def(resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ if (res) {
+ if (typeof res.then === 'function') {
+ res.then(resolve, reject);
+ } else {
+ // new syntax in Vue 2.3
+ var comp = res.component;
+ if (comp && typeof comp.then === 'function') {
+ comp.then(resolve, reject);
+ }
+ }
+ }
+ }
+ });
+
+ if (!hasAsync) { next(); }
+ }
+}
+
+function flatMapComponents (
+ matched,
+ fn
+) {
+ return flatten(matched.map(function (m) {
+ return Object.keys(m.components).map(function (key) { return fn(
+ m.components[key],
+ m.instances[key],
+ m, key
+ ); })
+ }))
+}
+
+function flatten (arr) {
+ return Array.prototype.concat.apply([], arr)
+}
+
+var hasSymbol =
+ typeof Symbol === 'function' &&
+ typeof Symbol.toStringTag === 'symbol';
+
+function isESModule (obj) {
+ return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
+}
+
+// in Webpack 2, require.ensure now also returns a Promise
+// so the resolve/reject functions may get called an extra time
+// if the user uses an arrow function shorthand that happens to
+// return that Promise.
+function once (fn) {
+ var called = false;
+ return function () {
+ var args = [], len = arguments.length;
+ while ( len-- ) args[ len ] = arguments[ len ];
+
+ if (called) { return }
+ called = true;
+ return fn.apply(this, args)
+ }
+}
+
+var NavigationDuplicated = /*@__PURE__*/(function (Error) {
+ function NavigationDuplicated (normalizedLocation) {
+ Error.call(this);
+ this.name = this._name = 'NavigationDuplicated';
+ // passing the message to super() doesn't seem to work in the transpiled version
+ this.message = "Navigating to current location (\"" + (normalizedLocation.fullPath) + "\") is not allowed";
+ // add a stack property so services like Sentry can correctly display it
+ Object.defineProperty(this, 'stack', {
+ value: new Error().stack,
+ writable: true,
+ configurable: true
+ });
+ // we could also have used
+ // Error.captureStackTrace(this, this.constructor)
+ // but it only exists on node and chrome
+ }
+
+ if ( Error ) NavigationDuplicated.__proto__ = Error;
+ NavigationDuplicated.prototype = Object.create( Error && Error.prototype );
+ NavigationDuplicated.prototype.constructor = NavigationDuplicated;
+
+ return NavigationDuplicated;
+}(Error));
+
+// support IE9
+NavigationDuplicated._name = 'NavigationDuplicated';
+
+/* */
+
+var History = function History (router, base) {
+ this.router = router;
+ this.base = normalizeBase(base);
+ // start with a route object that stands for "nowhere"
+ this.current = START;
+ this.pending = null;
+ this.ready = false;
+ this.readyCbs = [];
+ this.readyErrorCbs = [];
+ this.errorCbs = [];
+};
+
+History.prototype.listen = function listen (cb) {
+ this.cb = cb;
+};
+
+History.prototype.onReady = function onReady (cb, errorCb) {
+ if (this.ready) {
+ cb();
+ } else {
+ this.readyCbs.push(cb);
+ if (errorCb) {
+ this.readyErrorCbs.push(errorCb);
+ }
+ }
+};
+
+History.prototype.onError = function onError (errorCb) {
+ this.errorCbs.push(errorCb);
+};
+
+History.prototype.transitionTo = function transitionTo (
+ location,
+ onComplete,
+ onAbort
+) {
+ var this$1 = this;
+
+ var route = this.router.match(location, this.current);
+ this.confirmTransition(
+ route,
+ function () {
+ this$1.updateRoute(route);
+ onComplete && onComplete(route);
+ this$1.ensureURL();
+
+ // fire ready cbs once
+ if (!this$1.ready) {
+ this$1.ready = true;
+ this$1.readyCbs.forEach(function (cb) {
+ cb(route);
+ });
+ }
+ },
+ function (err) {
+ if (onAbort) {
+ onAbort(err);
+ }
+ if (err && !this$1.ready) {
+ this$1.ready = true;
+ this$1.readyErrorCbs.forEach(function (cb) {
+ cb(err);
+ });
+ }
+ }
+ );
+};
+
+History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
+ var this$1 = this;
+
+ var current = this.current;
+ var abort = function (err) {
+ // after merging https://github.com/vuejs/vue-router/pull/2771 we
+ // When the user navigates through history through back/forward buttons
+ // we do not want to throw the error. We only throw it if directly calling
+ // push/replace. That's why it's not included in isError
+ if (!isExtendedError(NavigationDuplicated, err) && isError(err)) {
+ if (this$1.errorCbs.length) {
+ this$1.errorCbs.forEach(function (cb) {
+ cb(err);
+ });
+ } else {
+ warn(false, 'uncaught error during route navigation:');
+ console.error(err);
+ }
+ }
+ onAbort && onAbort(err);
+ };
+ if (
+ isSameRoute(route, current) &&
+ // in the case the route map has been dynamically appended to
+ route.matched.length === current.matched.length
+ ) {
+ this.ensureURL();
+ return abort(new NavigationDuplicated(route))
+ }
+
+ var ref = resolveQueue(
+ this.current.matched,
+ route.matched
+ );
+ var updated = ref.updated;
+ var deactivated = ref.deactivated;
+ var activated = ref.activated;
+
+ var queue = [].concat(
+ // in-component leave guards
+ extractLeaveGuards(deactivated),
+ // global before hooks
+ this.router.beforeHooks,
+ // in-component update hooks
+ extractUpdateHooks(updated),
+ // in-config enter guards
+ activated.map(function (m) { return m.beforeEnter; }),
+ // async components
+ resolveAsyncComponents(activated)
+ );
+
+ this.pending = route;
+ var iterator = function (hook, next) {
+ if (this$1.pending !== route) {
+ return abort()
+ }
+ try {
+ hook(route, current, function (to) {
+ if (to === false || isError(to)) {
+ // next(false) -> abort navigation, ensure current URL
+ this$1.ensureURL(true);
+ abort(to);
+ } else if (
+ typeof to === 'string' ||
+ (typeof to === 'object' &&
+ (typeof to.path === 'string' || typeof to.name === 'string'))
+ ) {
+ // next('/') or next({ path: '/' }) -> redirect
+ abort();
+ if (typeof to === 'object' && to.replace) {
+ this$1.replace(to);
+ } else {
+ this$1.push(to);
+ }
+ } else {
+ // confirm transition and pass on the value
+ next(to);
+ }
+ });
+ } catch (e) {
+ abort(e);
+ }
+ };
+
+ runQueue(queue, iterator, function () {
+ var postEnterCbs = [];
+ var isValid = function () { return this$1.current === route; };
+ // wait until async components are resolved before
+ // extracting in-component enter guards
+ var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
+ var queue = enterGuards.concat(this$1.router.resolveHooks);
+ runQueue(queue, iterator, function () {
+ if (this$1.pending !== route) {
+ return abort()
+ }
+ this$1.pending = null;
+ onComplete(route);
+ if (this$1.router.app) {
+ this$1.router.app.$nextTick(function () {
+ postEnterCbs.forEach(function (cb) {
+ cb();
+ });
+ });
+ }
+ });
+ });
+};
+
+History.prototype.updateRoute = function updateRoute (route) {
+ var prev = this.current;
+ this.current = route;
+ this.cb && this.cb(route);
+ this.router.afterHooks.forEach(function (hook) {
+ hook && hook(route, prev);
+ });
+};
+
+function normalizeBase (base) {
+ if (!base) {
+ if (inBrowser) {
+ // respect tag
+ var baseEl = document.querySelector('base');
+ base = (baseEl && baseEl.getAttribute('href')) || '/';
+ // strip full URL origin
+ base = base.replace(/^https?:\/\/[^\/]+/, '');
+ } else {
+ base = '/';
+ }
+ }
+ // make sure there's the starting slash
+ if (base.charAt(0) !== '/') {
+ base = '/' + base;
+ }
+ // remove trailing slash
+ return base.replace(/\/$/, '')
+}
+
+function resolveQueue (
+ current,
+ next
+) {
+ var i;
+ var max = Math.max(current.length, next.length);
+ for (i = 0; i < max; i++) {
+ if (current[i] !== next[i]) {
+ break
+ }
+ }
+ return {
+ updated: next.slice(0, i),
+ activated: next.slice(i),
+ deactivated: current.slice(i)
+ }
+}
+
+function extractGuards (
+ records,
+ name,
+ bind,
+ reverse
+) {
+ var guards = flatMapComponents(records, function (def, instance, match, key) {
+ var guard = extractGuard(def, name);
+ if (guard) {
+ return Array.isArray(guard)
+ ? guard.map(function (guard) { return bind(guard, instance, match, key); })
+ : bind(guard, instance, match, key)
+ }
+ });
+ return flatten(reverse ? guards.reverse() : guards)
+}
+
+function extractGuard (
+ def,
+ key
+) {
+ if (typeof def !== 'function') {
+ // extend now so that global mixins are applied.
+ def = _Vue.extend(def);
+ }
+ return def.options[key]
+}
+
+function extractLeaveGuards (deactivated) {
+ return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
+}
+
+function extractUpdateHooks (updated) {
+ return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
+}
+
+function bindGuard (guard, instance) {
+ if (instance) {
+ return function boundRouteGuard () {
+ return guard.apply(instance, arguments)
+ }
+ }
+}
+
+function extractEnterGuards (
+ activated,
+ cbs,
+ isValid
+) {
+ return extractGuards(
+ activated,
+ 'beforeRouteEnter',
+ function (guard, _, match, key) {
+ return bindEnterGuard(guard, match, key, cbs, isValid)
+ }
+ )
+}
+
+function bindEnterGuard (
+ guard,
+ match,
+ key,
+ cbs,
+ isValid
+) {
+ return function routeEnterGuard (to, from, next) {
+ return guard(to, from, function (cb) {
+ if (typeof cb === 'function') {
+ cbs.push(function () {
+ // #750
+ // if a router-view is wrapped with an out-in transition,
+ // the instance may not have been registered at this time.
+ // we will need to poll for registration until current route
+ // is no longer valid.
+ poll(cb, match.instances, key, isValid);
+ });
+ }
+ next(cb);
+ })
+ }
+}
+
+function poll (
+ cb, // somehow flow cannot infer this is a function
+ instances,
+ key,
+ isValid
+) {
+ if (
+ instances[key] &&
+ !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
+ ) {
+ cb(instances[key]);
+ } else if (isValid()) {
+ setTimeout(function () {
+ poll(cb, instances, key, isValid);
+ }, 16);
+ }
+}
+
+/* */
+
+var HTML5History = /*@__PURE__*/(function (History) {
+ function HTML5History (router, base) {
+ var this$1 = this;
+
+ History.call(this, router, base);
+
+ var expectScroll = router.options.scrollBehavior;
+ var supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ var initLocation = getLocation(this.base);
+ window.addEventListener('popstate', function (e) {
+ var current = this$1.current;
+
+ // Avoiding first `popstate` event dispatched in some browsers but first
+ // history route not updated since async guard at the same time.
+ var location = getLocation(this$1.base);
+ if (this$1.current === START && location === initLocation) {
+ return
+ }
+
+ this$1.transitionTo(location, function (route) {
+ if (supportsScroll) {
+ handleScroll(router, route, current, true);
+ }
+ });
+ });
+ }
+
+ if ( History ) HTML5History.__proto__ = History;
+ HTML5History.prototype = Object.create( History && History.prototype );
+ HTML5History.prototype.constructor = HTML5History;
+
+ HTML5History.prototype.go = function go (n) {
+ window.history.go(n);
+ };
+
+ HTML5History.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(location, function (route) {
+ pushState(cleanPath(this$1.base + route.fullPath));
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ };
+
+ HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(location, function (route) {
+ replaceState(cleanPath(this$1.base + route.fullPath));
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ };
+
+ HTML5History.prototype.ensureURL = function ensureURL (push) {
+ if (getLocation(this.base) !== this.current.fullPath) {
+ var current = cleanPath(this.base + this.current.fullPath);
+ push ? pushState(current) : replaceState(current);
+ }
+ };
+
+ HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
+ return getLocation(this.base)
+ };
+
+ return HTML5History;
+}(History));
+
+function getLocation (base) {
+ var path = decodeURI(window.location.pathname);
+ if (base && path.indexOf(base) === 0) {
+ path = path.slice(base.length);
+ }
+ return (path || '/') + window.location.search + window.location.hash
+}
+
+/* */
+
+var HashHistory = /*@__PURE__*/(function (History) {
+ function HashHistory (router, base, fallback) {
+ History.call(this, router, base);
+ // check history fallback deeplinking
+ if (fallback && checkFallback(this.base)) {
+ return
+ }
+ ensureSlash();
+ }
+
+ if ( History ) HashHistory.__proto__ = History;
+ HashHistory.prototype = Object.create( History && History.prototype );
+ HashHistory.prototype.constructor = HashHistory;
+
+ // this is delayed until the app mounts
+ // to avoid the hashchange listener being fired too early
+ HashHistory.prototype.setupListeners = function setupListeners () {
+ var this$1 = this;
+
+ var router = this.router;
+ var expectScroll = router.options.scrollBehavior;
+ var supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ window.addEventListener(
+ supportsPushState ? 'popstate' : 'hashchange',
+ function () {
+ var current = this$1.current;
+ if (!ensureSlash()) {
+ return
+ }
+ this$1.transitionTo(getHash(), function (route) {
+ if (supportsScroll) {
+ handleScroll(this$1.router, route, current, true);
+ }
+ if (!supportsPushState) {
+ replaceHash(route.fullPath);
+ }
+ });
+ }
+ );
+ };
+
+ HashHistory.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(
+ location,
+ function (route) {
+ pushHash(route.fullPath);
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(
+ location,
+ function (route) {
+ replaceHash(route.fullPath);
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ HashHistory.prototype.go = function go (n) {
+ window.history.go(n);
+ };
+
+ HashHistory.prototype.ensureURL = function ensureURL (push) {
+ var current = this.current.fullPath;
+ if (getHash() !== current) {
+ push ? pushHash(current) : replaceHash(current);
+ }
+ };
+
+ HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+ return getHash()
+ };
+
+ return HashHistory;
+}(History));
+
+function checkFallback (base) {
+ var location = getLocation(base);
+ if (!/^\/#/.test(location)) {
+ window.location.replace(cleanPath(base + '/#' + location));
+ return true
+ }
+}
+
+function ensureSlash () {
+ var path = getHash();
+ if (path.charAt(0) === '/') {
+ return true
+ }
+ replaceHash('/' + path);
+ return false
+}
+
+function getHash () {
+ // We can't use window.location.hash here because it's not
+ // consistent across browsers - Firefox will pre-decode it!
+ var href = window.location.href;
+ var index = href.indexOf('#');
+ // empty path
+ if (index < 0) { return '' }
+
+ href = href.slice(index + 1);
+ // decode the hash but not the search or hash
+ // as search(query) is already decoded
+ // https://github.com/vuejs/vue-router/issues/2708
+ var searchIndex = href.indexOf('?');
+ if (searchIndex < 0) {
+ var hashIndex = href.indexOf('#');
+ if (hashIndex > -1) {
+ href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex);
+ } else { href = decodeURI(href); }
+ } else {
+ if (searchIndex > -1) {
+ href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex);
+ }
+ }
+
+ return href
+}
+
+function getUrl (path) {
+ var href = window.location.href;
+ var i = href.indexOf('#');
+ var base = i >= 0 ? href.slice(0, i) : href;
+ return (base + "#" + path)
+}
+
+function pushHash (path) {
+ if (supportsPushState) {
+ pushState(getUrl(path));
+ } else {
+ window.location.hash = path;
+ }
+}
+
+function replaceHash (path) {
+ if (supportsPushState) {
+ replaceState(getUrl(path));
+ } else {
+ window.location.replace(getUrl(path));
+ }
+}
+
+/* */
+
+var AbstractHistory = /*@__PURE__*/(function (History) {
+ function AbstractHistory (router, base) {
+ History.call(this, router, base);
+ this.stack = [];
+ this.index = -1;
+ }
+
+ if ( History ) AbstractHistory.__proto__ = History;
+ AbstractHistory.prototype = Object.create( History && History.prototype );
+ AbstractHistory.prototype.constructor = AbstractHistory;
+
+ AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ this.transitionTo(
+ location,
+ function (route) {
+ this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
+ this$1.index++;
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ this.transitionTo(
+ location,
+ function (route) {
+ this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ AbstractHistory.prototype.go = function go (n) {
+ var this$1 = this;
+
+ var targetIndex = this.index + n;
+ if (targetIndex < 0 || targetIndex >= this.stack.length) {
+ return
+ }
+ var route = this.stack[targetIndex];
+ this.confirmTransition(
+ route,
+ function () {
+ this$1.index = targetIndex;
+ this$1.updateRoute(route);
+ },
+ function (err) {
+ if (isExtendedError(NavigationDuplicated, err)) {
+ this$1.index = targetIndex;
+ }
+ }
+ );
+ };
+
+ AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+ var current = this.stack[this.stack.length - 1];
+ return current ? current.fullPath : '/'
+ };
+
+ AbstractHistory.prototype.ensureURL = function ensureURL () {
+ // noop
+ };
+
+ return AbstractHistory;
+}(History));
+
+/* */
+
+
+
+var VueRouter = function VueRouter (options) {
+ if ( options === void 0 ) options = {};
+
+ this.app = null;
+ this.apps = [];
+ this.options = options;
+ this.beforeHooks = [];
+ this.resolveHooks = [];
+ this.afterHooks = [];
+ this.matcher = createMatcher(options.routes || [], this);
+
+ var mode = options.mode || 'hash';
+ this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
+ if (this.fallback) {
+ mode = 'hash';
+ }
+ if (!inBrowser) {
+ mode = 'abstract';
+ }
+ this.mode = mode;
+
+ switch (mode) {
+ case 'history':
+ this.history = new HTML5History(this, options.base);
+ break
+ case 'hash':
+ this.history = new HashHistory(this, options.base, this.fallback);
+ break
+ case 'abstract':
+ this.history = new AbstractHistory(this, options.base);
+ break
+ default:
+ if (process.env.NODE_ENV !== 'production') {
+ assert(false, ("invalid mode: " + mode));
+ }
+ }
+};
+
+var prototypeAccessors = { currentRoute: { configurable: true } };
+
+VueRouter.prototype.match = function match (
+ raw,
+ current,
+ redirectedFrom
+) {
+ return this.matcher.match(raw, current, redirectedFrom)
+};
+
+prototypeAccessors.currentRoute.get = function () {
+ return this.history && this.history.current
+};
+
+VueRouter.prototype.init = function init (app /* Vue component instance */) {
+ var this$1 = this;
+
+ process.env.NODE_ENV !== 'production' && assert(
+ install.installed,
+ "not installed. Make sure to call `Vue.use(VueRouter)` " +
+ "before creating root instance."
+ );
+
+ this.apps.push(app);
+
+ // set up app destroyed handler
+ // https://github.com/vuejs/vue-router/issues/2639
+ app.$once('hook:destroyed', function () {
+ // clean out app from this.apps array once destroyed
+ var index = this$1.apps.indexOf(app);
+ if (index > -1) { this$1.apps.splice(index, 1); }
+ // ensure we still have a main app or null if no apps
+ // we do not release the router so it can be reused
+ if (this$1.app === app) { this$1.app = this$1.apps[0] || null; }
+ });
+
+ // main app previously initialized
+ // return as we don't need to set up new history listener
+ if (this.app) {
+ return
+ }
+
+ this.app = app;
+
+ var history = this.history;
+
+ if (history instanceof HTML5History) {
+ history.transitionTo(history.getCurrentLocation());
+ } else if (history instanceof HashHistory) {
+ var setupHashListener = function () {
+ history.setupListeners();
+ };
+ history.transitionTo(
+ history.getCurrentLocation(),
+ setupHashListener,
+ setupHashListener
+ );
+ }
+
+ history.listen(function (route) {
+ this$1.apps.forEach(function (app) {
+ app._route = route;
+ });
+ });
+};
+
+VueRouter.prototype.beforeEach = function beforeEach (fn) {
+ return registerHook(this.beforeHooks, fn)
+};
+
+VueRouter.prototype.beforeResolve = function beforeResolve (fn) {
+ return registerHook(this.resolveHooks, fn)
+};
+
+VueRouter.prototype.afterEach = function afterEach (fn) {
+ return registerHook(this.afterHooks, fn)
+};
+
+VueRouter.prototype.onReady = function onReady (cb, errorCb) {
+ this.history.onReady(cb, errorCb);
+};
+
+VueRouter.prototype.onError = function onError (errorCb) {
+ this.history.onError(errorCb);
+};
+
+VueRouter.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise(function (resolve, reject) {
+ this$1.history.push(location, resolve, reject);
+ })
+ } else {
+ this.history.push(location, onComplete, onAbort);
+ }
+};
+
+VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise(function (resolve, reject) {
+ this$1.history.replace(location, resolve, reject);
+ })
+ } else {
+ this.history.replace(location, onComplete, onAbort);
+ }
+};
+
+VueRouter.prototype.go = function go (n) {
+ this.history.go(n);
+};
+
+VueRouter.prototype.back = function back () {
+ this.go(-1);
+};
+
+VueRouter.prototype.forward = function forward () {
+ this.go(1);
+};
+
+VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
+ var route = to
+ ? to.matched
+ ? to
+ : this.resolve(to).route
+ : this.currentRoute;
+ if (!route) {
+ return []
+ }
+ return [].concat.apply([], route.matched.map(function (m) {
+ return Object.keys(m.components).map(function (key) {
+ return m.components[key]
+ })
+ }))
+};
+
+VueRouter.prototype.resolve = function resolve (
+ to,
+ current,
+ append
+) {
+ current = current || this.history.current;
+ var location = normalizeLocation(
+ to,
+ current,
+ append,
+ this
+ );
+ var route = this.match(location, current);
+ var fullPath = route.redirectedFrom || route.fullPath;
+ var base = this.history.base;
+ var href = createHref(base, fullPath, this.mode);
+ return {
+ location: location,
+ route: route,
+ href: href,
+ // for backwards compat
+ normalizedTo: location,
+ resolved: route
+ }
+};
+
+VueRouter.prototype.addRoutes = function addRoutes (routes) {
+ this.matcher.addRoutes(routes);
+ if (this.history.current !== START) {
+ this.history.transitionTo(this.history.getCurrentLocation());
+ }
+};
+
+Object.defineProperties( VueRouter.prototype, prototypeAccessors );
+
+function registerHook (list, fn) {
+ list.push(fn);
+ return function () {
+ var i = list.indexOf(fn);
+ if (i > -1) { list.splice(i, 1); }
+ }
+}
+
+function createHref (base, fullPath, mode) {
+ var path = mode === 'hash' ? '#' + fullPath : fullPath;
+ return base ? cleanPath(base + '/' + path) : path
+}
+
+VueRouter.install = install;
+VueRouter.version = '3.1.3';
+
+if (inBrowser && window.Vue) {
+ window.Vue.use(VueRouter);
+}
+
+export default VueRouter;
diff --git a/node_modules/vue-router/dist/vue-router.js b/node_modules/vue-router/dist/vue-router.js
new file mode 100644
index 0000000..fa6ff7c
--- /dev/null
+++ b/node_modules/vue-router/dist/vue-router.js
@@ -0,0 +1,2890 @@
+/*!
+ * vue-router v3.1.3
+ * (c) 2019 Evan You
+ * @license MIT
+ */
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global = global || self, global.VueRouter = factory());
+}(this, function () { 'use strict';
+
+ /* */
+
+ function assert (condition, message) {
+ if (!condition) {
+ throw new Error(("[vue-router] " + message))
+ }
+ }
+
+ function warn (condition, message) {
+ if ( !condition) {
+ typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
+ }
+ }
+
+ function isError (err) {
+ return Object.prototype.toString.call(err).indexOf('Error') > -1
+ }
+
+ function isExtendedError (constructor, err) {
+ return (
+ err instanceof constructor ||
+ // _name is to support IE9 too
+ (err && (err.name === constructor.name || err._name === constructor._name))
+ )
+ }
+
+ function extend (a, b) {
+ for (var key in b) {
+ a[key] = b[key];
+ }
+ return a
+ }
+
+ var View = {
+ name: 'RouterView',
+ functional: true,
+ props: {
+ name: {
+ type: String,
+ default: 'default'
+ }
+ },
+ render: function render (_, ref) {
+ var props = ref.props;
+ var children = ref.children;
+ var parent = ref.parent;
+ var data = ref.data;
+
+ // used by devtools to display a router-view badge
+ data.routerView = true;
+
+ // directly use parent context's createElement() function
+ // so that components rendered by router-view can resolve named slots
+ var h = parent.$createElement;
+ var name = props.name;
+ var route = parent.$route;
+ var cache = parent._routerViewCache || (parent._routerViewCache = {});
+
+ // determine current view depth, also check to see if the tree
+ // has been toggled inactive but kept-alive.
+ var depth = 0;
+ var inactive = false;
+ while (parent && parent._routerRoot !== parent) {
+ var vnodeData = parent.$vnode && parent.$vnode.data;
+ if (vnodeData) {
+ if (vnodeData.routerView) {
+ depth++;
+ }
+ if (vnodeData.keepAlive && parent._inactive) {
+ inactive = true;
+ }
+ }
+ parent = parent.$parent;
+ }
+ data.routerViewDepth = depth;
+
+ // render previous view if the tree is inactive and kept-alive
+ if (inactive) {
+ return h(cache[name], data, children)
+ }
+
+ var matched = route.matched[depth];
+ // render empty node if no matched route
+ if (!matched) {
+ cache[name] = null;
+ return h()
+ }
+
+ var component = cache[name] = matched.components[name];
+
+ // attach instance registration hook
+ // this will be called in the instance's injected lifecycle hooks
+ data.registerRouteInstance = function (vm, val) {
+ // val could be undefined for unregistration
+ var current = matched.instances[name];
+ if (
+ (val && current !== vm) ||
+ (!val && current === vm)
+ ) {
+ matched.instances[name] = val;
+ }
+ }
+
+ // also register instance in prepatch hook
+ // in case the same component instance is reused across different routes
+ ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
+ matched.instances[name] = vnode.componentInstance;
+ };
+
+ // register instance in init hook
+ // in case kept-alive component be actived when routes changed
+ data.hook.init = function (vnode) {
+ if (vnode.data.keepAlive &&
+ vnode.componentInstance &&
+ vnode.componentInstance !== matched.instances[name]
+ ) {
+ matched.instances[name] = vnode.componentInstance;
+ }
+ };
+
+ // resolve props
+ var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
+ if (propsToPass) {
+ // clone to prevent mutation
+ propsToPass = data.props = extend({}, propsToPass);
+ // pass non-declared props as attrs
+ var attrs = data.attrs = data.attrs || {};
+ for (var key in propsToPass) {
+ if (!component.props || !(key in component.props)) {
+ attrs[key] = propsToPass[key];
+ delete propsToPass[key];
+ }
+ }
+ }
+
+ return h(component, data, children)
+ }
+ };
+
+ function resolveProps (route, config) {
+ switch (typeof config) {
+ case 'undefined':
+ return
+ case 'object':
+ return config
+ case 'function':
+ return config(route)
+ case 'boolean':
+ return config ? route.params : undefined
+ default:
+ {
+ warn(
+ false,
+ "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " +
+ "expecting an object, function or boolean."
+ );
+ }
+ }
+ }
+
+ /* */
+
+ var encodeReserveRE = /[!'()*]/g;
+ var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
+ var commaRE = /%2C/g;
+
+ // fixed encodeURIComponent which is more conformant to RFC3986:
+ // - escapes [!'()*]
+ // - preserve commas
+ var encode = function (str) { return encodeURIComponent(str)
+ .replace(encodeReserveRE, encodeReserveReplacer)
+ .replace(commaRE, ','); };
+
+ var decode = decodeURIComponent;
+
+ function resolveQuery (
+ query,
+ extraQuery,
+ _parseQuery
+ ) {
+ if ( extraQuery === void 0 ) extraQuery = {};
+
+ var parse = _parseQuery || parseQuery;
+ var parsedQuery;
+ try {
+ parsedQuery = parse(query || '');
+ } catch (e) {
+ warn(false, e.message);
+ parsedQuery = {};
+ }
+ for (var key in extraQuery) {
+ parsedQuery[key] = extraQuery[key];
+ }
+ return parsedQuery
+ }
+
+ function parseQuery (query) {
+ var res = {};
+
+ query = query.trim().replace(/^(\?|#|&)/, '');
+
+ if (!query) {
+ return res
+ }
+
+ query.split('&').forEach(function (param) {
+ var parts = param.replace(/\+/g, ' ').split('=');
+ var key = decode(parts.shift());
+ var val = parts.length > 0
+ ? decode(parts.join('='))
+ : null;
+
+ if (res[key] === undefined) {
+ res[key] = val;
+ } else if (Array.isArray(res[key])) {
+ res[key].push(val);
+ } else {
+ res[key] = [res[key], val];
+ }
+ });
+
+ return res
+ }
+
+ function stringifyQuery (obj) {
+ var res = obj ? Object.keys(obj).map(function (key) {
+ var val = obj[key];
+
+ if (val === undefined) {
+ return ''
+ }
+
+ if (val === null) {
+ return encode(key)
+ }
+
+ if (Array.isArray(val)) {
+ var result = [];
+ val.forEach(function (val2) {
+ if (val2 === undefined) {
+ return
+ }
+ if (val2 === null) {
+ result.push(encode(key));
+ } else {
+ result.push(encode(key) + '=' + encode(val2));
+ }
+ });
+ return result.join('&')
+ }
+
+ return encode(key) + '=' + encode(val)
+ }).filter(function (x) { return x.length > 0; }).join('&') : null;
+ return res ? ("?" + res) : ''
+ }
+
+ /* */
+
+ var trailingSlashRE = /\/?$/;
+
+ function createRoute (
+ record,
+ location,
+ redirectedFrom,
+ router
+ ) {
+ var stringifyQuery = router && router.options.stringifyQuery;
+
+ var query = location.query || {};
+ try {
+ query = clone(query);
+ } catch (e) {}
+
+ var route = {
+ name: location.name || (record && record.name),
+ meta: (record && record.meta) || {},
+ path: location.path || '/',
+ hash: location.hash || '',
+ query: query,
+ params: location.params || {},
+ fullPath: getFullPath(location, stringifyQuery),
+ matched: record ? formatMatch(record) : []
+ };
+ if (redirectedFrom) {
+ route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery);
+ }
+ return Object.freeze(route)
+ }
+
+ function clone (value) {
+ if (Array.isArray(value)) {
+ return value.map(clone)
+ } else if (value && typeof value === 'object') {
+ var res = {};
+ for (var key in value) {
+ res[key] = clone(value[key]);
+ }
+ return res
+ } else {
+ return value
+ }
+ }
+
+ // the starting route that represents the initial state
+ var START = createRoute(null, {
+ path: '/'
+ });
+
+ function formatMatch (record) {
+ var res = [];
+ while (record) {
+ res.unshift(record);
+ record = record.parent;
+ }
+ return res
+ }
+
+ function getFullPath (
+ ref,
+ _stringifyQuery
+ ) {
+ var path = ref.path;
+ var query = ref.query; if ( query === void 0 ) query = {};
+ var hash = ref.hash; if ( hash === void 0 ) hash = '';
+
+ var stringify = _stringifyQuery || stringifyQuery;
+ return (path || '/') + stringify(query) + hash
+ }
+
+ function isSameRoute (a, b) {
+ if (b === START) {
+ return a === b
+ } else if (!b) {
+ return false
+ } else if (a.path && b.path) {
+ return (
+ a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query)
+ )
+ } else if (a.name && b.name) {
+ return (
+ a.name === b.name &&
+ a.hash === b.hash &&
+ isObjectEqual(a.query, b.query) &&
+ isObjectEqual(a.params, b.params)
+ )
+ } else {
+ return false
+ }
+ }
+
+ function isObjectEqual (a, b) {
+ if ( a === void 0 ) a = {};
+ if ( b === void 0 ) b = {};
+
+ // handle null value #1566
+ if (!a || !b) { return a === b }
+ var aKeys = Object.keys(a);
+ var bKeys = Object.keys(b);
+ if (aKeys.length !== bKeys.length) {
+ return false
+ }
+ return aKeys.every(function (key) {
+ var aVal = a[key];
+ var bVal = b[key];
+ // check nested equality
+ if (typeof aVal === 'object' && typeof bVal === 'object') {
+ return isObjectEqual(aVal, bVal)
+ }
+ return String(aVal) === String(bVal)
+ })
+ }
+
+ function isIncludedRoute (current, target) {
+ return (
+ current.path.replace(trailingSlashRE, '/').indexOf(
+ target.path.replace(trailingSlashRE, '/')
+ ) === 0 &&
+ (!target.hash || current.hash === target.hash) &&
+ queryIncludes(current.query, target.query)
+ )
+ }
+
+ function queryIncludes (current, target) {
+ for (var key in target) {
+ if (!(key in current)) {
+ return false
+ }
+ }
+ return true
+ }
+
+ /* */
+
+ function resolvePath (
+ relative,
+ base,
+ append
+ ) {
+ var firstChar = relative.charAt(0);
+ if (firstChar === '/') {
+ return relative
+ }
+
+ if (firstChar === '?' || firstChar === '#') {
+ return base + relative
+ }
+
+ var stack = base.split('/');
+
+ // remove trailing segment if:
+ // - not appending
+ // - appending to trailing slash (last segment is empty)
+ if (!append || !stack[stack.length - 1]) {
+ stack.pop();
+ }
+
+ // resolve relative path
+ var segments = relative.replace(/^\//, '').split('/');
+ for (var i = 0; i < segments.length; i++) {
+ var segment = segments[i];
+ if (segment === '..') {
+ stack.pop();
+ } else if (segment !== '.') {
+ stack.push(segment);
+ }
+ }
+
+ // ensure leading slash
+ if (stack[0] !== '') {
+ stack.unshift('');
+ }
+
+ return stack.join('/')
+ }
+
+ function parsePath (path) {
+ var hash = '';
+ var query = '';
+
+ var hashIndex = path.indexOf('#');
+ if (hashIndex >= 0) {
+ hash = path.slice(hashIndex);
+ path = path.slice(0, hashIndex);
+ }
+
+ var queryIndex = path.indexOf('?');
+ if (queryIndex >= 0) {
+ query = path.slice(queryIndex + 1);
+ path = path.slice(0, queryIndex);
+ }
+
+ return {
+ path: path,
+ query: query,
+ hash: hash
+ }
+ }
+
+ function cleanPath (path) {
+ return path.replace(/\/\//g, '/')
+ }
+
+ var isarray = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]';
+ };
+
+ /**
+ * Expose `pathToRegexp`.
+ */
+ var pathToRegexp_1 = pathToRegexp;
+ var parse_1 = parse;
+ var compile_1 = compile;
+ var tokensToFunction_1 = tokensToFunction;
+ var tokensToRegExp_1 = tokensToRegExp;
+
+ /**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+ var PATH_REGEXP = new RegExp([
+ // Match escaped characters that would otherwise appear in future matches.
+ // This allows the user to escape special characters that won't transform.
+ '(\\\\.)',
+ // Match Express-style parameters and un-named parameters with a prefix
+ // and optional suffixes. Matches appear as:
+ //
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
+ ].join('|'), 'g');
+
+ /**
+ * Parse a string for the raw tokens.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!Array}
+ */
+ function parse (str, options) {
+ var tokens = [];
+ var key = 0;
+ var index = 0;
+ var path = '';
+ var defaultDelimiter = options && options.delimiter || '/';
+ var res;
+
+ while ((res = PATH_REGEXP.exec(str)) != null) {
+ var m = res[0];
+ var escaped = res[1];
+ var offset = res.index;
+ path += str.slice(index, offset);
+ index = offset + m.length;
+
+ // Ignore already escaped sequences.
+ if (escaped) {
+ path += escaped[1];
+ continue
+ }
+
+ var next = str[index];
+ var prefix = res[2];
+ var name = res[3];
+ var capture = res[4];
+ var group = res[5];
+ var modifier = res[6];
+ var asterisk = res[7];
+
+ // Push the current path onto the tokens.
+ if (path) {
+ tokens.push(path);
+ path = '';
+ }
+
+ var partial = prefix != null && next != null && next !== prefix;
+ var repeat = modifier === '+' || modifier === '*';
+ var optional = modifier === '?' || modifier === '*';
+ var delimiter = res[2] || defaultDelimiter;
+ var pattern = capture || group;
+
+ tokens.push({
+ name: name || key++,
+ prefix: prefix || '',
+ delimiter: delimiter,
+ optional: optional,
+ repeat: repeat,
+ partial: partial,
+ asterisk: !!asterisk,
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
+ });
+ }
+
+ // Match any characters still remaining.
+ if (index < str.length) {
+ path += str.substr(index);
+ }
+
+ // If the path exists, push it onto the end.
+ if (path) {
+ tokens.push(path);
+ }
+
+ return tokens
+ }
+
+ /**
+ * Compile a string to a template function for the path.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!function(Object=, Object=)}
+ */
+ function compile (str, options) {
+ return tokensToFunction(parse(str, options))
+ }
+
+ /**
+ * Prettier encoding of URI path segments.
+ *
+ * @param {string}
+ * @return {string}
+ */
+ function encodeURIComponentPretty (str) {
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+ }
+
+ /**
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
+ *
+ * @param {string}
+ * @return {string}
+ */
+ function encodeAsterisk (str) {
+ return encodeURI(str).replace(/[?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+ }
+
+ /**
+ * Expose a method for transforming tokens into the path function.
+ */
+ function tokensToFunction (tokens) {
+ // Compile all the tokens into regexps.
+ var matches = new Array(tokens.length);
+
+ // Compile all the patterns before compilation.
+ for (var i = 0; i < tokens.length; i++) {
+ if (typeof tokens[i] === 'object') {
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
+ }
+ }
+
+ return function (obj, opts) {
+ var path = '';
+ var data = obj || {};
+ var options = opts || {};
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
+
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ path += token;
+
+ continue
+ }
+
+ var value = data[token.name];
+ var segment;
+
+ if (value == null) {
+ if (token.optional) {
+ // Prepend partial segment prefixes.
+ if (token.partial) {
+ path += token.prefix;
+ }
+
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to be defined')
+ }
+ }
+
+ if (isarray(value)) {
+ if (!token.repeat) {
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
+ }
+
+ if (value.length === 0) {
+ if (token.optional) {
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
+ }
+ }
+
+ for (var j = 0; j < value.length; j++) {
+ segment = encode(value[j]);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
+ }
+
+ path += (j === 0 ? token.prefix : token.delimiter) + segment;
+ }
+
+ continue
+ }
+
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value);
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
+ }
+
+ path += token.prefix + segment;
+ }
+
+ return path
+ }
+ }
+
+ /**
+ * Escape a regular expression string.
+ *
+ * @param {string} str
+ * @return {string}
+ */
+ function escapeString (str) {
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
+ }
+
+ /**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param {string} group
+ * @return {string}
+ */
+ function escapeGroup (group) {
+ return group.replace(/([=!:$\/()])/g, '\\$1')
+ }
+
+ /**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param {!RegExp} re
+ * @param {Array} keys
+ * @return {!RegExp}
+ */
+ function attachKeys (re, keys) {
+ re.keys = keys;
+ return re
+ }
+
+ /**
+ * Get the flags for a regexp from the options.
+ *
+ * @param {Object} options
+ * @return {string}
+ */
+ function flags (options) {
+ return options.sensitive ? '' : 'i'
+ }
+
+ /**
+ * Pull out keys from a regexp.
+ *
+ * @param {!RegExp} path
+ * @param {!Array} keys
+ * @return {!RegExp}
+ */
+ function regexpToRegexp (path, keys) {
+ // Use a negative lookahead to match only capturing groups.
+ var groups = path.source.match(/\((?!\?)/g);
+
+ if (groups) {
+ for (var i = 0; i < groups.length; i++) {
+ keys.push({
+ name: i,
+ prefix: null,
+ delimiter: null,
+ optional: false,
+ repeat: false,
+ partial: false,
+ asterisk: false,
+ pattern: null
+ });
+ }
+ }
+
+ return attachKeys(path, keys)
+ }
+
+ /**
+ * Transform an array into a regexp.
+ *
+ * @param {!Array} path
+ * @param {Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+ function arrayToRegexp (path, keys, options) {
+ var parts = [];
+
+ for (var i = 0; i < path.length; i++) {
+ parts.push(pathToRegexp(path[i], keys, options).source);
+ }
+
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
+
+ return attachKeys(regexp, keys)
+ }
+
+ /**
+ * Create a path regexp from string input.
+ *
+ * @param {string} path
+ * @param {!Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+ function stringToRegexp (path, keys, options) {
+ return tokensToRegExp(parse(path, options), keys, options)
+ }
+
+ /**
+ * Expose a function for taking tokens and returning a RegExp.
+ *
+ * @param {!Array} tokens
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+ function tokensToRegExp (tokens, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ var strict = options.strict;
+ var end = options.end !== false;
+ var route = '';
+
+ // Iterate over the tokens and create our regexp string.
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (typeof token === 'string') {
+ route += escapeString(token);
+ } else {
+ var prefix = escapeString(token.prefix);
+ var capture = '(?:' + token.pattern + ')';
+
+ keys.push(token);
+
+ if (token.repeat) {
+ capture += '(?:' + prefix + capture + ')*';
+ }
+
+ if (token.optional) {
+ if (!token.partial) {
+ capture = '(?:' + prefix + '(' + capture + '))?';
+ } else {
+ capture = prefix + '(' + capture + ')?';
+ }
+ } else {
+ capture = prefix + '(' + capture + ')';
+ }
+
+ route += capture;
+ }
+ }
+
+ var delimiter = escapeString(options.delimiter || '/');
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
+
+ // In non-strict mode we allow a slash at the end of match. If the path to
+ // match already ends with a slash, we remove it for consistency. The slash
+ // is valid at the end of a path match, not in the middle. This is important
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
+ if (!strict) {
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
+ }
+
+ if (end) {
+ route += '$';
+ } else {
+ // In non-ending mode, we need the capturing groups to match as much as
+ // possible by using a positive lookahead to the end or next path segment.
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
+ }
+
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
+ }
+
+ /**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param {(string|RegExp|Array)} path
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+ function pathToRegexp (path, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options);
+ keys = [];
+ }
+
+ options = options || {};
+
+ if (path instanceof RegExp) {
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
+ }
+
+ if (isarray(path)) {
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
+ }
+
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
+ }
+ pathToRegexp_1.parse = parse_1;
+ pathToRegexp_1.compile = compile_1;
+ pathToRegexp_1.tokensToFunction = tokensToFunction_1;
+ pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
+
+ /* */
+
+ // $flow-disable-line
+ var regexpCompileCache = Object.create(null);
+
+ function fillParams (
+ path,
+ params,
+ routeMsg
+ ) {
+ params = params || {};
+ try {
+ var filler =
+ regexpCompileCache[path] ||
+ (regexpCompileCache[path] = pathToRegexp_1.compile(path));
+
+ // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
+ if (params.pathMatch) { params[0] = params.pathMatch; }
+
+ return filler(params, { pretty: true })
+ } catch (e) {
+ {
+ warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
+ }
+ return ''
+ } finally {
+ // delete the 0 if it was added
+ delete params[0];
+ }
+ }
+
+ /* */
+
+ function normalizeLocation (
+ raw,
+ current,
+ append,
+ router
+ ) {
+ var next = typeof raw === 'string' ? { path: raw } : raw;
+ // named target
+ if (next._normalized) {
+ return next
+ } else if (next.name) {
+ return extend({}, raw)
+ }
+
+ // relative params
+ if (!next.path && next.params && current) {
+ next = extend({}, next);
+ next._normalized = true;
+ var params = extend(extend({}, current.params), next.params);
+ if (current.name) {
+ next.name = current.name;
+ next.params = params;
+ } else if (current.matched.length) {
+ var rawPath = current.matched[current.matched.length - 1].path;
+ next.path = fillParams(rawPath, params, ("path " + (current.path)));
+ } else {
+ warn(false, "relative params navigation requires a current route.");
+ }
+ return next
+ }
+
+ var parsedPath = parsePath(next.path || '');
+ var basePath = (current && current.path) || '/';
+ var path = parsedPath.path
+ ? resolvePath(parsedPath.path, basePath, append || next.append)
+ : basePath;
+
+ var query = resolveQuery(
+ parsedPath.query,
+ next.query,
+ router && router.options.parseQuery
+ );
+
+ var hash = next.hash || parsedPath.hash;
+ if (hash && hash.charAt(0) !== '#') {
+ hash = "#" + hash;
+ }
+
+ return {
+ _normalized: true,
+ path: path,
+ query: query,
+ hash: hash
+ }
+ }
+
+ /* */
+
+ // work around weird flow bug
+ var toTypes = [String, Object];
+ var eventTypes = [String, Array];
+
+ var noop = function () {};
+
+ var Link = {
+ name: 'RouterLink',
+ props: {
+ to: {
+ type: toTypes,
+ required: true
+ },
+ tag: {
+ type: String,
+ default: 'a'
+ },
+ exact: Boolean,
+ append: Boolean,
+ replace: Boolean,
+ activeClass: String,
+ exactActiveClass: String,
+ event: {
+ type: eventTypes,
+ default: 'click'
+ }
+ },
+ render: function render (h) {
+ var this$1 = this;
+
+ var router = this.$router;
+ var current = this.$route;
+ var ref = router.resolve(
+ this.to,
+ current,
+ this.append
+ );
+ var location = ref.location;
+ var route = ref.route;
+ var href = ref.href;
+
+ var classes = {};
+ var globalActiveClass = router.options.linkActiveClass;
+ var globalExactActiveClass = router.options.linkExactActiveClass;
+ // Support global empty active class
+ var activeClassFallback =
+ globalActiveClass == null ? 'router-link-active' : globalActiveClass;
+ var exactActiveClassFallback =
+ globalExactActiveClass == null
+ ? 'router-link-exact-active'
+ : globalExactActiveClass;
+ var activeClass =
+ this.activeClass == null ? activeClassFallback : this.activeClass;
+ var exactActiveClass =
+ this.exactActiveClass == null
+ ? exactActiveClassFallback
+ : this.exactActiveClass;
+
+ var compareTarget = route.redirectedFrom
+ ? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)
+ : route;
+
+ classes[exactActiveClass] = isSameRoute(current, compareTarget);
+ classes[activeClass] = this.exact
+ ? classes[exactActiveClass]
+ : isIncludedRoute(current, compareTarget);
+
+ var handler = function (e) {
+ if (guardEvent(e)) {
+ if (this$1.replace) {
+ router.replace(location, noop);
+ } else {
+ router.push(location, noop);
+ }
+ }
+ };
+
+ var on = { click: guardEvent };
+ if (Array.isArray(this.event)) {
+ this.event.forEach(function (e) {
+ on[e] = handler;
+ });
+ } else {
+ on[this.event] = handler;
+ }
+
+ var data = { class: classes };
+
+ var scopedSlot =
+ !this.$scopedSlots.$hasNormal &&
+ this.$scopedSlots.default &&
+ this.$scopedSlots.default({
+ href: href,
+ route: route,
+ navigate: handler,
+ isActive: classes[activeClass],
+ isExactActive: classes[exactActiveClass]
+ });
+
+ if (scopedSlot) {
+ if (scopedSlot.length === 1) {
+ return scopedSlot[0]
+ } else if (scopedSlot.length > 1 || !scopedSlot.length) {
+ {
+ warn(
+ false,
+ ("RouterLink with to=\"" + (this.props.to) + "\" is trying to use a scoped slot but it didn't provide exactly one child.")
+ );
+ }
+ return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)
+ }
+ }
+
+ if (this.tag === 'a') {
+ data.on = on;
+ data.attrs = { href: href };
+ } else {
+ // find the first child and apply listener and href
+ var a = findAnchor(this.$slots.default);
+ if (a) {
+ // in case the is a static node
+ a.isStatic = false;
+ var aData = (a.data = extend({}, a.data));
+ aData.on = aData.on || {};
+ // transform existing events in both objects into arrays so we can push later
+ for (var event in aData.on) {
+ var handler$1 = aData.on[event];
+ if (event in on) {
+ aData.on[event] = Array.isArray(handler$1) ? handler$1 : [handler$1];
+ }
+ }
+ // append new listeners for router-link
+ for (var event$1 in on) {
+ if (event$1 in aData.on) {
+ // on[event] is always a function
+ aData.on[event$1].push(on[event$1]);
+ } else {
+ aData.on[event$1] = handler;
+ }
+ }
+
+ var aAttrs = (a.data.attrs = extend({}, a.data.attrs));
+ aAttrs.href = href;
+ } else {
+ // doesn't have child, apply listener to self
+ data.on = on;
+ }
+ }
+
+ return h(this.tag, data, this.$slots.default)
+ }
+ };
+
+ function guardEvent (e) {
+ // don't redirect with control keys
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
+ // don't redirect when preventDefault called
+ if (e.defaultPrevented) { return }
+ // don't redirect on right click
+ if (e.button !== undefined && e.button !== 0) { return }
+ // don't redirect if `target="_blank"`
+ if (e.currentTarget && e.currentTarget.getAttribute) {
+ var target = e.currentTarget.getAttribute('target');
+ if (/\b_blank\b/i.test(target)) { return }
+ }
+ // this may be a Weex event which doesn't have this method
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ return true
+ }
+
+ function findAnchor (children) {
+ if (children) {
+ var child;
+ for (var i = 0; i < children.length; i++) {
+ child = children[i];
+ if (child.tag === 'a') {
+ return child
+ }
+ if (child.children && (child = findAnchor(child.children))) {
+ return child
+ }
+ }
+ }
+ }
+
+ var _Vue;
+
+ function install (Vue) {
+ if (install.installed && _Vue === Vue) { return }
+ install.installed = true;
+
+ _Vue = Vue;
+
+ var isDef = function (v) { return v !== undefined; };
+
+ var registerInstance = function (vm, callVal) {
+ var i = vm.$options._parentVnode;
+ if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
+ i(vm, callVal);
+ }
+ };
+
+ Vue.mixin({
+ beforeCreate: function beforeCreate () {
+ if (isDef(this.$options.router)) {
+ this._routerRoot = this;
+ this._router = this.$options.router;
+ this._router.init(this);
+ Vue.util.defineReactive(this, '_route', this._router.history.current);
+ } else {
+ this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
+ }
+ registerInstance(this, this);
+ },
+ destroyed: function destroyed () {
+ registerInstance(this);
+ }
+ });
+
+ Object.defineProperty(Vue.prototype, '$router', {
+ get: function get () { return this._routerRoot._router }
+ });
+
+ Object.defineProperty(Vue.prototype, '$route', {
+ get: function get () { return this._routerRoot._route }
+ });
+
+ Vue.component('RouterView', View);
+ Vue.component('RouterLink', Link);
+
+ var strats = Vue.config.optionMergeStrategies;
+ // use the same hook merging strategy for route hooks
+ strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
+ }
+
+ /* */
+
+ var inBrowser = typeof window !== 'undefined';
+
+ /* */
+
+ function createRouteMap (
+ routes,
+ oldPathList,
+ oldPathMap,
+ oldNameMap
+ ) {
+ // the path list is used to control path matching priority
+ var pathList = oldPathList || [];
+ // $flow-disable-line
+ var pathMap = oldPathMap || Object.create(null);
+ // $flow-disable-line
+ var nameMap = oldNameMap || Object.create(null);
+
+ routes.forEach(function (route) {
+ addRouteRecord(pathList, pathMap, nameMap, route);
+ });
+
+ // ensure wildcard routes are always at the end
+ for (var i = 0, l = pathList.length; i < l; i++) {
+ if (pathList[i] === '*') {
+ pathList.push(pathList.splice(i, 1)[0]);
+ l--;
+ i--;
+ }
+ }
+
+ {
+ // warn if routes do not include leading slashes
+ var found = pathList
+ // check for missing leading slash
+ .filter(function (path) { return path && path.charAt(0) !== '*' && path.charAt(0) !== '/'; });
+
+ if (found.length > 0) {
+ var pathNames = found.map(function (path) { return ("- " + path); }).join('\n');
+ warn(false, ("Non-nested routes must include a leading slash character. Fix the following routes: \n" + pathNames));
+ }
+ }
+
+ return {
+ pathList: pathList,
+ pathMap: pathMap,
+ nameMap: nameMap
+ }
+ }
+
+ function addRouteRecord (
+ pathList,
+ pathMap,
+ nameMap,
+ route,
+ parent,
+ matchAs
+ ) {
+ var path = route.path;
+ var name = route.name;
+ {
+ assert(path != null, "\"path\" is required in a route configuration.");
+ assert(
+ typeof route.component !== 'string',
+ "route config \"component\" for path: " + (String(
+ path || name
+ )) + " cannot be a " + "string id. Use an actual component instead."
+ );
+ }
+
+ var pathToRegexpOptions =
+ route.pathToRegexpOptions || {};
+ var normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict);
+
+ if (typeof route.caseSensitive === 'boolean') {
+ pathToRegexpOptions.sensitive = route.caseSensitive;
+ }
+
+ var record = {
+ path: normalizedPath,
+ regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
+ components: route.components || { default: route.component },
+ instances: {},
+ name: name,
+ parent: parent,
+ matchAs: matchAs,
+ redirect: route.redirect,
+ beforeEnter: route.beforeEnter,
+ meta: route.meta || {},
+ props:
+ route.props == null
+ ? {}
+ : route.components
+ ? route.props
+ : { default: route.props }
+ };
+
+ if (route.children) {
+ // Warn if route is named, does not redirect and has a default child route.
+ // If users navigate to this route by name, the default child will
+ // not be rendered (GH Issue #629)
+ {
+ if (
+ route.name &&
+ !route.redirect &&
+ route.children.some(function (child) { return /^\/?$/.test(child.path); })
+ ) {
+ warn(
+ false,
+ "Named Route '" + (route.name) + "' has a default child route. " +
+ "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
+ "the default child route will not be rendered. Remove the name from " +
+ "this route and use the name of the default child route for named " +
+ "links instead."
+ );
+ }
+ }
+ route.children.forEach(function (child) {
+ var childMatchAs = matchAs
+ ? cleanPath((matchAs + "/" + (child.path)))
+ : undefined;
+ addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
+ });
+ }
+
+ if (!pathMap[record.path]) {
+ pathList.push(record.path);
+ pathMap[record.path] = record;
+ }
+
+ if (route.alias !== undefined) {
+ var aliases = Array.isArray(route.alias) ? route.alias : [route.alias];
+ for (var i = 0; i < aliases.length; ++i) {
+ var alias = aliases[i];
+ if ( alias === path) {
+ warn(
+ false,
+ ("Found an alias with the same value as the path: \"" + path + "\". You have to remove that alias. It will be ignored in development.")
+ );
+ // skip in dev to make it work
+ continue
+ }
+
+ var aliasRoute = {
+ path: alias,
+ children: route.children
+ };
+ addRouteRecord(
+ pathList,
+ pathMap,
+ nameMap,
+ aliasRoute,
+ parent,
+ record.path || '/' // matchAs
+ );
+ }
+ }
+
+ if (name) {
+ if (!nameMap[name]) {
+ nameMap[name] = record;
+ } else if ( !matchAs) {
+ warn(
+ false,
+ "Duplicate named routes definition: " +
+ "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
+ );
+ }
+ }
+ }
+
+ function compileRouteRegex (
+ path,
+ pathToRegexpOptions
+ ) {
+ var regex = pathToRegexp_1(path, [], pathToRegexpOptions);
+ {
+ var keys = Object.create(null);
+ regex.keys.forEach(function (key) {
+ warn(
+ !keys[key.name],
+ ("Duplicate param keys in route with path: \"" + path + "\"")
+ );
+ keys[key.name] = true;
+ });
+ }
+ return regex
+ }
+
+ function normalizePath (
+ path,
+ parent,
+ strict
+ ) {
+ if (!strict) { path = path.replace(/\/$/, ''); }
+ if (path[0] === '/') { return path }
+ if (parent == null) { return path }
+ return cleanPath(((parent.path) + "/" + path))
+ }
+
+ /* */
+
+
+
+ function createMatcher (
+ routes,
+ router
+ ) {
+ var ref = createRouteMap(routes);
+ var pathList = ref.pathList;
+ var pathMap = ref.pathMap;
+ var nameMap = ref.nameMap;
+
+ function addRoutes (routes) {
+ createRouteMap(routes, pathList, pathMap, nameMap);
+ }
+
+ function match (
+ raw,
+ currentRoute,
+ redirectedFrom
+ ) {
+ var location = normalizeLocation(raw, currentRoute, false, router);
+ var name = location.name;
+
+ if (name) {
+ var record = nameMap[name];
+ {
+ warn(record, ("Route with name '" + name + "' does not exist"));
+ }
+ if (!record) { return _createRoute(null, location) }
+ var paramNames = record.regex.keys
+ .filter(function (key) { return !key.optional; })
+ .map(function (key) { return key.name; });
+
+ if (typeof location.params !== 'object') {
+ location.params = {};
+ }
+
+ if (currentRoute && typeof currentRoute.params === 'object') {
+ for (var key in currentRoute.params) {
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
+ location.params[key] = currentRoute.params[key];
+ }
+ }
+ }
+
+ location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
+ return _createRoute(record, location, redirectedFrom)
+ } else if (location.path) {
+ location.params = {};
+ for (var i = 0; i < pathList.length; i++) {
+ var path = pathList[i];
+ var record$1 = pathMap[path];
+ if (matchRoute(record$1.regex, location.path, location.params)) {
+ return _createRoute(record$1, location, redirectedFrom)
+ }
+ }
+ }
+ // no match
+ return _createRoute(null, location)
+ }
+
+ function redirect (
+ record,
+ location
+ ) {
+ var originalRedirect = record.redirect;
+ var redirect = typeof originalRedirect === 'function'
+ ? originalRedirect(createRoute(record, location, null, router))
+ : originalRedirect;
+
+ if (typeof redirect === 'string') {
+ redirect = { path: redirect };
+ }
+
+ if (!redirect || typeof redirect !== 'object') {
+ {
+ warn(
+ false, ("invalid redirect option: " + (JSON.stringify(redirect)))
+ );
+ }
+ return _createRoute(null, location)
+ }
+
+ var re = redirect;
+ var name = re.name;
+ var path = re.path;
+ var query = location.query;
+ var hash = location.hash;
+ var params = location.params;
+ query = re.hasOwnProperty('query') ? re.query : query;
+ hash = re.hasOwnProperty('hash') ? re.hash : hash;
+ params = re.hasOwnProperty('params') ? re.params : params;
+
+ if (name) {
+ // resolved named direct
+ var targetRecord = nameMap[name];
+ {
+ assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
+ }
+ return match({
+ _normalized: true,
+ name: name,
+ query: query,
+ hash: hash,
+ params: params
+ }, undefined, location)
+ } else if (path) {
+ // 1. resolve relative redirect
+ var rawPath = resolveRecordPath(path, record);
+ // 2. resolve params
+ var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
+ // 3. rematch with existing query and hash
+ return match({
+ _normalized: true,
+ path: resolvedPath,
+ query: query,
+ hash: hash
+ }, undefined, location)
+ } else {
+ {
+ warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
+ }
+ return _createRoute(null, location)
+ }
+ }
+
+ function alias (
+ record,
+ location,
+ matchAs
+ ) {
+ var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
+ var aliasedMatch = match({
+ _normalized: true,
+ path: aliasedPath
+ });
+ if (aliasedMatch) {
+ var matched = aliasedMatch.matched;
+ var aliasedRecord = matched[matched.length - 1];
+ location.params = aliasedMatch.params;
+ return _createRoute(aliasedRecord, location)
+ }
+ return _createRoute(null, location)
+ }
+
+ function _createRoute (
+ record,
+ location,
+ redirectedFrom
+ ) {
+ if (record && record.redirect) {
+ return redirect(record, redirectedFrom || location)
+ }
+ if (record && record.matchAs) {
+ return alias(record, location, record.matchAs)
+ }
+ return createRoute(record, location, redirectedFrom, router)
+ }
+
+ return {
+ match: match,
+ addRoutes: addRoutes
+ }
+ }
+
+ function matchRoute (
+ regex,
+ path,
+ params
+ ) {
+ var m = path.match(regex);
+
+ if (!m) {
+ return false
+ } else if (!params) {
+ return true
+ }
+
+ for (var i = 1, len = m.length; i < len; ++i) {
+ var key = regex.keys[i - 1];
+ var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
+ if (key) {
+ // Fix #1994: using * with props: true generates a param named 0
+ params[key.name || 'pathMatch'] = val;
+ }
+ }
+
+ return true
+ }
+
+ function resolveRecordPath (path, record) {
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
+ }
+
+ /* */
+
+ // use User Timing api (if present) for more accurate key precision
+ var Time =
+ inBrowser && window.performance && window.performance.now
+ ? window.performance
+ : Date;
+
+ function genStateKey () {
+ return Time.now().toFixed(3)
+ }
+
+ var _key = genStateKey();
+
+ function getStateKey () {
+ return _key
+ }
+
+ function setStateKey (key) {
+ return (_key = key)
+ }
+
+ /* */
+
+ var positionStore = Object.create(null);
+
+ function setupScroll () {
+ // Fix for #1585 for Firefox
+ // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
+ // Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
+ // window.location.protocol + '//' + window.location.host
+ // location.host contains the port and location.hostname doesn't
+ var protocolAndPath = window.location.protocol + '//' + window.location.host;
+ var absolutePath = window.location.href.replace(protocolAndPath, '');
+ window.history.replaceState({ key: getStateKey() }, '', absolutePath);
+ window.addEventListener('popstate', function (e) {
+ saveScrollPosition();
+ if (e.state && e.state.key) {
+ setStateKey(e.state.key);
+ }
+ });
+ }
+
+ function handleScroll (
+ router,
+ to,
+ from,
+ isPop
+ ) {
+ if (!router.app) {
+ return
+ }
+
+ var behavior = router.options.scrollBehavior;
+ if (!behavior) {
+ return
+ }
+
+ {
+ assert(typeof behavior === 'function', "scrollBehavior must be a function");
+ }
+
+ // wait until re-render finishes before scrolling
+ router.app.$nextTick(function () {
+ var position = getScrollPosition();
+ var shouldScroll = behavior.call(
+ router,
+ to,
+ from,
+ isPop ? position : null
+ );
+
+ if (!shouldScroll) {
+ return
+ }
+
+ if (typeof shouldScroll.then === 'function') {
+ shouldScroll
+ .then(function (shouldScroll) {
+ scrollToPosition((shouldScroll), position);
+ })
+ .catch(function (err) {
+ {
+ assert(false, err.toString());
+ }
+ });
+ } else {
+ scrollToPosition(shouldScroll, position);
+ }
+ });
+ }
+
+ function saveScrollPosition () {
+ var key = getStateKey();
+ if (key) {
+ positionStore[key] = {
+ x: window.pageXOffset,
+ y: window.pageYOffset
+ };
+ }
+ }
+
+ function getScrollPosition () {
+ var key = getStateKey();
+ if (key) {
+ return positionStore[key]
+ }
+ }
+
+ function getElementPosition (el, offset) {
+ var docEl = document.documentElement;
+ var docRect = docEl.getBoundingClientRect();
+ var elRect = el.getBoundingClientRect();
+ return {
+ x: elRect.left - docRect.left - offset.x,
+ y: elRect.top - docRect.top - offset.y
+ }
+ }
+
+ function isValidPosition (obj) {
+ return isNumber(obj.x) || isNumber(obj.y)
+ }
+
+ function normalizePosition (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : window.pageXOffset,
+ y: isNumber(obj.y) ? obj.y : window.pageYOffset
+ }
+ }
+
+ function normalizeOffset (obj) {
+ return {
+ x: isNumber(obj.x) ? obj.x : 0,
+ y: isNumber(obj.y) ? obj.y : 0
+ }
+ }
+
+ function isNumber (v) {
+ return typeof v === 'number'
+ }
+
+ var hashStartsWithNumberRE = /^#\d/;
+
+ function scrollToPosition (shouldScroll, position) {
+ var isObject = typeof shouldScroll === 'object';
+ if (isObject && typeof shouldScroll.selector === 'string') {
+ // getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
+ // but at the same time, it doesn't make much sense to select an element with an id and an extra selector
+ var el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
+ ? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
+ : document.querySelector(shouldScroll.selector);
+
+ if (el) {
+ var offset =
+ shouldScroll.offset && typeof shouldScroll.offset === 'object'
+ ? shouldScroll.offset
+ : {};
+ offset = normalizeOffset(offset);
+ position = getElementPosition(el, offset);
+ } else if (isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+ } else if (isObject && isValidPosition(shouldScroll)) {
+ position = normalizePosition(shouldScroll);
+ }
+
+ if (position) {
+ window.scrollTo(position.x, position.y);
+ }
+ }
+
+ /* */
+
+ var supportsPushState =
+ inBrowser &&
+ (function () {
+ var ua = window.navigator.userAgent;
+
+ if (
+ (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
+ ua.indexOf('Mobile Safari') !== -1 &&
+ ua.indexOf('Chrome') === -1 &&
+ ua.indexOf('Windows Phone') === -1
+ ) {
+ return false
+ }
+
+ return window.history && 'pushState' in window.history
+ })();
+
+ function pushState (url, replace) {
+ saveScrollPosition();
+ // try...catch the pushState call to get around Safari
+ // DOM Exception 18 where it limits to 100 pushState calls
+ var history = window.history;
+ try {
+ if (replace) {
+ history.replaceState({ key: getStateKey() }, '', url);
+ } else {
+ history.pushState({ key: setStateKey(genStateKey()) }, '', url);
+ }
+ } catch (e) {
+ window.location[replace ? 'replace' : 'assign'](url);
+ }
+ }
+
+ function replaceState (url) {
+ pushState(url, true);
+ }
+
+ /* */
+
+ function runQueue (queue, fn, cb) {
+ var step = function (index) {
+ if (index >= queue.length) {
+ cb();
+ } else {
+ if (queue[index]) {
+ fn(queue[index], function () {
+ step(index + 1);
+ });
+ } else {
+ step(index + 1);
+ }
+ }
+ };
+ step(0);
+ }
+
+ /* */
+
+ function resolveAsyncComponents (matched) {
+ return function (to, from, next) {
+ var hasAsync = false;
+ var pending = 0;
+ var error = null;
+
+ flatMapComponents(matched, function (def, _, match, key) {
+ // if it's a function and doesn't have cid attached,
+ // assume it's an async component resolve function.
+ // we are not using Vue's default async resolving mechanism because
+ // we want to halt the navigation until the incoming component has been
+ // resolved.
+ if (typeof def === 'function' && def.cid === undefined) {
+ hasAsync = true;
+ pending++;
+
+ var resolve = once(function (resolvedDef) {
+ if (isESModule(resolvedDef)) {
+ resolvedDef = resolvedDef.default;
+ }
+ // save resolved on async factory in case it's used elsewhere
+ def.resolved = typeof resolvedDef === 'function'
+ ? resolvedDef
+ : _Vue.extend(resolvedDef);
+ match.components[key] = resolvedDef;
+ pending--;
+ if (pending <= 0) {
+ next();
+ }
+ });
+
+ var reject = once(function (reason) {
+ var msg = "Failed to resolve async component " + key + ": " + reason;
+ warn(false, msg);
+ if (!error) {
+ error = isError(reason)
+ ? reason
+ : new Error(msg);
+ next(error);
+ }
+ });
+
+ var res;
+ try {
+ res = def(resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ if (res) {
+ if (typeof res.then === 'function') {
+ res.then(resolve, reject);
+ } else {
+ // new syntax in Vue 2.3
+ var comp = res.component;
+ if (comp && typeof comp.then === 'function') {
+ comp.then(resolve, reject);
+ }
+ }
+ }
+ }
+ });
+
+ if (!hasAsync) { next(); }
+ }
+ }
+
+ function flatMapComponents (
+ matched,
+ fn
+ ) {
+ return flatten(matched.map(function (m) {
+ return Object.keys(m.components).map(function (key) { return fn(
+ m.components[key],
+ m.instances[key],
+ m, key
+ ); })
+ }))
+ }
+
+ function flatten (arr) {
+ return Array.prototype.concat.apply([], arr)
+ }
+
+ var hasSymbol =
+ typeof Symbol === 'function' &&
+ typeof Symbol.toStringTag === 'symbol';
+
+ function isESModule (obj) {
+ return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
+ }
+
+ // in Webpack 2, require.ensure now also returns a Promise
+ // so the resolve/reject functions may get called an extra time
+ // if the user uses an arrow function shorthand that happens to
+ // return that Promise.
+ function once (fn) {
+ var called = false;
+ return function () {
+ var args = [], len = arguments.length;
+ while ( len-- ) args[ len ] = arguments[ len ];
+
+ if (called) { return }
+ called = true;
+ return fn.apply(this, args)
+ }
+ }
+
+ var NavigationDuplicated = /*@__PURE__*/(function (Error) {
+ function NavigationDuplicated (normalizedLocation) {
+ Error.call(this);
+ this.name = this._name = 'NavigationDuplicated';
+ // passing the message to super() doesn't seem to work in the transpiled version
+ this.message = "Navigating to current location (\"" + (normalizedLocation.fullPath) + "\") is not allowed";
+ // add a stack property so services like Sentry can correctly display it
+ Object.defineProperty(this, 'stack', {
+ value: new Error().stack,
+ writable: true,
+ configurable: true
+ });
+ // we could also have used
+ // Error.captureStackTrace(this, this.constructor)
+ // but it only exists on node and chrome
+ }
+
+ if ( Error ) NavigationDuplicated.__proto__ = Error;
+ NavigationDuplicated.prototype = Object.create( Error && Error.prototype );
+ NavigationDuplicated.prototype.constructor = NavigationDuplicated;
+
+ return NavigationDuplicated;
+ }(Error));
+
+ // support IE9
+ NavigationDuplicated._name = 'NavigationDuplicated';
+
+ /* */
+
+ var History = function History (router, base) {
+ this.router = router;
+ this.base = normalizeBase(base);
+ // start with a route object that stands for "nowhere"
+ this.current = START;
+ this.pending = null;
+ this.ready = false;
+ this.readyCbs = [];
+ this.readyErrorCbs = [];
+ this.errorCbs = [];
+ };
+
+ History.prototype.listen = function listen (cb) {
+ this.cb = cb;
+ };
+
+ History.prototype.onReady = function onReady (cb, errorCb) {
+ if (this.ready) {
+ cb();
+ } else {
+ this.readyCbs.push(cb);
+ if (errorCb) {
+ this.readyErrorCbs.push(errorCb);
+ }
+ }
+ };
+
+ History.prototype.onError = function onError (errorCb) {
+ this.errorCbs.push(errorCb);
+ };
+
+ History.prototype.transitionTo = function transitionTo (
+ location,
+ onComplete,
+ onAbort
+ ) {
+ var this$1 = this;
+
+ var route = this.router.match(location, this.current);
+ this.confirmTransition(
+ route,
+ function () {
+ this$1.updateRoute(route);
+ onComplete && onComplete(route);
+ this$1.ensureURL();
+
+ // fire ready cbs once
+ if (!this$1.ready) {
+ this$1.ready = true;
+ this$1.readyCbs.forEach(function (cb) {
+ cb(route);
+ });
+ }
+ },
+ function (err) {
+ if (onAbort) {
+ onAbort(err);
+ }
+ if (err && !this$1.ready) {
+ this$1.ready = true;
+ this$1.readyErrorCbs.forEach(function (cb) {
+ cb(err);
+ });
+ }
+ }
+ );
+ };
+
+ History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
+ var this$1 = this;
+
+ var current = this.current;
+ var abort = function (err) {
+ // after merging https://github.com/vuejs/vue-router/pull/2771 we
+ // When the user navigates through history through back/forward buttons
+ // we do not want to throw the error. We only throw it if directly calling
+ // push/replace. That's why it's not included in isError
+ if (!isExtendedError(NavigationDuplicated, err) && isError(err)) {
+ if (this$1.errorCbs.length) {
+ this$1.errorCbs.forEach(function (cb) {
+ cb(err);
+ });
+ } else {
+ warn(false, 'uncaught error during route navigation:');
+ console.error(err);
+ }
+ }
+ onAbort && onAbort(err);
+ };
+ if (
+ isSameRoute(route, current) &&
+ // in the case the route map has been dynamically appended to
+ route.matched.length === current.matched.length
+ ) {
+ this.ensureURL();
+ return abort(new NavigationDuplicated(route))
+ }
+
+ var ref = resolveQueue(
+ this.current.matched,
+ route.matched
+ );
+ var updated = ref.updated;
+ var deactivated = ref.deactivated;
+ var activated = ref.activated;
+
+ var queue = [].concat(
+ // in-component leave guards
+ extractLeaveGuards(deactivated),
+ // global before hooks
+ this.router.beforeHooks,
+ // in-component update hooks
+ extractUpdateHooks(updated),
+ // in-config enter guards
+ activated.map(function (m) { return m.beforeEnter; }),
+ // async components
+ resolveAsyncComponents(activated)
+ );
+
+ this.pending = route;
+ var iterator = function (hook, next) {
+ if (this$1.pending !== route) {
+ return abort()
+ }
+ try {
+ hook(route, current, function (to) {
+ if (to === false || isError(to)) {
+ // next(false) -> abort navigation, ensure current URL
+ this$1.ensureURL(true);
+ abort(to);
+ } else if (
+ typeof to === 'string' ||
+ (typeof to === 'object' &&
+ (typeof to.path === 'string' || typeof to.name === 'string'))
+ ) {
+ // next('/') or next({ path: '/' }) -> redirect
+ abort();
+ if (typeof to === 'object' && to.replace) {
+ this$1.replace(to);
+ } else {
+ this$1.push(to);
+ }
+ } else {
+ // confirm transition and pass on the value
+ next(to);
+ }
+ });
+ } catch (e) {
+ abort(e);
+ }
+ };
+
+ runQueue(queue, iterator, function () {
+ var postEnterCbs = [];
+ var isValid = function () { return this$1.current === route; };
+ // wait until async components are resolved before
+ // extracting in-component enter guards
+ var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
+ var queue = enterGuards.concat(this$1.router.resolveHooks);
+ runQueue(queue, iterator, function () {
+ if (this$1.pending !== route) {
+ return abort()
+ }
+ this$1.pending = null;
+ onComplete(route);
+ if (this$1.router.app) {
+ this$1.router.app.$nextTick(function () {
+ postEnterCbs.forEach(function (cb) {
+ cb();
+ });
+ });
+ }
+ });
+ });
+ };
+
+ History.prototype.updateRoute = function updateRoute (route) {
+ var prev = this.current;
+ this.current = route;
+ this.cb && this.cb(route);
+ this.router.afterHooks.forEach(function (hook) {
+ hook && hook(route, prev);
+ });
+ };
+
+ function normalizeBase (base) {
+ if (!base) {
+ if (inBrowser) {
+ // respect tag
+ var baseEl = document.querySelector('base');
+ base = (baseEl && baseEl.getAttribute('href')) || '/';
+ // strip full URL origin
+ base = base.replace(/^https?:\/\/[^\/]+/, '');
+ } else {
+ base = '/';
+ }
+ }
+ // make sure there's the starting slash
+ if (base.charAt(0) !== '/') {
+ base = '/' + base;
+ }
+ // remove trailing slash
+ return base.replace(/\/$/, '')
+ }
+
+ function resolveQueue (
+ current,
+ next
+ ) {
+ var i;
+ var max = Math.max(current.length, next.length);
+ for (i = 0; i < max; i++) {
+ if (current[i] !== next[i]) {
+ break
+ }
+ }
+ return {
+ updated: next.slice(0, i),
+ activated: next.slice(i),
+ deactivated: current.slice(i)
+ }
+ }
+
+ function extractGuards (
+ records,
+ name,
+ bind,
+ reverse
+ ) {
+ var guards = flatMapComponents(records, function (def, instance, match, key) {
+ var guard = extractGuard(def, name);
+ if (guard) {
+ return Array.isArray(guard)
+ ? guard.map(function (guard) { return bind(guard, instance, match, key); })
+ : bind(guard, instance, match, key)
+ }
+ });
+ return flatten(reverse ? guards.reverse() : guards)
+ }
+
+ function extractGuard (
+ def,
+ key
+ ) {
+ if (typeof def !== 'function') {
+ // extend now so that global mixins are applied.
+ def = _Vue.extend(def);
+ }
+ return def.options[key]
+ }
+
+ function extractLeaveGuards (deactivated) {
+ return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
+ }
+
+ function extractUpdateHooks (updated) {
+ return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
+ }
+
+ function bindGuard (guard, instance) {
+ if (instance) {
+ return function boundRouteGuard () {
+ return guard.apply(instance, arguments)
+ }
+ }
+ }
+
+ function extractEnterGuards (
+ activated,
+ cbs,
+ isValid
+ ) {
+ return extractGuards(
+ activated,
+ 'beforeRouteEnter',
+ function (guard, _, match, key) {
+ return bindEnterGuard(guard, match, key, cbs, isValid)
+ }
+ )
+ }
+
+ function bindEnterGuard (
+ guard,
+ match,
+ key,
+ cbs,
+ isValid
+ ) {
+ return function routeEnterGuard (to, from, next) {
+ return guard(to, from, function (cb) {
+ if (typeof cb === 'function') {
+ cbs.push(function () {
+ // #750
+ // if a router-view is wrapped with an out-in transition,
+ // the instance may not have been registered at this time.
+ // we will need to poll for registration until current route
+ // is no longer valid.
+ poll(cb, match.instances, key, isValid);
+ });
+ }
+ next(cb);
+ })
+ }
+ }
+
+ function poll (
+ cb, // somehow flow cannot infer this is a function
+ instances,
+ key,
+ isValid
+ ) {
+ if (
+ instances[key] &&
+ !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
+ ) {
+ cb(instances[key]);
+ } else if (isValid()) {
+ setTimeout(function () {
+ poll(cb, instances, key, isValid);
+ }, 16);
+ }
+ }
+
+ /* */
+
+ var HTML5History = /*@__PURE__*/(function (History) {
+ function HTML5History (router, base) {
+ var this$1 = this;
+
+ History.call(this, router, base);
+
+ var expectScroll = router.options.scrollBehavior;
+ var supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ var initLocation = getLocation(this.base);
+ window.addEventListener('popstate', function (e) {
+ var current = this$1.current;
+
+ // Avoiding first `popstate` event dispatched in some browsers but first
+ // history route not updated since async guard at the same time.
+ var location = getLocation(this$1.base);
+ if (this$1.current === START && location === initLocation) {
+ return
+ }
+
+ this$1.transitionTo(location, function (route) {
+ if (supportsScroll) {
+ handleScroll(router, route, current, true);
+ }
+ });
+ });
+ }
+
+ if ( History ) HTML5History.__proto__ = History;
+ HTML5History.prototype = Object.create( History && History.prototype );
+ HTML5History.prototype.constructor = HTML5History;
+
+ HTML5History.prototype.go = function go (n) {
+ window.history.go(n);
+ };
+
+ HTML5History.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(location, function (route) {
+ pushState(cleanPath(this$1.base + route.fullPath));
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ };
+
+ HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(location, function (route) {
+ replaceState(cleanPath(this$1.base + route.fullPath));
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ }, onAbort);
+ };
+
+ HTML5History.prototype.ensureURL = function ensureURL (push) {
+ if (getLocation(this.base) !== this.current.fullPath) {
+ var current = cleanPath(this.base + this.current.fullPath);
+ push ? pushState(current) : replaceState(current);
+ }
+ };
+
+ HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
+ return getLocation(this.base)
+ };
+
+ return HTML5History;
+ }(History));
+
+ function getLocation (base) {
+ var path = decodeURI(window.location.pathname);
+ if (base && path.indexOf(base) === 0) {
+ path = path.slice(base.length);
+ }
+ return (path || '/') + window.location.search + window.location.hash
+ }
+
+ /* */
+
+ var HashHistory = /*@__PURE__*/(function (History) {
+ function HashHistory (router, base, fallback) {
+ History.call(this, router, base);
+ // check history fallback deeplinking
+ if (fallback && checkFallback(this.base)) {
+ return
+ }
+ ensureSlash();
+ }
+
+ if ( History ) HashHistory.__proto__ = History;
+ HashHistory.prototype = Object.create( History && History.prototype );
+ HashHistory.prototype.constructor = HashHistory;
+
+ // this is delayed until the app mounts
+ // to avoid the hashchange listener being fired too early
+ HashHistory.prototype.setupListeners = function setupListeners () {
+ var this$1 = this;
+
+ var router = this.router;
+ var expectScroll = router.options.scrollBehavior;
+ var supportsScroll = supportsPushState && expectScroll;
+
+ if (supportsScroll) {
+ setupScroll();
+ }
+
+ window.addEventListener(
+ supportsPushState ? 'popstate' : 'hashchange',
+ function () {
+ var current = this$1.current;
+ if (!ensureSlash()) {
+ return
+ }
+ this$1.transitionTo(getHash(), function (route) {
+ if (supportsScroll) {
+ handleScroll(this$1.router, route, current, true);
+ }
+ if (!supportsPushState) {
+ replaceHash(route.fullPath);
+ }
+ });
+ }
+ );
+ };
+
+ HashHistory.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(
+ location,
+ function (route) {
+ pushHash(route.fullPath);
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ var ref = this;
+ var fromRoute = ref.current;
+ this.transitionTo(
+ location,
+ function (route) {
+ replaceHash(route.fullPath);
+ handleScroll(this$1.router, route, fromRoute, false);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ HashHistory.prototype.go = function go (n) {
+ window.history.go(n);
+ };
+
+ HashHistory.prototype.ensureURL = function ensureURL (push) {
+ var current = this.current.fullPath;
+ if (getHash() !== current) {
+ push ? pushHash(current) : replaceHash(current);
+ }
+ };
+
+ HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+ return getHash()
+ };
+
+ return HashHistory;
+ }(History));
+
+ function checkFallback (base) {
+ var location = getLocation(base);
+ if (!/^\/#/.test(location)) {
+ window.location.replace(cleanPath(base + '/#' + location));
+ return true
+ }
+ }
+
+ function ensureSlash () {
+ var path = getHash();
+ if (path.charAt(0) === '/') {
+ return true
+ }
+ replaceHash('/' + path);
+ return false
+ }
+
+ function getHash () {
+ // We can't use window.location.hash here because it's not
+ // consistent across browsers - Firefox will pre-decode it!
+ var href = window.location.href;
+ var index = href.indexOf('#');
+ // empty path
+ if (index < 0) { return '' }
+
+ href = href.slice(index + 1);
+ // decode the hash but not the search or hash
+ // as search(query) is already decoded
+ // https://github.com/vuejs/vue-router/issues/2708
+ var searchIndex = href.indexOf('?');
+ if (searchIndex < 0) {
+ var hashIndex = href.indexOf('#');
+ if (hashIndex > -1) {
+ href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex);
+ } else { href = decodeURI(href); }
+ } else {
+ if (searchIndex > -1) {
+ href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex);
+ }
+ }
+
+ return href
+ }
+
+ function getUrl (path) {
+ var href = window.location.href;
+ var i = href.indexOf('#');
+ var base = i >= 0 ? href.slice(0, i) : href;
+ return (base + "#" + path)
+ }
+
+ function pushHash (path) {
+ if (supportsPushState) {
+ pushState(getUrl(path));
+ } else {
+ window.location.hash = path;
+ }
+ }
+
+ function replaceHash (path) {
+ if (supportsPushState) {
+ replaceState(getUrl(path));
+ } else {
+ window.location.replace(getUrl(path));
+ }
+ }
+
+ /* */
+
+ var AbstractHistory = /*@__PURE__*/(function (History) {
+ function AbstractHistory (router, base) {
+ History.call(this, router, base);
+ this.stack = [];
+ this.index = -1;
+ }
+
+ if ( History ) AbstractHistory.__proto__ = History;
+ AbstractHistory.prototype = Object.create( History && History.prototype );
+ AbstractHistory.prototype.constructor = AbstractHistory;
+
+ AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ this.transitionTo(
+ location,
+ function (route) {
+ this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
+ this$1.index++;
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ this.transitionTo(
+ location,
+ function (route) {
+ this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
+ onComplete && onComplete(route);
+ },
+ onAbort
+ );
+ };
+
+ AbstractHistory.prototype.go = function go (n) {
+ var this$1 = this;
+
+ var targetIndex = this.index + n;
+ if (targetIndex < 0 || targetIndex >= this.stack.length) {
+ return
+ }
+ var route = this.stack[targetIndex];
+ this.confirmTransition(
+ route,
+ function () {
+ this$1.index = targetIndex;
+ this$1.updateRoute(route);
+ },
+ function (err) {
+ if (isExtendedError(NavigationDuplicated, err)) {
+ this$1.index = targetIndex;
+ }
+ }
+ );
+ };
+
+ AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
+ var current = this.stack[this.stack.length - 1];
+ return current ? current.fullPath : '/'
+ };
+
+ AbstractHistory.prototype.ensureURL = function ensureURL () {
+ // noop
+ };
+
+ return AbstractHistory;
+ }(History));
+
+ /* */
+
+
+
+ var VueRouter = function VueRouter (options) {
+ if ( options === void 0 ) options = {};
+
+ this.app = null;
+ this.apps = [];
+ this.options = options;
+ this.beforeHooks = [];
+ this.resolveHooks = [];
+ this.afterHooks = [];
+ this.matcher = createMatcher(options.routes || [], this);
+
+ var mode = options.mode || 'hash';
+ this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
+ if (this.fallback) {
+ mode = 'hash';
+ }
+ if (!inBrowser) {
+ mode = 'abstract';
+ }
+ this.mode = mode;
+
+ switch (mode) {
+ case 'history':
+ this.history = new HTML5History(this, options.base);
+ break
+ case 'hash':
+ this.history = new HashHistory(this, options.base, this.fallback);
+ break
+ case 'abstract':
+ this.history = new AbstractHistory(this, options.base);
+ break
+ default:
+ {
+ assert(false, ("invalid mode: " + mode));
+ }
+ }
+ };
+
+ var prototypeAccessors = { currentRoute: { configurable: true } };
+
+ VueRouter.prototype.match = function match (
+ raw,
+ current,
+ redirectedFrom
+ ) {
+ return this.matcher.match(raw, current, redirectedFrom)
+ };
+
+ prototypeAccessors.currentRoute.get = function () {
+ return this.history && this.history.current
+ };
+
+ VueRouter.prototype.init = function init (app /* Vue component instance */) {
+ var this$1 = this;
+
+ assert(
+ install.installed,
+ "not installed. Make sure to call `Vue.use(VueRouter)` " +
+ "before creating root instance."
+ );
+
+ this.apps.push(app);
+
+ // set up app destroyed handler
+ // https://github.com/vuejs/vue-router/issues/2639
+ app.$once('hook:destroyed', function () {
+ // clean out app from this.apps array once destroyed
+ var index = this$1.apps.indexOf(app);
+ if (index > -1) { this$1.apps.splice(index, 1); }
+ // ensure we still have a main app or null if no apps
+ // we do not release the router so it can be reused
+ if (this$1.app === app) { this$1.app = this$1.apps[0] || null; }
+ });
+
+ // main app previously initialized
+ // return as we don't need to set up new history listener
+ if (this.app) {
+ return
+ }
+
+ this.app = app;
+
+ var history = this.history;
+
+ if (history instanceof HTML5History) {
+ history.transitionTo(history.getCurrentLocation());
+ } else if (history instanceof HashHistory) {
+ var setupHashListener = function () {
+ history.setupListeners();
+ };
+ history.transitionTo(
+ history.getCurrentLocation(),
+ setupHashListener,
+ setupHashListener
+ );
+ }
+
+ history.listen(function (route) {
+ this$1.apps.forEach(function (app) {
+ app._route = route;
+ });
+ });
+ };
+
+ VueRouter.prototype.beforeEach = function beforeEach (fn) {
+ return registerHook(this.beforeHooks, fn)
+ };
+
+ VueRouter.prototype.beforeResolve = function beforeResolve (fn) {
+ return registerHook(this.resolveHooks, fn)
+ };
+
+ VueRouter.prototype.afterEach = function afterEach (fn) {
+ return registerHook(this.afterHooks, fn)
+ };
+
+ VueRouter.prototype.onReady = function onReady (cb, errorCb) {
+ this.history.onReady(cb, errorCb);
+ };
+
+ VueRouter.prototype.onError = function onError (errorCb) {
+ this.history.onError(errorCb);
+ };
+
+ VueRouter.prototype.push = function push (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise(function (resolve, reject) {
+ this$1.history.push(location, resolve, reject);
+ })
+ } else {
+ this.history.push(location, onComplete, onAbort);
+ }
+ };
+
+ VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
+ var this$1 = this;
+
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise(function (resolve, reject) {
+ this$1.history.replace(location, resolve, reject);
+ })
+ } else {
+ this.history.replace(location, onComplete, onAbort);
+ }
+ };
+
+ VueRouter.prototype.go = function go (n) {
+ this.history.go(n);
+ };
+
+ VueRouter.prototype.back = function back () {
+ this.go(-1);
+ };
+
+ VueRouter.prototype.forward = function forward () {
+ this.go(1);
+ };
+
+ VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
+ var route = to
+ ? to.matched
+ ? to
+ : this.resolve(to).route
+ : this.currentRoute;
+ if (!route) {
+ return []
+ }
+ return [].concat.apply([], route.matched.map(function (m) {
+ return Object.keys(m.components).map(function (key) {
+ return m.components[key]
+ })
+ }))
+ };
+
+ VueRouter.prototype.resolve = function resolve (
+ to,
+ current,
+ append
+ ) {
+ current = current || this.history.current;
+ var location = normalizeLocation(
+ to,
+ current,
+ append,
+ this
+ );
+ var route = this.match(location, current);
+ var fullPath = route.redirectedFrom || route.fullPath;
+ var base = this.history.base;
+ var href = createHref(base, fullPath, this.mode);
+ return {
+ location: location,
+ route: route,
+ href: href,
+ // for backwards compat
+ normalizedTo: location,
+ resolved: route
+ }
+ };
+
+ VueRouter.prototype.addRoutes = function addRoutes (routes) {
+ this.matcher.addRoutes(routes);
+ if (this.history.current !== START) {
+ this.history.transitionTo(this.history.getCurrentLocation());
+ }
+ };
+
+ Object.defineProperties( VueRouter.prototype, prototypeAccessors );
+
+ function registerHook (list, fn) {
+ list.push(fn);
+ return function () {
+ var i = list.indexOf(fn);
+ if (i > -1) { list.splice(i, 1); }
+ }
+ }
+
+ function createHref (base, fullPath, mode) {
+ var path = mode === 'hash' ? '#' + fullPath : fullPath;
+ return base ? cleanPath(base + '/' + path) : path
+ }
+
+ VueRouter.install = install;
+ VueRouter.version = '3.1.3';
+
+ if (inBrowser && window.Vue) {
+ window.Vue.use(VueRouter);
+ }
+
+ return VueRouter;
+
+}));
diff --git a/node_modules/vue-router/dist/vue-router.min.js b/node_modules/vue-router/dist/vue-router.min.js
new file mode 100644
index 0000000..b94a085
--- /dev/null
+++ b/node_modules/vue-router/dist/vue-router.min.js
@@ -0,0 +1,6 @@
+/*!
+ * vue-router v3.1.3
+ * (c) 2019 Evan You
+ * @license MIT
+ */
+var t,e;t=this,e=function(){"use strict";function t(t){return Object.prototype.toString.call(t).indexOf("Error")>-1}function e(t,e){return e instanceof t||e&&(e.name===t.name||e._name===t._name)}function r(t,e){for(var r in e)t[r]=e[r];return t}var n={name:"RouterView",functional:!0,props:{name:{type:String,default:"default"}},render:function(t,e){var n=e.props,o=e.children,i=e.parent,a=e.data;a.routerView=!0;for(var c=i.$createElement,u=n.name,s=i.$route,p=i._routerViewCache||(i._routerViewCache={}),f=0,h=!1;i&&i._routerRoot!==i;){var l=i.$vnode&&i.$vnode.data;l&&(l.routerView&&f++,l.keepAlive&&i._inactive&&(h=!0)),i=i.$parent}if(a.routerViewDepth=f,h)return c(p[u],a,o);var d=s.matched[f];if(!d)return p[u]=null,c();var v=p[u]=d.components[u];a.registerRouteInstance=function(t,e){var r=d.instances[u];(e&&r!==t||!e&&r===t)&&(d.instances[u]=e)},(a.hook||(a.hook={})).prepatch=function(t,e){d.instances[u]=e.componentInstance},a.hook.init=function(t){t.data.keepAlive&&t.componentInstance&&t.componentInstance!==d.instances[u]&&(d.instances[u]=t.componentInstance)};var y=a.props=function(t,e){switch(typeof e){case"undefined":return;case"object":return e;case"function":return e(t);case"boolean":return e?t.params:void 0}}(s,d.props&&d.props[u]);if(y){y=a.props=r({},y);var m=a.attrs=a.attrs||{};for(var g in y)v.props&&g in v.props||(m[g]=y[g],delete y[g])}return c(v,a,o)}},o=/[!'()*]/g,i=function(t){return"%"+t.charCodeAt(0).toString(16)},a=/%2C/g,c=function(t){return encodeURIComponent(t).replace(o,i).replace(a,",")},u=decodeURIComponent;function s(t){var e={};return(t=t.trim().replace(/^(\?|#|&)/,""))?(t.split("&").forEach(function(t){var r=t.replace(/\+/g," ").split("="),n=u(r.shift()),o=r.length>0?u(r.join("=")):null;void 0===e[n]?e[n]=o:Array.isArray(e[n])?e[n].push(o):e[n]=[e[n],o]}),e):e}function p(t){var e=t?Object.keys(t).map(function(e){var r=t[e];if(void 0===r)return"";if(null===r)return c(e);if(Array.isArray(r)){var n=[];return r.forEach(function(t){void 0!==t&&(null===t?n.push(c(e)):n.push(c(e)+"="+c(t)))}),n.join("&")}return c(e)+"="+c(r)}).filter(function(t){return t.length>0}).join("&"):null;return e?"?"+e:""}var f=/\/?$/;function h(t,e,r,n){var o=n&&n.options.stringifyQuery,i=e.query||{};try{i=l(i)}catch(t){}var a={name:e.name||t&&t.name,meta:t&&t.meta||{},path:e.path||"/",hash:e.hash||"",query:i,params:e.params||{},fullPath:y(e,o),matched:t?v(t):[]};return r&&(a.redirectedFrom=y(r,o)),Object.freeze(a)}function l(t){if(Array.isArray(t))return t.map(l);if(t&&"object"==typeof t){var e={};for(var r in t)e[r]=l(t[r]);return e}return t}var d=h(null,{path:"/"});function v(t){for(var e=[];t;)e.unshift(t),t=t.parent;return e}function y(t,e){var r=t.path,n=t.query;void 0===n&&(n={});var o=t.hash;return void 0===o&&(o=""),(r||"/")+(e||p)(n)+o}function m(t,e){return e===d?t===e:!!e&&(t.path&&e.path?t.path.replace(f,"")===e.path.replace(f,"")&&t.hash===e.hash&&g(t.query,e.query):!(!t.name||!e.name)&&t.name===e.name&&t.hash===e.hash&&g(t.query,e.query)&&g(t.params,e.params))}function g(t,e){if(void 0===t&&(t={}),void 0===e&&(e={}),!t||!e)return t===e;var r=Object.keys(t),n=Object.keys(e);return r.length===n.length&&r.every(function(r){var n=t[r],o=e[r];return"object"==typeof n&&"object"==typeof o?g(n,o):String(n)===String(o)})}function b(t,e,r){var n=t.charAt(0);if("/"===n)return t;if("?"===n||"#"===n)return e+t;var o=e.split("/");r&&o[o.length-1]||o.pop();for(var i=t.replace(/^\//,"").split("/"),a=0;a=0&&(e=t.slice(n),t=t.slice(0,n));var o=t.indexOf("?");return o>=0&&(r=t.slice(o+1),t=t.slice(0,o)),{path:t,query:r,hash:e}}(i.path||""),p=e&&e.path||"/",f=u.path?b(u.path,p,n||i.append):p,h=function(t,e,r){void 0===e&&(e={});var n,o=r||s;try{n=o(t||"")}catch(t){n={}}for(var i in e)n[i]=e[i];return n}(u.query,i.query,o&&o.options.parseQuery),l=i.hash||u.hash;return l&&"#"!==l.charAt(0)&&(l="#"+l),{_normalized:!0,path:f,query:h,hash:l}}var B,H=[String,Object],z=[String,Array],D=function(){},F={name:"RouterLink",props:{to:{type:H,required:!0},tag:{type:String,default:"a"},exact:Boolean,append:Boolean,replace:Boolean,activeClass:String,exactActiveClass:String,event:{type:z,default:"click"}},render:function(t){var e=this,n=this.$router,o=this.$route,i=n.resolve(this.to,o,this.append),a=i.location,c=i.route,u=i.href,s={},p=n.options.linkActiveClass,l=n.options.linkExactActiveClass,d=null==p?"router-link-active":p,v=null==l?"router-link-exact-active":l,y=null==this.activeClass?d:this.activeClass,g=null==this.exactActiveClass?v:this.exactActiveClass,b=c.redirectedFrom?h(null,V(c.redirectedFrom),null,n):c;s[g]=m(o,b),s[y]=this.exact?s[g]:function(t,e){return 0===t.path.replace(f,"/").indexOf(e.path.replace(f,"/"))&&(!e.hash||t.hash===e.hash)&&function(t,e){for(var r in e)if(!(r in t))return!1;return!0}(t.query,e.query)}(o,b);var w=function(t){N(t)&&(e.replace?n.replace(a,D):n.push(a,D))},x={click:N};Array.isArray(this.event)?this.event.forEach(function(t){x[t]=w}):x[this.event]=w;var k={class:s},R=!this.$scopedSlots.$hasNormal&&this.$scopedSlots.default&&this.$scopedSlots.default({href:u,route:c,navigate:w,isActive:s[y],isExactActive:s[g]});if(R){if(1===R.length)return R[0];if(R.length>1||!R.length)return 0===R.length?t():t("span",{},R)}if("a"===this.tag)k.on=x,k.attrs={href:u};else{var E=function t(e){if(e)for(var r,n=0;n-1&&(c.params[h]=r.params[h]);return c.path=M(p.path,c.params),u(p,c,a)}if(c.path){c.params={};for(var l=0;l=t.length?r():t[o]?e(t[o],function(){n(o+1)}):n(o+1)};n(0)}function yt(e){return function(r,n,o){var i=!1,a=0,c=null;mt(e,function(e,r,n,u){if("function"==typeof e&&void 0===e.cid){i=!0,a++;var s,p=wt(function(t){var r;((r=t).__esModule||bt&&"Module"===r[Symbol.toStringTag])&&(t=t.default),e.resolved="function"==typeof t?t:B.extend(t),n.components[u]=t,--a<=0&&o()}),f=wt(function(e){var r="Failed to resolve async component "+u+": "+e;c||(c=t(e)?e:new Error(r),o(c))});try{s=e(p,f)}catch(t){f(t)}if(s)if("function"==typeof s.then)s.then(p,f);else{var h=s.component;h&&"function"==typeof h.then&&h.then(p,f)}}}),i||o()}}function mt(t,e){return gt(t.map(function(t){return Object.keys(t.components).map(function(r){return e(t.components[r],t.instances[r],t,r)})}))}function gt(t){return Array.prototype.concat.apply([],t)}var bt="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag;function wt(t){var e=!1;return function(){for(var r=[],n=arguments.length;n--;)r[n]=arguments[n];if(!e)return e=!0,t.apply(this,r)}}var xt=function(t){function e(e){t.call(this),this.name=this._name="NavigationDuplicated",this.message='Navigating to current location ("'+e.fullPath+'") is not allowed',Object.defineProperty(this,"stack",{value:(new t).stack,writable:!0,configurable:!0})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(Error);xt._name="NavigationDuplicated";var kt=function(t,e){this.router=t,this.base=function(t){if(!t)if(K){var e=document.querySelector("base");t=(t=e&&e.getAttribute("href")||"/").replace(/^https?:\/\/[^\/]+/,"")}else t="/";return"/"!==t.charAt(0)&&(t="/"+t),t.replace(/\/$/,"")}(e),this.current=d,this.pending=null,this.ready=!1,this.readyCbs=[],this.readyErrorCbs=[],this.errorCbs=[]};function Rt(t,e,r,n){var o=mt(t,function(t,n,o,i){var a=function(t,e){return"function"!=typeof t&&(t=B.extend(t)),t.options[e]}(t,e);if(a)return Array.isArray(a)?a.map(function(t){return r(t,n,o,i)}):r(a,n,o,i)});return gt(n?o.reverse():o)}function Et(t,e){if(e)return function(){return t.apply(e,arguments)}}kt.prototype.listen=function(t){this.cb=t},kt.prototype.onReady=function(t,e){this.ready?t():(this.readyCbs.push(t),e&&this.readyErrorCbs.push(e))},kt.prototype.onError=function(t){this.errorCbs.push(t)},kt.prototype.transitionTo=function(t,e,r){var n=this,o=this.router.match(t,this.current);this.confirmTransition(o,function(){n.updateRoute(o),e&&e(o),n.ensureURL(),n.ready||(n.ready=!0,n.readyCbs.forEach(function(t){t(o)}))},function(t){r&&r(t),t&&!n.ready&&(n.ready=!0,n.readyErrorCbs.forEach(function(e){e(t)}))})},kt.prototype.confirmTransition=function(r,n,o){var i=this,a=this.current,c=function(r){!e(xt,r)&&t(r)&&(i.errorCbs.length?i.errorCbs.forEach(function(t){t(r)}):console.error(r)),o&&o(r)};if(m(r,a)&&r.matched.length===a.matched.length)return this.ensureURL(),c(new xt(r));var u=function(t,e){var r,n=Math.max(t.length,e.length);for(r=0;r-1?decodeURI(t.slice(0,n))+t.slice(n):decodeURI(t)}else r>-1&&(t=decodeURI(t.slice(0,r))+t.slice(r));return t}function St(t){var e=window.location.href,r=e.indexOf("#");return(r>=0?e.slice(0,r):e)+"#"+t}function $t(t){ht?lt(St(t)):window.location.hash=t}function Tt(t){ht?dt(St(t)):window.location.replace(St(t))}var Pt=function(t){function r(e,r){t.call(this,e,r),this.stack=[],this.index=-1}return t&&(r.__proto__=t),r.prototype=Object.create(t&&t.prototype),r.prototype.constructor=r,r.prototype.push=function(t,e,r){var n=this;this.transitionTo(t,function(t){n.stack=n.stack.slice(0,n.index+1).concat(t),n.index++,e&&e(t)},r)},r.prototype.replace=function(t,e,r){var n=this;this.transitionTo(t,function(t){n.stack=n.stack.slice(0,n.index).concat(t),e&&e(t)},r)},r.prototype.go=function(t){var r=this,n=this.index+t;if(!(n<0||n>=this.stack.length)){var o=this.stack[n];this.confirmTransition(o,function(){r.index=n,r.updateRoute(o)},function(t){e(xt,t)&&(r.index=n)})}},r.prototype.getCurrentLocation=function(){var t=this.stack[this.stack.length-1];return t?t.fullPath:"/"},r.prototype.ensureURL=function(){},r}(kt),Lt=function(t){void 0===t&&(t={}),this.app=null,this.apps=[],this.options=t,this.beforeHooks=[],this.resolveHooks=[],this.afterHooks=[],this.matcher=X(t.routes||[],this);var e=t.mode||"hash";switch(this.fallback="history"===e&&!ht&&!1!==t.fallback,this.fallback&&(e="hash"),K||(e="abstract"),this.mode=e,e){case"history":this.history=new Ot(this,t.base);break;case"hash":this.history=new At(this,t.base,this.fallback);break;case"abstract":this.history=new Pt(this,t.base)}},qt={currentRoute:{configurable:!0}};function Ut(t,e){return t.push(e),function(){var r=t.indexOf(e);r>-1&&t.splice(r,1)}}return Lt.prototype.match=function(t,e,r){return this.matcher.match(t,e,r)},qt.currentRoute.get=function(){return this.history&&this.history.current},Lt.prototype.init=function(t){var e=this;if(this.apps.push(t),t.$once("hook:destroyed",function(){var r=e.apps.indexOf(t);r>-1&&e.apps.splice(r,1),e.app===t&&(e.app=e.apps[0]||null)}),!this.app){this.app=t;var r=this.history;if(r instanceof Ot)r.transitionTo(r.getCurrentLocation());else if(r instanceof At){var n=function(){r.setupListeners()};r.transitionTo(r.getCurrentLocation(),n,n)}r.listen(function(t){e.apps.forEach(function(e){e._route=t})})}},Lt.prototype.beforeEach=function(t){return Ut(this.beforeHooks,t)},Lt.prototype.beforeResolve=function(t){return Ut(this.resolveHooks,t)},Lt.prototype.afterEach=function(t){return Ut(this.afterHooks,t)},Lt.prototype.onReady=function(t,e){this.history.onReady(t,e)},Lt.prototype.onError=function(t){this.history.onError(t)},Lt.prototype.push=function(t,e,r){var n=this;if(!e&&!r&&"undefined"!=typeof Promise)return new Promise(function(e,r){n.history.push(t,e,r)});this.history.push(t,e,r)},Lt.prototype.replace=function(t,e,r){var n=this;if(!e&&!r&&"undefined"!=typeof Promise)return new Promise(function(e,r){n.history.replace(t,e,r)});this.history.replace(t,e,r)},Lt.prototype.go=function(t){this.history.go(t)},Lt.prototype.back=function(){this.go(-1)},Lt.prototype.forward=function(){this.go(1)},Lt.prototype.getMatchedComponents=function(t){var e=t?t.matched?t:this.resolve(t).route:this.currentRoute;return e?[].concat.apply([],e.matched.map(function(t){return Object.keys(t.components).map(function(e){return t.components[e]})})):[]},Lt.prototype.resolve=function(t,e,r){var n=V(t,e=e||this.history.current,r,this),o=this.match(n,e),i=o.redirectedFrom||o.fullPath;return{location:n,route:o,href:function(t,e,r){var n="hash"===r?"#"+e:e;return t?w(t+"/"+n):n}(this.history.base,i,this.mode),normalizedTo:n,resolved:o}},Lt.prototype.addRoutes=function(t){this.matcher.addRoutes(t),this.history.current!==d&&this.history.transitionTo(this.history.getCurrentLocation())},Object.defineProperties(Lt.prototype,qt),Lt.install=function t(e){if(!t.installed||B!==e){t.installed=!0,B=e;var r=function(t){return void 0!==t},o=function(t,e){var n=t.$options._parentVnode;r(n)&&r(n=n.data)&&r(n=n.registerRouteInstance)&&n(t,e)};e.mixin({beforeCreate:function(){r(this.$options.router)?(this._routerRoot=this,this._router=this.$options.router,this._router.init(this),e.util.defineReactive(this,"_route",this._router.history.current)):this._routerRoot=this.$parent&&this.$parent._routerRoot||this,o(this,this)},destroyed:function(){o(this)}}),Object.defineProperty(e.prototype,"$router",{get:function(){return this._routerRoot._router}}),Object.defineProperty(e.prototype,"$route",{get:function(){return this._routerRoot._route}}),e.component("RouterView",n),e.component("RouterLink",F);var i=e.config.optionMergeStrategies;i.beforeRouteEnter=i.beforeRouteLeave=i.beforeRouteUpdate=i.created}},Lt.version="3.1.3",K&&window.Vue&&window.Vue.use(Lt),Lt},"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).VueRouter=e();
\ No newline at end of file
diff --git a/node_modules/vue-router/package.json b/node_modules/vue-router/package.json
new file mode 100644
index 0000000..236da09
--- /dev/null
+++ b/node_modules/vue-router/package.json
@@ -0,0 +1,107 @@
+{
+ "name": "vue-router",
+ "version": "3.1.3",
+ "description": "Official router for Vue.js 2",
+ "author": "Evan You",
+ "license": "MIT",
+ "main": "dist/vue-router.common.js",
+ "module": "dist/vue-router.esm.js",
+ "unpkg": "dist/vue-router.js",
+ "jsdelivr": "dist/vue-router.js",
+ "sideEffects": false,
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/vuejs/vue-router.git"
+ },
+ "typings": "types/index.d.ts",
+ "files": [
+ "src/*.js",
+ "dist/*.js",
+ "types/*.d.ts"
+ ],
+ "keywords": [
+ "vue",
+ "router",
+ "routing"
+ ],
+ "scripts": {
+ "dev": "node examples/server.js",
+ "dev:dist": "rollup -wm -c build/rollup.dev.config.js",
+ "build": "node build/build.js",
+ "lint": "eslint src examples test",
+ "test": "npm run lint && npm run flow && npm run test:unit && npm run test:e2e && npm run test:types",
+ "flow": "flow check",
+ "test:unit": "jasmine JASMINE_CONFIG_PATH=test/unit/jasmine.json",
+ "test:e2e": "node test/e2e/runner.js",
+ "test:e2e:ci": "node test/e2e/runner.js --local -e ie,android44 -c test/e2e/nightwatch.browserstack.js test/e2e/specs/active-links.js",
+ "test:e2e:ff": "node test/e2e/runner.js -e firefox -c test/e2e/nightwatch.config.js",
+ "test:e2e:ie9": "node test/e2e/runner.js --local -e ie9 -c test/e2e/nightwatch.browserstack.js --skiptags history,ie9-fail",
+ "test:types": "tsc -p types/test",
+ "docs": "vuepress dev docs",
+ "docs:build": "vuepress build docs",
+ "changelog": "conventional-changelog -p angular -r 2 -i CHANGELOG.md -s",
+ "release": "bash scripts/release.sh"
+ },
+ "gitHooks": {
+ "pre-commit": "lint-staged",
+ "commit-msg": "node scripts/verifyCommitMsg.js"
+ },
+ "lint-staged": {
+ "*.{js,vue}": [
+ "eslint --fix",
+ "git add"
+ ]
+ },
+ "devDependencies": {
+ "axios": "^0.19.0",
+ "babel-core": "^6.24.1",
+ "babel-eslint": "^10.0.2",
+ "babel-loader": "^7.1.3",
+ "babel-plugin-syntax-dynamic-import": "^6.18.0",
+ "babel-preset-env": "^1.6.1",
+ "babel-preset-flow-vue": "^1.0.0",
+ "browserstack-local": "^1.4.0",
+ "buble": "^0.19.8",
+ "chromedriver": "^76.0.0",
+ "conventional-changelog-cli": "^2.0.11",
+ "cross-spawn": "^6.0.5",
+ "css-loader": "^2.1.1",
+ "dotenv": "^8.0.0",
+ "es6-promise": "^4.2.8",
+ "eslint": "^4.19.1",
+ "eslint-plugin-flowtype": "^2.46.1",
+ "eslint-plugin-jasmine": "^2.10.1",
+ "eslint-plugin-vue-libs": "^2.1.0",
+ "express": "^4.17.1",
+ "express-urlrewrite": "^1.2.0",
+ "flow-bin": "^0.66.0",
+ "geckodriver": "^1.16.2",
+ "jasmine": "2.8.0",
+ "lint-staged": "^8.2.0",
+ "nightwatch": "^1.1.13",
+ "nightwatch-helpers": "^1.0.0",
+ "path-to-regexp": "^1.7.0",
+ "rollup": "^1.20.1",
+ "rollup-plugin-buble": "^0.19.8",
+ "rollup-plugin-commonjs": "^10.0.2",
+ "rollup-plugin-flow-no-whitespace": "^1.0.0",
+ "rollup-plugin-node-resolve": "^5.2.0",
+ "rollup-plugin-replace": "^2.0.0",
+ "rollup-watch": "^4.0.0",
+ "selenium-server": "^3.141.59",
+ "terser": "^4.2.0",
+ "typescript": "^3.5.2",
+ "vue": "^2.5.16",
+ "vue-loader": "^15.2.1",
+ "vue-template-compiler": "^2.5.16",
+ "vuepress": "^0.14.11",
+ "vuepress-theme-vue": "^1.1.0",
+ "webpack": "^4.35.2",
+ "webpack-dev-middleware": "^3.7.0",
+ "yorkie": "^2.0.0"
+ },
+ "bugs": {
+ "url": "https://github.com/vuejs/vue-router/issues"
+ },
+ "homepage": "https://github.com/vuejs/vue-router#readme"
+}
diff --git a/node_modules/vue-router/src/create-matcher.js b/node_modules/vue-router/src/create-matcher.js
new file mode 100644
index 0000000..ab62be4
--- /dev/null
+++ b/node_modules/vue-router/src/create-matcher.js
@@ -0,0 +1,200 @@
+/* @flow */
+
+import type VueRouter from './index'
+import { resolvePath } from './util/path'
+import { assert, warn } from './util/warn'
+import { createRoute } from './util/route'
+import { fillParams } from './util/params'
+import { createRouteMap } from './create-route-map'
+import { normalizeLocation } from './util/location'
+
+export type Matcher = {
+ match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
+ addRoutes: (routes: Array) => void;
+};
+
+export function createMatcher (
+ routes: Array,
+ router: VueRouter
+): Matcher {
+ const { pathList, pathMap, nameMap } = createRouteMap(routes)
+
+ function addRoutes (routes) {
+ createRouteMap(routes, pathList, pathMap, nameMap)
+ }
+
+ function match (
+ raw: RawLocation,
+ currentRoute?: Route,
+ redirectedFrom?: Location
+ ): Route {
+ const location = normalizeLocation(raw, currentRoute, false, router)
+ const { name } = location
+
+ if (name) {
+ const record = nameMap[name]
+ if (process.env.NODE_ENV !== 'production') {
+ warn(record, `Route with name '${name}' does not exist`)
+ }
+ if (!record) return _createRoute(null, location)
+ const paramNames = record.regex.keys
+ .filter(key => !key.optional)
+ .map(key => key.name)
+
+ if (typeof location.params !== 'object') {
+ location.params = {}
+ }
+
+ if (currentRoute && typeof currentRoute.params === 'object') {
+ for (const key in currentRoute.params) {
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
+ location.params[key] = currentRoute.params[key]
+ }
+ }
+ }
+
+ location.path = fillParams(record.path, location.params, `named route "${name}"`)
+ return _createRoute(record, location, redirectedFrom)
+ } else if (location.path) {
+ location.params = {}
+ for (let i = 0; i < pathList.length; i++) {
+ const path = pathList[i]
+ const record = pathMap[path]
+ if (matchRoute(record.regex, location.path, location.params)) {
+ return _createRoute(record, location, redirectedFrom)
+ }
+ }
+ }
+ // no match
+ return _createRoute(null, location)
+ }
+
+ function redirect (
+ record: RouteRecord,
+ location: Location
+ ): Route {
+ const originalRedirect = record.redirect
+ let redirect = typeof originalRedirect === 'function'
+ ? originalRedirect(createRoute(record, location, null, router))
+ : originalRedirect
+
+ if (typeof redirect === 'string') {
+ redirect = { path: redirect }
+ }
+
+ if (!redirect || typeof redirect !== 'object') {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(
+ false, `invalid redirect option: ${JSON.stringify(redirect)}`
+ )
+ }
+ return _createRoute(null, location)
+ }
+
+ const re: Object = redirect
+ const { name, path } = re
+ let { query, hash, params } = location
+ query = re.hasOwnProperty('query') ? re.query : query
+ hash = re.hasOwnProperty('hash') ? re.hash : hash
+ params = re.hasOwnProperty('params') ? re.params : params
+
+ if (name) {
+ // resolved named direct
+ const targetRecord = nameMap[name]
+ if (process.env.NODE_ENV !== 'production') {
+ assert(targetRecord, `redirect failed: named route "${name}" not found.`)
+ }
+ return match({
+ _normalized: true,
+ name,
+ query,
+ hash,
+ params
+ }, undefined, location)
+ } else if (path) {
+ // 1. resolve relative redirect
+ const rawPath = resolveRecordPath(path, record)
+ // 2. resolve params
+ const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`)
+ // 3. rematch with existing query and hash
+ return match({
+ _normalized: true,
+ path: resolvedPath,
+ query,
+ hash
+ }, undefined, location)
+ } else {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`)
+ }
+ return _createRoute(null, location)
+ }
+ }
+
+ function alias (
+ record: RouteRecord,
+ location: Location,
+ matchAs: string
+ ): Route {
+ const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`)
+ const aliasedMatch = match({
+ _normalized: true,
+ path: aliasedPath
+ })
+ if (aliasedMatch) {
+ const matched = aliasedMatch.matched
+ const aliasedRecord = matched[matched.length - 1]
+ location.params = aliasedMatch.params
+ return _createRoute(aliasedRecord, location)
+ }
+ return _createRoute(null, location)
+ }
+
+ function _createRoute (
+ record: ?RouteRecord,
+ location: Location,
+ redirectedFrom?: Location
+ ): Route {
+ if (record && record.redirect) {
+ return redirect(record, redirectedFrom || location)
+ }
+ if (record && record.matchAs) {
+ return alias(record, location, record.matchAs)
+ }
+ return createRoute(record, location, redirectedFrom, router)
+ }
+
+ return {
+ match,
+ addRoutes
+ }
+}
+
+function matchRoute (
+ regex: RouteRegExp,
+ path: string,
+ params: Object
+): boolean {
+ const m = path.match(regex)
+
+ if (!m) {
+ return false
+ } else if (!params) {
+ return true
+ }
+
+ for (let i = 1, len = m.length; i < len; ++i) {
+ const key = regex.keys[i - 1]
+ const val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i]
+ if (key) {
+ // Fix #1994: using * with props: true generates a param named 0
+ params[key.name || 'pathMatch'] = val
+ }
+ }
+
+ return true
+}
+
+function resolveRecordPath (path: string, record: RouteRecord): string {
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
+}
diff --git a/node_modules/vue-router/src/create-route-map.js b/node_modules/vue-router/src/create-route-map.js
new file mode 100644
index 0000000..aa51864
--- /dev/null
+++ b/node_modules/vue-router/src/create-route-map.js
@@ -0,0 +1,205 @@
+/* @flow */
+
+import Regexp from 'path-to-regexp'
+import { cleanPath } from './util/path'
+import { assert, warn } from './util/warn'
+
+export function createRouteMap (
+ routes: Array,
+ oldPathList?: Array,
+ oldPathMap?: Dictionary,
+ oldNameMap?: Dictionary
+): {
+ pathList: Array,
+ pathMap: Dictionary,
+ nameMap: Dictionary
+} {
+ // the path list is used to control path matching priority
+ const pathList: Array = oldPathList || []
+ // $flow-disable-line
+ const pathMap: Dictionary = oldPathMap || Object.create(null)
+ // $flow-disable-line
+ const nameMap: Dictionary = oldNameMap || Object.create(null)
+
+ routes.forEach(route => {
+ addRouteRecord(pathList, pathMap, nameMap, route)
+ })
+
+ // ensure wildcard routes are always at the end
+ for (let i = 0, l = pathList.length; i < l; i++) {
+ if (pathList[i] === '*') {
+ pathList.push(pathList.splice(i, 1)[0])
+ l--
+ i--
+ }
+ }
+
+ if (process.env.NODE_ENV === 'development') {
+ // warn if routes do not include leading slashes
+ const found = pathList
+ // check for missing leading slash
+ .filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/')
+
+ if (found.length > 0) {
+ const pathNames = found.map(path => `- ${path}`).join('\n')
+ warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \n${pathNames}`)
+ }
+ }
+
+ return {
+ pathList,
+ pathMap,
+ nameMap
+ }
+}
+
+function addRouteRecord (
+ pathList: Array,
+ pathMap: Dictionary,
+ nameMap: Dictionary,
+ route: RouteConfig,
+ parent?: RouteRecord,
+ matchAs?: string
+) {
+ const { path, name } = route
+ if (process.env.NODE_ENV !== 'production') {
+ assert(path != null, `"path" is required in a route configuration.`)
+ assert(
+ typeof route.component !== 'string',
+ `route config "component" for path: ${String(
+ path || name
+ )} cannot be a ` + `string id. Use an actual component instead.`
+ )
+ }
+
+ const pathToRegexpOptions: PathToRegexpOptions =
+ route.pathToRegexpOptions || {}
+ const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)
+
+ if (typeof route.caseSensitive === 'boolean') {
+ pathToRegexpOptions.sensitive = route.caseSensitive
+ }
+
+ const record: RouteRecord = {
+ path: normalizedPath,
+ regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
+ components: route.components || { default: route.component },
+ instances: {},
+ name,
+ parent,
+ matchAs,
+ redirect: route.redirect,
+ beforeEnter: route.beforeEnter,
+ meta: route.meta || {},
+ props:
+ route.props == null
+ ? {}
+ : route.components
+ ? route.props
+ : { default: route.props }
+ }
+
+ if (route.children) {
+ // Warn if route is named, does not redirect and has a default child route.
+ // If users navigate to this route by name, the default child will
+ // not be rendered (GH Issue #629)
+ if (process.env.NODE_ENV !== 'production') {
+ if (
+ route.name &&
+ !route.redirect &&
+ route.children.some(child => /^\/?$/.test(child.path))
+ ) {
+ warn(
+ false,
+ `Named Route '${route.name}' has a default child route. ` +
+ `When navigating to this named route (:to="{name: '${
+ route.name
+ }'"), ` +
+ `the default child route will not be rendered. Remove the name from ` +
+ `this route and use the name of the default child route for named ` +
+ `links instead.`
+ )
+ }
+ }
+ route.children.forEach(child => {
+ const childMatchAs = matchAs
+ ? cleanPath(`${matchAs}/${child.path}`)
+ : undefined
+ addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)
+ })
+ }
+
+ if (!pathMap[record.path]) {
+ pathList.push(record.path)
+ pathMap[record.path] = record
+ }
+
+ if (route.alias !== undefined) {
+ const aliases = Array.isArray(route.alias) ? route.alias : [route.alias]
+ for (let i = 0; i < aliases.length; ++i) {
+ const alias = aliases[i]
+ if (process.env.NODE_ENV !== 'production' && alias === path) {
+ warn(
+ false,
+ `Found an alias with the same value as the path: "${path}". You have to remove that alias. It will be ignored in development.`
+ )
+ // skip in dev to make it work
+ continue
+ }
+
+ const aliasRoute = {
+ path: alias,
+ children: route.children
+ }
+ addRouteRecord(
+ pathList,
+ pathMap,
+ nameMap,
+ aliasRoute,
+ parent,
+ record.path || '/' // matchAs
+ )
+ }
+ }
+
+ if (name) {
+ if (!nameMap[name]) {
+ nameMap[name] = record
+ } else if (process.env.NODE_ENV !== 'production' && !matchAs) {
+ warn(
+ false,
+ `Duplicate named routes definition: ` +
+ `{ name: "${name}", path: "${record.path}" }`
+ )
+ }
+ }
+}
+
+function compileRouteRegex (
+ path: string,
+ pathToRegexpOptions: PathToRegexpOptions
+): RouteRegExp {
+ const regex = Regexp(path, [], pathToRegexpOptions)
+ if (process.env.NODE_ENV !== 'production') {
+ const keys: any = Object.create(null)
+ regex.keys.forEach(key => {
+ warn(
+ !keys[key.name],
+ `Duplicate param keys in route with path: "${path}"`
+ )
+ keys[key.name] = true
+ })
+ }
+ return regex
+}
+
+function normalizePath (
+ path: string,
+ parent?: RouteRecord,
+ strict?: boolean
+): string {
+ if (!strict) path = path.replace(/\/$/, '')
+ if (path[0] === '/') return path
+ if (parent == null) return path
+ return cleanPath(`${parent.path}/${path}`)
+}
diff --git a/node_modules/vue-router/src/index.js b/node_modules/vue-router/src/index.js
new file mode 100644
index 0000000..e95ace6
--- /dev/null
+++ b/node_modules/vue-router/src/index.js
@@ -0,0 +1,262 @@
+/* @flow */
+
+import { install } from './install'
+import { START } from './util/route'
+import { assert } from './util/warn'
+import { inBrowser } from './util/dom'
+import { cleanPath } from './util/path'
+import { createMatcher } from './create-matcher'
+import { normalizeLocation } from './util/location'
+import { supportsPushState } from './util/push-state'
+
+import { HashHistory } from './history/hash'
+import { HTML5History } from './history/html5'
+import { AbstractHistory } from './history/abstract'
+
+import type { Matcher } from './create-matcher'
+
+export default class VueRouter {
+ static install: () => void;
+ static version: string;
+
+ app: any;
+ apps: Array;
+ ready: boolean;
+ readyCbs: Array;
+ options: RouterOptions;
+ mode: string;
+ history: HashHistory | HTML5History | AbstractHistory;
+ matcher: Matcher;
+ fallback: boolean;
+ beforeHooks: Array;
+ resolveHooks: Array;
+ afterHooks: Array;
+
+ constructor (options: RouterOptions = {}) {
+ this.app = null
+ this.apps = []
+ this.options = options
+ this.beforeHooks = []
+ this.resolveHooks = []
+ this.afterHooks = []
+ this.matcher = createMatcher(options.routes || [], this)
+
+ let mode = options.mode || 'hash'
+ this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
+ if (this.fallback) {
+ mode = 'hash'
+ }
+ if (!inBrowser) {
+ mode = 'abstract'
+ }
+ this.mode = mode
+
+ switch (mode) {
+ case 'history':
+ this.history = new HTML5History(this, options.base)
+ break
+ case 'hash':
+ this.history = new HashHistory(this, options.base, this.fallback)
+ break
+ case 'abstract':
+ this.history = new AbstractHistory(this, options.base)
+ break
+ default:
+ if (process.env.NODE_ENV !== 'production') {
+ assert(false, `invalid mode: ${mode}`)
+ }
+ }
+ }
+
+ match (
+ raw: RawLocation,
+ current?: Route,
+ redirectedFrom?: Location
+ ): Route {
+ return this.matcher.match(raw, current, redirectedFrom)
+ }
+
+ get currentRoute (): ?Route {
+ return this.history && this.history.current
+ }
+
+ init (app: any /* Vue component instance */) {
+ process.env.NODE_ENV !== 'production' && assert(
+ install.installed,
+ `not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
+ `before creating root instance.`
+ )
+
+ this.apps.push(app)
+
+ // set up app destroyed handler
+ // https://github.com/vuejs/vue-router/issues/2639
+ app.$once('hook:destroyed', () => {
+ // clean out app from this.apps array once destroyed
+ const index = this.apps.indexOf(app)
+ if (index > -1) this.apps.splice(index, 1)
+ // ensure we still have a main app or null if no apps
+ // we do not release the router so it can be reused
+ if (this.app === app) this.app = this.apps[0] || null
+ })
+
+ // main app previously initialized
+ // return as we don't need to set up new history listener
+ if (this.app) {
+ return
+ }
+
+ this.app = app
+
+ const history = this.history
+
+ if (history instanceof HTML5History) {
+ history.transitionTo(history.getCurrentLocation())
+ } else if (history instanceof HashHistory) {
+ const setupHashListener = () => {
+ history.setupListeners()
+ }
+ history.transitionTo(
+ history.getCurrentLocation(),
+ setupHashListener,
+ setupHashListener
+ )
+ }
+
+ history.listen(route => {
+ this.apps.forEach((app) => {
+ app._route = route
+ })
+ })
+ }
+
+ beforeEach (fn: Function): Function {
+ return registerHook(this.beforeHooks, fn)
+ }
+
+ beforeResolve (fn: Function): Function {
+ return registerHook(this.resolveHooks, fn)
+ }
+
+ afterEach (fn: Function): Function {
+ return registerHook(this.afterHooks, fn)
+ }
+
+ onReady (cb: Function, errorCb?: Function) {
+ this.history.onReady(cb, errorCb)
+ }
+
+ onError (errorCb: Function) {
+ this.history.onError(errorCb)
+ }
+
+ push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise((resolve, reject) => {
+ this.history.push(location, resolve, reject)
+ })
+ } else {
+ this.history.push(location, onComplete, onAbort)
+ }
+ }
+
+ replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
+ // $flow-disable-line
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
+ return new Promise((resolve, reject) => {
+ this.history.replace(location, resolve, reject)
+ })
+ } else {
+ this.history.replace(location, onComplete, onAbort)
+ }
+ }
+
+ go (n: number) {
+ this.history.go(n)
+ }
+
+ back () {
+ this.go(-1)
+ }
+
+ forward () {
+ this.go(1)
+ }
+
+ getMatchedComponents (to?: RawLocation | Route): Array {
+ const route: any = to
+ ? to.matched
+ ? to
+ : this.resolve(to).route
+ : this.currentRoute
+ if (!route) {
+ return []
+ }
+ return [].concat.apply([], route.matched.map(m => {
+ return Object.keys(m.components).map(key => {
+ return m.components[key]
+ })
+ }))
+ }
+
+ resolve (
+ to: RawLocation,
+ current?: Route,
+ append?: boolean
+ ): {
+ location: Location,
+ route: Route,
+ href: string,
+ // for backwards compat
+ normalizedTo: Location,
+ resolved: Route
+ } {
+ current = current || this.history.current
+ const location = normalizeLocation(
+ to,
+ current,
+ append,
+ this
+ )
+ const route = this.match(location, current)
+ const fullPath = route.redirectedFrom || route.fullPath
+ const base = this.history.base
+ const href = createHref(base, fullPath, this.mode)
+ return {
+ location,
+ route,
+ href,
+ // for backwards compat
+ normalizedTo: location,
+ resolved: route
+ }
+ }
+
+ addRoutes (routes: Array) {
+ this.matcher.addRoutes(routes)
+ if (this.history.current !== START) {
+ this.history.transitionTo(this.history.getCurrentLocation())
+ }
+ }
+}
+
+function registerHook (list: Array, fn: Function): Function {
+ list.push(fn)
+ return () => {
+ const i = list.indexOf(fn)
+ if (i > -1) list.splice(i, 1)
+ }
+}
+
+function createHref (base: string, fullPath: string, mode) {
+ var path = mode === 'hash' ? '#' + fullPath : fullPath
+ return base ? cleanPath(base + '/' + path) : path
+}
+
+VueRouter.install = install
+VueRouter.version = '__VERSION__'
+
+if (inBrowser && window.Vue) {
+ window.Vue.use(VueRouter)
+}
diff --git a/node_modules/vue-router/src/install.js b/node_modules/vue-router/src/install.js
new file mode 100644
index 0000000..ee8506a
--- /dev/null
+++ b/node_modules/vue-router/src/install.js
@@ -0,0 +1,52 @@
+import View from './components/view'
+import Link from './components/link'
+
+export let _Vue
+
+export function install (Vue) {
+ if (install.installed && _Vue === Vue) return
+ install.installed = true
+
+ _Vue = Vue
+
+ const isDef = v => v !== undefined
+
+ const registerInstance = (vm, callVal) => {
+ let i = vm.$options._parentVnode
+ if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
+ i(vm, callVal)
+ }
+ }
+
+ Vue.mixin({
+ beforeCreate () {
+ if (isDef(this.$options.router)) {
+ this._routerRoot = this
+ this._router = this.$options.router
+ this._router.init(this)
+ Vue.util.defineReactive(this, '_route', this._router.history.current)
+ } else {
+ this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
+ }
+ registerInstance(this, this)
+ },
+ destroyed () {
+ registerInstance(this)
+ }
+ })
+
+ Object.defineProperty(Vue.prototype, '$router', {
+ get () { return this._routerRoot._router }
+ })
+
+ Object.defineProperty(Vue.prototype, '$route', {
+ get () { return this._routerRoot._route }
+ })
+
+ Vue.component('RouterView', View)
+ Vue.component('RouterLink', Link)
+
+ const strats = Vue.config.optionMergeStrategies
+ // use the same hook merging strategy for route hooks
+ strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
+}
diff --git a/node_modules/vue-router/types/index.d.ts b/node_modules/vue-router/types/index.d.ts
new file mode 100644
index 0000000..a66f5ba
--- /dev/null
+++ b/node_modules/vue-router/types/index.d.ts
@@ -0,0 +1,16 @@
+import './vue'
+import { VueRouter } from './router'
+
+export default VueRouter
+
+export {
+ RouterMode,
+ RawLocation,
+ RedirectOption,
+ RouterOptions,
+ RouteConfig,
+ RouteRecord,
+ Location,
+ Route,
+ NavigationGuard
+} from './router'
diff --git a/node_modules/vue-router/types/router.d.ts b/node_modules/vue-router/types/router.d.ts
new file mode 100644
index 0000000..137261e
--- /dev/null
+++ b/node_modules/vue-router/types/router.d.ts
@@ -0,0 +1,145 @@
+import Vue, { ComponentOptions, PluginFunction, AsyncComponent } from 'vue'
+
+type Component = ComponentOptions | typeof Vue | AsyncComponent
+type Dictionary < T > = { [key: string]: T }
+type ErrorHandler = (err: Error) => void
+
+export type RouterMode = 'hash' | 'history' | 'abstract'
+export type RawLocation = string | Location
+export type RedirectOption = RawLocation | ((to: Route) => RawLocation)
+export type NavigationGuard < V extends Vue = Vue > = (
+ to: Route,
+ from: Route,
+ next: (to?: RawLocation | false | ((vm: V) => any) | void) => void
+) => any
+
+export declare class VueRouter {
+ constructor(options?: RouterOptions)
+
+ app: Vue
+ mode: RouterMode
+ currentRoute: Route
+
+ beforeEach(guard: NavigationGuard): Function
+ beforeResolve(guard: NavigationGuard): Function
+ afterEach(hook: (to: Route, from: Route) => any): Function
+ push(location: RawLocation): Promise
+ replace(location: RawLocation): Promise
+ push(
+ location: RawLocation,
+ onComplete?: Function,
+ onAbort?: ErrorHandler
+ ): void
+ replace(
+ location: RawLocation,
+ onComplete?: Function,
+ onAbort?: ErrorHandler
+ ): void
+ go(n: number): void
+ back(): void
+ forward(): void
+ getMatchedComponents(to?: RawLocation | Route): Component[]
+ onReady(cb: Function, errorCb?: ErrorHandler): void
+ onError(cb: ErrorHandler): void
+ addRoutes(routes: RouteConfig[]): void
+ resolve(
+ to: RawLocation,
+ current?: Route,
+ append?: boolean
+ ): {
+ location: Location
+ route: Route
+ href: string
+ // backwards compat
+ normalizedTo: Location
+ resolved: Route
+ }
+
+ static install: PluginFunction
+}
+
+type Position = { x: number; y: number }
+type PositionResult = Position | { selector: string; offset?: Position } | void
+
+export interface RouterOptions {
+ routes?: RouteConfig[]
+ mode?: RouterMode
+ fallback?: boolean
+ base?: string
+ linkActiveClass?: string
+ linkExactActiveClass?: string
+ parseQuery?: (query: string) => Object
+ stringifyQuery?: (query: Object) => string
+ scrollBehavior?: (
+ to: Route,
+ from: Route,
+ savedPosition: Position | void
+ ) => PositionResult | Promise
+}
+
+type RoutePropsFunction = (route: Route) => Object
+
+export interface PathToRegexpOptions {
+ sensitive?: boolean
+ strict?: boolean
+ end?: boolean
+}
+
+export interface RouteConfig {
+ path: string
+ name?: string
+ component?: Component
+ components?: Dictionary
+ redirect?: RedirectOption
+ alias?: string | string[]
+ children?: RouteConfig[]
+ meta?: any
+ beforeEnter?: NavigationGuard
+ props?: boolean | Object | RoutePropsFunction
+ caseSensitive?: boolean
+ pathToRegexpOptions?: PathToRegexpOptions
+}
+
+export interface RouteRecord {
+ path: string
+ regex: RegExp
+ components: Dictionary
+ instances: Dictionary
+ name?: string
+ parent?: RouteRecord
+ redirect?: RedirectOption
+ matchAs?: string
+ meta: any
+ beforeEnter?: (
+ route: Route,
+ redirect: (location: RawLocation) => void,
+ next: () => void
+ ) => any
+ props:
+ | boolean
+ | Object
+ | RoutePropsFunction
+ | Dictionary
+}
+
+export interface Location {
+ name?: string
+ path?: string
+ hash?: string
+ query?: Dictionary
+ params?: Dictionary
+ append?: boolean
+ replace?: boolean
+}
+
+export interface Route {
+ path: string
+ name?: string
+ hash: string
+ query: Dictionary
+ params: Dictionary
+ fullPath: string
+ matched: RouteRecord[]
+ redirectedFrom?: string
+ meta?: any
+}
diff --git a/node_modules/vue-router/types/vue.d.ts b/node_modules/vue-router/types/vue.d.ts
new file mode 100644
index 0000000..307515c
--- /dev/null
+++ b/node_modules/vue-router/types/vue.d.ts
@@ -0,0 +1,22 @@
+/**
+ * Augment the typings of Vue.js
+ */
+
+import Vue from 'vue'
+import VueRouter, { Route, RawLocation, NavigationGuard } from './index'
+
+declare module 'vue/types/vue' {
+ interface Vue {
+ $router: VueRouter
+ $route: Route
+ }
+}
+
+declare module 'vue/types/options' {
+ interface ComponentOptions {
+ router?: VueRouter
+ beforeRouteEnter?: NavigationGuard
+ beforeRouteLeave?: NavigationGuard
+ beforeRouteUpdate?: NavigationGuard
+ }
+}
diff --git a/package.json b/package.json
index 3639dee..f191080 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,6 @@
{
"dependencies": {
- "axios": "^0.19.0"
+ "axios": "^0.19.0",
+ "vue-router": "^3.1.3"
}
}
diff --git a/yarn.lock b/yarn.lock
index 350b108..98b7102 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -33,3 +33,8 @@ ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+vue-router@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.3.tgz#e6b14fabc0c0ee9fda0e2cbbda74b350e28e412b"
+ integrity sha512-8iSa4mGNXBjyuSZFCCO4fiKfvzqk+mhL0lnKuGcQtO1eoj8nq3CmbEG8FwK5QqoqwDgsjsf1GDuisDX4cdb/aQ==