diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index befce81de3e..aa458f7d408 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -33,6 +33,12 @@ jobs: distribution: temurin cache: maven + - name: Build debug client + working-directory: ./client-next + run: | + npm install + npm run build + - name: Prepare coverage agent, build and test # these are split into two steps because otherwise maven keeps long-running HTTP connections # to Maven Central open which then hang during the package phase because the Azure (Github Actions) @@ -250,6 +256,14 @@ jobs: java-version: 21 distribution: temurin cache: maven + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Build debug client + working-directory: ./client-next + run: | + npm install + npm run build - name: Build container image with Jib, push to Dockerhub env: CONTAINER_REPO: docker.io/opentripplanner/opentripplanner diff --git a/.gitignore b/.gitignore index b98d0263a70..ec589dcbd0a 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ gen-py/ node_modules/ target/ /graphs +/src/client/debug-client-preview/ # for local dev only /src/test/resources/speedtest/travelSearch-results-*.csv diff --git a/client-next/.env b/client-next/.env new file mode 100644 index 00000000000..003970b4e1f --- /dev/null +++ b/client-next/.env @@ -0,0 +1 @@ +VITE_API_URL=/otp/routers/default/transmodel/index/graphql \ No newline at end of file diff --git a/client-next/.env.development b/client-next/.env.development new file mode 100644 index 00000000000..e11b45c4411 --- /dev/null +++ b/client-next/.env.development @@ -0,0 +1 @@ +VITE_API_URL=http://localhost:8080/otp/routers/default/transmodel/index/graphql \ No newline at end of file diff --git a/client-next/.eslintrc.cjs b/client-next/.eslintrc.cjs new file mode 100644 index 00000000000..516e639be09 --- /dev/null +++ b/client-next/.eslintrc.cjs @@ -0,0 +1,42 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'plugin:import/recommended', + 'plugin:jsx-a11y/recommended', + 'plugin:@typescript-eslint/recommended', + 'eslint-config-prettier', + ], + ignorePatterns: ['node_modules', 'dist', '.prettierrc.js', '.eslintrc.cjs', 'src/gql/**/*'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + settings: { + react: { + // Tells eslint-plugin-react to automatically detect the version of React to use. + version: 'detect', + }, + // Tells eslint how to resolve imports + 'import/resolver': { + node: { + paths: ['src'], + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + }, + }, + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + "react/jsx-uses-react": "off", + "react/react-in-jsx-scope": "off", + '@typescript-eslint/ban-ts-comment': "off", + + // TODO: this is a temporary fix for + // https://github.com/typescript-eslint/typescript-eslint/issues/154 + "import/named": "off" + }, +} diff --git a/client-next/.gitignore b/client-next/.gitignore new file mode 100644 index 00000000000..049d26604a9 --- /dev/null +++ b/client-next/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# generated code +src/gql/ + +# Vite cache folder +.vite/ \ No newline at end of file diff --git a/client-next/.prettierignore b/client-next/.prettierignore new file mode 100644 index 00000000000..c0aafcabe5f --- /dev/null +++ b/client-next/.prettierignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +src/gql/ diff --git a/client-next/.prettierrc.cjs b/client-next/.prettierrc.cjs new file mode 100644 index 00000000000..6111ad4264d --- /dev/null +++ b/client-next/.prettierrc.cjs @@ -0,0 +1,8 @@ +module.exports = { + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "printWidth": 120, + "bracketSpacing": true +} \ No newline at end of file diff --git a/client-next/README-vite.md b/client-next/README-vite.md new file mode 100644 index 00000000000..1ebe379f5f4 --- /dev/null +++ b/client-next/README-vite.md @@ -0,0 +1,27 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list diff --git a/client-next/README.md b/client-next/README.md new file mode 100644 index 00000000000..a6c8e76cfad --- /dev/null +++ b/client-next/README.md @@ -0,0 +1,65 @@ +# OTP debug client (next) + +This is the next version of the debug client, intended to replace `../src/client`. + +It is designed to work with the Transmodel GraphQL API. + +## Stack notes + +This is a true Single Page Application (SPA) written in TypeScript on the React framework. It uses `vite` to run +(locally) and for building static assets. It requires no server runtime, and can be served from a CDN and run entirely +in the browser. + +The design framework is Bootstrap with React support from `react-bootstrap`. + +The map framework is MapLibre, using `MapLibre GL JS` with React support from `react-map-gl`. + +GraphQL integration is provided by `graphql-request`, with type support added with `@graphql-codegen`. Types are +generated during build and are not checked into the repository. + +## Prerequisites + +Use latest LTS version of Node/npm (currently v18). Recommend using a version manager such as `nvm`. + +The dev and production builds require graphql schema to be present at +`../src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql`. + +## Getting started (development) + +Change directory to `client-next` (current) if you haven't already. + + npm install + +Then + + npm run dev + +The debug client will now be available at `http://localhost:5173/debug-client-preview`. It has +hot reloading enabled, so you don't have to restart it when you save files. + +If you change graphql code during development you can issue the following command: + + npm run codegen + +You don't have to restart the development server for the changes to take effect. + +## Build for production + +Change directory to `client-next` (current) if you haven't already. + + npm install + +Then + + npm run build + +## Which OTP instance do I use? + +In development mode, the debug client by default assumes you are running an OTP instance locally at +port 8080 (see `.env.development`). If you wish to point to a different OTP instance +(like a remote server), use the environment variable`VITE_API_URL`, either at the command line, +or add it to a new `.env.development.local` file (this file will be ignored by git). + +In production mode, the default is to access OTP via the same origin as the client (see `.env`). +This behavior can also be modified by changing the previously mentioned environment variable at +build-time. diff --git a/client-next/codegen.ts b/client-next/codegen.ts new file mode 100644 index 00000000000..b5b68a0650a --- /dev/null +++ b/client-next/codegen.ts @@ -0,0 +1,15 @@ +import type { CodegenConfig } from '@graphql-codegen/cli'; + +const config: CodegenConfig = { + overwrite: true, + schema: '../src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql', + documents: 'src/**/*.{ts,tsx}', + generates: { + 'src/gql/': { + preset: 'client', + plugins: [], + }, + }, +}; + +export default config; diff --git a/client-next/index.html b/client-next/index.html new file mode 100644 index 00000000000..77eb289e595 --- /dev/null +++ b/client-next/index.html @@ -0,0 +1,13 @@ + + + + + + + OTP Debug Client + + +
+ + + diff --git a/client-next/package-lock.json b/client-next/package-lock.json new file mode 100644 index 00000000000..85a29784489 --- /dev/null +++ b/client-next/package-lock.json @@ -0,0 +1,9842 @@ +{ + "name": "otp-debug-client-next", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "otp-debug-client-next", + "version": "0.0.0", + "dependencies": { + "@googlemaps/polyline-codec": "^1.0.28", + "bootstrap": "^5.3.1", + "graphql": "^16.8.0", + "graphql-request": "^6.1.0", + "maplibre-gl": "^3.3.0", + "react": "^18.2.0", + "react-bootstrap": "^2.8.0", + "react-dom": "^18.2.0", + "react-map-gl": "^7.1.5" + }, + "devDependencies": { + "@graphql-codegen/cli": "5.0.0", + "@graphql-codegen/client-preset": "4.1.0", + "@graphql-codegen/introspection": "4.0.0", + "@parcel/watcher": "^2.3.0", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.0.3", + "eslint": "^8.45.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "prettier": "^3.0.3", + "typescript": "^5.2.2", + "vite": "^4.4.5" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ardatan/relay-compiler": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz", + "integrity": "sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.14.0", + "@babel/generator": "^7.14.0", + "@babel/parser": "^7.14.0", + "@babel/runtime": "^7.0.0", + "@babel/traverse": "^7.14.0", + "@babel/types": "^7.0.0", + "babel-preset-fbjs": "^3.4.0", + "chalk": "^4.0.0", + "fb-watchman": "^2.0.0", + "fbjs": "^3.0.0", + "glob": "^7.1.1", + "immutable": "~3.7.6", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "relay-runtime": "12.0.0", + "signedsource": "^1.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "relay-compiler": "bin/relay-compiler" + }, + "peerDependencies": { + "graphql": "*" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@ardatan/relay-compiler/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/@ardatan/relay-compiler/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ardatan/relay-compiler/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@ardatan/sync-fetch": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz", + "integrity": "sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.11.tgz", + "integrity": "sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-compilation-targets": "^7.22.10", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.11", + "@babel/parser": "^7.22.11", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", + "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.10", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", + "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz", + "integrity": "sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", + "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", + "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.13.tgz", + "integrity": "sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", + "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz", + "integrity": "sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz", + "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz", + "integrity": "sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", + "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-flow": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", + "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.11.tgz", + "integrity": "sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", + "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.5.tgz", + "integrity": "sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.22.5.tgz", + "integrity": "sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.22.5.tgz", + "integrity": "sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.11.tgz", + "integrity": "sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", + "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.11", + "@babel/types": "^7.22.11", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", + "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@googlemaps/polyline-codec": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/@googlemaps/polyline-codec/-/polyline-codec-1.0.28.tgz", + "integrity": "sha512-m7rh8sbxlrHvebXEweBHX8r1uPtToPRYxWDD6p6k2YG8hyhBe0Wi6xRUVFpxpEseMNgF+OBotFQC5senj8K7TQ==" + }, + "node_modules/@graphql-codegen/add": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-5.0.0.tgz", + "integrity": "sha512-ynWDOsK2yxtFHwcJTB9shoSkUd7YXd6ZE57f0nk7W5cu/nAgxZZpEsnTPEpZB/Mjf14YRGe2uJHQ7AfElHjqUQ==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/add/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/cli": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.0.tgz", + "integrity": "sha512-A7J7+be/a6e+/ul2KI5sfJlpoqeqwX8EzktaKCeduyVKgOLA6W5t+NUGf6QumBDXU8PEOqXk3o3F+RAwCWOiqA==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.18.13", + "@babel/template": "^7.18.10", + "@babel/types": "^7.18.13", + "@graphql-codegen/core": "^4.0.0", + "@graphql-codegen/plugin-helpers": "^5.0.1", + "@graphql-tools/apollo-engine-loader": "^8.0.0", + "@graphql-tools/code-file-loader": "^8.0.0", + "@graphql-tools/git-loader": "^8.0.0", + "@graphql-tools/github-loader": "^8.0.0", + "@graphql-tools/graphql-file-loader": "^8.0.0", + "@graphql-tools/json-file-loader": "^8.0.0", + "@graphql-tools/load": "^8.0.0", + "@graphql-tools/prisma-loader": "^8.0.0", + "@graphql-tools/url-loader": "^8.0.0", + "@graphql-tools/utils": "^10.0.0", + "@whatwg-node/fetch": "^0.8.0", + "chalk": "^4.1.0", + "cosmiconfig": "^8.1.3", + "debounce": "^1.2.0", + "detect-indent": "^6.0.0", + "graphql-config": "^5.0.2", + "inquirer": "^8.0.0", + "is-glob": "^4.0.1", + "jiti": "^1.17.1", + "json-to-pretty-yaml": "^1.2.2", + "listr2": "^4.0.5", + "log-symbols": "^4.0.0", + "micromatch": "^4.0.5", + "shell-quote": "^1.7.3", + "string-env-interpolation": "^1.0.1", + "ts-log": "^2.2.3", + "tslib": "^2.4.0", + "yaml": "^2.3.1", + "yargs": "^17.0.0" + }, + "bin": { + "gql-gen": "cjs/bin.js", + "graphql-code-generator": "cjs/bin.js", + "graphql-codegen": "cjs/bin.js", + "graphql-codegen-esm": "esm/bin.js" + }, + "peerDependencies": { + "@parcel/watcher": "^2.1.0", + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "@parcel/watcher": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@graphql-codegen/cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@graphql-codegen/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@graphql-codegen/cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@graphql-codegen/cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-codegen/cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-codegen/client-preset": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.1.0.tgz", + "integrity": "sha512-/3Ymb/fjxIF1+HGmaI1YwSZbWsrZAWMSQjh3dU425eBjctjsVQ6gzGRr+l/gE5F1mtmCf+vlbTAT03heAc/QIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7", + "@graphql-codegen/add": "^5.0.0", + "@graphql-codegen/gql-tag-operations": "4.0.1", + "@graphql-codegen/plugin-helpers": "^5.0.1", + "@graphql-codegen/typed-document-node": "^5.0.1", + "@graphql-codegen/typescript": "^4.0.1", + "@graphql-codegen/typescript-operations": "^4.0.1", + "@graphql-codegen/visitor-plugin-common": "^4.0.1", + "@graphql-tools/documents": "^1.0.0", + "@graphql-tools/utils": "^10.0.0", + "@graphql-typed-document-node/core": "3.2.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/client-preset/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/core": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-4.0.0.tgz", + "integrity": "sha512-JAGRn49lEtSsZVxeIlFVIRxts2lWObR+OQo7V2LHDJ7ohYYw3ilv7nJ8pf8P4GTg/w6ptcYdSdVVdkI8kUHB/Q==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-tools/schema": "^10.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/core/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/gql-tag-operations": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.1.tgz", + "integrity": "sha512-qF6wIbBzW8BNT+wiVsBxrYOs2oYcsxQ7mRvCpfEI3HnNZMAST/uX76W8MqFEJvj4mw7NIDv7xYJAcAZIWM5LWw==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-codegen/visitor-plugin-common": "4.0.1", + "@graphql-tools/utils": "^10.0.0", + "auto-bind": "~4.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/gql-tag-operations/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/introspection": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-4.0.0.tgz", + "integrity": "sha512-t9g3AkK99dfHblMWtG4ynUM9+A7JrWq5110zSpNV2wlSnv0+bRKagDW8gozwgXfR5i1IIG8QDjJZ6VgXQVqCZw==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-codegen/visitor-plugin-common": "^4.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/introspection/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/plugin-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.0.1.tgz", + "integrity": "sha512-6L5sb9D8wptZhnhLLBcheSPU7Tg//DGWgc5tQBWX46KYTOTQHGqDpv50FxAJJOyFVJrveN9otWk9UT9/yfY4ww==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "change-case-all": "1.0.15", + "common-tags": "1.8.2", + "import-from": "4.0.0", + "lodash": "~4.17.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/schema-ast": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-4.0.0.tgz", + "integrity": "sha512-WIzkJFa9Gz28FITAPILbt+7A8+yzOyd1NxgwFh7ie+EmO9a5zQK6UQ3U/BviirguXCYnn+AR4dXsoDrSrtRA1g==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/schema-ast/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/typed-document-node": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.1.tgz", + "integrity": "sha512-VFkhCuJnkgtbbgzoCAwTdJe2G1H6sd3LfCrDqWUrQe53y2ukfSb5Ov1PhAIkCBStKCMQBUY9YgGz9GKR40qQ8g==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-codegen/visitor-plugin-common": "4.0.1", + "auto-bind": "~4.0.0", + "change-case-all": "1.0.15", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/typescript": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.0.1.tgz", + "integrity": "sha512-3YziQ21dCVdnHb+Us1uDb3pA6eG5Chjv0uTK+bt9dXeMlwYBU8MbtzvQTo4qvzWVC1AxSOKj0rgfNu1xCXqJyA==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-codegen/schema-ast": "^4.0.0", + "@graphql-codegen/visitor-plugin-common": "4.0.1", + "auto-bind": "~4.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typescript-operations": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.0.1.tgz", + "integrity": "sha512-GpUWWdBVUec/Zqo23aFLBMrXYxN2irypHqDcKjN78JclDPdreasAEPcIpMfqf4MClvpmvDLy4ql+djVAwmkjbw==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-codegen/typescript": "^4.0.1", + "@graphql-codegen/visitor-plugin-common": "4.0.1", + "auto-bind": "~4.0.0", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typescript-operations/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/typescript/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-codegen/visitor-plugin-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-4.0.1.tgz", + "integrity": "sha512-Bi/1z0nHg4QMsAqAJhds+ForyLtk7A3HQOlkrZNm3xEkY7lcBzPtiOTLBtvziwopBsXUxqeSwVjOOFPLS5Yw1Q==", + "dev": true, + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.0", + "@graphql-tools/optimize": "^2.0.0", + "@graphql-tools/relay-operation-optimizer": "^7.0.0", + "@graphql-tools/utils": "^10.0.0", + "auto-bind": "~4.0.0", + "change-case-all": "1.0.15", + "dependency-graph": "^0.11.0", + "graphql-tag": "^2.11.0", + "parse-filepath": "^1.0.2", + "tslib": "~2.5.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/tslib": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", + "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==", + "dev": true + }, + "node_modules/@graphql-tools/apollo-engine-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.0.tgz", + "integrity": "sha512-axQTbN5+Yxs1rJ6cWQBOfw3AEeC+fvIuZSfJLPLLvFJLj4pUm9fhxey/g6oQZAAQJqKPfw+tLDUQvnfvRK8Kmg==", + "dev": true, + "dependencies": { + "@ardatan/sync-fetch": "^0.0.1", + "@graphql-tools/utils": "^10.0.0", + "@whatwg-node/fetch": "^0.9.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.1.1.tgz", + "integrity": "sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/fetch": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.9.tgz", + "integrity": "sha512-OTVoDm039CNyAWSRc2WBimMl/N9J4Fk2le21Xzcf+3OiWPNNSIbMnpWKBUyraPh2d9SAEgoBdQxTfVNihXgiUw==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.4.8", + "urlpattern-polyfill": "^9.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.4.14.tgz", + "integrity": "sha512-ii/eZz2PcjLGj9D6WfsmfzlTzZV1Kz6MxYpq2Vc5P21J8vkKfENWC9B2ISsFCKovxElLukIwPg8HTrHFsLNflg==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.1.0", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/urlpattern-polyfill": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz", + "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==", + "dev": true + }, + "node_modules/@graphql-tools/batch-execute": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.2.tgz", + "integrity": "sha512-Y2uwdZI6ZnatopD/SYfZ1eGuQFI7OU2KGZ2/B/7G9ISmgMl5K+ZZWz/PfIEXeiHirIDhyk54s4uka5rj2xwKqQ==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.5", + "dataloader": "^2.2.2", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/code-file-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.0.2.tgz", + "integrity": "sha512-AKNpkElUL2cWocYpC4DzNEpo6qJw8Lp+L3bKQ/mIfmbsQxgLz5uve6zHBMhDaFPdlwfIox41N3iUSvi77t9e8A==", + "dev": true, + "dependencies": { + "@graphql-tools/graphql-tag-pluck": "8.0.2", + "@graphql-tools/utils": "^10.0.0", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/delegate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.0.2.tgz", + "integrity": "sha512-ZU7VnR2xFgHrGnsuw6+nRJkcvSucn7w5ooxb/lTKlVfrNJfTwJevNcNKMnbtPUSajG3+CaFym/nU6v44GXCmNw==", + "dev": true, + "dependencies": { + "@graphql-tools/batch-execute": "^9.0.1", + "@graphql-tools/executor": "^1.0.0", + "@graphql-tools/schema": "^10.0.0", + "@graphql-tools/utils": "^10.0.5", + "dataloader": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/documents": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/documents/-/documents-1.0.0.tgz", + "integrity": "sha512-rHGjX1vg/nZ2DKqRGfDPNC55CWZBMldEVcH+91BThRa6JeT80NqXknffLLEZLRUxyikCfkwMsk6xR3UNMqG0Rg==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.2.0.tgz", + "integrity": "sha512-SKlIcMA71Dha5JnEWlw4XxcaJ+YupuXg0QCZgl2TOLFz4SkGCwU/geAsJvUJFwK2RbVLpQv/UMq67lOaBuwDtg==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "@graphql-typed-document-node/core": "3.2.0", + "@repeaterjs/repeater": "^3.0.4", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-graphql-ws": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.1.0.tgz", + "integrity": "sha512-yM67SzwE8rYRpm4z4AuGtABlOp9mXXVy6sxXnTJRoYIdZrmDbKVfIY+CpZUJCqS0FX3xf2+GoHlsj7Qswaxgcg==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.2", + "@types/ws": "^8.0.0", + "graphql-ws": "^5.14.0", + "isomorphic-ws": "^5.0.0", + "tslib": "^2.4.0", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-http": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.0.2.tgz", + "integrity": "sha512-JKTB4E3kdQM2/1NEcyrVPyQ8057ZVthCV5dFJiKktqY9IdmF00M8gupFcW3jlbM/Udn78ickeUBsUzA3EouqpA==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.2", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/fetch": "^0.9.0", + "extract-files": "^11.0.0", + "meros": "^1.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.1.1.tgz", + "integrity": "sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/fetch": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.9.tgz", + "integrity": "sha512-OTVoDm039CNyAWSRc2WBimMl/N9J4Fk2le21Xzcf+3OiWPNNSIbMnpWKBUyraPh2d9SAEgoBdQxTfVNihXgiUw==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.4.8", + "urlpattern-polyfill": "^9.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/node-fetch": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.4.14.tgz", + "integrity": "sha512-ii/eZz2PcjLGj9D6WfsmfzlTzZV1Kz6MxYpq2Vc5P21J8vkKfENWC9B2ISsFCKovxElLukIwPg8HTrHFsLNflg==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.1.0", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/urlpattern-polyfill": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz", + "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==", + "dev": true + }, + "node_modules/@graphql-tools/executor-legacy-ws": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.1.tgz", + "integrity": "sha512-PQrTJ+ncHMEQspBARc2lhwiQFfRAX/z/CsOdZTFjIljOHgRWGAA1DAx7pEN0j6PflbLCfZ3NensNq2jCBwF46w==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "@types/ws": "^8.0.0", + "isomorphic-ws": "5.0.0", + "tslib": "^2.4.0", + "ws": "8.13.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/git-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.2.tgz", + "integrity": "sha512-AuCB0nlPvsHh8u42zRZdlD/ZMaWP9A44yAkQUVCZir1E/LG63fsZ9svTWJ+CbusW3Hd0ZP9qpxEhlHxnd4Tlsg==", + "dev": true, + "dependencies": { + "@graphql-tools/graphql-tag-pluck": "8.0.2", + "@graphql-tools/utils": "^10.0.0", + "is-glob": "4.0.3", + "micromatch": "^4.0.4", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/github-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.0.tgz", + "integrity": "sha512-VuroArWKcG4yaOWzV0r19ElVIV6iH6UKDQn1MXemND0xu5TzrFme0kf3U9o0YwNo0kUYEk9CyFM0BYg4he17FA==", + "dev": true, + "dependencies": { + "@ardatan/sync-fetch": "^0.0.1", + "@graphql-tools/executor-http": "^1.0.0", + "@graphql-tools/graphql-tag-pluck": "^8.0.0", + "@graphql-tools/utils": "^10.0.0", + "@whatwg-node/fetch": "^0.9.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.1.1.tgz", + "integrity": "sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/fetch": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.9.tgz", + "integrity": "sha512-OTVoDm039CNyAWSRc2WBimMl/N9J4Fk2le21Xzcf+3OiWPNNSIbMnpWKBUyraPh2d9SAEgoBdQxTfVNihXgiUw==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.4.8", + "urlpattern-polyfill": "^9.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.4.14.tgz", + "integrity": "sha512-ii/eZz2PcjLGj9D6WfsmfzlTzZV1Kz6MxYpq2Vc5P21J8vkKfENWC9B2ISsFCKovxElLukIwPg8HTrHFsLNflg==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.1.0", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/urlpattern-polyfill": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz", + "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==", + "dev": true + }, + "node_modules/@graphql-tools/graphql-file-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.0.tgz", + "integrity": "sha512-wRXj9Z1IFL3+zJG1HWEY0S4TXal7+s1vVhbZva96MSp0kbb/3JBF7j0cnJ44Eq0ClccMgGCDFqPFXty4JlpaPg==", + "dev": true, + "dependencies": { + "@graphql-tools/import": "7.0.0", + "@graphql-tools/utils": "^10.0.0", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/graphql-tag-pluck": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.0.2.tgz", + "integrity": "sha512-U6fE4yEHxuk/nqmPixHpw1WhqdS6aYuaV60m1bEmUmGJNbpAhaMBy01JncpvpF15yZR5LZ0UjkHg+A3Lhoc8YQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.22.9", + "@babel/parser": "^7.16.8", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8", + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/import": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.0.0.tgz", + "integrity": "sha512-NVZiTO8o1GZs6OXzNfjB+5CtQtqsZZpQOq+Uu0w57kdUkT4RlQKlwhT8T81arEsbV55KpzkpFsOZP7J1wdmhBw==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "resolve-from": "5.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/import/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-tools/json-file-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.0.tgz", + "integrity": "sha512-ki6EF/mobBWJjAAC84xNrFMhNfnUFD6Y0rQMGXekrUgY0NdeYXHU0ZUgHzC9O5+55FslqUmAUHABePDHTyZsLg==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/load": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.0.tgz", + "integrity": "sha512-Cy874bQJH0FP2Az7ELPM49iDzOljQmK1PPH6IuxsWzLSTxwTqd8dXA09dcVZrI7/LsN26heTY2R8q2aiiv0GxQ==", + "dev": true, + "dependencies": { + "@graphql-tools/schema": "^10.0.0", + "@graphql-tools/utils": "^10.0.0", + "p-limit": "3.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/merge": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.0.tgz", + "integrity": "sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/optimize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-2.0.0.tgz", + "integrity": "sha512-nhdT+CRGDZ+bk68ic+Jw1OZ99YCDIKYA5AlVAnBHJvMawSx9YQqQAIj4refNc1/LRieGiuWvhbG3jvPVYho0Dg==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.1.tgz", + "integrity": "sha512-bl6e5sAYe35Z6fEbgKXNrqRhXlCJYeWKBkarohgYA338/SD9eEhXtg3Cedj7fut3WyRLoQFpHzfiwxKs7XrgXg==", + "dev": true, + "dependencies": { + "@graphql-tools/url-loader": "^8.0.0", + "@graphql-tools/utils": "^10.0.0", + "@types/js-yaml": "^4.0.0", + "@types/json-stable-stringify": "^1.0.32", + "@whatwg-node/fetch": "^0.9.0", + "chalk": "^4.1.0", + "debug": "^4.3.1", + "dotenv": "^16.0.0", + "graphql-request": "^6.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "jose": "^4.11.4", + "js-yaml": "^4.0.0", + "json-stable-stringify": "^1.0.1", + "lodash": "^4.17.20", + "scuid": "^1.1.0", + "tslib": "^2.4.0", + "yaml-ast-parser": "^0.0.43" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.1.1.tgz", + "integrity": "sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/fetch": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.9.tgz", + "integrity": "sha512-OTVoDm039CNyAWSRc2WBimMl/N9J4Fk2le21Xzcf+3OiWPNNSIbMnpWKBUyraPh2d9SAEgoBdQxTfVNihXgiUw==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.4.8", + "urlpattern-polyfill": "^9.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.4.14.tgz", + "integrity": "sha512-ii/eZz2PcjLGj9D6WfsmfzlTzZV1Kz6MxYpq2Vc5P21J8vkKfENWC9B2ISsFCKovxElLukIwPg8HTrHFsLNflg==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.1.0", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/urlpattern-polyfill": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz", + "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==", + "dev": true + }, + "node_modules/@graphql-tools/relay-operation-optimizer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.0.tgz", + "integrity": "sha512-UNlJi5y3JylhVWU4MBpL0Hun4Q7IoJwv9xYtmAz+CgRa066szzY7dcuPfxrA7cIGgG/Q6TVsKsYaiF4OHPs1Fw==", + "dev": true, + "dependencies": { + "@ardatan/relay-compiler": "12.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/schema": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.0.tgz", + "integrity": "sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg==", + "dev": true, + "dependencies": { + "@graphql-tools/merge": "^9.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/url-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.0.tgz", + "integrity": "sha512-rPc9oDzMnycvz+X+wrN3PLrhMBQkG4+sd8EzaFN6dypcssiefgWKToXtRKI8HHK68n2xEq1PyrOpkjHFJB+GwA==", + "dev": true, + "dependencies": { + "@ardatan/sync-fetch": "^0.0.1", + "@graphql-tools/delegate": "^10.0.0", + "@graphql-tools/executor-graphql-ws": "^1.0.0", + "@graphql-tools/executor-http": "^1.0.0", + "@graphql-tools/executor-legacy-ws": "^1.0.0", + "@graphql-tools/utils": "^10.0.0", + "@graphql-tools/wrap": "^10.0.0", + "@types/ws": "^8.0.0", + "@whatwg-node/fetch": "^0.9.0", + "isomorphic-ws": "^5.0.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.11", + "ws": "^8.12.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/events": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.1.1.tgz", + "integrity": "sha512-AyQEn5hIPV7Ze+xFoXVU3QTHXVbWPrzaOkxtENMPMuNL6VVHrp4hHfDt9nrQpjO7BgvuM95dMtkycX5M/DZR3w==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/fetch": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.9.tgz", + "integrity": "sha512-OTVoDm039CNyAWSRc2WBimMl/N9J4Fk2le21Xzcf+3OiWPNNSIbMnpWKBUyraPh2d9SAEgoBdQxTfVNihXgiUw==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.4.8", + "urlpattern-polyfill": "^9.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.4.14.tgz", + "integrity": "sha512-ii/eZz2PcjLGj9D6WfsmfzlTzZV1Kz6MxYpq2Vc5P21J8vkKfENWC9B2ISsFCKovxElLukIwPg8HTrHFsLNflg==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.1.0", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/urlpattern-polyfill": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz", + "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==", + "dev": true + }, + "node_modules/@graphql-tools/utils": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.5.tgz", + "integrity": "sha512-ZTioQqg9z9eCG3j+KDy54k1gp6wRIsLqkx5yi163KVvXVkfjsrdErCyZjrEug21QnKE9piP4tyxMpMMOT1RuRw==", + "dev": true, + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "dset": "^3.1.2", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/wrap": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.0.tgz", + "integrity": "sha512-HDOeUUh6UhpiH0WPJUQl44ODt1x5pnMUbOJZ7GjTdGQ7LK0AgVt3ftaAQ9duxLkiAtYJmu5YkULirfZGj4HzDg==", + "dev": true, + "dependencies": { + "@graphql-tools/delegate": "^10.0.0", + "@graphql-tools/schema": "^10.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", + "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.0.tgz", + "integrity": "sha512-ZbhX9CTV+Z7vHwkRIasDOwTSzr76e8Q6a55RMsAibjyX6+P0ZNL1qAKNzOjjBDP3+aEfNMl7hHo5knuY6pTAUQ==", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^3.0.0", + "minimist": "^1.2.8", + "rw": "^1.3.3", + "sort-object": "^3.0.3" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", + "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.3.0", + "@parcel/watcher-darwin-arm64": "2.3.0", + "@parcel/watcher-darwin-x64": "2.3.0", + "@parcel/watcher-freebsd-x64": "2.3.0", + "@parcel/watcher-linux-arm-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-musl": "2.3.0", + "@parcel/watcher-linux-x64-glibc": "2.3.0", + "@parcel/watcher-linux-x64-musl": "2.3.0", + "@parcel/watcher-win32-arm64": "2.3.0", + "@parcel/watcher-win32-ia32": "2.3.0", + "@parcel/watcher-win32-x64": "2.3.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", + "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", + "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", + "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", + "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", + "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", + "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", + "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", + "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", + "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", + "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", + "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", + "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz", + "integrity": "sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==", + "dev": true, + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.3.tgz", + "integrity": "sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.2", + "tslib": "^2.5.0", + "webcrypto-core": "^1.7.7" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.1.tgz", + "integrity": "sha512-ovVPSD1WlRpZHt7GI9DqJrWG3OIYS+NXQ9y5HIewMJpSe+jPQmMQfyRmgX4EnvmxSlp0u04Wg/7oItcoSIb/RA==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@repeaterjs/repeater": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz", + "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==", + "dev": true + }, + "node_modules/@restart/hooks": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz", + "integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", + "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@popperjs/core": "^2.11.6", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.4.9", + "@types/warning": "^3.0.0", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "peerDependencies": { + "react": ">=16.14.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" + }, + "node_modules/@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/json-stable-stringify": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz", + "integrity": "sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.2.tgz", + "integrity": "sha512-D0lgCq+3VWV85ey1MZVkE8ZveyuvW5VAfuahVTQRpXFQTxw03SuIf1/K4UQ87MMIXVKzpFjXFiFMZzLj2kU+iA==" + }, + "node_modules/@types/mapbox__vector-tile": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.0.tgz", + "integrity": "sha512-kDwVreQO5V4c8yAxzZVQLE5tyWF+IPToAanloQaSnwfXmIcJ7cyOrv8z4Ft4y7PsLYmhWXmON8MBV8RX0Rgr8g==", + "dependencies": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, + "node_modules/@types/mapbox-gl": { + "version": "2.7.13", + "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.7.13.tgz", + "integrity": "sha512-qNffhTdYkeFl8QG9Q1zPPJmcs8PvHgmLa1PcwP1rxvcfMsIgcFr/FnrCttG0ZnH7Kzdd7xfECSRNTWSr4jC3PQ==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/node": { + "version": "20.5.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", + "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==", + "dev": true + }, + "node_modules/@types/pbf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.2.tgz", + "integrity": "sha512-EDrLIPaPXOZqDjrkzxxbX7UlJSeQVgah3i0aA4pOSzmK9zq3BIh7/MZIQxED7slJByvKM4Gc6Hypyu2lJzh3SQ==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, + "node_modules/@types/react": { + "version": "18.2.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", + "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", + "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", + "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, + "node_modules/@types/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "dev": true + }, + "node_modules/@types/supercluster": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.0.tgz", + "integrity": "sha512-6JapQ2GmEkH66r23BK49I+u6zczVDGTtiJEVvKDYZVSm/vepWaJuTq6BXzJ6I4agG5s8vA1KM7m/gXWDg03O4Q==", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", + "integrity": "sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/type-utils": "6.5.0", + "@typescript-eslint/utils": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", + "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", + "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz", + "integrity": "sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/utils": "6.5.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz", + "integrity": "sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.5.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz", + "integrity": "sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.22.9", + "@babel/plugin-transform-react-jsx-self": "^7.22.5", + "@babel/plugin-transform-react-jsx-source": "^7.22.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0" + } + }, + "node_modules/@whatwg-node/events": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.0.3.tgz", + "integrity": "sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==", + "dev": true + }, + "node_modules/@whatwg-node/fetch": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", + "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", + "dev": true, + "dependencies": { + "@peculiar/webcrypto": "^1.4.0", + "@whatwg-node/node-fetch": "^0.3.6", + "busboy": "^1.6.0", + "urlpattern-polyfill": "^8.0.0", + "web-streams-polyfill": "^3.2.1" + } + }, + "node_modules/@whatwg-node/node-fetch": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz", + "integrity": "sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.0.3", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + } + }, + "node_modules/auto-bind": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-4.0.0.tgz", + "integrity": "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", + "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-plugin-syntax-trailing-function-commas": { + "version": "7.0.0-beta.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", + "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==", + "dev": true + }, + "node_modules/babel-preset-fbjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", + "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==", + "dev": true, + "dependencies": { + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-class-properties": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-member-expression-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-property-literals": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "babel-plugin-syntax-trailing-function-commas": "^7.0.0-beta.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bootstrap": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.1.tgz", + "integrity": "sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytewise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", + "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", + "dependencies": { + "bytewise-core": "^1.2.2", + "typewise": "^1.0.3" + } + }, + "node_modules/bytewise-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", + "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", + "dependencies": { + "typewise-core": "^1.2" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001524", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz", + "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/change-case-all": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/change-case-all/-/change-case-all-1.0.15.tgz", + "integrity": "sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==", + "dev": true, + "dependencies": { + "change-case": "^4.1.2", + "is-lower-case": "^2.0.2", + "is-upper-case": "^2.0.2", + "lower-case": "^2.0.2", + "lower-case-first": "^2.0.2", + "sponge-case": "^1.0.1", + "swap-case": "^2.0.2", + "title-case": "^3.0.3", + "upper-case": "^2.0.2", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "dev": true, + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/dataloader": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", + "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", + "dev": true + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dset": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", + "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.504", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.504.tgz", + "integrity": "sha512-cSMwIAd8yUh54VwitVRVvHK66QqHWE39C3DRj8SWiXitEpVSY3wNPD9y1pxQtLIi4w3UdzF9klLsmuPshz09DQ==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz", + "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==", + "dev": true, + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.0", + "safe-array-concat": "^1.0.0" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.48.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", + "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.13.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.3.tgz", + "integrity": "sha512-Hh0wv8bUNY877+sI0BlCUlsS0TYYQqvzEwJsJJPM2WF4RnTStSnSR3zdJYa2nPOJgg3UghXi54lVyMSmpCalzA==", + "dev": true, + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extract-files": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz", + "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==", + "dev": true, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "funding": { + "url": "https://github.com/sponsors/jaydenseric" + } + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dev": true, + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fast-url-parser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fbjs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "dev": true, + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^1.0.35" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", + "dev": true + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/geojson-vt": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", + "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphql": { + "version": "16.8.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.0.tgz", + "integrity": "sha512-0oKGaR+y3qcS5mCu1vb7KG+a89vjn06C7Ihq/dDl3jA+A8B3TKomvi3CiEcVLJQGalbu8F52LxkOym7U5sSfbg==", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-config": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-5.0.2.tgz", + "integrity": "sha512-7TPxOrlbiG0JplSZYCyxn2XQtqVhXomEjXUmWJVSS5ET1nPhOJSsIb/WTwqWhcYX6G0RlHXSj9PLtGTKmxLNGg==", + "dev": true, + "dependencies": { + "@graphql-tools/graphql-file-loader": "^8.0.0", + "@graphql-tools/json-file-loader": "^8.0.0", + "@graphql-tools/load": "^8.0.0", + "@graphql-tools/merge": "^9.0.0", + "@graphql-tools/url-loader": "^8.0.0", + "@graphql-tools/utils": "^10.0.0", + "cosmiconfig": "^8.1.0", + "jiti": "^1.18.2", + "minimatch": "^4.2.3", + "string-env-interpolation": "^1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "cosmiconfig-toml-loader": "^1.0.0", + "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "cosmiconfig-toml-loader": { + "optional": true + } + } + }, + "node_modules/graphql-config/node_modules/minimatch": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.3.tgz", + "integrity": "sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/graphql-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", + "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "cross-fetch": "^3.1.5" + }, + "peerDependencies": { + "graphql": "14 - 16" + } + }, + "node_modules/graphql-tag": { + "version": "2.12.6", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", + "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/graphql-ws": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.14.0.tgz", + "integrity": "sha512-itrUTQZP/TgswR4GSSYuwWUzrE/w5GhbwM2GX3ic2U7aw33jgEsayfIlvaj7/GcIvZgNMzsPTrE5hqPuFUiE5g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": ">=0.11 <=16" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, + "dependencies": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", + "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", + "dev": true, + "engines": { + "node": ">=12.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", + "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", + "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "dev": true, + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.0.tgz", + "integrity": "sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "has-tostringtag": "^1.0.0", + "reflect.getprototypeof": "^1.0.3" + } + }, + "node_modules/jiti": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz", + "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", + "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", + "dev": true, + "dependencies": { + "jsonify": "^0.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" + }, + "node_modules/json-to-pretty-yaml": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz", + "integrity": "sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==", + "dev": true, + "dependencies": { + "remedial": "^1.0.7", + "remove-trailing-spaces": "^1.0.6" + }, + "engines": { + "node": ">= 0.2.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/listr2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lower-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-2.0.2.tgz", + "integrity": "sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/maplibre-gl": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-3.3.0.tgz", + "integrity": "sha512-LDia3b8u2S8qtl50n8TYJM0IPLzfc01KDc71LNuydvDiEXAGBI5togty+juVtUipRZZjs4dAW6xhgrabc6lIgw==", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^19.3.0", + "@types/geojson": "^7946.0.10", + "@types/mapbox__point-geometry": "^0.1.2", + "@types/mapbox__vector-tile": "^1.3.0", + "@types/pbf": "^3.0.2", + "@types/supercluster": "^7.1.0", + "earcut": "^2.2.4", + "geojson-vt": "^3.2.1", + "gl-matrix": "^3.4.3", + "global-prefix": "^3.0.0", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^3.2.1", + "potpack": "^2.0.0", + "quickselect": "^2.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^2.0.3", + "vt-pbf": "^3.1.3" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/meros": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz", + "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==", + "dev": true, + "engines": { + "node": ">=13" + }, + "peerDependencies": { + "@types/node": ">=13" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pbf": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", + "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", + "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/potpack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", + "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", + "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "dev": true, + "dependencies": { + "tslib": "^2.6.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-bootstrap": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz", + "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==", + "dependencies": { + "@babel/runtime": "^7.21.0", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.6.3", + "@types/react-transition-group": "^4.4.5", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-map-gl": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.5.tgz", + "integrity": "sha512-YS2u2cSLlZVGjfa394f0snO6f6ZwZVTKqQwjbq/jj0w7fHU01Mn+Xqvm/Qr7nZChoT3OG7kh8JluDcXeBrDG/g==", + "dependencies": { + "@maplibre/maplibre-gl-style-spec": "^19.2.1", + "@types/mapbox-gl": ">=1.0.0" + }, + "peerDependencies": { + "mapbox-gl": ">=1.13.0", + "maplibre-gl": ">=1.13.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + }, + "maplibre-gl": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz", + "integrity": "sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/relay-runtime": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-12.0.0.tgz", + "integrity": "sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.0.0", + "fbjs": "^3.0.0", + "invariant": "^2.2.4" + } + }, + "node_modules/remedial": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/remedial/-/remedial-1.0.8.tgz", + "integrity": "sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "node_modules/remove-trailing-spaces": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz", + "integrity": "sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", + "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/scuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz", + "integrity": "sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==", + "dev": true + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/signedsource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/signedsource/-/signedsource-1.0.0.tgz", + "integrity": "sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sort-asc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz", + "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-desc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz", + "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-object": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz", + "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", + "dependencies": { + "bytewise": "^1.1.0", + "get-value": "^2.0.2", + "is-extendable": "^0.1.1", + "sort-asc": "^0.2.0", + "sort-desc": "^0.2.0", + "union-value": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sponge-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sponge-case/-/sponge-case-1.0.1.tgz", + "integrity": "sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-env-interpolation": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz", + "integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz", + "integrity": "sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swap-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-2.0.2.tgz", + "integrity": "sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + }, + "node_modules/title-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-3.0.3.tgz", + "integrity": "sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-api-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", + "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-log": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", + "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==", + "dev": true + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typewise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", + "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", + "dependencies": { + "typewise-core": "^1.2.0" + } + }, + "node_modules/typewise-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", + "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==" + }, + "node_modules/ua-parser-js": { + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", + "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unixify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", + "dev": true, + "dependencies": { + "normalize-path": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz", + "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/value-or-promise": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", + "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vite": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vt-pbf": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", + "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "dependencies": { + "@mapbox/point-geometry": "0.1.0", + "@mapbox/vector-tile": "^1.3.1", + "pbf": "^3.2.1" + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webcrypto-core": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.7.tgz", + "integrity": "sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", + "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/client-next/package.json b/client-next/package.json new file mode 100644 index 00000000000..4d453ed37ca --- /dev/null +++ b/client-next/package.json @@ -0,0 +1,49 @@ +{ + "name": "otp-debug-client-next", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --report-unused-disable-directives --max-warnings 0", + "check-format": "prettier --check \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"", + "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"", + "preview": "vite preview", + "prebuild": "npm run codegen && npm run lint && npm run check-format", + "predev": "npm run codegen", + "codegen": "graphql-codegen --config codegen.ts" + }, + "dependencies": { + "@googlemaps/polyline-codec": "^1.0.28", + "bootstrap": "^5.3.1", + "graphql": "^16.8.0", + "graphql-request": "^6.1.0", + "maplibre-gl": "^3.3.0", + "react": "^18.2.0", + "react-bootstrap": "^2.8.0", + "react-dom": "^18.2.0", + "react-map-gl": "^7.1.5" + }, + "devDependencies": { + "@graphql-codegen/cli": "5.0.0", + "@graphql-codegen/client-preset": "4.1.0", + "@graphql-codegen/introspection": "4.0.0", + "@parcel/watcher": "^2.3.0", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.0.3", + "eslint": "^8.45.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "prettier": "^3.0.3", + "typescript": "^5.2.2", + "vite": "^4.4.5" + } +} diff --git a/client-next/public/img/marker-flag-end-shadowed.png b/client-next/public/img/marker-flag-end-shadowed.png new file mode 100644 index 00000000000..ed8177fc2cf Binary files /dev/null and b/client-next/public/img/marker-flag-end-shadowed.png differ diff --git a/client-next/public/img/marker-flag-start-shadowed.png b/client-next/public/img/marker-flag-start-shadowed.png new file mode 100644 index 00000000000..7e565d59cf9 Binary files /dev/null and b/client-next/public/img/marker-flag-start-shadowed.png differ diff --git a/client-next/public/img/mode/air.png b/client-next/public/img/mode/air.png new file mode 100644 index 00000000000..69ea123a099 Binary files /dev/null and b/client-next/public/img/mode/air.png differ diff --git a/client-next/public/img/mode/bicycle.png b/client-next/public/img/mode/bicycle.png new file mode 100644 index 00000000000..c5a366b0e01 Binary files /dev/null and b/client-next/public/img/mode/bicycle.png differ diff --git a/client-next/public/img/mode/bus.png b/client-next/public/img/mode/bus.png new file mode 100644 index 00000000000..36fd81e008b Binary files /dev/null and b/client-next/public/img/mode/bus.png differ diff --git a/client-next/public/img/mode/cableway.png b/client-next/public/img/mode/cableway.png new file mode 100644 index 00000000000..f0b9d8469bd Binary files /dev/null and b/client-next/public/img/mode/cableway.png differ diff --git a/client-next/public/img/mode/car.png b/client-next/public/img/mode/car.png new file mode 100644 index 00000000000..e2f09986591 Binary files /dev/null and b/client-next/public/img/mode/car.png differ diff --git a/client-next/public/img/mode/coach.png b/client-next/public/img/mode/coach.png new file mode 100644 index 00000000000..36fd81e008b Binary files /dev/null and b/client-next/public/img/mode/coach.png differ diff --git a/client-next/public/img/mode/foot.png b/client-next/public/img/mode/foot.png new file mode 100644 index 00000000000..68025c60543 Binary files /dev/null and b/client-next/public/img/mode/foot.png differ diff --git a/client-next/public/img/mode/funicular.png b/client-next/public/img/mode/funicular.png new file mode 100644 index 00000000000..f0b9d8469bd Binary files /dev/null and b/client-next/public/img/mode/funicular.png differ diff --git a/client-next/public/img/mode/metro.png b/client-next/public/img/mode/metro.png new file mode 100644 index 00000000000..850f387481a Binary files /dev/null and b/client-next/public/img/mode/metro.png differ diff --git a/client-next/public/img/mode/monorail.png b/client-next/public/img/mode/monorail.png new file mode 100644 index 00000000000..2b720907fbb Binary files /dev/null and b/client-next/public/img/mode/monorail.png differ diff --git a/client-next/public/img/mode/rail.png b/client-next/public/img/mode/rail.png new file mode 100644 index 00000000000..f0b9d8469bd Binary files /dev/null and b/client-next/public/img/mode/rail.png differ diff --git a/client-next/public/img/mode/taxi.png b/client-next/public/img/mode/taxi.png new file mode 100644 index 00000000000..e2f09986591 Binary files /dev/null and b/client-next/public/img/mode/taxi.png differ diff --git a/client-next/public/img/mode/tram.png b/client-next/public/img/mode/tram.png new file mode 100644 index 00000000000..19a62327b2e Binary files /dev/null and b/client-next/public/img/mode/tram.png differ diff --git a/client-next/public/img/mode/trolleybus.png b/client-next/public/img/mode/trolleybus.png new file mode 100644 index 00000000000..b6d5bcd209a Binary files /dev/null and b/client-next/public/img/mode/trolleybus.png differ diff --git a/client-next/public/img/mode/water.png b/client-next/public/img/mode/water.png new file mode 100644 index 00000000000..abf995c8f15 Binary files /dev/null and b/client-next/public/img/mode/water.png differ diff --git a/client-next/public/img/otp-logo.svg b/client-next/public/img/otp-logo.svg new file mode 100644 index 00000000000..1ed23d0be8e --- /dev/null +++ b/client-next/public/img/otp-logo.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/client-next/src/components/ItineraryList/ItineraryDetails.tsx b/client-next/src/components/ItineraryList/ItineraryDetails.tsx new file mode 100644 index 00000000000..11fe14c73fb --- /dev/null +++ b/client-next/src/components/ItineraryList/ItineraryDetails.tsx @@ -0,0 +1,15 @@ +import { TripPattern } from '../../gql/graphql.ts'; +import { ItineraryLegDetails } from './ItineraryLegDetails.tsx'; + +export function ItineraryDetails({ tripPattern }: { tripPattern: TripPattern }) { + return ( +
+ {tripPattern.systemNotices.length > 0 && ( +

System tags: {tripPattern.systemNotices.map((systemNotice) => systemNotice.tag).join(', ')}

+ )} + {tripPattern.legs.map((leg, i) => ( + + ))} +
+ ); +} diff --git a/client-next/src/components/ItineraryList/ItineraryHeaderContent.tsx b/client-next/src/components/ItineraryList/ItineraryHeaderContent.tsx new file mode 100644 index 00000000000..419b7a2ebb9 --- /dev/null +++ b/client-next/src/components/ItineraryList/ItineraryHeaderContent.tsx @@ -0,0 +1,77 @@ +import { TripPattern } from '../../gql/graphql.ts'; +import { TIME_BOX_WIDTH, useHeaderContentStyleCalculations } from './useHeaderContentStyleCalculations.ts'; +import { ItineraryHeaderLegContent } from './ItineraryHeaderLegContent.tsx'; +import { useMemo } from 'react'; +import { formatTime } from '../../util/formatTime.ts'; + +export function ItineraryHeaderContent({ + tripPattern, + itineraryIndex, + containerWidth, + earliestStartTime, + latestEndTime, +}: { + tripPattern: TripPattern; + itineraryIndex: number; + containerWidth: number; + earliestStartTime: string | null; + latestEndTime: string | null; +}) { + const { maxSpan, pxSpan, startPx, widthPx, leftPx } = useHeaderContentStyleCalculations( + tripPattern, + containerWidth, + earliestStartTime, + latestEndTime, + ); + + const formattedStartTime = useMemo( + () => formatTime(tripPattern.expectedStartTime, 'short'), + [tripPattern.expectedStartTime], + ); + + const formattedEndTime = useMemo( + () => formatTime(tripPattern.expectedEndTime, 'short'), + [tripPattern.expectedEndTime], + ); + + return ( +
+
{itineraryIndex + 1}.
+
+
+ {formattedStartTime} +
+ + {tripPattern.legs.map((leg, i) => ( + + ))} + +
+ {formattedEndTime} +
+
+ ); +} diff --git a/client-next/src/components/ItineraryList/ItineraryHeaderLegContent.tsx b/client-next/src/components/ItineraryList/ItineraryHeaderLegContent.tsx new file mode 100644 index 00000000000..93ee400fa2a --- /dev/null +++ b/client-next/src/components/ItineraryList/ItineraryHeaderLegContent.tsx @@ -0,0 +1,46 @@ +import { Leg } from '../../gql/graphql.ts'; +import { useHeaderLegContentStyleCalculations } from './useHeaderLegContentStyleCalculations.ts'; + +export function ItineraryHeaderLegContent({ + leg, + earliestStartTime, + maxSpan, + startPx, + pxSpan, +}: { + leg: Leg; + earliestStartTime: string | null; + maxSpan: number; + startPx: number; + pxSpan: number; +}) { + const { widthPx, leftPx, legTextColor, modeColor, showPublicCode } = useHeaderLegContentStyleCalculations( + leg, + earliestStartTime, + maxSpan, + startPx, + pxSpan, + ); + + return ( +
+
+ {showPublicCode && {leg.line?.publicCode}} +
+ ); +} diff --git a/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx b/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx new file mode 100644 index 00000000000..f6df37c2d1d --- /dev/null +++ b/client-next/src/components/ItineraryList/ItineraryLegDetails.tsx @@ -0,0 +1,24 @@ +import { Leg, Mode } from '../../gql/graphql.ts'; +import { LegTime } from './LegTime.tsx'; +import { formatDistance } from '../../util/formatDistance.ts'; +import { formatDuration } from '../../util/formatDuration.ts'; + +export function ItineraryLegDetails({ leg, isLast }: { leg: Leg; isLast: boolean }) { + return ( +
+ -{' '} + {' '} + {leg.mode}{' '} + {leg.line && ( + <> + + {leg.line.publicCode} {leg.toEstimatedCall?.destinationDisplay?.frontText} + + , {leg.authority?.name} + + )}{' '} + {formatDistance(leg.distance)}, {formatDuration(leg.duration)} + {leg.mode !== Mode.Foot && from {leg.fromPlace.name}} {!isLast && to {leg.toPlace.name}} +
+ ); +} diff --git a/client-next/src/components/ItineraryList/ItineraryListContainer.tsx b/client-next/src/components/ItineraryList/ItineraryListContainer.tsx new file mode 100644 index 00000000000..feaf29aa514 --- /dev/null +++ b/client-next/src/components/ItineraryList/ItineraryListContainer.tsx @@ -0,0 +1,61 @@ +import { QueryType } from '../../gql/graphql.ts'; +import { Accordion } from 'react-bootstrap'; +import { useContainerWidth } from './useContainerWidth.ts'; +import { ItineraryHeaderContent } from './ItineraryHeaderContent.tsx'; +import { useEarliestAndLatestTimes } from './useEarliestAndLatestTimes.ts'; +import { ItineraryDetails } from './ItineraryDetails.tsx'; +import { ItineraryPaginationControl } from './ItineraryPaginationControl.tsx'; + +export function ItineraryListContainer({ + tripQueryResult, + selectedTripPatternIndex, + setSelectedTripPatternIndex, + pageResults, + loading, +}: { + tripQueryResult: QueryType | null; + selectedTripPatternIndex: number; + setSelectedTripPatternIndex: (selectedTripPatterIndex: number) => void; + pageResults: (cursor: string) => void; + loading: boolean; +}) { + const [earliestStartTime, latestEndTime] = useEarliestAndLatestTimes(tripQueryResult); + const { containerRef, containerWidth } = useContainerWidth(); + + return ( +
+ + setSelectedTripPatternIndex(parseInt(eventKey as string))} + > + {tripQueryResult && + tripQueryResult.trip.tripPatterns.map((tripPattern, itineraryIndex) => ( + + + + + + + + + ))} + +
+ ); +} diff --git a/client-next/src/components/ItineraryList/ItineraryPaginationControl.tsx b/client-next/src/components/ItineraryList/ItineraryPaginationControl.tsx new file mode 100644 index 00000000000..ecc1ffd45db --- /dev/null +++ b/client-next/src/components/ItineraryList/ItineraryPaginationControl.tsx @@ -0,0 +1,34 @@ +import { Button } from 'react-bootstrap'; + +export function ItineraryPaginationControl({ + previousPageCursor, + nextPageCursor, + onPagination, + loading, +}: { + previousPageCursor?: string | null; + nextPageCursor?: string | null; + onPagination: (cursor: string) => void; + loading: boolean; +}) { + return ( +
+ {' '} + +
+ ); +} diff --git a/client-next/src/components/ItineraryList/LegTime.tsx b/client-next/src/components/ItineraryList/LegTime.tsx new file mode 100644 index 00000000000..5bd4aa56b1a --- /dev/null +++ b/client-next/src/components/ItineraryList/LegTime.tsx @@ -0,0 +1,23 @@ +import { formatTime } from '../../util/formatTime.ts'; + +export function LegTime({ + aimedTime, + expectedTime, + hasRealtime, +}: { + aimedTime: string; + expectedTime: string; + hasRealtime: boolean; +}) { + return aimedTime !== expectedTime ? ( + <> + {formatTime(expectedTime)} + {formatTime(aimedTime)} + + ) : ( + + {formatTime(expectedTime)} + {hasRealtime && (on time)} + + ); +} diff --git a/client-next/src/components/ItineraryList/useContainerWidth.ts b/client-next/src/components/ItineraryList/useContainerWidth.ts new file mode 100644 index 00000000000..f3ee97c9dcc --- /dev/null +++ b/client-next/src/components/ItineraryList/useContainerWidth.ts @@ -0,0 +1,28 @@ +import { useEffect, useLayoutEffect, useRef, useState } from 'react'; + +export function useContainerWidth() { + const [containerWidth, setContainerWidth] = useState(0); + const containerRef = useRef(null); + + useLayoutEffect(() => { + if (containerRef.current) { + setContainerWidth(containerRef.current.getBoundingClientRect().width); + } + }, []); + + useEffect(() => { + const listener = () => { + if (containerRef.current) { + setContainerWidth(containerRef.current.getBoundingClientRect().width); + } + }; + + window.addEventListener('resize', listener); + + return () => { + window.removeEventListener('resize', listener); + }; + }, []); + + return { containerRef, containerWidth }; +} diff --git a/client-next/src/components/ItineraryList/useEarliestAndLatestTimes.ts b/client-next/src/components/ItineraryList/useEarliestAndLatestTimes.ts new file mode 100644 index 00000000000..49d548f8787 --- /dev/null +++ b/client-next/src/components/ItineraryList/useEarliestAndLatestTimes.ts @@ -0,0 +1,30 @@ +import { useMemo } from 'react'; +import { TripQuery } from '../../gql/graphql.ts'; + +export function useEarliestAndLatestTimes(tripQueryResult: TripQuery | null) { + const earliestStartTime = useMemo(() => { + return ( + tripQueryResult?.trip.tripPatterns.reduce((acc, current) => { + if (acc === null) { + return current?.expectedStartTime; + } else { + return new Date(current?.expectedStartTime) < new Date(acc) ? current.expectedStartTime : acc; + } + }, null) || null + ); + }, [tripQueryResult?.trip]); + + const latestEndTime = useMemo(() => { + return ( + tripQueryResult?.trip.tripPatterns.reduce((acc, current) => { + if (acc === null) { + return current?.expectedEndTime; + } else { + return new Date(current?.expectedEndTime) > new Date(acc) ? current.expectedEndTime : acc; + } + }, null) || null + ); + }, [tripQueryResult?.trip]); + + return [earliestStartTime, latestEndTime]; +} diff --git a/client-next/src/components/ItineraryList/useHeaderContentStyleCalculations.ts b/client-next/src/components/ItineraryList/useHeaderContentStyleCalculations.ts new file mode 100644 index 00000000000..91695f6ae6e --- /dev/null +++ b/client-next/src/components/ItineraryList/useHeaderContentStyleCalculations.ts @@ -0,0 +1,44 @@ +import { useMemo } from 'react'; +import { TripPattern } from '../../gql/graphql.ts'; + +const CONTAINER_WIDTH_PADDING = 70; +const START_PX_PADDING = 20; + +// Width of time box +export const TIME_BOX_WIDTH = 40; + +export function useHeaderContentStyleCalculations( + tripPattern: TripPattern, + containerWidth: number, + earliestStartTime: string | null, + latestEndTime: string | null, +) { + const maxSpan = useMemo( + () => new Date(latestEndTime!).getTime() - new Date(earliestStartTime!).getTime(), + [earliestStartTime, latestEndTime], + ); + + const startPct = useMemo( + () => (new Date(tripPattern.expectedStartTime).getTime() - new Date(earliestStartTime!).getTime()) / maxSpan, + [tripPattern.expectedStartTime, earliestStartTime, maxSpan], + ); + + const itinSpan = useMemo( + () => new Date(tripPattern.expectedEndTime).getTime() - new Date(tripPattern.expectedStartTime).getTime(), + [tripPattern.expectedStartTime, tripPattern.expectedEndTime], + ); + + const startPx = START_PX_PADDING + TIME_BOX_WIDTH; + const endPx = containerWidth - CONTAINER_WIDTH_PADDING - TIME_BOX_WIDTH; + const pxSpan = endPx - startPx; + const leftPx = startPx + startPct * pxSpan; + const widthPx = pxSpan * (itinSpan / maxSpan); + + return { + maxSpan, + startPx, + pxSpan, + widthPx, + leftPx, + }; +} diff --git a/client-next/src/components/ItineraryList/useHeaderLegContentStyleCalculations.ts b/client-next/src/components/ItineraryList/useHeaderLegContentStyleCalculations.ts new file mode 100644 index 00000000000..642a71320b7 --- /dev/null +++ b/client-next/src/components/ItineraryList/useHeaderLegContentStyleCalculations.ts @@ -0,0 +1,34 @@ +import { useMemo } from 'react'; +import { isTransitMode } from '../../util/isTransitMode.ts'; +import { getColorForMode } from '../../util/getColorForMode.ts'; +import { generateTextColor } from '../../util/generateTextColor.ts'; +import { Leg } from '../../gql/graphql.ts'; + +export function useHeaderLegContentStyleCalculations( + leg: Leg, + earliestStartTime: string | null, + maxSpan: number, + startPx: number, + pxSpan: number, +) { + const startPct = useMemo( + () => (new Date(leg.expectedStartTime).getTime() - new Date(earliestStartTime!).getTime()) / maxSpan, + [leg.expectedStartTime, earliestStartTime, maxSpan], + ); + + const widthPx = useMemo( + () => + (pxSpan * (new Date(leg.expectedEndTime).getTime() - new Date(leg.expectedStartTime).getTime())) / maxSpan - 1, + [pxSpan, leg, maxSpan], + ); + + const leftPx = startPx + startPct * pxSpan + 1; + + const showPublicCode = + widthPx > 40 && isTransitMode(leg.mode) && leg.line?.publicCode && leg.line.publicCode.length <= 6; + + const modeColor = getColorForMode(leg.mode); + const legTextColor = useMemo(() => generateTextColor(modeColor), [modeColor]); + + return { widthPx, leftPx, legTextColor, modeColor, showPublicCode }; +} diff --git a/client-next/src/components/MapView/ContextMenuPopup.tsx b/client-next/src/components/MapView/ContextMenuPopup.tsx new file mode 100644 index 00000000000..52dd3858298 --- /dev/null +++ b/client-next/src/components/MapView/ContextMenuPopup.tsx @@ -0,0 +1,54 @@ +import { TripQueryVariables } from '../../gql/graphql.ts'; +import { LngLat, Popup } from 'react-map-gl'; +import { Button, ButtonGroup } from 'react-bootstrap'; + +export function ContextMenuPopup({ + tripQueryVariables, + setTripQueryVariables, + coordinates, + onClose, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (variables: TripQueryVariables) => void; + coordinates: LngLat; + onClose: () => void; +}) { + return ( + + + + + + + ); +} diff --git a/client-next/src/components/MapView/LegLines.tsx b/client-next/src/components/MapView/LegLines.tsx new file mode 100644 index 00000000000..41b02ece83a --- /dev/null +++ b/client-next/src/components/MapView/LegLines.tsx @@ -0,0 +1,40 @@ +import { TripPattern } from '../../gql/graphql.ts'; +import { Layer, Source } from 'react-map-gl'; +import { decode } from '@googlemaps/polyline-codec'; +import { getColorForMode } from '../../util/getColorForMode.ts'; + +export function LegLines({ tripPattern }: { tripPattern?: TripPattern }) { + return ( + <> + {tripPattern?.legs.map( + (leg, i) => + leg.pointsOnLink && ( + value.reverse()), + }, + }} + > + + + ), + )} + + ); +} diff --git a/client-next/src/components/MapView/MapView.tsx b/client-next/src/components/MapView/MapView.tsx new file mode 100644 index 00000000000..011d9408148 --- /dev/null +++ b/client-next/src/components/MapView/MapView.tsx @@ -0,0 +1,67 @@ +import { LngLat, Map, NavigationControl } from 'react-map-gl'; +import 'maplibre-gl/dist/maplibre-gl.css'; +import { TripPattern, TripQuery, TripQueryVariables } from '../../gql/graphql.ts'; +import { NavigationMarkers } from './NavigationMarkers.tsx'; +import { LegLines } from './LegLines.tsx'; +import { useMapDoubleClick } from './useMapDoubleClick.ts'; +import { mapStyle } from './mapStyle.ts'; +import { useState } from 'react'; +import { ContextMenuPopup } from './ContextMenuPopup.tsx'; + +// TODO: this should be configurable +const initialViewState = { + latitude: 60.7554885, + longitude: 10.2332855, + zoom: 4, +}; + +export function MapView({ + tripQueryVariables, + setTripQueryVariables, + tripQueryResult, + selectedTripPatternIndex, + loading, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (variables: TripQueryVariables) => void; + tripQueryResult: TripQuery | null; + selectedTripPatternIndex: number; + loading: boolean; +}) { + const onMapDoubleClick = useMapDoubleClick({ tripQueryVariables, setTripQueryVariables }); + const [showPopup, setShowPopup] = useState(null); + + return ( +
+ { + setShowPopup(e.lngLat); + }} + > + + + {tripQueryResult?.trip.tripPatterns.length && ( + + )} + {showPopup && ( + setShowPopup(null)} + /> + )} + +
+ ); +} diff --git a/client-next/src/components/MapView/NavigationMarkers.tsx b/client-next/src/components/MapView/NavigationMarkers.tsx new file mode 100644 index 00000000000..a99590bd068 --- /dev/null +++ b/client-next/src/components/MapView/NavigationMarkers.tsx @@ -0,0 +1,53 @@ +import { TripQueryVariables } from '../../gql/graphql.ts'; +import { Marker } from 'react-map-gl'; + +export function NavigationMarkers({ + tripQueryVariables, + setTripQueryVariables, + loading, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (variables: TripQueryVariables) => void; + loading: boolean; +}) { + return ( + <> + {tripQueryVariables.from.coordinates && ( + { + if (!loading) { + setTripQueryVariables({ + ...tripQueryVariables, + from: { coordinates: { latitude: e.lngLat.lat, longitude: e.lngLat.lng } }, + }); + } + }} + anchor="bottom-right" + > + + + )} + {tripQueryVariables.to.coordinates && ( + { + if (!loading) { + setTripQueryVariables({ + ...tripQueryVariables, + to: { coordinates: { latitude: e.lngLat.lat, longitude: e.lngLat.lng } }, + }); + } + }} + anchor="bottom-right" + > + + + )} + + ); +} diff --git a/client-next/src/components/MapView/mapStyle.ts b/client-next/src/components/MapView/mapStyle.ts new file mode 100644 index 00000000000..ecaa88c0354 --- /dev/null +++ b/client-next/src/components/MapView/mapStyle.ts @@ -0,0 +1,19 @@ +export const mapStyle = { + version: 8, + sources: { + osm: { + type: 'raster', + tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'], + tileSize: 256, + attribution: '© OpenStreetMap Contributors', + maxzoom: 19, + }, + }, + layers: [ + { + id: 'osm', + type: 'raster', + source: 'osm', // This must match the source key above + }, + ], +}; diff --git a/client-next/src/components/MapView/useMapDoubleClick.ts b/client-next/src/components/MapView/useMapDoubleClick.ts new file mode 100644 index 00000000000..35cb1d76a62 --- /dev/null +++ b/client-next/src/components/MapView/useMapDoubleClick.ts @@ -0,0 +1,39 @@ +import { useCallback } from 'react'; +import { TripQueryVariables } from '../../gql/graphql.ts'; +import { LngLat, MapLayerMouseEvent } from 'react-map-gl'; + +const setCoordinates = (tripQueryVariables: TripQueryVariables, lngLat: LngLat, key: 'from' | 'to') => ({ + ...tripQueryVariables, + [key]: { + coordinates: { + latitude: lngLat.lat, + longitude: lngLat.lng, + }, + }, +}); + +const setFromCoordinates = (tripQueryVariables: TripQueryVariables, lngLat: LngLat) => + setCoordinates(tripQueryVariables, lngLat, 'from'); + +const setToCoordinates = (tripQueryVariables: TripQueryVariables, lngLat: LngLat) => + setCoordinates(tripQueryVariables, lngLat, 'to'); + +export function useMapDoubleClick({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (variables: TripQueryVariables) => void; +}) { + return useCallback( + (event: MapLayerMouseEvent) => { + event.preventDefault(); + if (!tripQueryVariables.from.coordinates) { + setTripQueryVariables(setFromCoordinates(tripQueryVariables, event.lngLat)); + } else { + setTripQueryVariables(setToCoordinates(tripQueryVariables, event.lngLat)); + } + }, + [tripQueryVariables, setTripQueryVariables], + ); +} diff --git a/client-next/src/components/SearchBar/AccessSelect.tsx b/client-next/src/components/SearchBar/AccessSelect.tsx new file mode 100644 index 00000000000..d76ea59207a --- /dev/null +++ b/client-next/src/components/SearchBar/AccessSelect.tsx @@ -0,0 +1,52 @@ +import { Form } from 'react-bootstrap'; +import { StreetMode, TripQueryVariables } from '../../gql/graphql.ts'; + +export function AccessSelect({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + return ( + + + Access + + { + if (e.target.value !== 'not_selected') { + setTripQueryVariables({ + ...tripQueryVariables, + modes: { + ...tripQueryVariables.modes, + accessMode: e.target.value as StreetMode, + }, + }); + } else { + setTripQueryVariables({ + ...tripQueryVariables, + modes: + tripQueryVariables.modes?.directMode || tripQueryVariables.modes?.transportModes + ? { + ...tripQueryVariables.modes, + accessMode: undefined, + } + : undefined, + }); + } + }} + value={tripQueryVariables.modes?.accessMode || 'not_selected'} + > + + {Object.values(StreetMode).map((mode) => ( + + ))} + + + ); +} diff --git a/client-next/src/components/SearchBar/DateInputField.tsx b/client-next/src/components/SearchBar/DateInputField.tsx new file mode 100644 index 00000000000..0b0eca38869 --- /dev/null +++ b/client-next/src/components/SearchBar/DateInputField.tsx @@ -0,0 +1,40 @@ +import { Form } from 'react-bootstrap'; +import { TripQueryVariables } from '../../gql/graphql.ts'; +import { ChangeEvent, useCallback, useMemo } from 'react'; + +export function DateInputField({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + const current = useMemo( + () => new Date(tripQueryVariables.dateTime).toISOString().split('T')[0], + [tripQueryVariables.dateTime], + ); + + const onChange = useCallback( + (event: ChangeEvent) => { + const oldDate = new Date(tripQueryVariables.dateTime); + const newDate = new Date(event.target.value); + + newDate.setHours(oldDate.getHours(), oldDate.getMinutes(), oldDate.getSeconds()); + + setTripQueryVariables({ + ...tripQueryVariables, + dateTime: newDate.toISOString(), + }); + }, + [tripQueryVariables, setTripQueryVariables], + ); + + return ( + + + Date + + + + ); +} diff --git a/client-next/src/components/SearchBar/DepartureArrivalSelect.tsx b/client-next/src/components/SearchBar/DepartureArrivalSelect.tsx new file mode 100644 index 00000000000..b6a92cdd495 --- /dev/null +++ b/client-next/src/components/SearchBar/DepartureArrivalSelect.tsx @@ -0,0 +1,33 @@ +import { Form } from 'react-bootstrap'; +import { TripQueryVariables } from '../../gql/graphql.ts'; + +export function DepartureArrivalSelect({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + const onChange = (arriveBy: boolean) => { + setTripQueryVariables({ + ...tripQueryVariables, + arriveBy, + }); + }; + + return ( + + + Departure/Arrival + + (e.target.value === 'arrival' ? onChange(true) : onChange(false))} + value={tripQueryVariables.arriveBy ? 'arrival' : 'departure'} + > + + + + + ); +} diff --git a/client-next/src/components/SearchBar/DirectModeSelect.tsx b/client-next/src/components/SearchBar/DirectModeSelect.tsx new file mode 100644 index 00000000000..459cb2e4d47 --- /dev/null +++ b/client-next/src/components/SearchBar/DirectModeSelect.tsx @@ -0,0 +1,54 @@ +import { Form } from 'react-bootstrap'; +import { StreetMode, TripQueryVariables } from '../../gql/graphql.ts'; + +export function DirectModeSelect({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + return ( + + + Direct mode + + { + if (e.target.value !== 'not_selected') { + setTripQueryVariables({ + ...tripQueryVariables, + modes: { + ...tripQueryVariables.modes, + directMode: e.target.value as StreetMode, + }, + }); + } else { + setTripQueryVariables({ + ...tripQueryVariables, + modes: + tripQueryVariables.modes?.accessMode || + tripQueryVariables.modes?.egressMode || + tripQueryVariables.modes?.transportModes + ? { + ...tripQueryVariables.modes, + directMode: undefined, + } + : undefined, + }); + } + }} + value={tripQueryVariables.modes?.directMode || 'not_selected'} + > + + {Object.values(StreetMode).map((mode) => ( + + ))} + + + ); +} diff --git a/client-next/src/components/SearchBar/EgressSelect.tsx b/client-next/src/components/SearchBar/EgressSelect.tsx new file mode 100644 index 00000000000..916588d08e9 --- /dev/null +++ b/client-next/src/components/SearchBar/EgressSelect.tsx @@ -0,0 +1,52 @@ +import { Form } from 'react-bootstrap'; +import { StreetMode, TripQueryVariables } from '../../gql/graphql.ts'; + +export function EgressSelect({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + return ( + + + Egress + + { + if (e.target.value !== 'not_selected') { + setTripQueryVariables({ + ...tripQueryVariables, + modes: { + ...tripQueryVariables.modes, + egressMode: e.target.value as StreetMode, + }, + }); + } else { + setTripQueryVariables({ + ...tripQueryVariables, + modes: + tripQueryVariables.modes?.directMode || tripQueryVariables.modes?.transportModes + ? { + ...tripQueryVariables.modes, + egressMode: undefined, + } + : undefined, + }); + } + }} + value={tripQueryVariables.modes?.egressMode || 'not_selected'} + > + + {Object.values(StreetMode).map((mode) => ( + + ))} + + + ); +} diff --git a/client-next/src/components/SearchBar/ItineraryFilterDebugSelect.tsx b/client-next/src/components/SearchBar/ItineraryFilterDebugSelect.tsx new file mode 100644 index 00000000000..636ba551541 --- /dev/null +++ b/client-next/src/components/SearchBar/ItineraryFilterDebugSelect.tsx @@ -0,0 +1,36 @@ +import { Form } from 'react-bootstrap'; +import { ItineraryFilterDebugProfile, TripQueryVariables } from '../../gql/graphql.ts'; + +export function ItineraryFilterDebugSelect({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + return ( + + + Itinerary filter debug + + { + setTripQueryVariables({ + ...tripQueryVariables, + itineraryFiltersDebug: e.target.value as ItineraryFilterDebugProfile, + }); + }} + value={tripQueryVariables.itineraryFiltersDebug || 'not_selected'} + > + + {Object.values(ItineraryFilterDebugProfile).map((debugProfile) => ( + + ))} + + + ); +} diff --git a/client-next/src/components/SearchBar/LocationInputField.tsx b/client-next/src/components/SearchBar/LocationInputField.tsx new file mode 100644 index 00000000000..ffa66702e81 --- /dev/null +++ b/client-next/src/components/SearchBar/LocationInputField.tsx @@ -0,0 +1,29 @@ +import { Form } from 'react-bootstrap'; +import { COORDINATE_PRECISION } from './constants.ts'; +import { Location } from '../../gql/graphql.ts'; + +export function LocationInputField({ location, id, label }: { location: Location; id: string; label: string }) { + return ( + + + {label} + + {}} + value={ + location.coordinates + ? `${location.coordinates?.latitude.toPrecision( + COORDINATE_PRECISION, + )} ${location.coordinates?.longitude.toPrecision(COORDINATE_PRECISION)}` + : '' + } + /> + + ); +} diff --git a/client-next/src/components/SearchBar/MultiSelectDropdown.tsx b/client-next/src/components/SearchBar/MultiSelectDropdown.tsx new file mode 100644 index 00000000000..fc20e6822ac --- /dev/null +++ b/client-next/src/components/SearchBar/MultiSelectDropdown.tsx @@ -0,0 +1,65 @@ +import { ChangeEvent, useState } from 'react'; +import { Form } from 'react-bootstrap'; + +type MultiSelectDropdownOption = { + id: T; + label: string; +}; + +type MultiSelectDropdownProps = { + label: string; + options: MultiSelectDropdownOption[]; + values: T[]; + onChange: (value: T[]) => void; +}; + +const MultiSelectDropdown = ({ label, options, values, onChange }: MultiSelectDropdownProps) => { + const [isOpen, setIsOpen] = useState(false); + + const toggleDropdown = () => { + setIsOpen(!isOpen); + }; + + const handleOptionChange = (event: ChangeEvent) => { + const optionId = event.target.value as T; + const isChecked = event.target.checked; + + if (isChecked) { + onChange([...values, optionId]); + } else { + onChange(values.filter((id) => id !== optionId)); + } + }; + + return ( +
+ + {label} + + 0 ? values.join(', ') : 'Not selected'} + onClick={toggleDropdown} + onChange={() => {}} + /> +
+ {options.map((option) => ( + + ))} +
+
+ ); +}; + +export default MultiSelectDropdown; diff --git a/client-next/src/components/SearchBar/NumTripPatternsInput.tsx b/client-next/src/components/SearchBar/NumTripPatternsInput.tsx new file mode 100644 index 00000000000..b77e70adb81 --- /dev/null +++ b/client-next/src/components/SearchBar/NumTripPatternsInput.tsx @@ -0,0 +1,32 @@ +import { Form } from 'react-bootstrap'; +import { TripQueryVariables } from '../../gql/graphql.ts'; + +export function NumTripPatternsInput({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + return ( + + + Number of trip patterns + + + setTripQueryVariables({ + ...tripQueryVariables, + numTripPatterns: Number(event.target.value) > 0 ? Number(event.target.value) : undefined, + }) + } + /> + + ); +} diff --git a/client-next/src/components/SearchBar/SearchBar.tsx b/client-next/src/components/SearchBar/SearchBar.tsx new file mode 100644 index 00000000000..ea1492fbe9b --- /dev/null +++ b/client-next/src/components/SearchBar/SearchBar.tsx @@ -0,0 +1,72 @@ +import { Button, Spinner } from 'react-bootstrap'; +import { ServerInfo, TripQueryVariables } from '../../gql/graphql.ts'; +import { LocationInputField } from './LocationInputField.tsx'; +import { DepartureArrivalSelect } from './DepartureArrivalSelect.tsx'; +import { TimeInputField } from './TimeInputField.tsx'; +import { DateInputField } from './DateInputField.tsx'; +import { SearchWindowInput } from './SearchWindowInput.tsx'; +import { AccessSelect } from './AccessSelect.tsx'; +import { EgressSelect } from './EgressSelect.tsx'; +import { DirectModeSelect } from './DirectModeSelect.tsx'; +import { TransitModeSelect } from './TransitModeSelect.tsx'; +import { NumTripPatternsInput } from './NumTripPatternsInput.tsx'; +import { ItineraryFilterDebugSelect } from './ItineraryFilterDebugSelect.tsx'; +import Navbar from 'react-bootstrap/Navbar'; +import { ServerInfoTooltip } from './ServerInfoTooltip.tsx'; +import { useRef, useState } from 'react'; + +type SearchBarProps = { + onRoute: () => void; + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; + serverInfo?: ServerInfo; + loading: boolean; +}; + +export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables, serverInfo, loading }: SearchBarProps) { + const [showServerInfo, setShowServerInfo] = useState(false); + const target = useRef(null); + + return ( +
+ setShowServerInfo((v) => !v)}> +
+ {' '} + OTP Debug Client + {showServerInfo && } +
+
+ + + + + + + + + + + + +
+ +
+
+ ); +} diff --git a/client-next/src/components/SearchBar/SearchWindowInput.tsx b/client-next/src/components/SearchBar/SearchWindowInput.tsx new file mode 100644 index 00000000000..5442784de8e --- /dev/null +++ b/client-next/src/components/SearchBar/SearchWindowInput.tsx @@ -0,0 +1,32 @@ +import { Form } from 'react-bootstrap'; +import { TripQueryVariables } from '../../gql/graphql.ts'; + +export function SearchWindowInput({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + return ( + + + Search window + + + setTripQueryVariables({ + ...tripQueryVariables, + searchWindow: Number(event.target.value) > 0 ? Number(event.target.value) : undefined, + }) + } + /> + + ); +} diff --git a/client-next/src/components/SearchBar/ServerInfoTooltip.tsx b/client-next/src/components/SearchBar/ServerInfoTooltip.tsx new file mode 100644 index 00000000000..a1aaed16f9c --- /dev/null +++ b/client-next/src/components/SearchBar/ServerInfoTooltip.tsx @@ -0,0 +1,21 @@ +import { ServerInfo } from '../../gql/graphql.ts'; +import { Overlay } from 'react-bootstrap'; +import { MutableRefObject } from 'react'; + +export function ServerInfoTooltip({ target, serverInfo }: { target: MutableRefObject; serverInfo?: ServerInfo }) { + return ( + +
+
{JSON.stringify(serverInfo, null, 2)}
+
+
+ ); +} diff --git a/client-next/src/components/SearchBar/TimeInputField.tsx b/client-next/src/components/SearchBar/TimeInputField.tsx new file mode 100644 index 00000000000..71bb7325340 --- /dev/null +++ b/client-next/src/components/SearchBar/TimeInputField.tsx @@ -0,0 +1,39 @@ +import { Form } from 'react-bootstrap'; +import { TripQueryVariables } from '../../gql/graphql.ts'; +import { ChangeEvent, useCallback, useMemo } from 'react'; + +export function TimeInputField({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + const current = useMemo( + () => new Date(tripQueryVariables.dateTime).toTimeString().split(' ')[0], + [tripQueryVariables.dateTime], + ); + + const onChange = useCallback( + (event: ChangeEvent) => { + const timeComponents = event.target.value.split(':'); + const newDate = new Date(tripQueryVariables.dateTime); + newDate.setHours(Number(timeComponents[0]), Number(timeComponents[1]), Number(timeComponents[2])); + + setTripQueryVariables({ + ...tripQueryVariables, + dateTime: newDate.toISOString(), + }); + }, + [tripQueryVariables, setTripQueryVariables], + ); + + return ( + + + Time + + + + ); +} diff --git a/client-next/src/components/SearchBar/TransitModeSelect.tsx b/client-next/src/components/SearchBar/TransitModeSelect.tsx new file mode 100644 index 00000000000..a5db4793991 --- /dev/null +++ b/client-next/src/components/SearchBar/TransitModeSelect.tsx @@ -0,0 +1,60 @@ +import { TransportMode, TripQueryVariables } from '../../gql/graphql.ts'; +import MultiSelectDropdown from './MultiSelectDropdown.tsx'; +import { useCallback, useMemo } from 'react'; + +export function TransitModeSelect({ + tripQueryVariables, + setTripQueryVariables, +}: { + tripQueryVariables: TripQueryVariables; + setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void; +}) { + const values = useMemo(() => { + return ( + tripQueryVariables?.modes?.transportModes + ?.map((transportMode) => transportMode?.transportMode) + .filter((v) => !!v) || [] + ); + }, [tripQueryVariables.modes?.transportModes]); + + const onChange = useCallback( + (values: (TransportMode | null | undefined)[]) => { + const newTransportModes = values.map((v) => ({ + transportMode: v, + })); + + if (newTransportModes.length === 0) { + setTripQueryVariables({ + ...tripQueryVariables, + modes: + tripQueryVariables.modes?.directMode || + tripQueryVariables.modes?.accessMode || + tripQueryVariables.modes?.egressMode + ? { ...tripQueryVariables.modes } + : undefined, + }); + } else { + setTripQueryVariables({ + ...tripQueryVariables, + modes: { + ...tripQueryVariables.modes, + transportModes: newTransportModes.length > 0 ? newTransportModes : undefined, + }, + }); + } + }, + [tripQueryVariables, setTripQueryVariables], + ); + + return ( + ({ + id: mode, + label: mode.toString(), + }))} + values={values} + onChange={onChange} + /> + ); +} diff --git a/client-next/src/components/SearchBar/constants.ts b/client-next/src/components/SearchBar/constants.ts new file mode 100644 index 00000000000..705f207de2d --- /dev/null +++ b/client-next/src/components/SearchBar/constants.ts @@ -0,0 +1 @@ +export const COORDINATE_PRECISION = 7; diff --git a/client-next/src/hooks/useServerInfo.ts b/client-next/src/hooks/useServerInfo.ts new file mode 100644 index 00000000000..aff463d571a --- /dev/null +++ b/client-next/src/hooks/useServerInfo.ts @@ -0,0 +1,31 @@ +import { useEffect, useState } from 'react'; +import { graphql } from '../gql'; +import request from 'graphql-request'; +import { QueryType } from '../gql/graphql.ts'; + +const endpoint = import.meta.env.VITE_API_URL; + +const query = graphql(` + query serverInfo { + serverInfo { + version + otpSerializationVersionId + buildConfigVersion + routerConfigVersion + gitCommit + gitBranch + } + } +`); + +export const useServerInfo = () => { + const [data, setData] = useState(null); + useEffect(() => { + const fetchData = async () => { + setData((await request(endpoint, query)) as QueryType); + }; + fetchData(); + }, []); + + return data?.serverInfo; +}; diff --git a/client-next/src/hooks/useTripQuery.ts b/client-next/src/hooks/useTripQuery.ts new file mode 100644 index 00000000000..3720e2c450a --- /dev/null +++ b/client-next/src/hooks/useTripQuery.ts @@ -0,0 +1,120 @@ +import { useCallback, useEffect, useState } from 'react'; +import { graphql } from '../gql'; +import request from 'graphql-request'; +import { QueryType, TripQueryVariables } from '../gql/graphql.ts'; + +const endpoint = import.meta.env.VITE_API_URL; + +/** + General purpose trip query document for debugging trip searches + TODO: should live in a separate file, and split into fragments for readability + */ +const query = graphql(` + query trip( + $from: Location! + $to: Location! + $arriveBy: Boolean + $dateTime: DateTime + $numTripPatterns: Int + $searchWindow: Int + $modes: Modes + $itineraryFiltersDebug: ItineraryFilterDebugProfile + $pageCursor: String + ) { + trip( + from: $from + to: $to + arriveBy: $arriveBy + dateTime: $dateTime + numTripPatterns: $numTripPatterns + searchWindow: $searchWindow + modes: $modes + itineraryFilters: { debug: $itineraryFiltersDebug } + pageCursor: $pageCursor + ) { + previousPageCursor + nextPageCursor + tripPatterns { + aimedStartTime + aimedEndTime + expectedEndTime + expectedStartTime + duration + distance + legs { + id + mode + aimedStartTime + aimedEndTime + expectedEndTime + expectedStartTime + realtime + distance + duration + fromPlace { + name + } + toPlace { + name + } + toEstimatedCall { + destinationDisplay { + frontText + } + } + line { + publicCode + name + } + authority { + name + } + pointsOnLink { + points + } + } + systemNotices { + tag + } + } + } + } +`); + +type TripQueryHook = ( + variables?: TripQueryVariables, +) => [QueryType | null, boolean, (pageCursor?: string) => Promise]; + +export const useTripQuery: TripQueryHook = (variables) => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(false); + const callback = useCallback( + async (pageCursor?: string) => { + if (loading) { + console.warn('Wait for previous search to finish'); + } else { + if (variables) { + setLoading(true); + if (pageCursor) { + setData((await request(endpoint, query, { ...variables, pageCursor })) as QueryType); + } else { + setData((await request(endpoint, query, variables)) as QueryType); + } + setLoading(false); + } else { + console.warn("Can't search without variables"); + } + } + }, + [setData, variables, loading], + ); + + useEffect(() => { + if (variables?.from.coordinates && variables?.to.coordinates) { + callback(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [variables?.from, variables?.to]); + + return [data, loading, callback]; +}; diff --git a/client-next/src/main.tsx b/client-next/src/main.tsx new file mode 100644 index 00000000000..b5de8eedd8f --- /dev/null +++ b/client-next/src/main.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import { App } from './screens/App.tsx'; +import './style.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/client-next/src/screens/App.tsx b/client-next/src/screens/App.tsx new file mode 100644 index 00000000000..df17bb713bf --- /dev/null +++ b/client-next/src/screens/App.tsx @@ -0,0 +1,50 @@ +import { Stack } from 'react-bootstrap'; +import { MapView } from '../components/MapView/MapView.tsx'; +import { SearchBar } from '../components/SearchBar/SearchBar.tsx'; +import { ItineraryListContainer } from '../components/ItineraryList/ItineraryListContainer.tsx'; +import { useState } from 'react'; +import { TripQueryVariables } from '../gql/graphql.ts'; +import { useTripQuery } from '../hooks/useTripQuery.ts'; +import { useServerInfo } from '../hooks/useServerInfo.ts'; + +const INITIAL_VARIABLES: TripQueryVariables = { + from: {}, + to: {}, + dateTime: new Date().toISOString(), +}; + +export function App() { + const [tripQueryVariables, setTripQueryVariables] = useState(INITIAL_VARIABLES); + const [tripQueryResult, loading, callback] = useTripQuery(tripQueryVariables); + const serverInfo = useServerInfo(); + const [selectedTripPatternIndex, setSelectedTripPatternIndex] = useState(0); + + return ( +
+ + + + + + +
+ ); +} diff --git a/client-next/src/style.css b/client-next/src/style.css new file mode 100644 index 00000000000..b7661779991 --- /dev/null +++ b/client-next/src/style.css @@ -0,0 +1,121 @@ +.app { + min-width: 810px; +} +.navbar-brand { + color: #4078bc; + margin-top: 20px; + margin-right: 14px; +} + +@media (min-width: 2160px) { + .top-content { + height: 75px; + } + + .below-content { + height: calc(100vh - 75px); + } +} + +@media (max-width: 2159px) { + .top-content { + height: 150px; + } + + .below-content { + height: calc(100vh - 150px); + } +} + +@media (max-width: 1120px) { + .top-content { + height: 200px; + } + + .below-content { + height: calc(100vh - 200px); + } +} + +.map-container { + width: 100%; +} + +.search-bar { + padding-left: 1rem; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + margin-right: 1rem; +} + +.search-bar-route-button-wrapper { + height: 5rem; + padding-top: 25px; +} + +.itinerary-list-container { + width: 36rem; + overflow-y: auto; +} + +.itinerary-header-wrapper { + position: relative; + background: #0a53be; +} + +.accordion-item-filtered { + margin-bottom: 0; + background-color: lightpink; + --bs-accordion-btn-bg: lightpink; + --bs-accordion-active-bg: pink; +} + +.itinerary-header-itinerary-number { + position: absolute; +} + +.itinerary-header-itinerary-line { + position: absolute; + height: 2px; + top: 9px; + background: #000; +} + +.itinerary-header-itinerary-time { + position: absolute; + background: #000; + color: #fff; + font-size: 12px; + width: 38px; + height: 15px; + text-align: center; + top: 2px; + padding: 1px; +} + +.itinerary-header-leg-wrapper { + position: absolute; + height: 22px; + font-weight: bold; + text-shadow: none; + margin-top: -1px; + padding-top: 3px; + text-align: center; + overflow: hidden; +} + +.itinerary-header-leg-icon { + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + width: 17px; + height: 17px; + display: inline-block; +} + +.itinerary-header-leg-public-code { + vertical-align: top; + font-size: 14px; + padding-left: 2px; +} diff --git a/client-next/src/util/formatDistance.ts b/client-next/src/util/formatDistance.ts new file mode 100644 index 00000000000..0aa67a030a4 --- /dev/null +++ b/client-next/src/util/formatDistance.ts @@ -0,0 +1,18 @@ +/** + * Format distance + * + * Adapted from src/client/js/otp/util/Geo.js#distanceStringMetric + */ +export function formatDistance(meters: number) { + const kilometers = meters / 1000; + if (kilometers > 100) { + //100 km => 999999999 km + return `${kilometers.toFixed(0)} km`; + } else if (kilometers > 1) { + //1.1 km => 99.9 km + return `${kilometers.toFixed(1)} km`; + } else { + //1m => 999m + return `${meters.toFixed(0)} m`; + } +} diff --git a/client-next/src/util/formatDuration.ts b/client-next/src/util/formatDuration.ts new file mode 100644 index 00000000000..94e51ad9d47 --- /dev/null +++ b/client-next/src/util/formatDuration.ts @@ -0,0 +1,32 @@ +/** + * Format duration in seconds + * + * Adapted from src/client/js/otp/util/Time.js#secsToHrMinSec + */ +export function formatDuration(seconds: number) { + const hrs = Math.floor(seconds / 3600); + const mins = Math.floor(seconds / 60) % 60; + const secs = seconds % 60; + + let formatted = ''; + + if (hrs === 1) { + formatted = `${formatted}${hrs} hr `; + } else if (hrs > 1) { + formatted = `${formatted}${hrs} hrs `; + } + + if (mins === 1) { + formatted = `${formatted}${mins} min `; + } else if (mins > 1) { + formatted = `${formatted}${mins} mins `; + } + + if (secs === 1) { + formatted = `${formatted}${secs} sec `; + } else if (secs > 1) { + formatted = `${formatted}${secs} secs `; + } + + return formatted; +} diff --git a/client-next/src/util/formatTime.ts b/client-next/src/util/formatTime.ts new file mode 100644 index 00000000000..1849640fe3f --- /dev/null +++ b/client-next/src/util/formatTime.ts @@ -0,0 +1,13 @@ +/** + * Format departure and arrival times from scalar dateTime strings + * + * If style argument is provided formatted with ('medium') or without ('short') seconds, + * otherwise seconds are shown if not 0. + */ +export function formatTime(dateTime: string, style?: 'short' | 'medium') { + const parsed = new Date(dateTime); + return parsed.toLocaleTimeString('en-US', { + timeStyle: style ? style : parsed.getSeconds() === 0 ? 'short' : 'medium', + hourCycle: 'h24', + }); +} diff --git a/client-next/src/util/generateTextColor.ts b/client-next/src/util/generateTextColor.ts new file mode 100644 index 00000000000..824dc87f3a2 --- /dev/null +++ b/client-next/src/util/generateTextColor.ts @@ -0,0 +1,40 @@ +/** + * textColor can be black or white. White for dark colors and black for light colors. + * Calculated based on luminance formula: + * sqrt( 0.299*Red^2 + 0.587*Green^2 + 0.114*Blue^2 ) + */ +export function generateTextColor(hexColor: string) { + const color = decodeColor(hexColor); + + //Calculates luminance based on https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color + const newRed = 0.299 * Math.pow(color[0] / 255.0, 2.0); + const newGreen = 0.587 * Math.pow(color[1] / 255.0, 2.0); + const newBlue = 0.114 * Math.pow(color[2] / 255.0, 2.0); + const luminance = Math.sqrt(newRed + newGreen + newBlue); + + if (luminance > 0.66) { + return '#000'; + } else { + return '#fff'; + } +} + +function decodeColor(hex: string): number[] { + return hex2rgb(hex); +} + +function hex2rgb(hex: string) { + if (hex.length === 4) { + return fullHex(hex); + } + + return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)]; +} + +function fullHex(hex: string) { + const r = hex.slice(1, 2); + const g = hex.slice(2, 3); + const b = hex.slice(3, 4); + + return [parseInt(r + r, 16), parseInt(g + g, 16), parseInt(b + b, 16)]; +} diff --git a/client-next/src/util/getColorForMode.ts b/client-next/src/util/getColorForMode.ts new file mode 100644 index 00000000000..0276a1bce52 --- /dev/null +++ b/client-next/src/util/getColorForMode.ts @@ -0,0 +1,21 @@ +import { Mode } from '../gql/graphql.ts'; + +export const getColorForMode = function (mode: Mode) { + if (mode === Mode.Foot) return '#444'; + if (mode === Mode.Bicycle) return '#44f'; + if (mode === Mode.Scooter) return '#88f'; + if (mode === Mode.Car) return '#444'; + if (mode === Mode.Rail) return '#b00'; + if (mode === Mode.Coach) return '#0f0'; + if (mode === Mode.Metro) return '#f00'; + if (mode === Mode.Bus) return '#0f0'; + if (mode === Mode.Tram) return '#f00'; + if (mode === Mode.Trolleybus) return '#0f0'; + if (mode === Mode.Water) return '#f0f'; + if (mode === Mode.Air) return '#f0f'; + if (mode === Mode.Cableway) return '#f0f'; + if (mode === Mode.Funicular) return '#f0f'; + if (mode === Mode.Monorail) return '#f0f'; + if (mode === Mode.Taxi) return '#f0f'; + return '#aaa'; +}; diff --git a/client-next/src/util/isTransitMode.ts b/client-next/src/util/isTransitMode.ts new file mode 100644 index 00000000000..17fa0279bbc --- /dev/null +++ b/client-next/src/util/isTransitMode.ts @@ -0,0 +1,18 @@ +import { Mode } from '../gql/graphql.ts'; + +export function isTransitMode(mode: Mode) { + return ( + mode === Mode.Rail || + mode === Mode.Coach || + mode === Mode.Metro || + mode === Mode.Bus || + mode === Mode.Tram || + mode === Mode.Water || + mode === Mode.Air || + mode === Mode.Cableway || + mode === Mode.Funicular || + mode === Mode.Trolleybus || + mode === Mode.Monorail || + mode === Mode.Taxi + ); +} diff --git a/client-next/src/vite-env.d.ts b/client-next/src/vite-env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/client-next/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/client-next/tsconfig.json b/client-next/tsconfig.json new file mode 100644 index 00000000000..a7fc6fbf23d --- /dev/null +++ b/client-next/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/client-next/tsconfig.node.json b/client-next/tsconfig.node.json new file mode 100644 index 00000000000..42872c59f5b --- /dev/null +++ b/client-next/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/client-next/vite.config.ts b/client-next/vite.config.ts new file mode 100644 index 00000000000..f5fa0ab82ee --- /dev/null +++ b/client-next/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + base: '/debug-client-preview/', + build: { + outDir: '../src/client/debug-client-preview', + emptyOutDir: true, + }, +}); diff --git a/docs/Changelog.md b/docs/Changelog.md index 08a323fe6f6..cffe55c0f6f 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -57,6 +57,12 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix issue where stop points are sometimes added twice to index [#5552](https://github.com/opentripplanner/OpenTripPlanner/pull/5552) - Improve shutdown logic [#5514](https://github.com/opentripplanner/OpenTripPlanner/pull/5514) - Create TripOnServiceDate for new siri realtime servicejourneys [#5542](https://github.com/opentripplanner/OpenTripPlanner/pull/5542) +- New debug client [#5334](https://github.com/opentripplanner/OpenTripPlanner/pull/5334) +- Improve paging - avoid duplicates and missed itineraries when paging [#5551](https://github.com/opentripplanner/OpenTripPlanner/pull/5551) +- Create own parking preferences for bike and car in the internal model [#5521](https://github.com/opentripplanner/OpenTripPlanner/pull/5521) +- Make Transmodel GraphQl API an official OTP API [#5573](https://github.com/opentripplanner/OpenTripPlanner/pull/5573) +- Add option to include stations in `nearest` search [#5390](https://github.com/opentripplanner/OpenTripPlanner/pull/5390) +- GTFS Flex spec update: separate columns for `location_id`, `location_group_id` [#5564](https://github.com/opentripplanner/OpenTripPlanner/pull/5564) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) diff --git a/docs/Configuration.md b/docs/Configuration.md index 998842d3ffb..f1c0af287ab 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -233,7 +233,8 @@ Here is a list of all features which can be toggled on/off and their default val | `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | | | `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | | | `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | | -| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_(GTFS) and Interchanges(NeTEx). Turing this _off_ will increase the routing performance a little. | ✓️ | | +| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | | +| `TransmodelGraphQlApi` | Enable Transmodel (NeTEx) GraphQL API. | ✓️ | ✓️ | | `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ | | `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | | | `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ | @@ -247,7 +248,6 @@ Here is a list of all features which can be toggled on/off and their default val | `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ | | `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ | | `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ | -| `SandboxAPITransmodelApi` | Enable Entur Transmodel(NeTEx) GraphQL API. | | ✓️ | | `SandboxAPITravelTime` | Enable the isochrone/travel time surface API. | | ✓️ | | `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ | | `VehicleToStopHeuristics` | Enable improved heuristic for park-and-ride queries. | | ✓️ | diff --git a/docs/RouteRequest.md b/docs/RouteRequest.md index af6dcf00142..9e891cf732d 100644 --- a/docs/RouteRequest.md +++ b/docs/RouteRequest.md @@ -19,7 +19,7 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe | arriveBy | `boolean` | Whether the trip should depart or arrive at the specified date and time. | *Optional* | `false` | 2.0 | | [bikeBoardCost](#rd_bikeBoardCost) | `integer` | Prevents unnecessary transfers by adding a cost for boarding a vehicle. | *Optional* | `600` | 2.0 | | bikeParkCost | `integer` | Cost to park a bike. | *Optional* | `120` | 2.0 | -| bikeParkTime | `integer` | Time to park a bike. | *Optional* | `60` | 2.0 | +| bikeParkTime | `duration` | Time to park a bike. | *Optional* | `"PT1M"` | 2.0 | | bikeReluctance | `double` | A multiplier for how bad biking is, compared to being in transit for equal lengths of time. | *Optional* | `2.0` | 2.0 | | bikeSpeed | `double` | Max bike speed along streets, in meters per second | *Optional* | `5.0` | 2.0 | | bikeStairsReluctance | `double` | How bad is it to walk the bicycle up/down a flight of stairs compared to taking a detour. | *Optional* | `10.0` | 2.3 | @@ -35,7 +35,7 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe | carDecelerationSpeed | `double` | The deceleration speed of an automobile, in meters per second per second. | *Optional* | `2.9` | 2.0 | | carDropoffTime | `integer` | Time to park a car in a park and ride, w/o taking into account driving and walking cost. | *Optional* | `120` | 2.0 | | carParkCost | `integer` | Cost of parking a car. | *Optional* | `120` | 2.1 | -| carParkTime | `integer` | Time to park a car | *Optional* | `60` | 2.1 | +| carParkTime | `duration` | Time to park a car | *Optional* | `"PT1M"` | 2.1 | | carPickupCost | `integer` | Add a cost for car pickup changes when a pickup or drop off takes place | *Optional* | `120` | 2.1 | | carPickupTime | `integer` | Add a time for car pickup changes when a pickup or drop off takes place | *Optional* | `60` | 2.1 | | carReluctance | `double` | A multiplier for how bad driving is, compared to being in transit for equal lengths of time. | *Optional* | `2.0` | 2.0 | @@ -480,6 +480,9 @@ Sometimes there is a need to configure a longer alighting times for specific mod Tags with which a vehicle parking will not be used. If empty, no tags are banned. +Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + +

boardSlackForMode

**Since version:** `2.0` ∙ **Type:** `enum map of duration` ∙ **Cardinality:** `Optional` @@ -714,6 +717,9 @@ done because some street modes searches are much more resource intensive than ot Vehicle parking facilities that don't have one of these tags will receive an extra cost and will therefore be penalised. +Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + +

requiredVehicleParkingTags

**Since version:** `2.1` ∙ **Type:** `string[]` ∙ **Cardinality:** `Optional` @@ -721,6 +727,9 @@ Vehicle parking facilities that don't have one of these tags will receive an ext Tags without which a vehicle parking will not be used. If empty, no tags are required. +Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + +

transferOptimization

**Since version:** `2.1` ∙ **Type:** `object` ∙ **Cardinality:** `Optional` @@ -810,10 +819,15 @@ If not enabled generalizedCost function is used to pick the optimal transfer poi Transit priority groups configuration -Use this to separate transit patterns into groups. Each group will be given a priority -when compared with other groups. Hence, two paths with a different set of groups will BOTH -be returned unless the cost is worse then the relaxation specified in the -`relaxTransitPriorityGroup` parameter. This is only available in the TransmodelAPI for now. +Use this to separate transit patterns into groups. Each group will be given a group-id. A +path (multiple legs) will then have a set of group-ids based on the group-id from each leg. +Hence, two paths with a different set of group-ids will BOTH be optimal unless the cost is +worse than the relaxation specified in the `relaxTransitPriorityGroup` parameter. This is +only available in the TransmodelAPI for now. + +Unmatched patterns are put in the BASE priority-group (group id: 0). This group is special. +If a path only have legs in the base group, then that path dominates other paths, but other +paths must be better to make it. **THIS IS STILL AN EXPERIMENTAL FEATURE - IT MAY CHANGE WITHOUT ANY NOTICE!** @@ -941,7 +955,7 @@ include stairs as a last result. "dropOffTime" : 30, "dropOffCost" : 30 }, - "bikeParkTime" : 60, + "bikeParkTime" : "1m", "bikeParkCost" : 120, "carDropoffTime" : 120, "waitReluctance" : 1.0, diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 34a3db8f6c6..65f50260ee5 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -473,7 +473,7 @@ Used to group requests when monitoring OTP. "dropOffTime" : 30, "dropOffCost" : 30 }, - "bikeParkTime" : 60, + "bikeParkTime" : "1m", "bikeParkCost" : 120, "carDropoffTime" : 120, "waitReluctance" : 1.0, diff --git a/docs/SandboxExtension.md b/docs/SandboxExtension.md index 4a3f500ae80..38988f8245f 100644 --- a/docs/SandboxExtension.md +++ b/docs/SandboxExtension.md @@ -14,7 +14,6 @@ provided "as is". - [Geocoder API](sandbox/GeocoderAPI.md) - Adds an API to search for corners, stops and stations. - [Transfer analyser](sandbox/transferanalyzer.md) - Module used for analyzing the transfers between nearby stops generated by routing via OSM data. -- [Transmodel API](sandbox/TransmodelApi.md) - Enturs GraphQL Transmodel API. - [SIRI Updater](sandbox/SiriUpdater.md) - Update OTP with real-time information from a Transmodel SIRI data source. - [SIRI Azure Updater](sandbox/SiriAzureUpdater.md) - fetch SIRI real-time data through *Azure Service Bus* - [VehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md) - GBFS service directory endpoint. diff --git a/docs/Version-Comparison.md b/docs/Version-Comparison.md index 8700b23e657..454188d022e 100644 --- a/docs/Version-Comparison.md +++ b/docs/Version-Comparison.md @@ -139,10 +139,10 @@ Details of those two APIs are available at the following pages: - [GTFS GraphQL API](apis/GTFS-GraphQL-API.md) - HSL's GraphQL API used by the Digitransit project. -- [Transmodel API](sandbox/TransmodelApi.md) - Entur´s Transmodel API +- [Transmodel API](apis/TransmodelApi.md) - Entur's Transmodel API The plan is to merge the two APIs above, clean it up and make it the new official API. The HSL API -uses GTFS terminology, while the Entur API is Transmodel(NeTEx) based. Both APIs are similar in +uses GTFS terminology, while the Entur API is Transmodel (NeTEx) based. Both APIs are similar in semantics and structure, and provide the same functionality. ## Additional characteristics added in OTP2 diff --git a/docs/apis/Apis.md b/docs/apis/Apis.md index 4d6c7f46694..48b530a57e1 100644 --- a/docs/apis/Apis.md +++ b/docs/apis/Apis.md @@ -6,7 +6,7 @@ The [GTFS GraphQL API](GTFS-GraphQL-API.md) has been used by the Digitransit and projects as a general purpose routing and transit data API in production for many years. If your input data is mostly GTFS then this is probably the best choice as it uses the same vocabulary. -The [Transmodel GraphQL API](../sandbox/TransmodelApi.md) is used at +The [Transmodel GraphQL API](TransmodelApi.md) is used at Entur in production since 2020. Like the GTFS GraphQL API it is also a general purpose API. If your input data is mostly NeTeX then you might want to investigate this API as it uses the [Transmodel vocabulary](https://en.wikipedia.org/wiki/Transmodel) to describe diff --git a/docs/sandbox/TransmodelApi.md b/docs/apis/TransmodelApi.md similarity index 77% rename from docs/sandbox/TransmodelApi.md rename to docs/apis/TransmodelApi.md index 5069966bdbd..ce772734276 100644 --- a/docs/sandbox/TransmodelApi.md +++ b/docs/apis/TransmodelApi.md @@ -4,7 +4,26 @@ - Entur, Norway -## Changelog +## Documentation + +This is the official OTP2 API for Transmodel (NeTEx). The terminology is based on the +Transmodel (NeTEx) with some limitations/simplification. It provides both a routing API +(trip query) and index API for transit data. + +Entur provides a [GraphQL explorer](https://api.entur.io/graphql-explorer) where you may browse the GraphQL schema and try your own +queries. + +When running OTP locally the endpoint is available at: `http://localhost:8080/otp/routers/default/transmodel/index/graphql` + +### Configuration + +To turn this API off, add the feature `TransmodelGraphQlApi : false` in _otp-config.json_. + + +## Changelog - old + +The Transmodel API is now part of the main OTP supported APIs. New changes in the changelog +will be added to the main change log, and NOT here (2023-12-13). - Initial version of Transmodel Graph QL API (September 2019) - Added support for multimodal StopPlaces (November 2019) @@ -43,7 +62,7 @@ [#4074](https://github.com/opentripplanner/OpenTripPlanner/pull/4074) - Transmodel API transport mode not present or null is all transport modes [#4123](https://github.com/opentripplanner/OpenTripPlanner/pull/4123) -- Expose datedServiceJourney from EstimatedCall +- Expose datedServiceJourney from EstimatedCall [#4128](https://github.com/opentripplanner/OpenTripPlanner/pull/4128) - Expose stop-to-stop journey pattern geometries [#4161](https://github.com/opentripplanner/OpenTripPlanner/pull/4161) @@ -58,26 +77,5 @@ - Add flexible stops [#4485](https://github.com/opentripplanner/OpenTripPlanner/pull/4485) -## Documentation - -This is the official Entur OTP2 API. The terminology is based on the Transmodel(NeTEx) with some -limitations/simplification. It provides both a routing API (trip query) and index API for transit -data. - -Entur provide a [GraphQL explorer](https://api.entur.io/graphql-explorer) where you may browse the -GraphQL schema and try your own queries. - -After enabling this feature (see below), the endpoint is available -at: `http://localhost:8080/otp/routers/default/transmodel/index/graphql` - -### OTP2 Official GraphQL API (Not available) - -We **plan** to make a new offical OTP2 API, replacing the REST API. The plan is to base the new API -on this API and the [GTFS GraphQL API](../apis/GTFS-GraphQL-API.md). The new API will most likely have two -"translations": A GTFS version and a Transmodel version, we will try to keep the semantics the same. - -### Configuration - -To enable this you need to add the feature `SandboxAPITransmodelApi`. diff --git a/docs/examples/entur/otp-config.json b/docs/examples/entur/otp-config.json index fb1520688a7..1746cd186d4 100644 --- a/docs/examples/entur/otp-config.json +++ b/docs/examples/entur/otp-config.json @@ -1,7 +1,6 @@ { "otpFeatures": { "ActuatorAPI": true, - "SandboxAPITransmodelApi": true, "FlexRouting": true, "FloatingBike": true, "OptimizeTransfers": true, diff --git a/docs/examples/entur/router-config.json b/docs/examples/entur/router-config.json index bc662453c91..0023dab130a 100644 --- a/docs/examples/entur/router-config.json +++ b/docs/examples/entur/router-config.json @@ -21,7 +21,7 @@ "dropOffTime": 30, "dropOffCost": 30 }, - "bikeParkTime": 60, + "bikeParkTime": "1m", "bikeParkCost": 120, "carDropoffTime": 120, "waitReluctance": 1.0, diff --git a/mkdocs.yml b/mkdocs.yml index 81d3e1c2052..e4341b296fc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -68,6 +68,7 @@ nav: - Introduction: 'apis/Apis.md' - GraphQL Tutorial: 'apis/GraphQL-Tutorial.md' - GTFS GraphQL API: 'apis/GTFS-GraphQL-API.md' + - Transmodel (NeTEx) GraphQL API: 'apis/TransmodelApi.md' - Configuration: - Introduction: 'Configuration.md' - Build: 'BuildConfiguration.md' @@ -94,7 +95,6 @@ nav: - Actuator API: 'sandbox/ActuatorAPI.md' - Direct Transfer Analyzer: 'sandbox/transferanalyzer.md' - Google Cloud Storage: 'sandbox/GoogleCloudStorage.md' - - Transmodel(NeTEx) GraphQL API: 'sandbox/TransmodelApi.md' - SIRI Updaters: 'sandbox/SiriUpdater.md' - SIRI Updater (Azure): 'sandbox/SiriAzureUpdater.md' - Vehicle Rental Service Directory API support: 'sandbox/VehicleRentalServiceDirectory.md' diff --git a/pom.xml b/pom.xml index 24384ffc45b..e740c782b4e 100644 --- a/pom.xml +++ b/pom.xml @@ -56,12 +56,12 @@ - 132 + 134 30.1 2.49 2.16.0 - 3.1.4 + 3.1.5 5.10.1 1.11.5 5.5.3 @@ -69,7 +69,7 @@ 9.8.0 2.0.9 2.0.15 - 1.25 + 1.26 4.0.4 UTF-8 @@ -144,7 +144,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.0 21 @@ -247,7 +247,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.2 + 3.2.3 me.fabriciorby @@ -867,7 +867,7 @@ org.onebusaway onebusaway-gtfs - 1.4.9 + 1.4.10 org.slf4j diff --git a/renovate.json5 b/renovate.json5 index b3511faba9b..5e12724db1b 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -29,6 +29,10 @@ ], "enabled": false }, + { + "matchFiles": ["client-next/package.json"], + "enabled": false + }, { // https://github.com/graphql-java-kickstart/renovate-config/blob/main/default.json "description": "GraphQL Java (ignoring snapshot builds)", @@ -93,7 +97,8 @@ "io.github.git-commit-id:git-commit-id-maven-plugin", "com.hubspot.maven.plugins:prettier-maven-plugin", "com.google.cloud.tools:jib-maven-plugin", - "org.apache.maven.plugins:maven-shade-plugin" + "org.apache.maven.plugins:maven-shade-plugin", + "org.apache.maven.plugins:maven-compiler-plugin" ], "matchPackagePrefixes": [ "org.junit.jupiter:", diff --git a/src/ext-test/java/org/opentripplanner/ext/emissions/EmissionsModuleTest.java b/src/ext-test/java/org/opentripplanner/ext/emissions/EmissionsModuleTest.java index 0594bb2d5af..e45e83a020d 100644 --- a/src/ext-test/java/org/opentripplanner/ext/emissions/EmissionsModuleTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/emissions/EmissionsModuleTest.java @@ -14,6 +14,7 @@ import org.opentripplanner.datastore.file.FileDataSource; import org.opentripplanner.framework.application.OtpFileNames; import org.opentripplanner.graph_builder.ConfiguredDataSource; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.graphbuilder.GtfsFeedParameters; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.test.support.ResourceLoader; @@ -42,7 +43,7 @@ void testMultipleGtfsDataReading() { configuredDataSource, buildConfig, emissionsDataModel, - null + DataImportIssueStore.NOOP ); emissionsModule.buildGraph(); assertEquals( diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java index 624330ba443..e30fb2d8b18 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java @@ -125,7 +125,7 @@ private static void assertLegFareEquals( void calculateFareForSingleAgency() { List rides = List.of(getLeg(COMM_TRANS_AGENCY_ID, "400", 0)); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE); - calculateFare(rides, FareType.senior, TWO_DOLLARS); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE); calculateFare(rides, FareType.youth, ZERO_USD); calculateFare(rides, FareType.electronicSpecial, TWO_DOLLARS); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE); @@ -145,11 +145,7 @@ void calculateFareWithNoFreeTransfer() { getLeg(COMM_TRANS_AGENCY_ID, 2) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3)); - calculateFare( - rides, - FareType.senior, - DEFAULT_TEST_RIDE_PRICE.plus(DEFAULT_TEST_RIDE_PRICE).plus(usDollars(1.25f)) - ); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(3)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare( rides, @@ -429,7 +425,7 @@ void calculateCashFreeTransferKCMetro() { getLeg(KC_METRO_AGENCY_ID, 130) ); calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3)); - calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(2).plus(usDollars(1.25f))); + calculateFare(rides, FareType.senior, DEFAULT_TEST_RIDE_PRICE.times(3)); calculateFare(rides, FareType.youth, Money.ZERO_USD); calculateFare(rides, FareType.electronicSpecial, usDollars(1.25f)); calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE.times(2)); diff --git a/src/ext-test/java/org/opentripplanner/ext/mapping/TransmodelMappingUtilTest.java b/src/ext-test/java/org/opentripplanner/ext/mapping/TransmodelMappingUtilTest.java index 0978bd0309a..ce841be54a7 100644 --- a/src/ext-test/java/org/opentripplanner/ext/mapping/TransmodelMappingUtilTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/mapping/TransmodelMappingUtilTest.java @@ -5,7 +5,7 @@ import java.util.List; import org.junit.jupiter.api.Test; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.organization.Agency; diff --git a/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs.zip b/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs.zip index 146ecfd2320..68c5a57484b 100644 Binary files a/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs.zip and b/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs.zip differ diff --git a/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs/emissions.txt b/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs/emissions.txt index 18fcb3e64de..b89e0c67fa0 100644 --- a/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs/emissions.txt +++ b/src/ext-test/resources/org/opentripplanner/ext/emissions/emissions-test-gtfs/emissions.txt @@ -5,3 +5,7 @@ route_id,avg_co2_per_vehicle_per_km,avg_passenger_count 1004,0.0,0.0 1005,0,-1 1006,0,1 +1007,, +,1, +,,2 +,, \ No newline at end of file diff --git a/src/ext/java/org/opentripplanner/ext/emissions/Co2EmissionsDataReader.java b/src/ext/java/org/opentripplanner/ext/emissions/Co2EmissionsDataReader.java index 54abf58e3a7..597a7d89380 100644 --- a/src/ext/java/org/opentripplanner/ext/emissions/Co2EmissionsDataReader.java +++ b/src/ext/java/org/opentripplanner/ext/emissions/Co2EmissionsDataReader.java @@ -12,6 +12,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.opentripplanner.framework.lang.Sandbox; +import org.opentripplanner.framework.lang.StringUtils; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.slf4j.Logger; @@ -92,30 +93,44 @@ private Map readEmissions(InputStream stream, String feedI String avgCo2PerVehiclePerKmString = reader.get("avg_co2_per_vehicle_per_km"); String avgPassengerCountString = reader.get("avg_passenger_count"); - if (avgCo2PerVehiclePerKmString.isEmpty()) { + if (!StringUtils.hasValue(routeId)) { issueStore.add( "InvalidEmissionData", - "Value for avg_co2_per_vehicle_per_km is missing in the Emissions.txt for route %s", + "Value for routeId is missing in the emissions.txt for line: %s.", + reader.getRawRecord() + ); + } + if (!StringUtils.hasValue(avgCo2PerVehiclePerKmString)) {} + { + issueStore.add( + "InvalidEmissionData", + "Value for avg_co2_per_vehicle_per_km is missing in the emissions.txt for route %s", routeId ); } - if (avgPassengerCountString.isEmpty()) { + if (!StringUtils.hasValue(avgPassengerCountString)) { issueStore.add( "InvalidEmissionData", - "Value for avg_passenger_count is missing in the Emissions.txt for route %s", + "Value for avg_passenger_count is missing in the emissions.txt for route %s", routeId ); } - - Double avgCo2PerVehiclePerMeter = Double.parseDouble(avgCo2PerVehiclePerKmString) / 1000; - Double avgPassengerCount = Double.parseDouble(reader.get("avg_passenger_count")); - Optional emissions = calculateEmissionsPerPassengerPerMeter( - routeId, - avgCo2PerVehiclePerMeter, - avgPassengerCount - ); - if (emissions.isPresent()) { - emissionsData.put(new FeedScopedId(feedId, routeId), emissions.get()); + if ( + StringUtils.hasValue(feedId) && + StringUtils.hasValue(routeId) && + StringUtils.hasValue(avgCo2PerVehiclePerKmString) && + StringUtils.hasValue(avgPassengerCountString) + ) { + Double avgCo2PerVehiclePerMeter = Double.parseDouble(avgCo2PerVehiclePerKmString) / 1000; + Double avgPassengerCount = Double.parseDouble(reader.get("avg_passenger_count")); + Optional emissions = calculateEmissionsPerPassengerPerMeter( + routeId, + avgCo2PerVehiclePerMeter, + avgPassengerCount + ); + if (emissions.isPresent()) { + emissionsData.put(new FeedScopedId(feedId, routeId), emissions.get()); + } } } return emissionsData; diff --git a/src/ext/java/org/opentripplanner/ext/emissions/EmissionsModule.java b/src/ext/java/org/opentripplanner/ext/emissions/EmissionsModule.java index 2da4b091138..a0eb21da779 100644 --- a/src/ext/java/org/opentripplanner/ext/emissions/EmissionsModule.java +++ b/src/ext/java/org/opentripplanner/ext/emissions/EmissionsModule.java @@ -58,6 +58,9 @@ public void buildGraph() { } this.emissionsDataModel.setCo2Emissions(emissionsData); this.emissionsDataModel.setCarAvgCo2PerMeter(carAvgEmissionsPerMeter); + LOG.info( + "Emissions building finished. Number of CO2 emission records saved: " + emissionsData.size() + ); } } } diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index 4f1aca5bf63..42736472767 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -299,18 +299,15 @@ private Optional getSeniorFare( Leg leg ) { var route = leg.getRoute(); + var regularFare = getRegularFare(fareType, rideType, defaultFare, leg); + // Many agencies only provide senior discount if using ORCA return switch (rideType) { - case COMM_TRANS_LOCAL_SWIFT -> optionalUSD(1.25f); - case COMM_TRANS_COMMUTER_EXPRESS -> optionalUSD(2f); - case EVERETT_TRANSIT, SKAGIT_TRANSIT, WHATCOM_LOCAL, SKAGIT_LOCAL -> optionalUSD(0.5f); - case KITSAP_TRANSIT_FAST_FERRY_EASTBOUND -> fareType.equals(FareType.electronicSenior) // Kitsap only provide discounted senior fare for orca. - ? optionalUSD(1f) - : optionalUSD(2f); - case KC_WATER_TAXI_VASHON_ISLAND -> usesOrca(fareType) ? optionalUSD(3f) : optionalUSD(6.75f); - case KC_WATER_TAXI_WEST_SEATTLE -> usesOrca(fareType) - ? optionalUSD(2.5f) - : optionalUSD(5.75f); - case SOUND_TRANSIT, + case COMM_TRANS_LOCAL_SWIFT -> usesOrca(fareType) ? optionalUSD(1.25f) : regularFare; + case COMM_TRANS_COMMUTER_EXPRESS -> usesOrca(fareType) ? optionalUSD(2f) : regularFare; + case SKAGIT_TRANSIT, WHATCOM_LOCAL, SKAGIT_LOCAL -> optionalUSD(0.5f); + case EVERETT_TRANSIT -> usesOrca(fareType) ? optionalUSD(0.5f) : regularFare; + case KITSAP_TRANSIT_FAST_FERRY_EASTBOUND, + SOUND_TRANSIT, SOUND_TRANSIT_BUS, SOUND_TRANSIT_LINK, SOUND_TRANSIT_SOUNDER, @@ -320,10 +317,12 @@ private Optional getSeniorFare( SEATTLE_STREET_CAR, KITSAP_TRANSIT -> fareType.equals(FareType.electronicSenior) ? optionalUSD(1f) - : getRegularFare(fareType, rideType, defaultFare, leg); + : regularFare; + case KC_WATER_TAXI_VASHON_ISLAND -> usesOrca(fareType) ? optionalUSD(3f) : regularFare; + case KC_WATER_TAXI_WEST_SEATTLE -> usesOrca(fareType) ? optionalUSD(2.5f) : regularFare; case KITSAP_TRANSIT_FAST_FERRY_WESTBOUND -> fareType.equals(FareType.electronicSenior) ? optionalUSD(5f) - : optionalUSD(10f); + : regularFare; // Discount specific to Skagit transit and not Orca. case WASHINGTON_STATE_FERRIES -> Optional.of( getWashingtonStateFerriesFare(route.getLongName(), fareType, defaultFare) diff --git a/src/ext/java/org/opentripplanner/ext/siri/SiriTimetableSnapshotSource.java b/src/ext/java/org/opentripplanner/ext/siri/SiriTimetableSnapshotSource.java index eab0496c4f2..345f8deba20 100644 --- a/src/ext/java/org/opentripplanner/ext/siri/SiriTimetableSnapshotSource.java +++ b/src/ext/java/org/opentripplanner/ext/siri/SiriTimetableSnapshotSource.java @@ -4,7 +4,7 @@ import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NOT_MONITORED; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_FUZZY_TRIP_MATCH; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_START_DATE; -import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.NO_TRIP_ID; +import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.TRIP_NOT_FOUND; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.TRIP_NOT_FOUND_IN_PATTERN; import static org.opentripplanner.updater.spi.UpdateError.UpdateErrorType.UNKNOWN; @@ -325,7 +325,7 @@ private Result handleModifiedTrip( trip = tripAndPattern.trip(); pattern = tripAndPattern.tripPattern(); } else { - return UpdateError.result(null, NO_TRIP_ID); + return UpdateError.result(null, TRIP_NOT_FOUND); } Timetable currentTimetable = getCurrentTimetable(pattern, serviceDate); diff --git a/src/ext/java/org/opentripplanner/ext/siri/updater/SiriETHttpTripUpdateSource.java b/src/ext/java/org/opentripplanner/ext/siri/updater/SiriETHttpTripUpdateSource.java index 9dab72446ea..b3abe95dfc2 100644 --- a/src/ext/java/org/opentripplanner/ext/siri/updater/SiriETHttpTripUpdateSource.java +++ b/src/ext/java/org/opentripplanner/ext/siri/updater/SiriETHttpTripUpdateSource.java @@ -49,7 +49,7 @@ public Optional getUpdates() { long t1 = System.currentTimeMillis(); try { var siri = siriLoader.fetchETFeed(requestorRef); - if (siri.isEmpty()) { + if (siri.map(Siri::getServiceDelivery).isEmpty()) { return Optional.empty(); } diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PreferencesMapper.java b/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PreferencesMapper.java deleted file mode 100644 index 35883c8e72b..00000000000 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PreferencesMapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.opentripplanner.ext.transmodelapi.mapping; - -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.BikePreferencesMapper.mapBikePreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.CarPreferencesMapper.mapCarPreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.ItineraryFilterPreferencesMapper.mapItineraryFilterPreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.ItineraryFilterPreferencesMapper.mapRentalPreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.StreetPreferencesMapper.mapStreetPreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.TransferPreferencesMapper.mapTransferPreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.TransitPreferencesMapper.mapTransitPreferences; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.WalkPreferencesMapper.mapWalkPreferences; - -import graphql.schema.DataFetchingEnvironment; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; -import org.opentripplanner.routing.api.request.preference.RoutingPreferences; - -class PreferencesMapper { - - static void mapPreferences( - DataFetchingEnvironment environment, - DataFetcherDecorator callWith, - RoutingPreferences.Builder preferences - ) { - preferences.withStreet(street -> mapStreetPreferences(street, environment, preferences.street()) - ); - preferences.withWalk(walk -> mapWalkPreferences(walk, callWith)); - preferences.withBike(bike -> mapBikePreferences(bike, callWith)); - preferences.withCar(car -> mapCarPreferences(car, callWith)); - preferences.withTransfer(transfer -> mapTransferPreferences(transfer, environment, callWith)); - preferences.withTransit(transit -> mapTransitPreferences(transit, environment, callWith)); - preferences.withItineraryFilter(itineraryFilter -> - mapItineraryFilterPreferences(itineraryFilter, environment, callWith) - ); - preferences.withRental(rental -> mapRentalPreferences(rental, environment, callWith)); - } -} diff --git a/src/main/java/org/opentripplanner/api/common/RequestToPreferencesMapper.java b/src/main/java/org/opentripplanner/api/common/RequestToPreferencesMapper.java index 3729752a593..aa827ae5b4c 100644 --- a/src/main/java/org/opentripplanner/api/common/RequestToPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/api/common/RequestToPreferencesMapper.java @@ -8,6 +8,7 @@ import org.opentripplanner.routing.api.request.preference.ItineraryFilterPreferences; import org.opentripplanner.routing.api.request.preference.Relax; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; +import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.core.BicycleOptimizeType; class RequestToPreferencesMapper { @@ -43,8 +44,11 @@ void map() { private void mapCar() { preferences.withCar(car -> { setIfNotNull(req.carReluctance, car::withReluctance); - setIfNotNull(req.carParkCost, car::withParkCost); - setIfNotNull(req.carParkTime, car::withParkTime); + car.withParking(parking -> { + mapParking(parking); + setIfNotNull(req.carParkCost, parking::withParkCost); + setIfNotNull(req.carParkTime, parking::withParkTime); + }); }); } @@ -64,8 +68,6 @@ private void mapBike() { setIfNotNull(req.bikeBoardCost, bike::withBoardCost); setIfNotNull(req.bikeWalkingSpeed, bike::withWalkingSpeed); setIfNotNull(req.bikeWalkingReluctance, bike::withWalkingReluctance); - setIfNotNull(req.bikeParkCost, bike::withParkCost); - setIfNotNull(req.bikeParkTime, bike::withParkTime); setIfNotNull(req.bikeSwitchTime, bike::withSwitchTime); setIfNotNull(req.bikeSwitchCost, bike::withSwitchCost); setIfNotNull(req.bikeOptimizeType, bike::withOptimizeType); @@ -77,6 +79,12 @@ private void mapBike() { setIfNotNull(req.triangleSafetyFactor, triangle::withSafety); }); } + + bike.withParking(parking -> { + mapParking(parking); + setIfNotNull(req.bikeParkCost, parking::withParkCost); + setIfNotNull(req.bikeParkTime, parking::withParkTime); + }); }); } @@ -167,6 +175,11 @@ private TransitGeneralizedCostFilterParams mapTransitGeneralizedCostFilterParams return new TransitGeneralizedCostFilterParams(costLimitFunction, intervalRelaxFactor); } + private void mapParking(VehicleParkingPreferences.Builder builder) { + builder.withRequiredVehicleParkingTags(req.requiredVehicleParkingTags); + builder.withBannedVehicleParkingTags(req.bannedVehicleParkingTags); + } + private void mapSystem() { preferences.withSystem(system -> { setIfNotNull(req.geoidElevation, system::withGeoidElevation); diff --git a/src/main/java/org/opentripplanner/api/common/RoutingResource.java b/src/main/java/org/opentripplanner/api/common/RoutingResource.java index 74d06e234f1..9cb4f139bc4 100644 --- a/src/main/java/org/opentripplanner/api/common/RoutingResource.java +++ b/src/main/java/org/opentripplanner/api/common/RoutingResource.java @@ -27,8 +27,6 @@ import org.opentripplanner.routing.api.request.preference.ItineraryFilterDebugProfile; import org.opentripplanner.routing.api.request.request.filter.SelectRequest; import org.opentripplanner.routing.api.request.request.filter.TransitFilterRequest; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter.TagsFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; import org.opentripplanner.routing.core.BicycleOptimizeType; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.standalone.config.framework.file.ConfigFileLoader; @@ -653,6 +651,10 @@ public abstract class RoutingResource { @QueryParam("geoidElevation") protected Boolean geoidElevation; + /** + * @deprecated Support has been removed. + */ + @Deprecated @QueryParam("useVehicleParkingAvailabilityInformation") protected Boolean useVehicleParkingAvailabilityInformation; @@ -752,20 +754,6 @@ protected RouteRequest buildRequest(MultivaluedMap queryParamete setIfNotNull(allowedVehicleRentalNetworks, rental::setAllowedNetworks); setIfNotNull(bannedVehicleRentalNetworks, rental::setBannedNetworks); } - { - var parking = journey.parking(); - setIfNotNull( - useVehicleParkingAvailabilityInformation, - parking::setUseAvailabilityInformation - ); - - parking.setFilter( - new VehicleParkingFilterRequest( - new TagsFilter(bannedVehicleParkingTags), - new TagsFilter(requiredVehicleParkingTags) - ) - ); - } setIfNotNull(arriveBy, request::setArriveBy); diff --git a/src/main/java/org/opentripplanner/api/configuration/APIEndpoints.java b/src/main/java/org/opentripplanner/api/configuration/APIEndpoints.java index 7873724dcf4..b0d38aa00cd 100644 --- a/src/main/java/org/opentripplanner/api/configuration/APIEndpoints.java +++ b/src/main/java/org/opentripplanner/api/configuration/APIEndpoints.java @@ -10,8 +10,8 @@ import static org.opentripplanner.framework.application.OTPFeature.SandboxAPIGeocoder; import static org.opentripplanner.framework.application.OTPFeature.SandboxAPIMapboxVectorTilesApi; import static org.opentripplanner.framework.application.OTPFeature.SandboxAPIParkAndRideApi; -import static org.opentripplanner.framework.application.OTPFeature.SandboxAPITransmodelApi; import static org.opentripplanner.framework.application.OTPFeature.SandboxAPITravelTime; +import static org.opentripplanner.framework.application.OTPFeature.TransmodelGraphQlApi; import java.util.ArrayList; import java.util.Collection; @@ -25,11 +25,11 @@ import org.opentripplanner.api.resource.ServerInfo; import org.opentripplanner.api.resource.UpdaterStatusResource; import org.opentripplanner.apis.gtfs.GtfsGraphQLAPI; +import org.opentripplanner.apis.transmodel.TransmodelAPI; import org.opentripplanner.ext.actuator.ActuatorAPI; import org.opentripplanner.ext.geocoder.GeocoderResource; import org.opentripplanner.ext.parkAndRideApi.ParkAndRideResource; import org.opentripplanner.ext.reportapi.resource.ReportResource; -import org.opentripplanner.ext.transmodelapi.TransmodelAPI; import org.opentripplanner.ext.traveltime.TravelTimeResource; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.framework.application.OTPFeature; @@ -51,16 +51,16 @@ private APIEndpoints() { // Add feature enabled APIs, these can be enabled by default, some is not. // See the OTPFeature enum for details. addIfEnabled(APIBikeRental, BikeRental.class); - addIfEnabled(APIServerInfo, ServerInfo.class); addIfEnabled(APIGraphInspectorTile, GraphInspectorTileResource.class); addIfEnabled(APIGraphInspectorTile, GraphInspectorVectorTileResource.class); + addIfEnabled(APIServerInfo, ServerInfo.class); addIfEnabled(APIUpdaterStatus, UpdaterStatusResource.class); + addIfEnabled(GtfsGraphQlApi, GtfsGraphQLAPI.class); + addIfEnabled(TransmodelGraphQlApi, TransmodelAPI.class); // Sandbox extension APIs addIfEnabled(ActuatorAPI, ActuatorAPI.class); addIfEnabled(ReportApi, ReportResource.class); - addIfEnabled(SandboxAPITransmodelApi, TransmodelAPI.class); - addIfEnabled(GtfsGraphQlApi, GtfsGraphQLAPI.class); addIfEnabled(SandboxAPIMapboxVectorTilesApi, VectorTilesResource.class); addIfEnabled(SandboxAPIParkAndRideApi, ParkAndRideResource.class); addIfEnabled(SandboxAPIGeocoder, GeocoderResource.class); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java index 18f5a7730d5..3fb339daa32 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java @@ -91,6 +91,7 @@ public static PlaceType toModel(GraphQLFilterPlaceType type) { case CAR_PARK -> PlaceType.CAR_PARK; case DEPARTURE_ROW -> PlaceType.PATTERN_AT_STOP; case STOP -> PlaceType.STOP; + case STATION -> PlaceType.STATION; }; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceInterfaceTypeResolver.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceInterfaceTypeResolver.java index 67ec004759d..cb2bfc77c32 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceInterfaceTypeResolver.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceInterfaceTypeResolver.java @@ -9,6 +9,7 @@ import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalVehicle; import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.site.Station; public class PlaceInterfaceTypeResolver implements TypeResolver { @@ -45,7 +46,7 @@ public GraphQLObjectType getType(TypeResolutionEnvironment environment) { if (o instanceof PatternAtStop) { return schema.getObjectType("DepartureRow"); } - if (o instanceof RegularStop) { + if (o instanceof RegularStop || o instanceof Station) { return schema.getObjectType("Stop"); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlanImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlanImpl.java index 4e5c4584495..9ae58be1334 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlanImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlanImpl.java @@ -8,7 +8,7 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.StopArrival; -import org.opentripplanner.model.plan.pagecursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; import org.opentripplanner.routing.api.response.RoutingError; import org.opentripplanner.routing.api.response.RoutingResponse; import org.opentripplanner.routing.api.response.TripSearchMetadata; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 1c2a7b7c72a..d749987384c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -17,9 +17,11 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.locationtech.jts.geom.Coordinate; @@ -75,6 +77,10 @@ public class QueryTypeImpl implements GraphQLDataFetchers.GraphQLQueryType { DataImportIssueStore.NOOP ); + private final List DEFAULT_PLACE_TYPES = List.copyOf( + EnumSet.complementOf(EnumSet.of(PlaceType.STATION)) + ); + @Override public DataFetcher> agencies() { return environment -> getTransitService(environment).getAgencies(); @@ -276,6 +282,7 @@ public DataFetcher fuzzyTrip() { public DataFetcher> nearest() { return environment -> { List filterByStops = null; + List filterByStations = null; List filterByRoutes = null; List filterByBikeRentalStations = null; // TODO implement @@ -293,6 +300,10 @@ public DataFetcher> nearest() { filterByIds.getGraphQLStops() != null ? filterByIds.getGraphQLStops().stream().map(FeedScopedId::parse).toList() : null; + filterByStations = + filterByIds.getGraphQLStations() != null + ? filterByIds.getGraphQLStations().stream().map(FeedScopedId::parse).toList() + : null; filterByRoutes = filterByIds.getGraphQLRoutes() != null ? filterByIds.getGraphQLRoutes().stream().map(FeedScopedId::parse).toList() @@ -318,7 +329,7 @@ public DataFetcher> nearest() { : null; List filterByPlaceTypes = args.getGraphQLFilterByPlaceTypes() != null ? args.getGraphQLFilterByPlaceTypes().stream().map(GraphQLUtils::toModel).toList() - : null; + : DEFAULT_PLACE_TYPES; List places; try { @@ -333,6 +344,7 @@ public DataFetcher> nearest() { filterByModes, filterByPlaceTypes, filterByStops, + filterByStations, filterByRoutes, filterByBikeRentalStations, getTransitService(environment) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index cba63739dd5..ecc038fec18 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -237,6 +237,7 @@ public enum GraphQLFilterPlaceType { BIKE_PARK, CAR_PARK, DEPARTURE_ROW, + STATION, STOP, VEHICLE_RENT, } @@ -372,6 +373,7 @@ public static class GraphQLInputFiltersInput { private List bikeRentalStations; private List carParks; private List routes; + private List stations; private List stops; public GraphQLInputFiltersInput(Map args) { @@ -380,6 +382,7 @@ public GraphQLInputFiltersInput(Map args) { this.bikeRentalStations = (List) args.get("bikeRentalStations"); this.carParks = (List) args.get("carParks"); this.routes = (List) args.get("routes"); + this.stations = (List) args.get("stations"); this.stops = (List) args.get("stops"); } } @@ -400,6 +403,10 @@ public List getGraphQLRoutes() { return this.routes; } + public List getGraphQLStations() { + return this.stations; + } + public List getGraphQLStops() { return this.stops; } @@ -420,6 +427,10 @@ public void setGraphQLRoutes(List routes) { this.routes = routes; } + public void setGraphQLStations(List stations) { + this.stations = stations; + } + public void setGraphQLStops(List stops) { this.stops = stops; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java b/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java index 9b8d8e02dec..ab9e8bce823 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapper.java @@ -21,11 +21,9 @@ import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.framework.CostLinearFunction; import org.opentripplanner.routing.api.request.preference.ItineraryFilterDebugProfile; +import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.api.request.request.filter.SelectRequest; import org.opentripplanner.routing.api.request.request.filter.TransitFilterRequest; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter.TagsFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; import org.opentripplanner.routing.core.BicycleOptimizeType; import org.opentripplanner.transit.model.basic.MainAndSubMode; import org.opentripplanner.transit.model.basic.TransitMode; @@ -84,9 +82,14 @@ public static RouteRequest toRouteRequest( callWith.argument("triangle.safetyFactor", triangle::withSafety); }); } + + bike.withParking(parking -> setParkingPreferences(callWith, parking)); }); - preferences.withCar(car -> callWith.argument("carReluctance", car::withReluctance)); + preferences.withCar(car -> { + callWith.argument("carReluctance", car::withReluctance); + car.withParking(parking -> setParkingPreferences(callWith, parking)); + }); preferences.withWalk(b -> { callWith.argument("walkReluctance", b::withReluctance); @@ -244,19 +247,6 @@ public static RouteRequest toRouteRequest( (Collection v) -> vehicleRental.setBannedNetworks(new HashSet<>(v)) ); - var parking = request.journey().parking(); - callWith.argument("parking.unpreferredCost", parking::setUnpreferredCost); - - callWith.argument( - "parking.filters", - (Collection> filters) -> parking.setFilter(parseFilters(filters)) - ); - - callWith.argument( - "parking.preferred", - (Collection> filters) -> parking.setPreferred(parseFilters(filters)) - ); - callWith.argument( "locale", (String v) -> request.setLocale(GraphQLUtils.getLocale(environment, v)) @@ -264,17 +254,16 @@ public static RouteRequest toRouteRequest( return request; } - private static VehicleParkingFilterRequest parseFilters(Collection> filters) { - var not = parseFilters(filters, "not"); - var select = parseFilters(filters, "select"); - return new VehicleParkingFilterRequest(not, select); + private static Set parseNotFilters(Collection> filters) { + return parseFilters(filters, "not"); + } + + private static Set parseSelectFilters(Collection> filters) { + return parseFilters(filters, "select"); } @Nonnull - private static Set parseFilters( - Collection> filters, - String key - ) { + private static Set parseFilters(Collection> filters, String key) { return filters .stream() .flatMap(f -> @@ -283,14 +272,12 @@ private static Set parseFilters( .collect(Collectors.toSet()); } - private static Stream parseOperation( - Collection>> map - ) { + private static Stream parseOperation(Collection>> map) { return map .stream() - .map(f -> { + .flatMap(f -> { var tags = f.getOrDefault("tags", List.of()); - return new TagsFilter(Set.copyOf(tags)); + return tags.stream(); }); } @@ -314,6 +301,29 @@ private static GenericLocation toGenericLocation(Map m) { return new GenericLocation(lat, lng); } + private static void setParkingPreferences( + CallerWithEnvironment callWith, + VehicleParkingPreferences.Builder parking + ) { + callWith.argument("parking.unpreferredCost", parking::withUnpreferredVehicleParkingTagCost); + + callWith.argument( + "parking.filters", + (Collection> filters) -> { + parking.withRequiredVehicleParkingTags(parseSelectFilters(filters)); + parking.withBannedVehicleParkingTags(parseNotFilters(filters)); + } + ); + + callWith.argument( + "parking.preferred", + (Collection> preferred) -> { + parking.withPreferredVehicleParkingTags(parseSelectFilters(preferred)); + parking.withNotPreferredVehicleParkingTags(parseNotFilters(preferred)); + } + ); + } + private static class CallerWithEnvironment { private final DataFetchingEnvironment environment; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelAPI.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelAPI.java rename to src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java index a1623e6eedf..6af4ab1953c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelAPI.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import com.fasterxml.jackson.databind.ObjectMapper; import graphql.schema.GraphQLSchema; @@ -22,8 +22,8 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.transit.service.TransitModel; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelAPIParameters.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPIParameters.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelAPIParameters.java rename to src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPIParameters.java index 498c8539b4d..5ab64dcd2e6 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelAPIParameters.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPIParameters.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import java.util.Collection; import org.opentripplanner.ext.actuator.MicrometerGraphQLInstrumentation; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraph.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraph.java rename to src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java index 66547da6653..051e369dde0 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraph.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraph.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import graphql.ExecutionInput; import graphql.ExecutionResult; @@ -17,9 +17,9 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.opentripplanner.apis.transmodel.support.AbortOnTimeoutExecutionStrategy; +import org.opentripplanner.apis.transmodel.support.ExecutionResultMapper; import org.opentripplanner.ext.actuator.MicrometerGraphQLInstrumentation; -import org.opentripplanner.ext.transmodelapi.support.AbortOnTimeoutExecutionStrategy; -import org.opentripplanner.ext.transmodelapi.support.ExecutionResultMapper; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.framework.application.OTPRequestTimeoutException; import org.opentripplanner.framework.concurrent.OtpRequestThreadFactory; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLPlanner.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLPlanner.java similarity index 91% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLPlanner.java rename to src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLPlanner.java index a9d369a3982..39c7aa9c851 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLPlanner.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLPlanner.java @@ -1,13 +1,13 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import graphql.execution.DataFetcherResult; import graphql.schema.DataFetchingEnvironment; import java.util.List; import java.util.Locale; import java.util.Map; -import org.opentripplanner.ext.transmodelapi.mapping.TripRequestMapper; -import org.opentripplanner.ext.transmodelapi.mapping.ViaRequestMapper; -import org.opentripplanner.ext.transmodelapi.model.PlanResponse; +import org.opentripplanner.apis.transmodel.mapping.TripRequestMapper; +import org.opentripplanner.apis.transmodel.mapping.ViaRequestMapper; +import org.opentripplanner.apis.transmodel.model.PlanResponse; import org.opentripplanner.routing.algorithm.mapping.TripPlanMapper; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.RouteViaRequest; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLSchema.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLSchema.java rename to src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java index 40a5d936885..00bf98c703f 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLSchema.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java @@ -1,12 +1,12 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import static java.lang.Boolean.TRUE; import static java.util.Collections.emptyList; -import static org.opentripplanner.ext.transmodelapi.mapping.SeverityMapper.getTransmodelSeverity; -import static org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper.mapIDsToDomainNullSafe; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.FILTER_PLACE_TYPE_ENUM; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.MULTI_MODAL_MODE; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; +import static org.opentripplanner.apis.transmodel.mapping.SeverityMapper.getTransmodelSeverity; +import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.FILTER_PLACE_TYPE_ENUM; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.MULTI_MODAL_MODE; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.TRANSPORT_MODE; import static org.opentripplanner.model.projectinfo.OtpProjectInfo.projectInfo; import graphql.Scalars; @@ -41,63 +41,63 @@ import java.util.stream.Stream; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Envelope; -import org.opentripplanner.ext.transmodelapi.mapping.PlaceMapper; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.model.DefaultRouteRequestType; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.TransmodelPlaceType; -import org.opentripplanner.ext.transmodelapi.model.framework.AuthorityType; -import org.opentripplanner.ext.transmodelapi.model.framework.BrandingType; -import org.opentripplanner.ext.transmodelapi.model.framework.InfoLinkType; -import org.opentripplanner.ext.transmodelapi.model.framework.MultilingualStringType; -import org.opentripplanner.ext.transmodelapi.model.framework.NoticeType; -import org.opentripplanner.ext.transmodelapi.model.framework.OperatorType; -import org.opentripplanner.ext.transmodelapi.model.framework.PenaltyForStreetModeType; -import org.opentripplanner.ext.transmodelapi.model.framework.PointsOnLinkType; -import org.opentripplanner.ext.transmodelapi.model.framework.RentalVehicleTypeType; -import org.opentripplanner.ext.transmodelapi.model.framework.ServerInfoType; -import org.opentripplanner.ext.transmodelapi.model.framework.StreetModeDurationInputType; -import org.opentripplanner.ext.transmodelapi.model.framework.SystemNoticeType; -import org.opentripplanner.ext.transmodelapi.model.framework.ValidityPeriodType; -import org.opentripplanner.ext.transmodelapi.model.network.DestinationDisplayType; -import org.opentripplanner.ext.transmodelapi.model.network.GroupOfLinesType; -import org.opentripplanner.ext.transmodelapi.model.network.JourneyPatternType; -import org.opentripplanner.ext.transmodelapi.model.network.LineType; -import org.opentripplanner.ext.transmodelapi.model.network.PresentationType; -import org.opentripplanner.ext.transmodelapi.model.network.StopToStopGeometryType; -import org.opentripplanner.ext.transmodelapi.model.plan.ElevationProfileStepType; -import org.opentripplanner.ext.transmodelapi.model.plan.LegType; -import org.opentripplanner.ext.transmodelapi.model.plan.PathGuidanceType; -import org.opentripplanner.ext.transmodelapi.model.plan.PlanPlaceType; -import org.opentripplanner.ext.transmodelapi.model.plan.RoutingErrorType; -import org.opentripplanner.ext.transmodelapi.model.plan.TripPatternType; -import org.opentripplanner.ext.transmodelapi.model.plan.TripQuery; -import org.opentripplanner.ext.transmodelapi.model.plan.TripType; -import org.opentripplanner.ext.transmodelapi.model.plan.ViaLocationInputType; -import org.opentripplanner.ext.transmodelapi.model.plan.ViaSegmentInputType; -import org.opentripplanner.ext.transmodelapi.model.plan.ViaTripQuery; -import org.opentripplanner.ext.transmodelapi.model.plan.ViaTripType; -import org.opentripplanner.ext.transmodelapi.model.siri.et.EstimatedCallType; -import org.opentripplanner.ext.transmodelapi.model.siri.sx.AffectsType; -import org.opentripplanner.ext.transmodelapi.model.siri.sx.PtSituationElementType; -import org.opentripplanner.ext.transmodelapi.model.stop.BikeParkType; -import org.opentripplanner.ext.transmodelapi.model.stop.BikeRentalStationType; -import org.opentripplanner.ext.transmodelapi.model.stop.MonoOrMultiModalStation; -import org.opentripplanner.ext.transmodelapi.model.stop.PlaceAtDistanceType; -import org.opentripplanner.ext.transmodelapi.model.stop.PlaceInterfaceType; -import org.opentripplanner.ext.transmodelapi.model.stop.QuayAtDistanceType; -import org.opentripplanner.ext.transmodelapi.model.stop.QuayType; -import org.opentripplanner.ext.transmodelapi.model.stop.RentalVehicleType; -import org.opentripplanner.ext.transmodelapi.model.stop.StopPlaceType; -import org.opentripplanner.ext.transmodelapi.model.stop.TariffZoneType; -import org.opentripplanner.ext.transmodelapi.model.timetable.BookingArrangementType; -import org.opentripplanner.ext.transmodelapi.model.timetable.DatedServiceJourneyQuery; -import org.opentripplanner.ext.transmodelapi.model.timetable.DatedServiceJourneyType; -import org.opentripplanner.ext.transmodelapi.model.timetable.InterchangeType; -import org.opentripplanner.ext.transmodelapi.model.timetable.ServiceJourneyType; -import org.opentripplanner.ext.transmodelapi.model.timetable.TimetabledPassingTimeType; -import org.opentripplanner.ext.transmodelapi.model.timetable.TripMetadataType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.PlaceMapper; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.model.DefaultRouteRequestType; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.TransmodelPlaceType; +import org.opentripplanner.apis.transmodel.model.framework.AuthorityType; +import org.opentripplanner.apis.transmodel.model.framework.BrandingType; +import org.opentripplanner.apis.transmodel.model.framework.InfoLinkType; +import org.opentripplanner.apis.transmodel.model.framework.MultilingualStringType; +import org.opentripplanner.apis.transmodel.model.framework.NoticeType; +import org.opentripplanner.apis.transmodel.model.framework.OperatorType; +import org.opentripplanner.apis.transmodel.model.framework.PenaltyForStreetModeType; +import org.opentripplanner.apis.transmodel.model.framework.PointsOnLinkType; +import org.opentripplanner.apis.transmodel.model.framework.RentalVehicleTypeType; +import org.opentripplanner.apis.transmodel.model.framework.ServerInfoType; +import org.opentripplanner.apis.transmodel.model.framework.StreetModeDurationInputType; +import org.opentripplanner.apis.transmodel.model.framework.SystemNoticeType; +import org.opentripplanner.apis.transmodel.model.framework.ValidityPeriodType; +import org.opentripplanner.apis.transmodel.model.network.DestinationDisplayType; +import org.opentripplanner.apis.transmodel.model.network.GroupOfLinesType; +import org.opentripplanner.apis.transmodel.model.network.JourneyPatternType; +import org.opentripplanner.apis.transmodel.model.network.LineType; +import org.opentripplanner.apis.transmodel.model.network.PresentationType; +import org.opentripplanner.apis.transmodel.model.network.StopToStopGeometryType; +import org.opentripplanner.apis.transmodel.model.plan.ElevationProfileStepType; +import org.opentripplanner.apis.transmodel.model.plan.LegType; +import org.opentripplanner.apis.transmodel.model.plan.PathGuidanceType; +import org.opentripplanner.apis.transmodel.model.plan.PlanPlaceType; +import org.opentripplanner.apis.transmodel.model.plan.RoutingErrorType; +import org.opentripplanner.apis.transmodel.model.plan.TripPatternType; +import org.opentripplanner.apis.transmodel.model.plan.TripQuery; +import org.opentripplanner.apis.transmodel.model.plan.TripType; +import org.opentripplanner.apis.transmodel.model.plan.ViaLocationInputType; +import org.opentripplanner.apis.transmodel.model.plan.ViaSegmentInputType; +import org.opentripplanner.apis.transmodel.model.plan.ViaTripQuery; +import org.opentripplanner.apis.transmodel.model.plan.ViaTripType; +import org.opentripplanner.apis.transmodel.model.siri.et.EstimatedCallType; +import org.opentripplanner.apis.transmodel.model.siri.sx.AffectsType; +import org.opentripplanner.apis.transmodel.model.siri.sx.PtSituationElementType; +import org.opentripplanner.apis.transmodel.model.stop.BikeParkType; +import org.opentripplanner.apis.transmodel.model.stop.BikeRentalStationType; +import org.opentripplanner.apis.transmodel.model.stop.MonoOrMultiModalStation; +import org.opentripplanner.apis.transmodel.model.stop.PlaceAtDistanceType; +import org.opentripplanner.apis.transmodel.model.stop.PlaceInterfaceType; +import org.opentripplanner.apis.transmodel.model.stop.QuayAtDistanceType; +import org.opentripplanner.apis.transmodel.model.stop.QuayType; +import org.opentripplanner.apis.transmodel.model.stop.RentalVehicleType; +import org.opentripplanner.apis.transmodel.model.stop.StopPlaceType; +import org.opentripplanner.apis.transmodel.model.stop.TariffZoneType; +import org.opentripplanner.apis.transmodel.model.timetable.BookingArrangementType; +import org.opentripplanner.apis.transmodel.model.timetable.DatedServiceJourneyQuery; +import org.opentripplanner.apis.transmodel.model.timetable.DatedServiceJourneyType; +import org.opentripplanner.apis.transmodel.model.timetable.InterchangeType; +import org.opentripplanner.apis.transmodel.model.timetable.ServiceJourneyType; +import org.opentripplanner.apis.transmodel.model.timetable.TimetabledPassingTimeType; +import org.opentripplanner.apis.transmodel.model.timetable.TripMetadataType; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.model.plan.legreference.LegReference; import org.opentripplanner.model.plan.legreference.LegReferenceSerializer; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -900,6 +900,7 @@ private GraphQLSchema create() { .argument(relay.getConnectionFieldArguments()) .dataFetcher(environment -> { List filterByStops = null; + List filterByStations = null; List filterByRoutes = null; List filterByBikeRentalStations = null; List filterByBikeParks = null; @@ -949,6 +950,7 @@ private GraphQLSchema create() { filterByTransportModes, filterByPlaceTypes, filterByStops, + filterByStations, filterByRoutes, filterByBikeRentalStations, GqlUtil.getTransitService(environment) diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelRequestContext.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelRequestContext.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelRequestContext.java rename to src/main/java/org/opentripplanner/apis/transmodel/TransmodelRequestContext.java index 66fae073975..ca4cdd62ee9 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/TransmodelRequestContext.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelRequestContext.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import org.opentripplanner.routing.api.RoutingService; import org.opentripplanner.standalone.api.OtpServerRequestContext; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/FilterMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/FilterMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java index c2282c46e4b..9141ce4c104 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/FilterMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java @@ -1,15 +1,15 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; -import static org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper.mapIDsToDomainNullSafe; +import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe; import graphql.schema.DataFetchingEnvironment; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.request.filter.SelectRequest; import org.opentripplanner.routing.api.request.request.filter.TransitFilter; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/GenericLocationMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/GenericLocationMapper.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/GenericLocationMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/GenericLocationMapper.java index 860e014f5b4..2fb0ca876e3 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/GenericLocationMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/GenericLocationMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import java.util.Map; import org.opentripplanner.model.GenericLocation; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/GeometryMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/GeometryMapper.java similarity index 87% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/GeometryMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/GeometryMapper.java index e69fd164c76..e2bf687e3b8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/GeometryMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/GeometryMapper.java @@ -1,8 +1,8 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import java.util.ArrayList; import java.util.List; -import org.opentripplanner.ext.transmodelapi.model.util.EncodedPolylineBeanWithStops; +import org.opentripplanner.apis.transmodel.model.util.EncodedPolylineBeanWithStops; import org.opentripplanner.framework.geometry.EncodedPolyline; import org.opentripplanner.transit.model.network.TripPattern; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/OccupancyStatusMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/OccupancyStatusMapper.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/OccupancyStatusMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/OccupancyStatusMapper.java index 978f8d46c2c..f764ca903bc 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/OccupancyStatusMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/OccupancyStatusMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import org.opentripplanner.transit.model.timetable.OccupancyStatus; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PassThroughLocationMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/PassThroughLocationMapper.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PassThroughLocationMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/PassThroughLocationMapper.java index 76bd1464e0f..951467e8727 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PassThroughLocationMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/PassThroughLocationMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PlaceMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/PlaceMapper.java similarity index 85% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PlaceMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/PlaceMapper.java index 93ca73cebfa..68f2ffe5199 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/PlaceMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/PlaceMapper.java @@ -1,8 +1,8 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import java.util.List; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.model.TransmodelPlaceType; +import org.opentripplanner.apis.transmodel.model.TransmodelPlaceType; import org.opentripplanner.routing.graphfinder.PlaceType; /** diff --git a/src/main/java/org/opentripplanner/apis/transmodel/mapping/PreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/PreferencesMapper.java new file mode 100644 index 00000000000..2f8ea15515e --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/PreferencesMapper.java @@ -0,0 +1,35 @@ +package org.opentripplanner.apis.transmodel.mapping; + +import static org.opentripplanner.apis.transmodel.mapping.preferences.BikePreferencesMapper.mapBikePreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.CarPreferencesMapper.mapCarPreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.ItineraryFilterPreferencesMapper.mapItineraryFilterPreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.ItineraryFilterPreferencesMapper.mapRentalPreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.StreetPreferencesMapper.mapStreetPreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.TransferPreferencesMapper.mapTransferPreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.TransitPreferencesMapper.mapTransitPreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.WalkPreferencesMapper.mapWalkPreferences; + +import graphql.schema.DataFetchingEnvironment; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; +import org.opentripplanner.routing.api.request.preference.RoutingPreferences; + +class PreferencesMapper { + + static void mapPreferences( + DataFetchingEnvironment environment, + DataFetcherDecorator callWith, + RoutingPreferences.Builder preferences + ) { + preferences.withStreet(street -> mapStreetPreferences(street, environment, preferences.street()) + ); + preferences.withWalk(walk -> mapWalkPreferences(walk, callWith)); + preferences.withBike(bike -> mapBikePreferences(bike, callWith)); + preferences.withCar(car -> mapCarPreferences(car, callWith)); + preferences.withTransfer(transfer -> mapTransferPreferences(transfer, environment, callWith)); + preferences.withTransit(transit -> mapTransitPreferences(transit, environment, callWith)); + preferences.withItineraryFilter(itineraryFilter -> + mapItineraryFilterPreferences(itineraryFilter, environment, callWith) + ); + preferences.withRental(rental -> mapRentalPreferences(rental, environment, callWith)); + } +} diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/RequestModesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/RequestModesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java index 78bbebe34fb..d02e251f4e2 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/RequestModesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import java.util.Map; import org.opentripplanner.routing.api.request.RequestModes; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/SelectRequestMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/SelectRequestMapper.java similarity index 89% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/SelectRequestMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/SelectRequestMapper.java index f4699ed7394..3d5de9bf9d0 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/SelectRequestMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/SelectRequestMapper.java @@ -1,11 +1,11 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; -import static org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper.mapIDsToDomainNullSafe; +import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe; import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; import org.opentripplanner.routing.api.request.request.filter.SelectRequest; import org.opentripplanner.transit.model.basic.MainAndSubMode; import org.opentripplanner.transit.model.basic.SubMode; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/SeverityMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/SeverityMapper.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/SeverityMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/SeverityMapper.java index 2bb1698c091..782bd4b1ae3 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/SeverityMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/SeverityMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import org.opentripplanner.routing.alertpatch.AlertSeverity; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/TransitIdMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapper.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/TransitIdMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapper.java index 52d7e0b0aba..1554a8c9d7c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/TransitIdMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import java.util.Collection; import java.util.List; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/TripRequestMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapper.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/TripRequestMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapper.java index d3dd06bb945..f27798c295a 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/TripRequestMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapper.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; -import static org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper.mapIDsToDomainNullSafe; +import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe; import graphql.schema.DataFetchingEnvironment; import java.time.Duration; @@ -11,9 +11,9 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import org.opentripplanner.ext.transmodelapi.TransmodelRequestContext; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.TransmodelRequestContext; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.transit.model.framework.FeedScopedId; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaLocationMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaLocationMapper.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaLocationMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaLocationMapper.java index fffeae5795c..af39338fb98 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaLocationMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaLocationMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import static org.opentripplanner.routing.api.response.InputField.INTERMEDIATE_PLACE; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaRequestMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaRequestMapper.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaRequestMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaRequestMapper.java index e2b52655360..0781fbe34a6 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaRequestMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaRequestMapper.java @@ -1,11 +1,11 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import graphql.schema.DataFetchingEnvironment; import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.Map; -import org.opentripplanner.ext.transmodelapi.TransmodelRequestContext; +import org.opentripplanner.apis.transmodel.TransmodelRequestContext; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.RouteViaRequest; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaSegmentMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaSegmentMapper.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaSegmentMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaSegmentMapper.java index c33045c3548..c86967667d1 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/ViaSegmentMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/ViaSegmentMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import java.util.List; import java.util.Map; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/BikePreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/BikePreferencesMapper.java similarity index 91% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/BikePreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/BikePreferencesMapper.java index a726309dc24..d56dc09c251 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/BikePreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/BikePreferencesMapper.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.BikePreferences; import org.opentripplanner.routing.core.BicycleOptimizeType; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/CarPreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/CarPreferencesMapper.java similarity index 84% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/CarPreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/CarPreferencesMapper.java index f962016ed5f..d6ba995f53c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/CarPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/CarPreferencesMapper.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.CarPreferences; public class CarPreferencesMapper { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/ItineraryFilterPreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/ItineraryFilterPreferencesMapper.java similarity index 82% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/ItineraryFilterPreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/ItineraryFilterPreferencesMapper.java index 25335b231e9..1f0b7ac3925 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/ItineraryFilterPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/ItineraryFilterPreferencesMapper.java @@ -1,8 +1,8 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import graphql.schema.DataFetchingEnvironment; -import org.opentripplanner.ext.transmodelapi.model.plan.ItineraryFiltersInputType; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.model.plan.ItineraryFiltersInputType; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.ItineraryFilterDebugProfile; import org.opentripplanner.routing.api.request.preference.ItineraryFilterPreferences; import org.opentripplanner.routing.api.request.preference.VehicleRentalPreferences; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/StreetPreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/StreetPreferencesMapper.java similarity index 78% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/StreetPreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/StreetPreferencesMapper.java index 99c6857bd61..78aaff13846 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/StreetPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/StreetPreferencesMapper.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import graphql.schema.DataFetchingEnvironment; -import org.opentripplanner.ext.transmodelapi.model.framework.PenaltyForStreetModeType; -import org.opentripplanner.ext.transmodelapi.model.framework.StreetModeDurationInputType; -import org.opentripplanner.ext.transmodelapi.model.plan.TripQuery; +import org.opentripplanner.apis.transmodel.model.framework.PenaltyForStreetModeType; +import org.opentripplanner.apis.transmodel.model.framework.StreetModeDurationInputType; +import org.opentripplanner.apis.transmodel.model.plan.TripQuery; import org.opentripplanner.routing.api.request.preference.StreetPreferences; public class StreetPreferencesMapper { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/TransferPreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/TransferPreferencesMapper.java similarity index 85% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/TransferPreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/TransferPreferencesMapper.java index 896edc8eb47..4bb8bbbcbec 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/TransferPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/TransferPreferencesMapper.java @@ -1,7 +1,7 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import graphql.schema.DataFetchingEnvironment; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.TransferPreferences; public class TransferPreferencesMapper { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/TransitPreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/TransitPreferencesMapper.java similarity index 87% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/TransitPreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/TransitPreferencesMapper.java index 8a03b570292..caa8ebf7715 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/TransitPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/TransitPreferencesMapper.java @@ -1,8 +1,8 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import graphql.schema.DataFetchingEnvironment; -import org.opentripplanner.ext.transmodelapi.model.TransportModeSlack; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.model.TransportModeSlack; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.TransitPreferences; public class TransitPreferencesMapper { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/WalkPreferencesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/WalkPreferencesMapper.java similarity index 75% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/WalkPreferencesMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/WalkPreferencesMapper.java index 6319eb7ded4..bc8f6350ac9 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/WalkPreferencesMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/preferences/WalkPreferencesMapper.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.WalkPreferences; public class WalkPreferencesMapper { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/DefaultRouteRequestType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/DefaultRouteRequestType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/DefaultRouteRequestType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/DefaultRouteRequestType.java index fd9af09822e..41f77669859 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/DefaultRouteRequestType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/DefaultRouteRequestType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; @@ -220,7 +220,7 @@ private GraphQLObjectType createGraphQLType() { .name("bikeParkTime") .description("Time to park a bike.") .type(Scalars.GraphQLInt) - .dataFetcher(env -> preferences.bike().parkTime()) + .dataFetcher(env -> (int) preferences.bike().parking().parkTime().toSeconds()) .build() ) .field( @@ -229,7 +229,7 @@ private GraphQLObjectType createGraphQLType() { .name("bikeParkCost") .description("Cost to park a bike.") .type(Scalars.GraphQLInt) - .dataFetcher(env -> preferences.bike().parkCost()) + .dataFetcher(env -> preferences.bike().parking().parkCost().toSeconds()) .build() ) .field( diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/EnumTypes.java b/src/main/java/org/opentripplanner/apis/transmodel/model/EnumTypes.java similarity index 99% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/EnumTypes.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/EnumTypes.java index e585ad55c57..70173062f8f 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/EnumTypes.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/EnumTypes.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import graphql.schema.GraphQLEnumType; import java.util.Arrays; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/PlanResponse.java b/src/main/java/org/opentripplanner/apis/transmodel/model/PlanResponse.java similarity index 88% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/PlanResponse.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/PlanResponse.java index 89456fd6f6a..127952be88c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/PlanResponse.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/PlanResponse.java @@ -1,10 +1,10 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import java.util.ArrayList; import java.util.List; import org.opentripplanner.api.resource.DebugOutput; import org.opentripplanner.model.plan.TripPlan; -import org.opentripplanner.model.plan.pagecursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; import org.opentripplanner.routing.api.response.RoutingError; import org.opentripplanner.routing.api.response.TripSearchMetadata; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelPlaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelPlaceType.java similarity index 65% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelPlaceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelPlaceType.java index fcd7a8d27e8..3abb54eccd8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelPlaceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelPlaceType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; public enum TransmodelPlaceType { QUAY, diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelStopPlaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelStopPlaceType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelStopPlaceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelStopPlaceType.java index 09b123076b6..7c2be97a2fa 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelStopPlaceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelStopPlaceType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; public enum TransmodelStopPlaceType { ONSTREET_BUS("onstreetBus"), diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelTransportSubmode.java b/src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelTransportSubmode.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelTransportSubmode.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelTransportSubmode.java index 7a41f1717fe..e7b544b4e0f 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransmodelTransportSubmode.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/TransmodelTransportSubmode.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import java.util.Arrays; import org.opentripplanner.transit.model.basic.SubMode; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransportModeSlack.java b/src/main/java/org/opentripplanner/apis/transmodel/model/TransportModeSlack.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransportModeSlack.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/TransportModeSlack.java index c4872d59195..ed26711de88 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TransportModeSlack.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/TransportModeSlack.java @@ -1,8 +1,8 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import static graphql.schema.GraphQLInputObjectField.newInputObjectField; import static graphql.schema.GraphQLNonNull.nonNull; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.TRANSPORT_MODE; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TripTimeShortHelper.java b/src/main/java/org/opentripplanner/apis/transmodel/model/TripTimeShortHelper.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/TripTimeShortHelper.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/TripTimeShortHelper.java index e3289bb4d72..2f2b38785bf 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/TripTimeShortHelper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/TripTimeShortHelper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import java.time.Instant; import java.time.LocalDate; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/AuthorityType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/AuthorityType.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/AuthorityType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/AuthorityType.java index c92606a5dbe..27d20c8e423 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/AuthorityType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/AuthorityType.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; -import static org.opentripplanner.ext.transmodelapi.support.GqlUtil.getTransitService; +import static org.opentripplanner.apis.transmodel.support.GqlUtil.getTransitService; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; @@ -10,7 +10,7 @@ import graphql.schema.GraphQLOutputType; import java.util.Objects; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.transit.model.organization.Agency; public class AuthorityType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/BrandingType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/BrandingType.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/BrandingType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/BrandingType.java index 34d1e11b9af..59406f0a06f 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/BrandingType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/BrandingType.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; import org.opentripplanner.transit.model.organization.Branding; public class BrandingType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/CoordinateInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/CoordinateInputType.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/CoordinateInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/CoordinateInputType.java index 20d244b6851..32ed3b7927e 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/CoordinateInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/CoordinateInputType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLInputObjectField; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/InfoLinkType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/InfoLinkType.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/InfoLinkType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/InfoLinkType.java index 4d0a133bc27..6541b48a44d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/InfoLinkType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/InfoLinkType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/LocationInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/LocationInputType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/LocationInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/LocationInputType.java index 9ab992c416b..e64c67d9910 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/LocationInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/LocationInputType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLInputObjectField; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/MultilingualStringType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/MultilingualStringType.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/MultilingualStringType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/MultilingualStringType.java index 33f48669d80..9bcaab1b4e5 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/MultilingualStringType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/MultilingualStringType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/NoticeType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/NoticeType.java similarity index 87% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/NoticeType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/NoticeType.java index 8291a08e1da..15ac3fd2356 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/NoticeType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/NoticeType.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.transit.model.basic.Notice; public class NoticeType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/OperatorType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/OperatorType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/OperatorType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/OperatorType.java index 1c1ac9a83c9..d45319b9d9e 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/OperatorType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/OperatorType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; @@ -8,7 +8,7 @@ import graphql.schema.GraphQLOutputType; import java.util.Objects; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; public class OperatorType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PassThroughPointInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/PassThroughPointInputType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PassThroughPointInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/PassThroughPointInputType.java index 55873844a5f..3bc6d9d2f4c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PassThroughPointInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/PassThroughPointInputType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLInputObjectField; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PenaltyForStreetModeType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/PenaltyForStreetModeType.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PenaltyForStreetModeType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/PenaltyForStreetModeType.java index 855dd5e98df..9fd91832117 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PenaltyForStreetModeType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/PenaltyForStreetModeType.java @@ -1,6 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.STREET_MODE; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.language.ArrayValue; @@ -17,8 +15,9 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.opentripplanner.ext.transmodelapi.model.scalars.DoubleFunction; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.scalars.DoubleFunction; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.lang.ObjectUtils; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.framework.TimeAndCostPenalty; @@ -56,7 +55,7 @@ public static GraphQLInputObjectType create(GqlUtil gqlUtil) { GraphQLInputObjectField .newInputObjectField() .name(FIELD_STREET_MODE) - .type(new GraphQLNonNull(STREET_MODE)) + .type(new GraphQLNonNull(EnumTypes.STREET_MODE)) .description( """ List of modes with the given penalty is applied to. A street-mode should not be listed @@ -98,7 +97,7 @@ public static GraphQLInputObjectType create(GqlUtil gqlUtil) { /** Return a list of access-egress penalties */ public static Value mapToGraphQLValue(TimeAndCostPenaltyForEnum accessEgressPenalty) { - List values = STREET_MODE + List values = EnumTypes.STREET_MODE .getValues() .stream() .map(gqlModeType -> { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PointsOnLinkType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/PointsOnLinkType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PointsOnLinkType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/PointsOnLinkType.java index 0311c677b17..9807d041613 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/PointsOnLinkType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/PointsOnLinkType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/RentalVehicleTypeType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/RentalVehicleTypeType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/RentalVehicleTypeType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/RentalVehicleTypeType.java index d128116fe42..f0f4ab03419 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/RentalVehicleTypeType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/RentalVehicleTypeType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/ServerInfoType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/ServerInfoType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/ServerInfoType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/ServerInfoType.java index 9997e86791e..ae6889ab033 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/ServerInfoType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/ServerInfoType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/StreetModeDurationInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/StreetModeDurationInputType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/StreetModeDurationInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/StreetModeDurationInputType.java index 80d168207a6..bf274688617 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/StreetModeDurationInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/StreetModeDurationInputType.java @@ -1,6 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.STREET_MODE; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.language.ArrayValue; import graphql.language.EnumValue; @@ -17,7 +15,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.framework.DurationForEnum; @@ -36,7 +35,7 @@ public static GraphQLInputObjectType create(GqlUtil gqlUtil) { GraphQLInputObjectField .newInputObjectField() .name(FIELD_STREET_MODE) - .type(new GraphQLNonNull(STREET_MODE)) + .type(new GraphQLNonNull(EnumTypes.STREET_MODE)) .build() ) .field( @@ -51,7 +50,7 @@ public static GraphQLInputObjectType create(GqlUtil gqlUtil) { public static Value mapDurationForStreetModeGraphQLValue( DurationForEnum durationForStreetMode ) { - List list = STREET_MODE + List list = EnumTypes.STREET_MODE .getValues() .stream() .map(gqlModeType -> { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/SystemNoticeType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/SystemNoticeType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/SystemNoticeType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/SystemNoticeType.java index 8b0952ba379..1cb237a1114 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/SystemNoticeType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/SystemNoticeType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/ValidityPeriodType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/ValidityPeriodType.java similarity index 84% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/ValidityPeriodType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/framework/ValidityPeriodType.java index d353431b791..35ea9258322 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/framework/ValidityPeriodType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/framework/ValidityPeriodType.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model.framework; +package org.opentripplanner.apis.transmodel.model.framework; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.model.siri.sx.ValidityPeriod; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.siri.sx.ValidityPeriod; +import org.opentripplanner.apis.transmodel.support.GqlUtil; public class ValidityPeriodType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/DestinationDisplayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/network/DestinationDisplayType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/DestinationDisplayType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/network/DestinationDisplayType.java index d797ed7b80c..ed5f82e58b0 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/DestinationDisplayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/network/DestinationDisplayType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.network; +package org.opentripplanner.apis.transmodel.model.network; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/GroupOfLinesType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/network/GroupOfLinesType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/GroupOfLinesType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/network/GroupOfLinesType.java index c316168b2e9..0339269dbd8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/GroupOfLinesType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/network/GroupOfLinesType.java @@ -1,12 +1,12 @@ -package org.opentripplanner.ext.transmodelapi.model.network; +package org.opentripplanner.apis.transmodel.model.network; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLList; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.transit.model.network.GroupOfRoutes; public class GroupOfLinesType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/JourneyPatternType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/network/JourneyPatternType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/JourneyPatternType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/network/JourneyPatternType.java index eaae58009bb..0743b02a3c4 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/JourneyPatternType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/network/JourneyPatternType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.network; +package org.opentripplanner.apis.transmodel.model.network; import gnu.trove.set.TIntSet; import graphql.Scalars; @@ -14,9 +14,9 @@ import java.util.Optional; import java.util.stream.Collectors; import org.locationtech.jts.geom.LineString; -import org.opentripplanner.ext.transmodelapi.mapping.GeometryMapper; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.GeometryMapper; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.geometry.EncodedPolyline; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.timetable.TripTimes; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/LineType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/network/LineType.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/LineType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/network/LineType.java index 3b8ecf93525..32ea357a0aa 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/LineType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/network/LineType.java @@ -1,6 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.network; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; +package org.opentripplanner.apis.transmodel.model.network; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; @@ -12,10 +10,10 @@ import graphql.schema.GraphQLTypeReference; import java.util.Collection; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; @@ -97,7 +95,7 @@ public static GraphQLObjectType create( GraphQLFieldDefinition .newFieldDefinition() .name("transportMode") - .type(TRANSPORT_MODE) + .type(EnumTypes.TRANSPORT_MODE) .dataFetcher(environment -> ((Route) environment.getSource()).getMode()) .build() ) diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/PresentationType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/network/PresentationType.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/PresentationType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/network/PresentationType.java index 4b2d45d81dd..0632ba10c1d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/PresentationType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/network/PresentationType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.network; +package org.opentripplanner.apis.transmodel.model.network; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/StopToStopGeometryType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/network/StopToStopGeometryType.java similarity index 91% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/StopToStopGeometryType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/network/StopToStopGeometryType.java index 00edaf2d9f8..800eda04cb2 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/network/StopToStopGeometryType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/network/StopToStopGeometryType.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model.network; +package org.opentripplanner.apis.transmodel.model.network; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; -import org.opentripplanner.ext.transmodelapi.model.util.EncodedPolylineBeanWithStops; +import org.opentripplanner.apis.transmodel.model.util.EncodedPolylineBeanWithStops; public class StopToStopGeometryType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/BannedInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/BannedInputType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/BannedInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/BannedInputType.java index 585638f8c31..ab78395a160 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/BannedInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/BannedInputType.java @@ -1,7 +1,7 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.schema.GraphQLInputObjectType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; public class BannedInputType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ElevationProfileStepType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ElevationProfileStepType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ElevationProfileStepType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ElevationProfileStepType.java index 828a806885c..bc1f1185463 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ElevationProfileStepType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ElevationProfileStepType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/FilterInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/FilterInputType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/FilterInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/FilterInputType.java index d37a8949212..ce792ca3790 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/FilterInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/FilterInputType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ItineraryFiltersInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ItineraryFiltersInputType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ItineraryFiltersInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ItineraryFiltersInputType.java index 4f384eee4ff..b5d82af5138 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ItineraryFiltersInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ItineraryFiltersInputType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; @@ -7,10 +7,10 @@ import graphql.schema.GraphQLNonNull; import java.util.Map; import java.util.function.Consumer; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.scalars.DoubleFunction; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.scalars.DoubleFunction; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.algorithm.filterchain.api.TransitGeneralizedCostFilterParams; import org.opentripplanner.routing.api.request.preference.ItineraryFilterPreferences; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/JourneyWhiteListed.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/JourneyWhiteListed.java similarity index 90% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/JourneyWhiteListed.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/JourneyWhiteListed.java index f7068060900..6d747ccb164 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/JourneyWhiteListed.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/JourneyWhiteListed.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; -import static org.opentripplanner.ext.transmodelapi.support.GqlUtil.newIdListInputField; +import static org.opentripplanner.apis.transmodel.support.GqlUtil.newIdListInputField; import graphql.schema.DataFetchingEnvironment; import graphql.schema.GraphQLInputObjectType; @@ -9,8 +9,8 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/LegType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/LegType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java index 0b9aa00bde0..be05d00e16d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/LegType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java @@ -1,7 +1,7 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.ALTERNATIVE_LEGS_FILTER; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.LEG_MODE; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.ALTERNATIVE_LEGS_FILTER; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.LEG_MODE; import graphql.Scalars; import graphql.scalars.ExtendedScalars; @@ -19,10 +19,10 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; -import org.opentripplanner.ext.transmodelapi.model.TripTimeShortHelper; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.model.TripTimeShortHelper; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.geometry.EncodedPolyline; import org.opentripplanner.model.plan.Leg; import org.opentripplanner.model.plan.StopArrival; @@ -30,7 +30,6 @@ import org.opentripplanner.model.plan.TransitLeg; import org.opentripplanner.model.plan.legreference.LegReferenceSerializer; import org.opentripplanner.routing.alternativelegs.AlternativeLegs; -import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; public class LegType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ModeAndSubModeInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ModeAndSubModeInputType.java similarity index 85% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ModeAndSubModeInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ModeAndSubModeInputType.java index 8d4a4520da3..d98108e6c7d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ModeAndSubModeInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ModeAndSubModeInputType.java @@ -1,11 +1,11 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.TRANSPORT_MODE; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; import graphql.schema.GraphQLList; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.EnumTypes; public class ModeAndSubModeInputType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ModeInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ModeInputType.java similarity index 90% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ModeInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ModeInputType.java index a5fcb51fb88..a5b7b533e94 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ModeInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ModeInputType.java @@ -1,10 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.STREET_MODE; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; import graphql.schema.GraphQLList; +import org.opentripplanner.apis.transmodel.model.EnumTypes; class ModeInputType { @@ -25,7 +24,7 @@ class ModeInputType { "network the transit network (first-mile). If the element is not present or null," + "only transit that can be immediately boarded from the origin will be used." ) - .type(STREET_MODE) + .type(EnumTypes.STREET_MODE) .build() ) .field( @@ -37,7 +36,7 @@ class ModeInputType { "the destination (last-mile). If the element is not present or null," + "only transit that can immediately arrive at the origin will be used." ) - .type(STREET_MODE) + .type(EnumTypes.STREET_MODE) .build() ) .field( @@ -49,7 +48,7 @@ class ModeInputType { "without using the transit network. If the element is not present or null," + "direct travel without using transit will be disallowed." ) - .type(STREET_MODE) + .type(EnumTypes.STREET_MODE) .build() ) .field( diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/PathGuidanceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/PathGuidanceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java index ce1f8909b79..c52baa0be4c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/PathGuidanceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PathGuidanceType.java @@ -1,11 +1,11 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLList; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.EnumTypes; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.plan.WalkStep; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/PlanPlaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PlanPlaceType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/PlanPlaceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/PlanPlaceType.java index 195046a06fd..a39a25ae93d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/PlanPlaceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/PlanPlaceType.java @@ -1,13 +1,12 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; -import java.util.Locale; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.scalars.GeoJSONCoordinatesScalar; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.scalars.GeoJSONCoordinatesScalar; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.VertexType; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/RelaxCostType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/RelaxCostType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/RelaxCostType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/RelaxCostType.java index b8cdc317cda..3bd3ed129ef 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/RelaxCostType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/RelaxCostType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.language.FloatValue; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/RoutingErrorType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/RoutingErrorType.java similarity index 86% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/RoutingErrorType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/RoutingErrorType.java index 52079d15167..79052f17b69 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/RoutingErrorType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/RoutingErrorType.java @@ -1,7 +1,7 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.INPUT_FIELD; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.ROUTING_ERROR_CODE; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.INPUT_FIELD; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.ROUTING_ERROR_CODE; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/SelectInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/SelectInputType.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/SelectInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/SelectInputType.java index 4935d1a23ef..900e8c927fb 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/SelectInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/SelectInputType.java @@ -1,13 +1,10 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; - -import static org.opentripplanner.ext.transmodelapi.support.GqlUtil.newIdListInputField; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; import graphql.schema.GraphQLList; import graphql.schema.GraphQLNonNull; -import java.util.List; public class SelectInputType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TriangleFactorsInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TriangleFactorsInputType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TriangleFactorsInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/TriangleFactorsInputType.java index 4263ca37cc9..73c96f7f726 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TriangleFactorsInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TriangleFactorsInputType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.GraphQLInputObjectField; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripPatternType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripPatternType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripPatternType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripPatternType.java index de90b89b38f..31e33ae6e4d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripPatternType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripPatternType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.scalars.ExtendedScalars; @@ -8,7 +8,7 @@ import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.model.plan.Itinerary; public class TripPatternType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripQuery.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripQuery.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripQuery.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripQuery.java index 4ac182f514f..d06c5954444 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripQuery.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripQuery.java @@ -1,6 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; -import static org.opentripplanner.ext.transmodelapi.model.framework.StreetModeDurationInputType.mapDurationForStreetModeGraphQLValue; +import static org.opentripplanner.apis.transmodel.model.framework.StreetModeDurationInputType.mapDurationForStreetModeGraphQLValue; import graphql.Scalars; import graphql.language.NullValue; @@ -11,14 +11,14 @@ import graphql.schema.GraphQLList; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLOutputType; -import org.opentripplanner.ext.transmodelapi.TransmodelGraphQLPlanner; -import org.opentripplanner.ext.transmodelapi.model.DefaultRouteRequestType; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.TransportModeSlack; -import org.opentripplanner.ext.transmodelapi.model.framework.LocationInputType; -import org.opentripplanner.ext.transmodelapi.model.framework.PassThroughPointInputType; -import org.opentripplanner.ext.transmodelapi.model.framework.PenaltyForStreetModeType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.TransmodelGraphQLPlanner; +import org.opentripplanner.apis.transmodel.model.DefaultRouteRequestType; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.TransportModeSlack; +import org.opentripplanner.apis.transmodel.model.framework.LocationInputType; +import org.opentripplanner.apis.transmodel.model.framework.PassThroughPointInputType; +import org.opentripplanner.apis.transmodel.model.framework.PenaltyForStreetModeType; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; import org.opentripplanner.routing.core.BicycleOptimizeType; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripType.java index 85fc140e2cb..d9c3c0caa02 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/TripType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.scalars.ExtendedScalars; @@ -9,10 +9,10 @@ import graphql.schema.GraphQLObjectType; import java.util.stream.Collectors; import org.opentripplanner.api.mapping.PlannerErrorMapper; -import org.opentripplanner.ext.transmodelapi.model.PlanResponse; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.PlanResponse; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.plan.pagecursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; public class TripType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaLocationInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaLocationInputType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaLocationInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaLocationInputType.java index fe5a3cf19e4..6ce02240817 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaLocationInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaLocationInputType.java @@ -1,10 +1,10 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; -import org.opentripplanner.ext.transmodelapi.model.framework.CoordinateInputType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.framework.CoordinateInputType; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.ViaLocation; public class ViaLocationInputType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaSegmentInputType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaSegmentInputType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaSegmentInputType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaSegmentInputType.java index fd5337d750f..0d591a1357a 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaSegmentInputType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaSegmentInputType.java @@ -1,11 +1,10 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.STREET_MODE; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLInputObjectType; import graphql.schema.GraphQLList; import graphql.schema.GraphQLNonNull; +import org.opentripplanner.apis.transmodel.model.EnumTypes; public class ViaSegmentInputType { @@ -26,7 +25,7 @@ public static GraphQLInputObjectType create() { "network the transit network (first-mile). If the element is not present or null," + "only transit that can be immediately boarded from the origin will be used." ) - .type(STREET_MODE) + .type(EnumTypes.STREET_MODE) .build() ) .field( @@ -38,7 +37,7 @@ public static GraphQLInputObjectType create() { "the destination (last-mile). If the element is not present or null," + "only transit that can immediately arrive at the origin will be used." ) - .type(STREET_MODE) + .type(EnumTypes.STREET_MODE) .build() ) .field( @@ -50,7 +49,7 @@ public static GraphQLInputObjectType create() { "without using the transit network. If the element is not present or null," + "direct travel without using transit will be disallowed." ) - .type(STREET_MODE) + .type(EnumTypes.STREET_MODE) .build() ) .build(); diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaTripQuery.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaTripQuery.java similarity index 94% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaTripQuery.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaTripQuery.java index da2b015ca97..8641dbc60c2 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaTripQuery.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaTripQuery.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.GraphQLArgument; @@ -7,11 +7,11 @@ import graphql.schema.GraphQLList; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLOutputType; -import org.opentripplanner.ext.transmodelapi.TransmodelGraphQLPlanner; -import org.opentripplanner.ext.transmodelapi.model.DefaultRouteRequestType; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.framework.LocationInputType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.TransmodelGraphQLPlanner; +import org.opentripplanner.apis.transmodel.model.DefaultRouteRequestType; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.framework.LocationInputType; +import org.opentripplanner.apis.transmodel.support.GqlUtil; public class ViaTripQuery { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaTripType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaTripType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaTripType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaTripType.java index 62e3447ce43..8b55222f3b8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/plan/ViaTripType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/ViaTripType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.plan; +package org.opentripplanner.apis.transmodel.model.plan; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateScalarFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateScalarFactory.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateScalarFactory.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateScalarFactory.java index de453447a0f..6d45018ed2a 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateScalarFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateScalarFactory.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import graphql.language.StringValue; import graphql.schema.Coercing; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateTimeScalarFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateTimeScalarFactory.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java index cd49e46e74a..706adc81704 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateTimeScalarFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import graphql.language.StringValue; import graphql.schema.Coercing; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DoubleFunction.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DoubleFunction.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DoubleFunction.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DoubleFunction.java index 3bf3980a146..c1f8bb0f3f8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DoubleFunction.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DoubleFunction.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import java.time.Duration; import org.opentripplanner.routing.api.request.framework.CostLinearFunction; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DoubleFunctionFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DoubleFunctionFactory.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DoubleFunctionFactory.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DoubleFunctionFactory.java index e6bc10fdc0d..fd45b001642 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/DoubleFunctionFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DoubleFunctionFactory.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import graphql.GraphQLContext; import graphql.execution.CoercedVariables; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/GeoJSONCoordinatesScalar.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/GeoJSONCoordinatesScalar.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/GeoJSONCoordinatesScalar.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/GeoJSONCoordinatesScalar.java index 2d373a01d45..2cb44433d50 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/GeoJSONCoordinatesScalar.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/GeoJSONCoordinatesScalar.java @@ -13,7 +13,7 @@ * limitations under the Licence. */ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import graphql.language.ArrayValue; import graphql.language.FloatValue; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/LocalTimeScalarFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/LocalTimeScalarFactory.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/LocalTimeScalarFactory.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/LocalTimeScalarFactory.java index 32877e129f1..1dbf2dce8e8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/LocalTimeScalarFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/LocalTimeScalarFactory.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import graphql.language.StringValue; import graphql.schema.Coercing; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/TimeScalarFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/TimeScalarFactory.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/TimeScalarFactory.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/scalars/TimeScalarFactory.java index 30f5c8236a1..318ceea034f 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/scalars/TimeScalarFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/TimeScalarFactory.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import graphql.Scalars; import graphql.language.StringValue; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/et/EstimatedCallType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/et/EstimatedCallType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/et/EstimatedCallType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/siri/et/EstimatedCallType.java index 3111f17b698..0c47fe36ba8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/et/EstimatedCallType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/et/EstimatedCallType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.siri.et; +package org.opentripplanner.apis.transmodel.model.siri.et; import static org.opentripplanner.model.PickDrop.COORDINATE_WITH_DRIVER; @@ -15,9 +15,9 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; -import org.opentripplanner.ext.transmodelapi.mapping.OccupancyStatusMapper; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.OccupancyStatusMapper; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.routing.alertpatch.StopCondition; import org.opentripplanner.routing.alertpatch.TransitAlert; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/AffectsType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/AffectsType.java similarity index 93% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/AffectsType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/AffectsType.java index 529e939bdac..4aded08e3e8 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/AffectsType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/AffectsType.java @@ -1,6 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.siri.sx; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.STOP_CONDITION_ENUM; +package org.opentripplanner.apis.transmodel.model.siri.sx; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; @@ -9,8 +7,9 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; import graphql.schema.GraphQLUnionType; -import org.opentripplanner.ext.transmodelapi.model.stop.StopPlaceType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.stop.StopPlaceType; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.alertpatch.EntitySelector; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; @@ -56,7 +55,9 @@ public static GraphQLOutputType create( GraphQLFieldDefinition .newFieldDefinition() .name("stopConditions") - .type(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(STOP_CONDITION_ENUM)))) + .type( + new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(EnumTypes.STOP_CONDITION_ENUM))) + ) .build() ) .build(); @@ -156,7 +157,9 @@ public static GraphQLOutputType create( GraphQLFieldDefinition .newFieldDefinition() .name("stopConditions") - .type(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(STOP_CONDITION_ENUM)))) + .type( + new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(EnumTypes.STOP_CONDITION_ENUM))) + ) .build() ) .build(); @@ -226,7 +229,9 @@ public static GraphQLOutputType create( GraphQLFieldDefinition .newFieldDefinition() .name("stopConditions") - .type(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(STOP_CONDITION_ENUM)))) + .type( + new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(EnumTypes.STOP_CONDITION_ENUM))) + ) .build() ) .build(); diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/PtSituationElementType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/PtSituationElementType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/PtSituationElementType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/PtSituationElementType.java index 6cc72568aab..b5616c2d3fc 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/PtSituationElementType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/PtSituationElementType.java @@ -1,7 +1,7 @@ -package org.opentripplanner.ext.transmodelapi.model.siri.sx; +package org.opentripplanner.apis.transmodel.model.siri.sx; import static java.util.Collections.emptyList; -import static org.opentripplanner.ext.transmodelapi.mapping.SeverityMapper.getTransmodelSeverity; +import static org.opentripplanner.apis.transmodel.mapping.SeverityMapper.getTransmodelSeverity; import graphql.Scalars; import graphql.relay.Relay; @@ -16,9 +16,9 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.stop.MonoOrMultiModalStation; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.stop.MonoOrMultiModalStation; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.TranslatedString; import org.opentripplanner.routing.alertpatch.AlertUrl; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/ValidityPeriod.java b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/ValidityPeriod.java similarity index 50% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/ValidityPeriod.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/ValidityPeriod.java index a154a22da4c..216be5a3867 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/siri/sx/ValidityPeriod.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/siri/sx/ValidityPeriod.java @@ -1,3 +1,3 @@ -package org.opentripplanner.ext.transmodelapi.model.siri.sx; +package org.opentripplanner.apis.transmodel.model.siri.sx; public record ValidityPeriod(Long startTime, Long endTime) {} diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/BikeParkType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/BikeParkType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/BikeParkType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/BikeParkType.java index 6805253dd3d..470111513bf 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/BikeParkType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/BikeParkType.java @@ -1,11 +1,11 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLInterfaceType; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; import org.opentripplanner.routing.vehicle_parking.VehicleParking; public class BikeParkType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/BikeRentalStationType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/BikeRentalStationType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/BikeRentalStationType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/BikeRentalStationType.java index 2732f68a1af..3f2988a95d7 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/BikeRentalStationType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/BikeRentalStationType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/MonoOrMultiModalStation.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/MonoOrMultiModalStation.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/MonoOrMultiModalStation.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/MonoOrMultiModalStation.java index 25fa78e4061..3055c1a0115 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/MonoOrMultiModalStation.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/MonoOrMultiModalStation.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import java.time.ZoneId; import java.util.Collection; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceAtDistanceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceAtDistanceType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceAtDistanceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceAtDistanceType.java index 0848f17202e..809164e9cd2 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceAtDistanceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceAtDistanceType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.relay.Relay; @@ -14,7 +14,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.opentripplanner.ext.transmodelapi.model.TransmodelPlaceType; +import org.opentripplanner.apis.transmodel.model.TransmodelPlaceType; import org.opentripplanner.routing.graphfinder.PlaceAtDistance; import org.opentripplanner.transit.model.site.MultiModalStation; import org.opentripplanner.transit.model.site.RegularStop; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceInterfaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceInterfaceType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceInterfaceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceInterfaceType.java index 9d757696bac..0b6238c119d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceInterfaceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceInterfaceType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceType.java similarity index 61% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceType.java index 8f264b0ae40..a00bb0f9e16 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/PlaceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/PlaceType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; public enum PlaceType { STOP, diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/QuayAtDistanceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayAtDistanceType.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/QuayAtDistanceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayAtDistanceType.java index 3a11c6ae5ba..51f62141e33 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/QuayAtDistanceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayAtDistanceType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.relay.Relay; @@ -6,7 +6,7 @@ import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; import org.opentripplanner.routing.graphfinder.NearbyStop; import org.opentripplanner.transit.model.framework.AbstractTransitEntity; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/QuayType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index 8b9296b9137..b80efab77b5 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -1,6 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.schema.GraphQLArgument; @@ -17,10 +15,10 @@ import java.util.Collection; import java.util.Objects; import java.util.Optional; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.plan.JourneyWhiteListed; -import org.opentripplanner.ext.transmodelapi.model.scalars.GeoJSONCoordinatesScalar; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.plan.JourneyWhiteListed; +import org.opentripplanner.apis.transmodel.model.scalars.GeoJSONCoordinatesScalar; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.routing.stoptimes.ArrivalDeparture; @@ -292,7 +290,7 @@ public static GraphQLObjectType create( .newArgument() .name("whiteListedModes") .description("Only show estimated calls for selected modes.") - .type(GraphQLList.list(TRANSPORT_MODE)) + .type(GraphQLList.list(EnumTypes.TRANSPORT_MODE)) .build() ) .argument( diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/RentalVehicleType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/RentalVehicleType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/RentalVehicleType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/RentalVehicleType.java index 7042099da32..e44639e09e7 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/RentalVehicleType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/RentalVehicleType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/StopPlaceType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/StopPlaceType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java index a60ee5df20f..accaf1e35fb 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/StopPlaceType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopPlaceType.java @@ -1,8 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import static java.lang.Boolean.TRUE; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_SUBMODE; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; @@ -27,11 +25,11 @@ import java.util.stream.Stream; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Envelope; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; -import org.opentripplanner.ext.transmodelapi.model.plan.JourneyWhiteListed; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.model.plan.JourneyWhiteListed; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.StopTimesInPattern; import org.opentripplanner.model.TripTimeOnDate; @@ -166,7 +164,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("transportMode") .description("The transport modes of quays under this stop place.") - .type(new GraphQLList(TRANSPORT_MODE)) + .type(new GraphQLList(EnumTypes.TRANSPORT_MODE)) .dataFetcher(environment -> ((MonoOrMultiModalStation) environment.getSource()).getChildStops() .stream() @@ -181,7 +179,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("transportSubmode") .description("The transport submode serviced by this stop place.") - .type(new GraphQLList(TRANSPORT_SUBMODE)) + .type(new GraphQLList(EnumTypes.TRANSPORT_SUBMODE)) .dataFetcher(environment -> ((MonoOrMultiModalStation) environment.getSource()).getChildStops() .stream() @@ -339,7 +337,7 @@ public static GraphQLObjectType create( .newArgument() .name("whiteListedModes") .description("Only show estimated calls for selected modes.") - .type(GraphQLList.list(TRANSPORT_MODE)) + .type(GraphQLList.list(EnumTypes.TRANSPORT_MODE)) .build() ) .argument( diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/TariffZoneType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/TariffZoneType.java similarity index 85% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/TariffZoneType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/stop/TariffZoneType.java index 6baed23aa65..c3953c7b88d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/stop/TariffZoneType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/TariffZoneType.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model.stop; +package org.opentripplanner.apis.transmodel.model.stop; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.transit.model.site.FareZone; public class TariffZoneType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/BookingArrangementType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/BookingArrangementType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/BookingArrangementType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/BookingArrangementType.java index 5cb3b0139af..c2a11441695 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/BookingArrangementType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/BookingArrangementType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; +package org.opentripplanner.apis.transmodel.model.timetable; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; @@ -6,8 +6,8 @@ import graphql.schema.GraphQLList; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.model.BookingInfo; import org.opentripplanner.model.BookingTime; import org.opentripplanner.transit.model.organization.ContactInfo; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/DatedServiceJourneyQuery.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyQuery.java similarity index 92% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/DatedServiceJourneyQuery.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyQuery.java index 1cc8aa51c98..c3c8ba420e4 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/DatedServiceJourneyQuery.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyQuery.java @@ -1,7 +1,6 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; +package org.opentripplanner.apis.transmodel.model.timetable; -import static org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper.mapIDsToDomainNullSafe; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.SERVICE_ALTERATION; +import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe; import graphql.Scalars; import graphql.schema.GraphQLArgument; @@ -12,8 +11,9 @@ import java.time.LocalDate; import java.util.List; import java.util.stream.Stream; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.timetable.TripAlteration; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -75,7 +75,7 @@ public static GraphQLFieldDefinition createQuery( GraphQLArgument .newArgument() .name("alterations") - .type(new GraphQLList(new GraphQLNonNull(SERVICE_ALTERATION))) + .type(new GraphQLList(new GraphQLNonNull(EnumTypes.SERVICE_ALTERATION))) ) .argument( GraphQLArgument diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/DatedServiceJourneyType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/DatedServiceJourneyType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java index e9cb689036b..ed06996301e 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/DatedServiceJourneyType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/DatedServiceJourneyType.java @@ -1,6 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.SERVICE_ALTERATION; +package org.opentripplanner.apis.transmodel.model.timetable; import graphql.AssertException; import graphql.Scalars; @@ -15,7 +13,8 @@ import graphql.schema.GraphQLTypeReference; import java.util.List; import java.util.Optional; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.TripTimesShortHelper; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; @@ -70,7 +69,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("tripAlteration") .description("Alterations specified on the Trip in the planned data") - .type(SERVICE_ALTERATION) + .type(EnumTypes.SERVICE_ALTERATION) .dataFetcher(environment -> tripOnServiceDate(environment).getTripAlteration()) ) .field( diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/InterchangeType.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/InterchangeType.java index 368784fa88a..35d32c51522 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/InterchangeType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/InterchangeType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; +package org.opentripplanner.apis.transmodel.model.timetable; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; @@ -6,7 +6,7 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; import java.util.function.Function; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.EnumTypes; import org.opentripplanner.model.transfer.ConstrainedTransfer; import org.opentripplanner.model.transfer.TransferConstraint; import org.opentripplanner.model.transfer.TransferPoint; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/ServiceJourneyType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/ServiceJourneyType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java index f03dad44fc1..0122cdbca5d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/ServiceJourneyType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/ServiceJourneyType.java @@ -1,7 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; - -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_MODE; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.TRANSPORT_SUBMODE; +package org.opentripplanner.apis.transmodel.model.timetable; import graphql.AssertException; import graphql.Scalars; @@ -18,9 +15,9 @@ import java.util.Optional; import java.util.stream.Collectors; import org.locationtech.jts.geom.LineString; -import org.opentripplanner.ext.transmodelapi.model.EnumTypes; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.model.EnumTypes; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.framework.geometry.EncodedPolyline; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.routing.TripTimesShortHelper; @@ -88,7 +85,7 @@ public static GraphQLObjectType create( GraphQLFieldDefinition .newFieldDefinition() .name("transportMode") - .type(TRANSPORT_MODE) + .type(EnumTypes.TRANSPORT_MODE) .dataFetcher(environment -> ((trip(environment)).getMode())) .build() ) @@ -96,7 +93,7 @@ public static GraphQLObjectType create( GraphQLFieldDefinition .newFieldDefinition() .name("transportSubmode") - .type(TRANSPORT_SUBMODE) + .type(EnumTypes.TRANSPORT_SUBMODE) .dataFetcher(environment -> TransmodelTransportSubmode.fromValue(((trip(environment))).getNetexSubMode()) ) diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/TimetabledPassingTimeType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/TimetabledPassingTimeType.java similarity index 98% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/TimetabledPassingTimeType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/TimetabledPassingTimeType.java index 596580ccb75..9370ed74d93 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/TimetabledPassingTimeType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/TimetabledPassingTimeType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; +package org.opentripplanner.apis.transmodel.model.timetable; import graphql.Scalars; import graphql.schema.DataFetchingEnvironment; @@ -8,8 +8,8 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; import graphql.schema.GraphQLTypeReference; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.ext.flex.trip.FlexTrip; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.StopTime; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/TripMetadataType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/TripMetadataType.java similarity index 95% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/TripMetadataType.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/timetable/TripMetadataType.java index 7e956f35bda..ccdb3a9b39d 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/timetable/TripMetadataType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/timetable/TripMetadataType.java @@ -1,10 +1,10 @@ -package org.opentripplanner.ext.transmodelapi.model.timetable; +package org.opentripplanner.apis.transmodel.model.timetable; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLObjectType; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.response.TripSearchMetadata; public class TripMetadataType { diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/util/EncodedPolylineBeanWithStops.java b/src/main/java/org/opentripplanner/apis/transmodel/model/util/EncodedPolylineBeanWithStops.java similarity index 81% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/model/util/EncodedPolylineBeanWithStops.java rename to src/main/java/org/opentripplanner/apis/transmodel/model/util/EncodedPolylineBeanWithStops.java index 98f68d24a01..92262a17381 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/model/util/EncodedPolylineBeanWithStops.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/util/EncodedPolylineBeanWithStops.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.util; +package org.opentripplanner.apis.transmodel.model.util; import org.opentripplanner.framework.geometry.EncodedPolyline; import org.opentripplanner.transit.model.site.StopLocation; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/AbortOnTimeoutExecutionStrategy.java b/src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnTimeoutExecutionStrategy.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/support/AbortOnTimeoutExecutionStrategy.java rename to src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnTimeoutExecutionStrategy.java index f7085ae8a74..d143d65421c 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/AbortOnTimeoutExecutionStrategy.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/support/AbortOnTimeoutExecutionStrategy.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.support; +package org.opentripplanner.apis.transmodel.support; import graphql.execution.AsyncExecutionStrategy; import graphql.schema.DataFetchingEnvironment; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/DataFetcherDecorator.java b/src/main/java/org/opentripplanner/apis/transmodel/support/DataFetcherDecorator.java similarity index 96% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/support/DataFetcherDecorator.java rename to src/main/java/org/opentripplanner/apis/transmodel/support/DataFetcherDecorator.java index 614b1cd8dbe..7c21d7e62ae 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/DataFetcherDecorator.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/support/DataFetcherDecorator.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.support; +package org.opentripplanner.apis.transmodel.support; import graphql.schema.DataFetchingEnvironment; import java.util.Arrays; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/ExecutionResultMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java similarity index 97% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/support/ExecutionResultMapper.java rename to src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java index 53b44944595..ecb5a38ef01 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/ExecutionResultMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapper.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.support; +package org.opentripplanner.apis.transmodel.support; import graphql.ErrorClassification; import graphql.ExecutionResult; diff --git a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/GqlUtil.java b/src/main/java/org/opentripplanner/apis/transmodel/support/GqlUtil.java similarity index 87% rename from src/ext/java/org/opentripplanner/ext/transmodelapi/support/GqlUtil.java rename to src/main/java/org/opentripplanner/apis/transmodel/support/GqlUtil.java index e4f5ae892fe..3700ea60332 100644 --- a/src/ext/java/org/opentripplanner/ext/transmodelapi/support/GqlUtil.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/support/GqlUtil.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.support; +package org.opentripplanner.apis.transmodel.support; import graphql.Scalars; import graphql.introspection.Introspection.DirectiveLocation; @@ -13,13 +13,13 @@ import java.time.ZoneId; import java.util.List; import java.util.Locale; -import org.opentripplanner.ext.transmodelapi.TransmodelRequestContext; -import org.opentripplanner.ext.transmodelapi.mapping.TransitIdMapper; -import org.opentripplanner.ext.transmodelapi.model.scalars.DateScalarFactory; -import org.opentripplanner.ext.transmodelapi.model.scalars.DateTimeScalarFactory; -import org.opentripplanner.ext.transmodelapi.model.scalars.DoubleFunctionFactory; -import org.opentripplanner.ext.transmodelapi.model.scalars.LocalTimeScalarFactory; -import org.opentripplanner.ext.transmodelapi.model.scalars.TimeScalarFactory; +import org.opentripplanner.apis.transmodel.TransmodelRequestContext; +import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; +import org.opentripplanner.apis.transmodel.model.scalars.DateScalarFactory; +import org.opentripplanner.apis.transmodel.model.scalars.DateTimeScalarFactory; +import org.opentripplanner.apis.transmodel.model.scalars.DoubleFunctionFactory; +import org.opentripplanner.apis.transmodel.model.scalars.LocalTimeScalarFactory; +import org.opentripplanner.apis.transmodel.model.scalars.TimeScalarFactory; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.framework.graphql.scalar.DurationScalarFactory; import org.opentripplanner.routing.graphfinder.GraphFinder; diff --git a/src/main/java/org/opentripplanner/framework/application/OTPFeature.java b/src/main/java/org/opentripplanner/framework/application/OTPFeature.java index 5f39872eed5..05d1284a883 100644 --- a/src/main/java/org/opentripplanner/framework/application/OTPFeature.java +++ b/src/main/java/org/opentripplanner/framework/application/OTPFeature.java @@ -61,8 +61,9 @@ public enum OTPFeature { TransferConstraints( true, false, - "Enforce transfers to happen according to the _transfers.txt_(GTFS) and Interchanges(NeTEx). Turing this _off_ will increase the routing performance a little." + "Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little." ), + TransmodelGraphQlApi(true, true, "Enable Transmodel (NeTEx) GraphQL API."), /* Sandbox extension features - Must be turned OFF by default */ @@ -95,7 +96,6 @@ public enum OTPFeature { SandboxAPIGeocoder(false, true, "Enable the Geocoder API."), SandboxAPIMapboxVectorTilesApi(false, true, "Enable Mapbox vector tiles API."), SandboxAPIParkAndRideApi(false, true, "Enable park-and-ride endpoint."), - SandboxAPITransmodelApi(false, true, "Enable Entur Transmodel(NeTEx) GraphQL API."), SandboxAPITravelTime(false, true, "Enable the isochrone/travel time surface API."), TransferAnalyzer(false, true, "Analyze transfers during graph build."), VehicleToStopHeuristics(false, true, "Enable improved heuristic for park-and-ride queries."); diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/ListSection.java b/src/main/java/org/opentripplanner/framework/collection/ListSection.java similarity index 54% rename from src/main/java/org/opentripplanner/routing/algorithm/filterchain/ListSection.java rename to src/main/java/org/opentripplanner/framework/collection/ListSection.java index a46756775df..d9878aa34b1 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/ListSection.java +++ b/src/main/java/org/opentripplanner/framework/collection/ListSection.java @@ -1,4 +1,4 @@ -package org.opentripplanner.routing.algorithm.filterchain; +package org.opentripplanner.framework.collection; /** * This enum is used to signal which part of a list an operation apply to. You may remove elements @@ -9,5 +9,16 @@ public enum ListSection { HEAD, /** The end of the list */ - TAIL, + TAIL; + + public boolean isHead() { + return this == HEAD; + } + + public ListSection invert() { + return switch (this) { + case HEAD -> TAIL; + case TAIL -> HEAD; + }; + } } diff --git a/src/main/java/org/opentripplanner/framework/collection/ListUtils.java b/src/main/java/org/opentripplanner/framework/collection/ListUtils.java index 481674bb7de..513c0bcc0d3 100644 --- a/src/main/java/org/opentripplanner/framework/collection/ListUtils.java +++ b/src/main/java/org/opentripplanner/framework/collection/ListUtils.java @@ -10,6 +10,22 @@ public class ListUtils { + /** + * Return the first element in the list. {@code null} is returned if the list is + * null or empty. + */ + public static T first(List list) { + return list == null || list.isEmpty() ? null : list.getFirst(); + } + + /** + * Return the last element in the list. {@code null} is returned if the list is + * null or empty. + */ + public static T last(List list) { + return list == null || list.isEmpty() ? null : list.getLast(); + } + /** * Combine a number of collections into a single list. */ diff --git a/src/main/java/org/opentripplanner/framework/lang/Box.java b/src/main/java/org/opentripplanner/framework/lang/Box.java new file mode 100644 index 00000000000..ae54a3c5b7f --- /dev/null +++ b/src/main/java/org/opentripplanner/framework/lang/Box.java @@ -0,0 +1,61 @@ +package org.opentripplanner.framework.lang; + +import java.util.Objects; +import javax.annotation.Nullable; + +/** + * A box around a mutable value reference. This can be used inside a lambda or passed into + * a function. + * @param the type of the wrapped value. + */ +public class Box { + + private T value; + + private Box(T value) { + this.value = value; + } + + public Box() { + this(null); + } + + public static Box empty() { + return new Box<>(); + } + + public static Box of(T value) { + return new Box<>(value); + } + + @Nullable + public T get() { + return value; + } + + public void set(@Nullable T value) { + this.value = value; + } + + public boolean isEmpty() { + return value == null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Box box = (Box) o; + return Objects.equals(value, box.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "[" + value + ']'; + } +} diff --git a/src/main/java/org/opentripplanner/framework/text/CharacterEscapeFormatter.java b/src/main/java/org/opentripplanner/framework/text/CharacterEscapeFormatter.java new file mode 100644 index 00000000000..2bd5bf14b71 --- /dev/null +++ b/src/main/java/org/opentripplanner/framework/text/CharacterEscapeFormatter.java @@ -0,0 +1,107 @@ +package org.opentripplanner.framework.text; + +/** + * This class is used to escape characters in a string, removing a special character from + * the string. For example, if you want to make sure a string does not contain {@code ';'}, + * the {@code ';'} can be replaced with {@code '\+'}. The slash({@code '\'}) is used as an + * escape character, so we need to escape all {@code '\'} as well. Now, the escaped string + * does not contain the special character anymore. The original string can be computed by + * reversing the process. + *

+ * A "special-character" is removed from a text using an escape character and + * a substitution character. For example, if: + *

    + *
  • the escape char is '\'
  • + *
  • the special char is ';'
  • + *
  • and the substitution char is '+'
  • + *
+ * + * then replace: + *
    + *
  • '\' with '\\' and
  • + *
  • ';' with '\;'
  • + *
+ * To get back the original text, the reverse process using {@link #decode(String)}. + *
+ *
+ * Original: "\tThis;is;an;example\+"
+ * Encoded:  "\\tThis\+is\+an\+example\\+"
+ * Decoded:  "\tThis;is;an;example\+"
+ * 
+ */ +public class CharacterEscapeFormatter { + + private final char escapeChar; + private final char specialChar; + private final char substitutionChar; + + /** + * @param escapeChar the character used as an escape character. + * @param specialChar the character to be removed/replaced in the encoded text. + * @param substitutionChar the character used together with the escape character to put in the + * encoded text as a placeholder for the special character. + */ + public CharacterEscapeFormatter(char escapeChar, char specialChar, char substitutionChar) { + this.escapeChar = escapeChar; + this.specialChar = specialChar; + this.substitutionChar = substitutionChar; + } + + /** + * Encode the given text and replace the {@code specialChar} with a placeholder. The original + * text can be retrieved by using {@link #decode(String)}. + * @param text the text to encode. + * @return the encoded text without the {@code specialChar}. + */ + public String encode(String text) { + final var buf = new StringBuilder(); + for (int i = 0; i < text.length(); ++i) { + char ch = text.charAt(i); + if (ch == escapeChar) { + buf.append(escapeChar).append(escapeChar); + } else if (ch == specialChar) { + buf.append(escapeChar).append(substitutionChar); + } else { + buf.append(ch); + } + } + return buf.toString(); + } + + /** + * Return the original text by decoding the encoded text. + * @see #encode(String) + */ + public String decode(String encodedText) { + if (encodedText.length() < 2) { + return encodedText; + } + final var buf = new StringBuilder(); + boolean prevEsc = false; + for (int i = 0; i < encodedText.length(); ++i) { + char ch = encodedText.charAt(i); + if (prevEsc) { + if (ch == escapeChar) { + buf.append(escapeChar); + } else if (ch == substitutionChar) { + buf.append(specialChar); + } else { + throw new IllegalStateException( + "Unexpected combination of escape-char '%c' and '%c' character at position %d. Text: '%s'.".formatted( + escapeChar, + ch, + i, + encodedText + ) + ); + } + prevEsc = false; + } else if (ch == escapeChar) { + prevEsc = true; + } else { + buf.append(ch); + } + } + return buf.toString(); + } +} diff --git a/src/main/java/org/opentripplanner/framework/token/Deserializer.java b/src/main/java/org/opentripplanner/framework/token/Deserializer.java index 6ca2a7977f0..c48723d2e69 100644 --- a/src/main/java/org/opentripplanner/framework/token/Deserializer.java +++ b/src/main/java/org/opentripplanner/framework/token/Deserializer.java @@ -1,97 +1,74 @@ package org.opentripplanner.framework.token; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.time.Duration; -import java.time.Instant; import java.util.ArrayList; import java.util.Base64; import java.util.List; -import org.opentripplanner.framework.time.DurationUtils; +import java.util.regex.Pattern; +import java.util.stream.Stream; class Deserializer { - private final ByteArrayInputStream input; + private static final Pattern SPLIT_PATTERN = Pattern.compile( + "[" + TokenFormatterConfiguration.fieldSeparator() + "]" + ); + + private final List values; Deserializer(String token) { - this.input = new ByteArrayInputStream(Base64.getUrlDecoder().decode(token)); + byte[] bytes = Base64.getUrlDecoder().decode(token); + var tokenFormatter = TokenFormatterConfiguration.tokenFormatter(); + this.values = + Stream.of(SPLIT_PATTERN.split(new String(bytes), -1)).map(tokenFormatter::decode).toList(); } - List deserialize(TokenDefinition definition) throws IOException { + List deserialize(TokenDefinition definition) { try { // Assume deprecated fields are included in the token return readFields(definition, false); - } catch (IOException ignore) { + } catch (Exception ignore) { // If the token is the next version, then deprecated field are removed. Try // skipping the deprecated tokens return readFields(definition, true); } } - private List readFields(TokenDefinition definition, boolean matchNewVersionPlusOne) - throws IOException { - input.reset(); + private List readFields(TokenDefinition definition, boolean matchNewVersionPlusOne) { List result = new ArrayList<>(); - - var in = new ObjectInputStream(input); - - readAndMatchVersion(in, definition, matchNewVersionPlusOne); + matchVersion(definition, matchNewVersionPlusOne); + int index = 1; for (FieldDefinition field : definition.listFields()) { if (matchNewVersionPlusOne && field.deprecated()) { continue; } - var v = read(in, field); + var v = read(field, index); if (!field.deprecated()) { result.add(v); } + ++index; } return result; } - private void readAndMatchVersion( - ObjectInputStream in, - TokenDefinition definition, - boolean matchVersionPlusOne - ) throws IOException { + private void matchVersion(TokenDefinition definition, boolean matchVersionPlusOne) { int matchVersion = (matchVersionPlusOne ? 1 : 0) + definition.version(); - int v = readInt(in); - if (v != matchVersion) { - throw new IOException( - "Version does not match. Token version: " + v + ", schema version: " + definition.version() + int version = readVersion(); + if (version != matchVersion) { + throw new IllegalStateException( + "Version does not match. Token version: " + + version + + ", schema version: " + + definition.version() ); } } - private Object read(ObjectInputStream in, FieldDefinition field) throws IOException { - return switch (field.type()) { - case BYTE -> readByte(in); - case DURATION -> readDuration(in); - case INT -> readInt(in); - case STRING -> readString(in); - case TIME_INSTANT -> readTimeInstant(in); - }; - } - - private static byte readByte(ObjectInputStream in) throws IOException { - return in.readByte(); - } - - private static int readInt(ObjectInputStream in) throws IOException { - return Integer.parseInt(in.readUTF()); - } - - private static String readString(ObjectInputStream in) throws IOException { - return in.readUTF(); - } - - private static Duration readDuration(ObjectInputStream in) throws IOException { - return DurationUtils.duration(in.readUTF()); + private Object read(FieldDefinition field, int index) { + return field.type().stringToValue(values.get(index)); } - private static Instant readTimeInstant(ObjectInputStream in) throws IOException { - return Instant.parse(in.readUTF()); + private int readVersion() { + return Integer.parseInt(values.get(0)); } } diff --git a/src/main/java/org/opentripplanner/framework/token/Serializer.java b/src/main/java/org/opentripplanner/framework/token/Serializer.java index d65f0b8983d..2d01a0ebf5e 100644 --- a/src/main/java/org/opentripplanner/framework/token/Serializer.java +++ b/src/main/java/org/opentripplanner/framework/token/Serializer.java @@ -1,81 +1,50 @@ package org.opentripplanner.framework.token; -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.time.Duration; -import java.time.Instant; import java.util.Base64; -import org.opentripplanner.framework.time.DurationUtils; +import org.opentripplanner.framework.text.CharacterEscapeFormatter; -class Serializer implements Closeable { +class Serializer { private final TokenDefinition definition; private final Object[] values; - private final ObjectOutputStream out; - private final ByteArrayOutputStream buf = new ByteArrayOutputStream(); + private final StringBuilder buf = new StringBuilder(); + private final CharacterEscapeFormatter tokenFormatter = TokenFormatterConfiguration.tokenFormatter(); - private Serializer(TokenDefinition definition, Object[] values) throws IOException { + private Serializer(TokenDefinition definition, Object[] values) { this.definition = definition; this.values = values; - this.out = new ObjectOutputStream(buf); } - @Override - public void close() throws IOException { - out.close(); - } - - static String serialize(TokenDefinition definition, Object[] values) throws IOException { - try (var s = new Serializer(definition, values)) { - s.writeInt(definition.version()); - - for (var fieldName : definition.fieldNames()) { - s.write(fieldName); - } - return s.serialize(); + static String serialize(TokenDefinition definition, Object[] values) { + var s = new Serializer(definition, values); + s.writeVersion(definition.version()); + for (var fieldName : definition.fieldNames()) { + s.write(fieldName); } + return s.serialize(); } - private String serialize() throws IOException { - out.close(); - return Base64.getUrlEncoder().encodeToString(buf.toByteArray()); + private String serialize() { + return Base64.getUrlEncoder().encodeToString(buf.toString().getBytes()); } - private void write(String fieldName) throws IOException { + private void write(String fieldName) { write(fieldName, values[definition.index(fieldName)]); } - private void write(String fieldName, Object value) throws IOException { + private void write(String fieldName, Object value) { var type = definition.type(fieldName); - switch (type) { - case BYTE -> writeByte((byte) value); - case DURATION -> writeDuration((Duration) value); - case INT -> writeInt((int) value); - case STRING -> writeString((String) value); - case TIME_INSTANT -> writeTimeInstant((Instant) value); - default -> throw new IllegalArgumentException("Unknown type: " + type); - } - } - - private void writeByte(byte value) throws IOException { - out.writeByte(value); + writeString(type.valueToString(value)); } - private void writeInt(int value) throws IOException { - out.writeUTF(Integer.toString(value)); + private void writeVersion(int value) { + writeString(TokenType.INT.valueToString(value)); } - private void writeString(String value) throws IOException { - out.writeUTF(value); - } - - private void writeDuration(Duration duration) throws IOException { - out.writeUTF(DurationUtils.durationToStr(duration)); - } - - private void writeTimeInstant(Instant time) throws IOException { - out.writeUTF(time.toString()); + private void writeString(String value) { + if (value != null) { + buf.append(tokenFormatter.encode(value)); + } + buf.append(TokenFormatterConfiguration.fieldSeparator()); } } diff --git a/src/main/java/org/opentripplanner/framework/token/Token.java b/src/main/java/org/opentripplanner/framework/token/Token.java index 0d527a16cbe..2dc02169271 100644 --- a/src/main/java/org/opentripplanner/framework/token/Token.java +++ b/src/main/java/org/opentripplanner/framework/token/Token.java @@ -4,6 +4,7 @@ import java.time.Instant; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; /** @@ -24,6 +25,10 @@ public int version() { return definition.version(); } + public boolean getBoolean(String fieldName) { + return (boolean) get(fieldName, TokenType.BOOLEAN); + } + public byte getByte(String fieldName) { return (byte) get(fieldName, TokenType.BYTE); } @@ -40,6 +45,26 @@ public String getString(String fieldName) { return (String) get(fieldName, TokenType.STRING); } + /** + * Be careful with enums. If values are added or deleted the backward/forward compatibility + * is compromised. This method return an empty value if the enum does not exist. + *

+ * To ensure that enum values are forward compatible the value must first be added, and then it + * can not be used in a token before OTP is released and deployed. Then when the enum value + * exist in the deployed server, then a new version of OTP can be rolled out which now can use + * the new value. + *

+ * To ensure backwards compatibility, enum values should be **deprecated**, not removed. The enum + * value can only be deleted, when all tokens with the value has expired (depends on use-case). + */ + public > Optional getEnum(String fieldName, Class enumClass) { + try { + return Optional.of(Enum.valueOf(enumClass, (String) get(fieldName, TokenType.ENUM))); + } catch (IllegalArgumentException ignore) { + return Optional.empty(); + } + } + public Instant getTimeInstant(String fieldName) { return (Instant) get(fieldName, TokenType.TIME_INSTANT); } diff --git a/src/main/java/org/opentripplanner/framework/token/TokenBuilder.java b/src/main/java/org/opentripplanner/framework/token/TokenBuilder.java index d5f1b043818..4061d073a2d 100644 --- a/src/main/java/org/opentripplanner/framework/token/TokenBuilder.java +++ b/src/main/java/org/opentripplanner/framework/token/TokenBuilder.java @@ -1,6 +1,5 @@ package org.opentripplanner.framework.token; -import java.io.IOException; import java.time.Duration; import java.time.Instant; import org.opentripplanner.framework.lang.ObjectUtils; @@ -18,10 +17,18 @@ public TokenBuilder(TokenDefinition definition) { this.values = new Object[definition.size()]; } + public TokenBuilder withBoolean(String fieldName, boolean v) { + return with(fieldName, TokenType.BOOLEAN, v); + } + public TokenBuilder withByte(String fieldName, byte v) { return with(fieldName, TokenType.BYTE, v); } + public TokenBuilder withEnum(String fieldName, Enum v) { + return with(fieldName, TokenType.ENUM, v); + } + public TokenBuilder withDuration(String fieldName, Duration v) { return with(fieldName, TokenType.DURATION, v); } @@ -39,11 +46,7 @@ public TokenBuilder withTimeInstant(String fieldName, Instant v) { } public String build() { - try { - return Serializer.serialize(definition, values); - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } + return Serializer.serialize(definition, values); } private TokenBuilder with(String fieldName, TokenType type, Object value) { diff --git a/src/main/java/org/opentripplanner/framework/token/TokenDefinitionBuilder.java b/src/main/java/org/opentripplanner/framework/token/TokenDefinitionBuilder.java index f4d3014128e..06a935c7b47 100644 --- a/src/main/java/org/opentripplanner/framework/token/TokenDefinitionBuilder.java +++ b/src/main/java/org/opentripplanner/framework/token/TokenDefinitionBuilder.java @@ -26,10 +26,18 @@ public TokenDefinitionBuilder addByte(String fieldName) { return add(fieldName, TokenType.BYTE); } + public TokenDefinitionBuilder addBoolean(String fieldName) { + return add(fieldName, TokenType.BOOLEAN); + } + public TokenDefinitionBuilder addDuration(String fieldName) { return add(fieldName, TokenType.DURATION); } + public TokenDefinitionBuilder addEnum(String fieldName) { + return add(fieldName, TokenType.ENUM); + } + public TokenDefinitionBuilder addInt(String fieldName) { return add(fieldName, TokenType.INT); } diff --git a/src/main/java/org/opentripplanner/framework/token/TokenFormatterConfiguration.java b/src/main/java/org/opentripplanner/framework/token/TokenFormatterConfiguration.java new file mode 100644 index 00000000000..3945014dad5 --- /dev/null +++ b/src/main/java/org/opentripplanner/framework/token/TokenFormatterConfiguration.java @@ -0,0 +1,25 @@ +package org.opentripplanner.framework.token; + +import org.opentripplanner.framework.text.CharacterEscapeFormatter; + +class TokenFormatterConfiguration { + + private static final char TOKEN_ESCAPE = '\\'; + private static final char TOKEN_SUBSTITUTION = '+'; + private static final char FIELD_SEPARATOR = '|'; + + /** Prevent instantiation - this is a utility class. */ + private TokenFormatterConfiguration() {} + + /** + * We use the pipe '|' for field separations. The IDs included in the token frequently use + * ':' so the visual difference is better than the alternatives like ',' ';' and TAB. + */ + static char fieldSeparator() { + return FIELD_SEPARATOR; + } + + static CharacterEscapeFormatter tokenFormatter() { + return new CharacterEscapeFormatter(TOKEN_ESCAPE, FIELD_SEPARATOR, TOKEN_SUBSTITUTION); + } +} diff --git a/src/main/java/org/opentripplanner/framework/token/TokenType.java b/src/main/java/org/opentripplanner/framework/token/TokenType.java index 0a890a44005..aea39949b0e 100644 --- a/src/main/java/org/opentripplanner/framework/token/TokenType.java +++ b/src/main/java/org/opentripplanner/framework/token/TokenType.java @@ -1,5 +1,10 @@ package org.opentripplanner.framework.token; +import java.time.Duration; +import java.time.Instant; +import javax.annotation.Nullable; +import org.opentripplanner.framework.time.DurationUtils; + /** * List of types we can store in a token. *

@@ -8,13 +13,47 @@ * compatible with the new value of the enum. */ public enum TokenType { + BOOLEAN, BYTE, DURATION, + ENUM, INT, STRING, TIME_INSTANT; + private static final String EMPTY = ""; + boolean isNot(TokenType other) { return this != other; } + + public String valueToString(@Nullable Object value) { + if (value == null) { + return EMPTY; + } + return switch (this) { + case BOOLEAN -> Boolean.toString((boolean) value); + case BYTE -> Byte.toString((byte) value); + case DURATION -> DurationUtils.durationToStr((Duration) value); + case ENUM -> ((Enum) value).name(); + case INT -> Integer.toString((int) value); + case STRING -> (String) value; + case TIME_INSTANT -> value.toString(); + }; + } + + public Object stringToValue(String value) { + if (EMPTY.equals(value)) { + return null; + } + return switch (this) { + case BOOLEAN -> Boolean.valueOf(value); + case BYTE -> Byte.valueOf(value); + case DURATION -> DurationUtils.duration(value); + case ENUM -> value; + case INT -> Integer.valueOf(value); + case STRING -> value; + case TIME_INSTANT -> Instant.parse(value); + }; + } } diff --git a/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java b/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java index d2cec512420..cb5d26294db 100644 --- a/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java +++ b/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java @@ -60,6 +60,14 @@ public static ToStringBuilder of(Class clazz) { return new ToStringBuilder(clazz.getSimpleName()); } + /** + * Create a ToStringBuilder for a "named" type. The preferred method is {@link #of(Class)}, + * but this can be used if the type is unknown or irrelevant. + */ + public static ToStringBuilder of(String name) { + return new ToStringBuilder(name); + } + /** * Create a ToStringBuilder for a regular POJO type without including the type in the name. Some * classes are always embedded in other classes and the type is given, for these cases this diff --git a/src/main/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilder.java b/src/main/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilder.java index 7882bd347da..14584a8dd4a 100644 --- a/src/main/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilder.java +++ b/src/main/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilder.java @@ -1,6 +1,7 @@ package org.opentripplanner.framework.tostring; import java.time.Duration; +import java.time.Instant; import java.util.function.Function; import org.opentripplanner.framework.lang.OtpNumberFormat; import org.opentripplanner.framework.time.DurationUtils; @@ -153,6 +154,10 @@ public ValueObjectToStringBuilder addDurationSec(Integer durationSeconds) { return addIt(durationSeconds, DurationUtils::durationToStr); } + public ValueObjectToStringBuilder addTime(Instant time) { + return addIt(time, Object::toString); + } + /** * Add a cost in the format $N, as in "transit seconds", not centi-seconds as used by Raptor. */ diff --git a/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java b/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java index 3a2bb777f04..8b2e55ffc2f 100644 --- a/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java +++ b/src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java @@ -160,6 +160,10 @@ public static GraphBuilder create( graphBuilder.addModule(factory.graphCoherencyCheckerModule()); } + if (OTPFeature.Co2Emissions.isOn()) { + graphBuilder.addModule(factory.emissionsModule()); + } + if (config.dataImportReport) { graphBuilder.addModule(factory.dataImportIssueReporter()); } @@ -168,10 +172,6 @@ public static GraphBuilder create( graphBuilder.addModuleOptional(factory.dataOverlayFactory()); } - if (OTPFeature.Co2Emissions.isOn()) { - graphBuilder.addModule(factory.emissionsModule()); - } - graphBuilder.addModule(factory.calculateWorldEnvelopeModule()); return graphBuilder; diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java index 4dec2b779ca..591a59c492e 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/LocationGroupMapper.java @@ -5,7 +5,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.onebusaway.gtfs.model.Location; +import org.onebusaway.gtfs.model.LocationGroup; import org.onebusaway.gtfs.model.Stop; import org.opentripplanner.framework.collection.MapUtils; import org.opentripplanner.framework.i18n.NonLocalizedString; @@ -19,7 +21,7 @@ public class LocationGroupMapper { private final LocationMapper locationMapper; private final StopModelBuilder stopModelBuilder; - private final Map mappedLocationGroups = new HashMap<>(); + private final Map mappedLocationGroups = new HashMap<>(); public LocationGroupMapper( StopMapper stopMapper, @@ -31,29 +33,34 @@ public LocationGroupMapper( this.stopModelBuilder = stopModelBuilder; } - Collection map(Collection allLocationGroups) { + Collection map(Collection allLocationGroups) { return MapUtils.mapToList(allLocationGroups, this::map); } /** Map from GTFS to OTP model, {@code null} safe. */ - GroupStop map(org.onebusaway.gtfs.model.LocationGroup original) { + GroupStop map(LocationGroup original) { return original == null ? null : mappedLocationGroups.computeIfAbsent(original, this::doMap); } - private GroupStop doMap(org.onebusaway.gtfs.model.LocationGroup element) { + private GroupStop doMap(LocationGroup element) { GroupStopBuilder groupStopBuilder = stopModelBuilder .groupStop(mapAgencyAndId(element.getId())) .withName(new NonLocalizedString(element.getName())); - for (org.onebusaway.gtfs.model.StopLocation location : element.getLocations()) { - if (location instanceof Stop) { - groupStopBuilder.addLocation(stopMapper.map((Stop) location)); - } else if (location instanceof Location) { - groupStopBuilder.addLocation(locationMapper.map((Location) location)); - } else if (location instanceof org.onebusaway.gtfs.model.LocationGroup) { - throw new RuntimeException("Nested GroupStops are not allowed"); - } else { - throw new RuntimeException("Unknown location type: " + location.getClass().getSimpleName()); + for (var location : element.getLocations()) { + Objects.requireNonNull( + location, + "Location group '%s' contains a null element.".formatted(element.getId()) + ); + switch (location) { + case Stop stop -> groupStopBuilder.addLocation(stopMapper.map(stop)); + case Location loc -> groupStopBuilder.addLocation(locationMapper.map(loc)); + case LocationGroup ignored -> throw new RuntimeException( + "Nested GroupStops are not allowed" + ); + default -> throw new RuntimeException( + "Unknown location type: " + location.getClass().getSimpleName() + ); } } diff --git a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java index 148a5160d24..47f49a58fc1 100644 --- a/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java +++ b/src/main/java/org/opentripplanner/gtfs/mapping/StopTimeMapper.java @@ -3,6 +3,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.onebusaway.gtfs.model.Location; import org.onebusaway.gtfs.model.LocationGroup; import org.onebusaway.gtfs.model.Stop; @@ -57,12 +58,18 @@ private StopTime doMap(org.onebusaway.gtfs.model.StopTime rhs) { StopTime lhs = new StopTime(); lhs.setTrip(tripMapper.map(rhs.getTrip())); - if (rhs.getStop() instanceof Stop) { - lhs.setStop(stopMapper.map((Stop) rhs.getStop())); - } else if (rhs.getStop() instanceof Location) { - lhs.setStop(locationMapper.map((Location) rhs.getStop())); - } else if (rhs.getStop() instanceof LocationGroup) { - lhs.setStop(locationGroupMapper.map((LocationGroup) rhs.getStop())); + var stopLocation = rhs.getStopLocation(); + Objects.requireNonNull( + stopLocation, + "Trip %s contains stop_time with no stop, location or group.".formatted(rhs.getTrip()) + ); + switch (stopLocation) { + case Stop stop -> lhs.setStop(stopMapper.map(stop)); + case Location location -> lhs.setStop(locationMapper.map(location)); + case LocationGroup locGroup -> lhs.setStop(locationGroupMapper.map(locGroup)); + default -> throw new IllegalArgumentException( + "Unknown location type: %s".formatted(stopLocation) + ); } I18NString stopHeadsign = null; diff --git a/src/main/java/org/opentripplanner/model/plan/ItinerarySortKey.java b/src/main/java/org/opentripplanner/model/plan/ItinerarySortKey.java index 0918f398325..b9165270444 100644 --- a/src/main/java/org/opentripplanner/model/plan/ItinerarySortKey.java +++ b/src/main/java/org/opentripplanner/model/plan/ItinerarySortKey.java @@ -1,6 +1,7 @@ package org.opentripplanner.model.plan; import java.time.Instant; +import org.opentripplanner.framework.tostring.ValueObjectToStringBuilder; import org.opentripplanner.routing.algorithm.filterchain.comparator.SortOrderComparator; import org.opentripplanner.routing.algorithm.filterchain.filter.SortingFilter; @@ -18,4 +19,21 @@ public interface ItinerarySortKey { int getGeneralizedCost(); int getNumberOfTransfers(); boolean isOnStreetAllTheWay(); + + default String keyAsString() { + return ValueObjectToStringBuilder + .of() + .addText("[") + .addTime(startTimeAsInstant()) + .addText(", ") + .addTime(endTimeAsInstant()) + .addText(", ") + .addCost(getGeneralizedCost()) + .addText(", Tx") + .addNum(getNumberOfTransfers()) + .addText(", ") + .addBool(isOnStreetAllTheWay(), "onStreet", "transit") + .addText("]") + .toString(); + } } diff --git a/src/main/java/org/opentripplanner/model/plan/Place.java b/src/main/java/org/opentripplanner/model/plan/Place.java index 6f39dcad3d1..71c6d9bc188 100644 --- a/src/main/java/org/opentripplanner/model/plan/Place.java +++ b/src/main/java/org/opentripplanner/model/plan/Place.java @@ -139,9 +139,9 @@ public static Place forVehicleParkingEntrance(VehicleParkingEntranceVertex verte traverseMode = TraverseMode.BICYCLE; } - boolean realTime = - request.parking().useAvailabilityInformation() && - vertex.getVehicleParking().hasRealTimeDataForMode(traverseMode, request.wheelchair()); + boolean realTime = vertex + .getVehicleParking() + .hasRealTimeDataForMode(traverseMode, request.wheelchair()); return new Place( vertex.getName(), WgsCoordinate.creatOptionalCoordinate(vertex.getLat(), vertex.getLon()), diff --git a/src/main/java/org/opentripplanner/model/plan/SortOrder.java b/src/main/java/org/opentripplanner/model/plan/SortOrder.java index 812973ebb4d..342f963ba00 100644 --- a/src/main/java/org/opentripplanner/model/plan/SortOrder.java +++ b/src/main/java/org/opentripplanner/model/plan/SortOrder.java @@ -39,7 +39,7 @@ public enum SortOrder { * This returns {@code true} for the default depart-after search, and {@code false} for an * arrive-by search. */ - public boolean isSortedByArrivalTimeAscending() { + public boolean isSortedByAscendingArrivalTime() { return this == STREET_AND_ARRIVAL_TIME; } } diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/ItineraryPageCut.java b/src/main/java/org/opentripplanner/model/plan/pagecursor/ItineraryPageCut.java deleted file mode 100644 index 53958837dd8..00000000000 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/ItineraryPageCut.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.opentripplanner.model.plan.pagecursor; - -import java.time.Instant; -import org.opentripplanner.framework.tostring.ToStringBuilder; -import org.opentripplanner.model.plan.ItinerarySortKey; -import org.opentripplanner.model.plan.SortOrder; -import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.DefaultCostCalculator; - -/** - * This class contains all the information needed to dedupe itineraries when - * paging. - *

- * It implements the ItinerarySortKey interface so that it can be sorted with itineraries which - * potentially contain duplicates. - */ -public record ItineraryPageCut( - Instant windowStart, - Instant windowEnd, - SortOrder sortOrder, - PagingDeduplicationSection deduplicationSection, - Instant arrivalTimeThreshold, - Instant departureTimeThreshold, - int generalizedCostThreshold, - int numOfTransfersThreshold, - boolean onStreetAllTheWayThreshold -) - implements ItinerarySortKey { - @Override - public String toString() { - return ToStringBuilder - .of(ItineraryPageCut.class) - .addDateTime("windowStart", windowStart) - .addDateTime("windowEnd", windowEnd) - .addEnum("sortOrder", sortOrder) - .addEnum("deduplicationSection", deduplicationSection) - .addBool("isOnStreetAllTheWayThreshold", onStreetAllTheWayThreshold) - .addDateTime("arrivalTimeThreshold", arrivalTimeThreshold) - .addCost( - "generalizedCostThreshold", - generalizedCostThreshold, - DefaultCostCalculator.ZERO_COST - ) - .addNum("numOfTransfersThreshold", numOfTransfersThreshold) - .addDateTime("departureTimeThreshold", departureTimeThreshold) - .toString(); - } - - @Override - public Instant startTimeAsInstant() { - return departureTimeThreshold(); - } - - @Override - public Instant endTimeAsInstant() { - return arrivalTimeThreshold(); - } - - @Override - public int getGeneralizedCost() { - return generalizedCostThreshold(); - } - - @Override - public int getNumberOfTransfers() { - return numOfTransfersThreshold(); - } - - @Override - public boolean isOnStreetAllTheWay() { - return isOnStreetAllTheWayThreshold(); - } - - public Instant windowStart() { - return windowStart; - } - - public Instant windowEnd() { - return windowEnd; - } - - public PagingDeduplicationSection deduplicationSection() { - return deduplicationSection; - } - - public SortOrder sortOrder() { - return sortOrder; - } - - public boolean isOnStreetAllTheWayThreshold() { - return onStreetAllTheWayThreshold; - } - - public Instant arrivalTimeThreshold() { - return arrivalTimeThreshold; - } - - public int generalizedCostThreshold() { - return generalizedCostThreshold; - } - - public int numOfTransfersThreshold() { - return numOfTransfersThreshold; - } - - public Instant departureTimeThreshold() { - return departureTimeThreshold; - } -} diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorInput.java b/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorInput.java deleted file mode 100644 index 58cd6c7e24b..00000000000 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorInput.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.opentripplanner.model.plan.pagecursor; - -import java.time.Instant; - -/** - * This class holds information needed to create the next/previous page cursors when there were - * itineraries removed due to cropping the list of itineraries using the numItineraries parameter. - *

- * The Instant fields come from the sets of itineraries that were removed and the ones that were - * kept as a result of using the numItineraries parameter. - */ -public interface PageCursorInput { - Instant earliestRemovedDeparture(); - Instant earliestKeptArrival(); - Instant latestRemovedDeparture(); - Instant latestRemovedArrival(); - Instant firstRemovedArrivalTime(); - boolean firstRemovedIsOnStreetAllTheWay(); - int firstRemovedGeneralizedCost(); - int firstRemovedNumOfTransfers(); - Instant firstRemovedDepartureTime(); - PagingDeduplicationSection deduplicationSection(); -} diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorSerializer.java b/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorSerializer.java deleted file mode 100644 index b01f07892ac..00000000000 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorSerializer.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.opentripplanner.model.plan.pagecursor; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.Base64; -import javax.annotation.Nullable; -import org.opentripplanner.framework.lang.StringUtils; -import org.opentripplanner.model.plan.SortOrder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class PageCursorSerializer { - - private static final int NOT_SET = Integer.MIN_VALUE; - private static final byte VERSION = 1; - private static final long TIME_ZERO = ZonedDateTime - .of(2020, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")) - .toEpochSecond(); - private static final Logger LOG = LoggerFactory.getLogger(PageCursor.class); - - /** private constructor to prevent instantiating this utility class */ - private PageCursorSerializer() { - /* empty */ - } - - @Nullable - public static String encode(PageCursor cursor) { - var buf = new ByteArrayOutputStream(); - try (var out = new ObjectOutputStream(buf)) { - // The order must be the same in the encode and decode function - writeByte(VERSION, out); - writeEnum(cursor.type, out); - writeTime(cursor.earliestDepartureTime, out); - writeTime(cursor.latestArrivalTime, out); - writeDuration(cursor.searchWindow, out); - writeEnum(cursor.originalSortOrder, out); - - if (cursor.containsItineraryPageCut()) { - writeTime(cursor.itineraryPageCut.windowStart(), out); - writeTime(cursor.itineraryPageCut.windowEnd(), out); - writeEnum(cursor.itineraryPageCut.deduplicationSection(), out); - writeBoolean(cursor.itineraryPageCut.isOnStreetAllTheWayThreshold(), out); - writeTime(cursor.itineraryPageCut.arrivalTimeThreshold(), out); - writeInt(cursor.itineraryPageCut.generalizedCostThreshold(), out); - writeInt(cursor.itineraryPageCut.numOfTransfersThreshold(), out); - writeTime(cursor.itineraryPageCut.departureTimeThreshold(), out); - } - out.flush(); - return Base64.getUrlEncoder().encodeToString(buf.toByteArray()); - } catch (IOException e) { - LOG.error("Failed to encode page cursor", e); - return null; - } - } - - @Nullable - public static PageCursor decode(String cursor) { - if (StringUtils.hasNoValueOrNullAsString(cursor)) { - return null; - } - try { - var buf = Base64.getUrlDecoder().decode(cursor); - var input = new ByteArrayInputStream(buf); - - var in = new ObjectInputStream(input); - // The order must be the same in the encode and decode function - - // The version should be used to make serialization read/write forward and backward - // compatible in the future. - var version = readByte(in); - var type = readEnum(in, PageType.class); - var edt = readTime(in); - var lat = readTime(in); - var searchWindow = readDuration(in); - var originalSortOrder = readEnum(in, SortOrder.class); - - if (in.available() > 0) { - var dedupeWindowStart = readTime(in); - var dedupeWindowEnd = readTime(in); - var cropSection = readEnum(in, PagingDeduplicationSection.class); - var isOnStreetAllTheWayThreshold = readBoolean(in); - var arrivalTimeDeletionThreshold = readTime(in); - var generalizedCostDeletionThreshold = readInt(in); - var numOfTransfersDeletionThreshold = readInt(in); - var departureTimeDeletionThreshold = readTime(in); - - ItineraryPageCut itineraryPageCut = new ItineraryPageCut( - dedupeWindowStart, - dedupeWindowEnd, - originalSortOrder, - cropSection, - arrivalTimeDeletionThreshold, - departureTimeDeletionThreshold, - generalizedCostDeletionThreshold, - numOfTransfersDeletionThreshold, - isOnStreetAllTheWayThreshold - ); - return new PageCursor(type, originalSortOrder, edt, lat, searchWindow) - .withItineraryPageCut(itineraryPageCut); - } - - return new PageCursor(type, originalSortOrder, edt, lat, searchWindow); - } catch (Exception e) { - String details = e.getMessage(); - if (details != null && !details.isBlank()) { - LOG.warn("Unable to decode page cursor: '{}'. Details: {}", cursor, details); - } else { - LOG.warn("Unable to decode page cursor: '{}'.", cursor); - } - return null; - } - } - - private static void writeByte(byte value, ObjectOutputStream out) throws IOException { - out.writeByte(value); - } - - private static byte readByte(ObjectInputStream in) throws IOException { - return in.readByte(); - } - - private static void writeInt(int value, ObjectOutputStream out) throws IOException { - out.writeInt(value); - } - - private static int readInt(ObjectInputStream in) throws IOException { - return in.readInt(); - } - - private static void writeBoolean(boolean value, ObjectOutputStream out) throws IOException { - out.writeBoolean(value); - } - - private static boolean readBoolean(ObjectInputStream in) throws IOException { - return in.readBoolean(); - } - - private static void writeTime(Instant time, ObjectOutputStream out) throws IOException { - out.writeInt(time == null ? NOT_SET : (int) (time.getEpochSecond() - TIME_ZERO)); - } - - @Nullable - private static Instant readTime(ObjectInputStream in) throws IOException { - var value = in.readInt(); - return value == NOT_SET ? null : Instant.ofEpochSecond(TIME_ZERO + value); - } - - private static void writeDuration(Duration duration, ObjectOutputStream out) throws IOException { - out.writeInt((int) duration.toSeconds()); - } - - private static Duration readDuration(ObjectInputStream in) throws IOException { - return Duration.ofSeconds(in.readInt()); - } - - private static > void writeEnum(T value, ObjectOutputStream out) - throws IOException { - out.writeUTF(value.name()); - } - - @SuppressWarnings("SameParameterValue") - private static > T readEnum(ObjectInputStream in, Class enumType) - throws IOException { - String value = in.readUTF(); - return Enum.valueOf(enumType, value); - } -} diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/PagingDeduplicationSection.java b/src/main/java/org/opentripplanner/model/plan/pagecursor/PagingDeduplicationSection.java deleted file mode 100644 index 0a469fdc6be..00000000000 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/PagingDeduplicationSection.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.opentripplanner.model.plan.pagecursor; - -/** - * The PagingDeduplicationSection enum is used to signal which part of an itinerary list may contain - * duplicates. When paging it is the opposite of the CropSection defined in ListSection. That is, if - * the list of itineraries was cropped at the bottom, then any duplicates will appear at the top of - * the list and vice versa. - */ -public enum PagingDeduplicationSection { - HEAD, - TAIL, -} diff --git a/src/main/java/org/opentripplanner/model/plan/PagingSearchWindowAdjuster.java b/src/main/java/org/opentripplanner/model/plan/paging/PagingSearchWindowAdjuster.java similarity index 99% rename from src/main/java/org/opentripplanner/model/plan/PagingSearchWindowAdjuster.java rename to src/main/java/org/opentripplanner/model/plan/paging/PagingSearchWindowAdjuster.java index 703499a5d26..f9e939532bb 100644 --- a/src/main/java/org/opentripplanner/model/plan/PagingSearchWindowAdjuster.java +++ b/src/main/java/org/opentripplanner/model/plan/paging/PagingSearchWindowAdjuster.java @@ -1,4 +1,4 @@ -package org.opentripplanner.model.plan; +package org.opentripplanner.model.plan.paging; import java.time.Duration; import java.time.Instant; diff --git a/src/main/java/org/opentripplanner/model/plan/paging/cursor/DeduplicationPageCut.java b/src/main/java/org/opentripplanner/model/plan/paging/cursor/DeduplicationPageCut.java new file mode 100644 index 00000000000..611b8116b8b --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/paging/cursor/DeduplicationPageCut.java @@ -0,0 +1,50 @@ +package org.opentripplanner.model.plan.paging.cursor; + +import java.time.Instant; +import org.opentripplanner.model.plan.ItinerarySortKey; + +/** + * This class contains all the information needed to dedupe itineraries when + * paging - the exact same information as the {@link ItinerarySortKey}. + *

+ * It implements the ItinerarySortKey interface so that it can be sorted with itineraries which + * potentially contain duplicates. + */ +record DeduplicationPageCut( + Instant departureTime, + Instant arrivalTime, + int generalizedCost, + int numOfTransfers, + boolean onStreet +) + implements ItinerarySortKey { + @Override + public Instant startTimeAsInstant() { + return departureTime; + } + + @Override + public Instant endTimeAsInstant() { + return arrivalTime; + } + + @Override + public int getGeneralizedCost() { + return generalizedCost; + } + + @Override + public int getNumberOfTransfers() { + return numOfTransfers; + } + + @Override + public boolean isOnStreetAllTheWay() { + return onStreet; + } + + @Override + public String toString() { + return keyAsString(); + } +} diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursor.java b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursor.java similarity index 51% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursor.java rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursor.java index e0c1e30c64d..a52dc0429c1 100644 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursor.java +++ b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursor.java @@ -1,9 +1,11 @@ -package org.opentripplanner.model.plan.pagecursor; +package org.opentripplanner.model.plan.paging.cursor; import java.time.Duration; import java.time.Instant; import javax.annotation.Nullable; +import org.opentripplanner.framework.collection.ListSection; import org.opentripplanner.framework.tostring.ToStringBuilder; +import org.opentripplanner.model.plan.ItinerarySortKey; import org.opentripplanner.model.plan.SortOrder; /** @@ -16,39 +18,17 @@ *

* THIS CLASS IS IMMUTABLE AND THREAD-SAFE */ -public class PageCursor { - - public final PageType type; - public final SortOrder originalSortOrder; - public final Instant earliestDepartureTime; - public final Instant latestArrivalTime; - public final Duration searchWindow; - - public ItineraryPageCut itineraryPageCut; - - PageCursor( - PageType type, - SortOrder originalSortOrder, - Instant earliestDepartureTime, - Instant latestArrivalTime, - Duration searchWindow - ) { - this.type = type; - this.searchWindow = searchWindow; - this.earliestDepartureTime = earliestDepartureTime; - this.latestArrivalTime = latestArrivalTime; - this.originalSortOrder = originalSortOrder; - } - - public PageCursor withItineraryPageCut(ItineraryPageCut itineraryPageCut) { - this.itineraryPageCut = itineraryPageCut; - return this; - } - +public record PageCursor( + PageType type, + SortOrder originalSortOrder, + Instant earliestDepartureTime, + Instant latestArrivalTime, + Duration searchWindow, + @Nullable ItinerarySortKey itineraryPageCut +) { public boolean containsItineraryPageCut() { return itineraryPageCut != null; } - @Nullable public String encode() { return PageCursorSerializer.encode(this); @@ -59,6 +39,27 @@ public static PageCursor decode(String cursor) { return PageCursorSerializer.decode(cursor); } + /** + * When paging we must crop the list of itineraries in the right end according to the sorting of + * the original search and according to the paging direction(next or previous). + */ + public ListSection cropItinerariesAt() { + // Depart after search + if (originalSortOrder().isSortedByAscendingArrivalTime()) { + return switch (type) { + case NEXT_PAGE -> ListSection.TAIL; + case PREVIOUS_PAGE -> ListSection.HEAD; + }; + } + // Arrive by search + else { + return switch (type) { + case NEXT_PAGE -> ListSection.HEAD; + case PREVIOUS_PAGE -> ListSection.TAIL; + }; + } + } + @Override public String toString() { return ToStringBuilder @@ -68,7 +69,8 @@ public String toString() { .addDateTime("edt", earliestDepartureTime) .addDateTime("lat", latestArrivalTime) .addDuration("searchWindow", searchWindow) - .addObj("itineraryPageCut", itineraryPageCut) + // This will only include the sort vector, not everything else in the itinerary + .addObjOp("itineraryPageCut", itineraryPageCut, ItinerarySortKey::keyAsString) .toString(); } } diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorFactory.java b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorFactory.java similarity index 55% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorFactory.java rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorFactory.java index a6073a540b5..92f59319cc1 100644 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageCursorFactory.java +++ b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorFactory.java @@ -1,13 +1,13 @@ -package org.opentripplanner.model.plan.pagecursor; +package org.opentripplanner.model.plan.paging.cursor; -import static org.opentripplanner.model.plan.pagecursor.PageType.NEXT_PAGE; -import static org.opentripplanner.model.plan.pagecursor.PageType.PREVIOUS_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.NEXT_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.PREVIOUS_PAGE; import java.time.Duration; import java.time.Instant; -import java.time.temporal.ChronoUnit; import javax.annotation.Nullable; import org.opentripplanner.framework.tostring.ToStringBuilder; +import org.opentripplanner.model.plan.ItinerarySortKey; import org.opentripplanner.model.plan.SortOrder; public class PageCursorFactory { @@ -15,10 +15,11 @@ public class PageCursorFactory { private final SortOrder sortOrder; private final Duration newSearchWindow; private PageType currentPageType; - private SearchTime current = null; + private Instant currentEdt = null; + private Instant currentLat = null; private Duration currentSearchWindow = null; private boolean wholeSwUsed = true; - private ItineraryPageCut itineraryPageCut = null; + private ItinerarySortKey itineraryPageCut = null; private PageCursorInput pageCursorInput = null; private PageCursor nextCursor = null; @@ -42,7 +43,8 @@ public PageCursorFactory withOriginalSearch( this.currentPageType = pageType == null ? resolvePageTypeForTheFirstSearch(sortOrder) : pageType; - this.current = new SearchTime(edt, lat); + this.currentEdt = edt; + this.currentLat = lat; this.currentSearchWindow = searchWindow; return this; } @@ -59,18 +61,7 @@ public PageCursorFactory withOriginalSearch( public PageCursorFactory withRemovedItineraries(PageCursorInput pageCursorFactoryParams) { this.wholeSwUsed = false; this.pageCursorInput = pageCursorFactoryParams; - this.itineraryPageCut = - new ItineraryPageCut( - pageCursorFactoryParams.earliestRemovedDeparture().truncatedTo(ChronoUnit.SECONDS), - current.edt.plus(currentSearchWindow), - sortOrder, - pageCursorFactoryParams.deduplicationSection(), - pageCursorFactoryParams.firstRemovedArrivalTime(), - pageCursorFactoryParams.firstRemovedDepartureTime(), - pageCursorFactoryParams.firstRemovedGeneralizedCost(), - pageCursorFactoryParams.firstRemovedNumOfTransfers(), - pageCursorFactoryParams.firstRemovedIsOnStreetAllTheWay() - ); + this.itineraryPageCut = pageCursorFactoryParams.pageCut(); return this; } @@ -92,7 +83,8 @@ public String toString() { .of(PageCursorFactory.class) .addEnum("sortOrder", sortOrder) .addEnum("currentPageType", currentPageType) - .addObj("current", current) + .addDateTime("currentEdt", currentEdt) + .addDateTime("currentLat", currentLat) .addDuration("currentSearchWindow", currentSearchWindow) .addDuration("newSearchWindow", newSearchWindow) .addBoolIfTrue("searchWindowCropped", !wholeSwUsed) @@ -108,77 +100,53 @@ public String toString() { * equivalent when creating new cursors. */ private static PageType resolvePageTypeForTheFirstSearch(SortOrder sortOrder) { - return sortOrder.isSortedByArrivalTimeAscending() ? NEXT_PAGE : PREVIOUS_PAGE; + return sortOrder.isSortedByAscendingArrivalTime() ? NEXT_PAGE : PREVIOUS_PAGE; } /** Create page cursor pair (next and previous) */ private void createPageCursors() { - if (current == null || nextCursor != null || prevCursor != null) { + if (currentEdt == null || nextCursor != null || prevCursor != null) { return; } - SearchTime prev = new SearchTime(null, null); - SearchTime next = new SearchTime(null, null); + Instant prevEdt; + Instant nextEdt; if (wholeSwUsed) { - prev.edt = edtBeforeNewSw(); - next.edt = edtAfterUsedSw(); - if (!sortOrder.isSortedByArrivalTimeAscending()) { - prev.lat = current.lat; - } - } else { // If the whole search window was not used (i.e. if there were removed itineraries) + prevEdt = edtBeforeNewSw(); + nextEdt = edtAfterUsedSw(); + } + // If the whole search window was not used (i.e. if there were removed itineraries) + else { if (currentPageType == NEXT_PAGE) { - prev.edt = edtBeforeNewSw(); - next.edt = pageCursorInput.earliestRemovedDeparture(); - if (sortOrder.isSortedByArrivalTimeAscending()) { - prev.lat = pageCursorInput.earliestKeptArrival().truncatedTo(ChronoUnit.MINUTES); - } else { - prev.lat = current.lat; - } + prevEdt = edtBeforeNewSw(); + nextEdt = pageCursorInput.earliestRemovedDeparture(); } else { // The search-window start and end is [inclusive, exclusive], so to calculate the start of the // search-window from the last time included in the search window we need to include one extra // minute at the end. - prev.edt = pageCursorInput.latestRemovedDeparture().minus(newSearchWindow).plusSeconds(60); - next.edt = edtAfterUsedSw(); - prev.lat = pageCursorInput.latestRemovedArrival(); + prevEdt = pageCursorInput.latestRemovedDeparture().minus(newSearchWindow).plusSeconds(60); + nextEdt = edtAfterUsedSw(); } } - prevCursor = new PageCursor(PREVIOUS_PAGE, sortOrder, prev.edt, prev.lat, newSearchWindow); - nextCursor = new PageCursor(NEXT_PAGE, sortOrder, next.edt, next.lat, newSearchWindow); - - if (itineraryPageCut != null) { - nextCursor = nextCursor.withItineraryPageCut(itineraryPageCut); - prevCursor = prevCursor.withItineraryPageCut(itineraryPageCut); - } + prevCursor = + new PageCursor( + PREVIOUS_PAGE, + sortOrder, + prevEdt, + currentLat, + newSearchWindow, + itineraryPageCut + ); + nextCursor = + new PageCursor(NEXT_PAGE, sortOrder, nextEdt, null, newSearchWindow, itineraryPageCut); } private Instant edtBeforeNewSw() { - return current.edt.minus(newSearchWindow); + return currentEdt.minus(newSearchWindow); } private Instant edtAfterUsedSw() { - return current.edt.plus(currentSearchWindow); - } - - /** Temporary data class used to hold a pair of edt and lat */ - private static class SearchTime { - - Instant edt; - Instant lat; - - private SearchTime(Instant edt, Instant lat) { - this.edt = edt; - this.lat = lat; - } - - @Override - public String toString() { - return ToStringBuilder - .of(SearchTime.class) - .addDateTime("edt", edt) - .addDateTime("lat", lat) - .toString(); - } + return currentEdt.plus(currentSearchWindow); } } diff --git a/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorInput.java b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorInput.java new file mode 100644 index 00000000000..a9bef266739 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorInput.java @@ -0,0 +1,29 @@ +package org.opentripplanner.model.plan.paging.cursor; + +import java.time.Instant; +import org.opentripplanner.model.plan.ItinerarySortKey; + +/** + * This class holds information needed to create the next/previous page cursors when there were + * itineraries removed due to cropping the list of itineraries using the numItineraries parameter. + *

+ * The Instant fields come from the sets of itineraries that were removed and the ones that were + * kept as a result of using the numItineraries parameter. + */ +public interface PageCursorInput { + /** + * The earliest-removed-departure defines the start of the search-window following the + * current window. To include this removed itinerary (and all other removed itineraries) + * in the next-page search the search windows must overlap. + */ + Instant earliestRemovedDeparture(); + Instant latestRemovedDeparture(); + + /** + * In case the result has too many results: The {@code numberOfItineraries} request parameter + * is less than the number of itineraries found, then we keep the last itinerary kept and + * returned as part of the result. The sort vector will be included in the page-cursor and + * used in the next/previous page to filter away duplicates. + */ + ItinerarySortKey pageCut(); +} diff --git a/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorSerializer.java b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorSerializer.java new file mode 100644 index 00000000000..98f64c68062 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageCursorSerializer.java @@ -0,0 +1,113 @@ +package org.opentripplanner.model.plan.paging.cursor; + +import javax.annotation.Nullable; +import org.opentripplanner.framework.lang.StringUtils; +import org.opentripplanner.framework.token.TokenSchema; +import org.opentripplanner.model.plan.ItinerarySortKey; +import org.opentripplanner.model.plan.SortOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class PageCursorSerializer { + + private static final byte VERSION = 1; + private static final Logger LOG = LoggerFactory.getLogger(PageCursor.class); + + private static final String TYPE_FIELD = "Type"; + private static final String EDT_FIELD = "EDT"; + private static final String LAT_FIELD = "LAT"; + private static final String SEARCH_WINDOW_FIELD = "SW"; + private static final String SORT_ORDER_FIELD = "SortOrder"; + private static final String CUT_ON_STREET_FIELD = "cutOnStreet"; + private static final String CUT_DEPARTURE_TIME_FIELD = "cutDepartureTime"; + private static final String CUT_ARRIVAL_TIME_FIELD = "cutArrivalTime"; + private static final String CUT_N_TRANSFERS_FIELD = "cutTx"; + private static final String CUT_COST_FIELD = "cutCost"; + + private static final TokenSchema SCHEMA_TOKEN = TokenSchema + .ofVersion(VERSION) + .addEnum(TYPE_FIELD) + .addTimeInstant(EDT_FIELD) + .addTimeInstant(LAT_FIELD) + .addDuration(SEARCH_WINDOW_FIELD) + .addEnum(SORT_ORDER_FIELD) + .addBoolean(CUT_ON_STREET_FIELD) + .addTimeInstant(CUT_DEPARTURE_TIME_FIELD) + .addTimeInstant(CUT_ARRIVAL_TIME_FIELD) + .addInt(CUT_N_TRANSFERS_FIELD) + .addInt(CUT_COST_FIELD) + .build(); + + /** private constructor to prevent instantiating this utility class */ + private PageCursorSerializer() {} + + @Nullable + public static String encode(PageCursor cursor) { + var tokenBuilder = SCHEMA_TOKEN + .encode() + .withEnum(TYPE_FIELD, cursor.type()) + .withTimeInstant(EDT_FIELD, cursor.earliestDepartureTime()) + .withTimeInstant(LAT_FIELD, cursor.latestArrivalTime()) + .withDuration(SEARCH_WINDOW_FIELD, cursor.searchWindow()) + .withEnum(SORT_ORDER_FIELD, cursor.originalSortOrder()); + + var cut = cursor.itineraryPageCut(); + if (cut != null) { + tokenBuilder + .withBoolean(CUT_ON_STREET_FIELD, cut.isOnStreetAllTheWay()) + .withTimeInstant(CUT_DEPARTURE_TIME_FIELD, cut.startTimeAsInstant()) + .withTimeInstant(CUT_ARRIVAL_TIME_FIELD, cut.endTimeAsInstant()) + .withInt(CUT_N_TRANSFERS_FIELD, cut.getNumberOfTransfers()) + .withInt(CUT_COST_FIELD, cut.getGeneralizedCost()); + } + + return tokenBuilder.build(); + } + + @Nullable + public static PageCursor decode(String cursor) { + if (StringUtils.hasNoValueOrNullAsString(cursor)) { + return null; + } + try { + ItinerarySortKey itineraryPageCut = null; + var token = SCHEMA_TOKEN.decode(cursor); + + // This throws an exception if an enum is serialized which is not in the code. + // This is a forward compatibility issue. To avoid this, add the value enum, role out. + // Start using the enum, roll out again. + PageType type = token.getEnum(TYPE_FIELD, PageType.class).orElseThrow(); + var edt = token.getTimeInstant(EDT_FIELD); + var lat = token.getTimeInstant(LAT_FIELD); + var searchWindow = token.getDuration(SEARCH_WINDOW_FIELD); + var originalSortOrder = token.getEnum(SORT_ORDER_FIELD, SortOrder.class).orElseThrow(); + + // We use the departure time to determine if the cut is present or not + var cutDepartureTime = token.getTimeInstant(CUT_DEPARTURE_TIME_FIELD); + + if (cutDepartureTime != null) { + itineraryPageCut = + new DeduplicationPageCut( + cutDepartureTime, + token.getTimeInstant(CUT_ARRIVAL_TIME_FIELD), + token.getInt(CUT_COST_FIELD), + token.getInt(CUT_N_TRANSFERS_FIELD), + token.getBoolean(CUT_ON_STREET_FIELD) + ); + } + + // Add logic to read in data from next version here. + // if(token.version() > 1) { /* get v2 here */} + + return new PageCursor(type, originalSortOrder, edt, lat, searchWindow, itineraryPageCut); + } catch (Exception e) { + String details = e.getMessage(); + if (StringUtils.hasValue(details)) { + LOG.warn("Unable to decode page cursor: '{}'. Details: {}", cursor, details); + } else { + LOG.warn("Unable to decode page cursor: '{}'.", cursor); + } + return null; + } + } +} diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageType.java b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageType.java similarity index 82% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/PageType.java rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/PageType.java index 94b2ce47c93..ad85e169448 100644 --- a/src/main/java/org/opentripplanner/model/plan/pagecursor/PageType.java +++ b/src/main/java/org/opentripplanner/model/plan/paging/cursor/PageType.java @@ -1,4 +1,4 @@ -package org.opentripplanner.model.plan.pagecursor; +package org.opentripplanner.model.plan.paging.cursor; /** * Used to tell which way the paging is going, to the {@link #NEXT_PAGE} or to the {@link @@ -17,5 +17,9 @@ public enum PageType { * the sort order, the next page may hold itineraries which depart/arrive after or before the * current result. */ - NEXT_PAGE, + NEXT_PAGE; + + public boolean isNext() { + return this == NEXT_PAGE; + } } diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/pagecursor.excalidraw b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/pagecursor.excalidraw similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/pagecursor.excalidraw rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/pagecursor.excalidraw diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-arrival-crop-sw-prev-page.svg b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-arrival-crop-sw-prev-page.svg similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-arrival-crop-sw-prev-page.svg rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-arrival-crop-sw-prev-page.svg diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-arrival-crop-sw.svg b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-arrival-crop-sw.svg similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-arrival-crop-sw.svg rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-arrival-crop-sw.svg diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-arrival.svg b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-arrival.svg similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-arrival.svg rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-arrival.svg diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-departure-crop-sw-next-page.svg b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-departure-crop-sw-next-page.svg similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-departure-crop-sw-next-page.svg rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-departure-crop-sw-next-page.svg diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-departure-crop-sw.svg b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-departure-crop-sw.svg similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-departure-crop-sw.svg rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-departure-crop-sw.svg diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-departure.svg b/src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-departure.svg similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/images/sort-by-departure.svg rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/images/sort-by-departure.svg diff --git a/src/main/java/org/opentripplanner/model/plan/pagecursor/readme.md b/src/main/java/org/opentripplanner/model/plan/paging/cursor/readme.md similarity index 100% rename from src/main/java/org/opentripplanner/model/plan/pagecursor/readme.md rename to src/main/java/org/opentripplanner/model/plan/paging/cursor/readme.md diff --git a/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java b/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java index 1953c60d5d6..16dff3b2e99 100644 --- a/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java +++ b/src/main/java/org/opentripplanner/raptor/api/model/RaptorAccessEgress.java @@ -4,7 +4,6 @@ import static org.opentripplanner.raptor.api.model.RaptorConstants.TIME_NOT_SET; import javax.annotation.Nullable; -import org.opentripplanner.framework.lang.OtpNumberFormat; import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.framework.time.TimeUtils; @@ -34,7 +33,7 @@ public interface RaptorAccessEgress { *

* If this is {@link #isFree()}, then this method must return 0(zero). */ - int generalizedCost(); + int c1(); /** * The time duration to walk or travel the path in seconds. This is not the entire duration from @@ -203,8 +202,8 @@ default String asString(boolean includeStop, boolean includeCost, @Nullable Stri buf.append("Walk"); } buf.append(' ').append(DurationUtils.durationToStr(durationInSeconds())); - if (includeCost && generalizedCost() > 0) { - buf.append(' ').append(OtpNumberFormat.formatCostCenti(generalizedCost())); + if (includeCost && c1() > 0) { + buf.append(' ').append(RaptorValueFormatter.formatC1(c1())); } if (hasRides()) { buf.append(' ').append(numberOfRides()).append('x'); diff --git a/src/main/java/org/opentripplanner/raptor/api/model/RaptorTransfer.java b/src/main/java/org/opentripplanner/raptor/api/model/RaptorTransfer.java index 5245c410266..bab4b9ab166 100644 --- a/src/main/java/org/opentripplanner/raptor/api/model/RaptorTransfer.java +++ b/src/main/java/org/opentripplanner/raptor/api/model/RaptorTransfer.java @@ -20,7 +20,7 @@ public interface RaptorTransfer { * This method is called many times, so care needs to be taken that the value is stored, not * calculated for each invocation. */ - int generalizedCost(); + int c1(); /** * The time duration to walk or travel the path in seconds. This is not the entire duration from diff --git a/src/main/java/org/opentripplanner/raptor/api/model/RaptorValueFormatter.java b/src/main/java/org/opentripplanner/raptor/api/model/RaptorValueFormatter.java new file mode 100644 index 00000000000..dd40c1175ee --- /dev/null +++ b/src/main/java/org/opentripplanner/raptor/api/model/RaptorValueFormatter.java @@ -0,0 +1,58 @@ +package org.opentripplanner.raptor.api.model; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +public class RaptorValueFormatter { + + private static final String UNIT_C1 = "C₁"; + private static final String UNIT_C2 = "C₂"; + private static final String UNIT_WAIT_TIME_COST = "wtC₁"; + private static final String UNIT_TRANSFER_PRIORITY = "Tₚ"; + private static final String UNIT_TRANSFERS = "Tₓ"; + + private static final DecimalFormatSymbols DECIMAL_SYMBOLS = new DecimalFormatSymbols(); + + static { + DECIMAL_SYMBOLS.setDecimalSeparator('.'); + DECIMAL_SYMBOLS.setGroupingSeparator('_'); + DECIMAL_SYMBOLS.setMinusSign('-'); + } + + // In general DecimalFormat is not thread-safe, but we are not changing the state here, + // so this is ok. The 'format' is not changing the state. + private static final DecimalFormat FORMAT_CENTI = new DecimalFormat("#,##0.0#", DECIMAL_SYMBOLS); + private static final DecimalFormat FORMAT_INT = new DecimalFormat("#,##0", DECIMAL_SYMBOLS); + + public static String formatC1(int c1) { + return UNIT_C1 + formatCenti(c1); + } + + public static String formatC2(int c2) { + return UNIT_C2 + c2; + } + + public static String formatWaitTimeCost(int value) { + return UNIT_WAIT_TIME_COST + formatCenti(value); + } + + public static String formatNumOfTransfers(int value) { + return UNIT_TRANSFERS + FORMAT_INT.format(value); + } + + public static String formatTransferPriority(int value) { + return UNIT_TRANSFER_PRIORITY + FORMAT_INT.format(value); + } + + /** Format integers in centi units like 1234 => 12.34. */ + private static String formatCenti(int value) { + if (value % 100 == 0) { + value /= 100; + return FORMAT_INT.format(value); + } + if (Math.abs(value) >= 1_000_000) { + return FORMAT_INT.format(value / 100); + } + return FORMAT_CENTI.format(value / 100.0); + } +} diff --git a/src/main/java/org/opentripplanner/raptor/api/path/AccessPathLeg.java b/src/main/java/org/opentripplanner/raptor/api/path/AccessPathLeg.java index 1b9673bd66e..b76e0a1df4d 100644 --- a/src/main/java/org/opentripplanner/raptor/api/path/AccessPathLeg.java +++ b/src/main/java/org/opentripplanner/raptor/api/path/AccessPathLeg.java @@ -16,20 +16,20 @@ public final class AccessPathLeg implements PathLe private final RaptorAccessEgress access; private final int fromTime; private final int toTime; - private final int generalizedCost; + private final int c1; private final PathLeg next; public AccessPathLeg( @Nonnull RaptorAccessEgress access, int fromTime, int toTime, - int generalizedCost, + int c1, @Nonnull PathLeg next ) { this.access = access; this.fromTime = fromTime; this.toTime = toTime; - this.generalizedCost = generalizedCost; + this.c1 = c1; this.next = next; } @@ -52,8 +52,8 @@ public int toStop() { } @Override - public int generalizedCost() { - return generalizedCost; + public int c1() { + return c1; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/api/path/EgressPathLeg.java b/src/main/java/org/opentripplanner/raptor/api/path/EgressPathLeg.java index fd137516cf4..2bbf06f1cda 100644 --- a/src/main/java/org/opentripplanner/raptor/api/path/EgressPathLeg.java +++ b/src/main/java/org/opentripplanner/raptor/api/path/EgressPathLeg.java @@ -15,13 +15,13 @@ public final class EgressPathLeg implements PathLe private final RaptorAccessEgress egress; private final int fromTime; private final int toTime; - private final int generalizedCost; + private final int c1; - public EgressPathLeg(RaptorAccessEgress egress, int fromTime, int toTime, int generalizedCost) { + public EgressPathLeg(RaptorAccessEgress egress, int fromTime, int toTime, int c1) { this.egress = egress; this.fromTime = fromTime; this.toTime = toTime; - this.generalizedCost = generalizedCost; + this.c1 = c1; } @Override @@ -43,8 +43,8 @@ public int toTime() { } @Override - public int generalizedCost() { - return generalizedCost; + public int c1() { + return c1; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/api/path/PathLeg.java b/src/main/java/org/opentripplanner/raptor/api/path/PathLeg.java index a0cabc7e1e9..35a351a4d77 100644 --- a/src/main/java/org/opentripplanner/raptor/api/path/PathLeg.java +++ b/src/main/java/org/opentripplanner/raptor/api/path/PathLeg.java @@ -69,20 +69,20 @@ default int duration() { *

* The unit is centi-seconds (Raptor cost unit) */ - int generalizedCost(); + int c1(); /** - * The computed generalized-cost for this leg plus all legs following it. + * The c1 for this leg plus all legs following it. *

* {@code -1} is returned if no cost is computed by raptor. *

* The unit is centi-seconds (Raptor cost unit) */ - default int generalizedCostTotal() { - if (generalizedCost() < 0) { - return generalizedCost(); + default int c1Total() { + if (c1() < 0) { + return c1(); } - return stream().mapToInt(PathLeg::generalizedCost).sum(); + return stream().mapToInt(PathLeg::c1).sum(); } /** diff --git a/src/main/java/org/opentripplanner/raptor/api/path/PathStringBuilder.java b/src/main/java/org/opentripplanner/raptor/api/path/PathStringBuilder.java index 34a9be91889..4cf13e362fd 100644 --- a/src/main/java/org/opentripplanner/raptor/api/path/PathStringBuilder.java +++ b/src/main/java/org/opentripplanner/raptor/api/path/PathStringBuilder.java @@ -3,11 +3,11 @@ import java.time.ZonedDateTime; import java.util.function.Consumer; import javax.annotation.Nullable; -import org.opentripplanner.framework.lang.OtpNumberFormat; import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.model.RaptorConstants; +import org.opentripplanner.raptor.api.model.RaptorValueFormatter; import org.opentripplanner.raptor.spi.RaptorCostCalculator; /** @@ -73,30 +73,32 @@ public PathStringBuilder street(String modeName, ZonedDateTime fromTime, ZonedDa return legSep().text(modeName).time(fromTime, toTime); } - public PathStringBuilder timeAndCostCentiSec(int fromTime, int toTime, int generalizedCost) { - return time(fromTime, toTime).generalizedCostSentiSec(generalizedCost); + public PathStringBuilder c1(int c1) { + if (c1 == RaptorCostCalculator.ZERO_COST) { + return this; + } + return text(RaptorValueFormatter.formatC1(c1)); } - /** Add generalizedCostCentiSec {@link #costCentiSec(int, int, String)} */ - public PathStringBuilder generalizedCostSentiSec(int cost) { - return costCentiSec(cost, RaptorCostCalculator.ZERO_COST, null); + public PathStringBuilder c2(int c2) { + if (c2 == RaptorConstants.NOT_SET) { + return this; + } + return text(RaptorValueFormatter.formatC2(c2)); } - /** - * Add a cost to the string with an optional unit. Try to be consistent with unit naming, use - * lower-case: - *

    - *
  • {@code null} - Generalized-cost (no unit used)
  • - *
  • {@code "wtc"} - Wait-time cost
  • - *
  • {@code "pri"} - Transfer priority cost
  • - *
- */ - public PathStringBuilder costCentiSec(int generalizedCostCents, int defaultValue, String unit) { - if (generalizedCostCents == defaultValue) { + public PathStringBuilder waitTimeCost(int wtc, int defaultValue) { + if (wtc == defaultValue) { + return this; + } + return text(RaptorValueFormatter.formatWaitTimeCost(wtc)); + } + + public PathStringBuilder transferPriority(int transferPriorityCost, int defaultValue) { + if (transferPriorityCost == defaultValue) { return this; } - var costText = OtpNumberFormat.formatCostCenti(generalizedCostCents); - return (unit != null) ? text(costText + unit) : text(costText); + return text(RaptorValueFormatter.formatTransferPriority(transferPriorityCost)); } public PathStringBuilder duration(int duration) { @@ -112,34 +114,34 @@ public PathStringBuilder time(int time) { } public PathStringBuilder numberOfTransfers(int nTransfers) { - return nTransfers != RaptorConstants.NOT_SET ? text(nTransfers + "tx") : this; + return nTransfers != RaptorConstants.NOT_SET + ? text(RaptorValueFormatter.formatNumOfTransfers(nTransfers)) + : this; } - public PathStringBuilder summary(int generalizedCostCents) { - return summaryStart().generalizedCostSentiSec(generalizedCostCents).summaryEnd(); + public PathStringBuilder summary(int c1) { + return summaryStart().c1(c1).summaryEnd(); } - public PathStringBuilder summary( - int startTime, - int endTime, - int nTransfers, - int generalizedCostCents - ) { - return summary(startTime, endTime, nTransfers, generalizedCostCents, null); + public PathStringBuilder summary(int startTime, int endTime, int nTransfers, int c1, int c2) { + return summary(startTime, endTime, nTransfers, c1, c2, null); } public PathStringBuilder summary( int startTime, int endTime, int nTransfers, - int generalizedCostCents, + int c1, + int c2, @Nullable Consumer appendToSummary ) { summaryStart() .time(startTime, endTime) .duration(Math.abs(endTime - startTime)) .numberOfTransfers(nTransfers) - .generalizedCostSentiSec(generalizedCostCents); + .c1(c1) + .c2(c2); + if (appendToSummary != null) { appendToSummary.accept(this); } diff --git a/src/main/java/org/opentripplanner/raptor/api/path/TransferPathLeg.java b/src/main/java/org/opentripplanner/raptor/api/path/TransferPathLeg.java index 4aba197f1ce..8e098add45b 100644 --- a/src/main/java/org/opentripplanner/raptor/api/path/TransferPathLeg.java +++ b/src/main/java/org/opentripplanner/raptor/api/path/TransferPathLeg.java @@ -15,7 +15,7 @@ public final class TransferPathLeg implements Path private final int fromTime; private final int toStop; private final int toTime; - private final int generalizedCost; + private final int c1; private final RaptorTransfer transfer; private final PathLeg next; @@ -23,7 +23,7 @@ public TransferPathLeg( int fromStop, int fromTime, int toTime, - int generalizedCost, + int c1, RaptorTransfer transfer, PathLeg next ) { @@ -31,7 +31,7 @@ public TransferPathLeg( this.fromTime = fromTime; this.toStop = transfer.stop(); this.toTime = toTime; - this.generalizedCost = generalizedCost; + this.c1 = c1; this.transfer = transfer; this.next = next; } @@ -61,8 +61,8 @@ public int toStop() { } @Override - public int generalizedCost() { - return generalizedCost; + public int c1() { + return c1; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/api/path/TransitPathLeg.java b/src/main/java/org/opentripplanner/raptor/api/path/TransitPathLeg.java index e752920b6da..a01fb32a28d 100644 --- a/src/main/java/org/opentripplanner/raptor/api/path/TransitPathLeg.java +++ b/src/main/java/org/opentripplanner/raptor/api/path/TransitPathLeg.java @@ -17,7 +17,7 @@ public final class TransitPathLeg implements PathL private final int boardStopPos; private final int alightStopPos; private final RaptorConstrainedTransfer constrainedTransferAfterLeg; - private final int generalizedCost; + private final int c1; private final PathLeg next; private final int boardStop; private final int alightStop; @@ -29,7 +29,7 @@ public TransitPathLeg( int boardStopPos, int alightStopPos, RaptorConstrainedTransfer constrainedTransferAfterLeg, - int generalizedCost, + int c1, PathLeg next ) { this.trip = trip; @@ -38,7 +38,7 @@ public TransitPathLeg( this.boardStopPos = boardStopPos; this.alightStopPos = alightStopPos; this.constrainedTransferAfterLeg = constrainedTransferAfterLeg; - this.generalizedCost = generalizedCost; + this.c1 = c1; this.next = next; this.boardStop = trip.pattern().stopIndex(boardStopPos); this.alightStop = trip.pattern().stopIndex(alightStopPos); @@ -90,8 +90,8 @@ public int toStop() { } @Override - public int generalizedCost() { - return generalizedCost; + public int c1() { + return c1; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java b/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java index cfd47614bfc..862f7f17fb6 100644 --- a/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java +++ b/src/main/java/org/opentripplanner/raptor/api/view/ArrivalView.java @@ -1,13 +1,16 @@ package org.opentripplanner.raptor.api.view; +import java.util.function.IntFunction; import javax.annotation.Nullable; -import org.opentripplanner.framework.lang.OtpNumberFormat; import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.raptor.api.model.PathLegType; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTransfer; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; +import org.opentripplanner.raptor.api.model.RaptorValueFormatter; import org.opentripplanner.raptor.api.model.TransitArrival; import org.opentripplanner.raptor.spi.RaptorCostCalculator; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.DefaultCostCalculator; /** * The purpose of the stop-arrival-view is to provide a common interface for stop-arrivals for @@ -80,20 +83,12 @@ default boolean isFirstRound() { */ int c1(); - /** - * Whether the model supports accumulated criteria TWO. If C2 is not supported then calling - * {@link #c2()} will result in an exception. - */ - default boolean supportsC2() { - return false; - } - /** * The accumulated criteria TWO. Can be used for any int criteria used during routing. A * state with c1 and c2 is created dynamically if c2 is in use, if not this method will * throw an exception. *

- * {@link RaptorCostCalculator#ZERO_COST} is returned if no criteria exist, but the model + * {@link RaptorConstants#NOT_SET} is returned if no criteria exist, but the model * support it. */ int c2(); @@ -157,13 +152,13 @@ default EgressPathView egressPath() { boolean arrivedOnBoard(); - /** Use this to easy create a to String implementation. */ + /** Use this to create a {@code toString()} implementation. */ default String asString() { String arrival = "[" + TimeUtils.timeToStrCompact(arrivalTime()) + - " " + - OtpNumberFormat.formatCostCenti(c1()) + + cost(c1(), DefaultCostCalculator.ZERO_COST, RaptorValueFormatter::formatC1) + + cost(c2(), RaptorConstants.NOT_SET, RaptorValueFormatter::formatC2) + "]"; return switch (arrivedBy()) { case ACCESS -> String.format( @@ -195,4 +190,8 @@ default String asString() { ); }; } + + private static String cost(int cost, int defaultValue, IntFunction toString) { + return cost == defaultValue ? "" : " " + toString.apply(cost); + } } diff --git a/src/main/java/org/opentripplanner/raptor/path/Path.java b/src/main/java/org/opentripplanner/raptor/path/Path.java index eb123131089..a4d7770dd64 100644 --- a/src/main/java/org/opentripplanner/raptor/path/Path.java +++ b/src/main/java/org/opentripplanner/raptor/path/Path.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTransferConstraint; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.path.AccessPathLeg; @@ -28,7 +29,7 @@ public class Path implements RaptorPath { private final int startTime; private final int endTime; private final int numberOfTransfers; - private final int generalizedCost; + private final int c1; private final int c2; private final AccessPathLeg accessLeg; private final EgressPathLeg egressLeg; @@ -39,22 +40,22 @@ private Path( int startTime, int endTime, int numberOfTransfers, - int generalizedCost + int c1 ) { this.iterationDepartureTime = iterationDepartureTime; this.startTime = startTime; this.endTime = endTime; this.numberOfTransfers = numberOfTransfers; - this.generalizedCost = generalizedCost; + this.c1 = c1; this.accessLeg = null; this.egressLeg = null; - this.c2 = 0; + this.c2 = RaptorConstants.NOT_SET; } - public Path(int iterationDepartureTime, AccessPathLeg accessLeg, int generalizedCost, int c2) { + public Path(int iterationDepartureTime, AccessPathLeg accessLeg, int c1, int c2) { this.iterationDepartureTime = iterationDepartureTime; this.startTime = accessLeg.fromTime(); - this.generalizedCost = generalizedCost; + this.c1 = c1; this.accessLeg = accessLeg; this.egressLeg = findEgressLeg(accessLeg); this.numberOfTransfers = countNumberOfTransfers(accessLeg, egressLeg); @@ -62,8 +63,8 @@ public Path(int iterationDepartureTime, AccessPathLeg accessLeg, int generali this.c2 = c2; } - public Path(int iterationDepartureTime, AccessPathLeg accessLeg, int generalizedCost) { - this(iterationDepartureTime, accessLeg, generalizedCost, 0); + public Path(int iterationDepartureTime, AccessPathLeg accessLeg, int c1) { + this(iterationDepartureTime, accessLeg, c1, RaptorConstants.NOT_SET); } /** Copy constructor */ @@ -122,7 +123,7 @@ public final int numberOfTransfersExAccessEgress() { @Override public final int c1() { - return generalizedCost; + return c1; } @Override @@ -240,7 +241,7 @@ protected String buildString( ); if (detailed) { buf.duration(leg.duration()); - buf.generalizedCostSentiSec(leg.generalizedCost()); + buf.c1(leg.c1()); } if (transitLeg.getConstrainedTransferAfterLeg() != null) { constraintPrevLeg = @@ -263,7 +264,7 @@ else if (leg.isEgressLeg()) { } } // Add summary info - buf.summary(startTime, endTime, numberOfTransfers, generalizedCost, appendToSummary); + buf.summary(startTime, endTime, numberOfTransfers, c1, c2, appendToSummary); return buf.toString(); } @@ -293,7 +294,10 @@ private static int countNumberOfTransfers( private void addWalkDetails(boolean detailed, PathStringBuilder buf, PathLeg leg) { if (detailed) { - buf.timeAndCostCentiSec(leg.fromTime(), leg.toTime(), leg.generalizedCost()); + int fromTime = leg.fromTime(); + int toTime = leg.toTime(); + int cost = leg.c1(); + buf.time(fromTime, toTime).c1(cost); } } } diff --git a/src/main/java/org/opentripplanner/raptor/path/PathBuilder.java b/src/main/java/org/opentripplanner/raptor/path/PathBuilder.java index 6dae7ee2c5a..c046a8f240d 100644 --- a/src/main/java/org/opentripplanner/raptor/path/PathBuilder.java +++ b/src/main/java/org/opentripplanner/raptor/path/PathBuilder.java @@ -185,7 +185,7 @@ public int c2() { public RaptorPath build() { updateAggregatedFields(); var pathLegs = createPathLegs(costCalculator, slackProvider); - return new Path<>(iterationDepartureTime, pathLegs, pathLegs.generalizedCostTotal(), c2()); + return new Path<>(iterationDepartureTime, pathLegs, pathLegs.c1Total(), c2()); } @Override diff --git a/src/main/java/org/opentripplanner/raptor/path/PathBuilderLeg.java b/src/main/java/org/opentripplanner/raptor/path/PathBuilderLeg.java index eebdf69bfd9..76d49ef4a0a 100644 --- a/src/main/java/org/opentripplanner/raptor/path/PathBuilderLeg.java +++ b/src/main/java/org/opentripplanner/raptor/path/PathBuilderLeg.java @@ -214,18 +214,15 @@ public void timeShiftThisAndNextLeg( *

* This method is safe to use event as long as the next leg is set. */ - public int generalizedCost( - RaptorCostCalculator costCalculator, - RaptorSlackProvider slackProvider - ) { + public int c1(RaptorCostCalculator costCalculator, RaptorSlackProvider slackProvider) { if (costCalculator == null) { return RaptorCostCalculator.ZERO_COST; } if (isAccess()) { - return asAccessLeg().streetPath.generalizedCost(); + return asAccessLeg().streetPath.c1(); } if (isTransfer()) { - return asTransferLeg().transfer.generalizedCost(); + return asTransferLeg().transfer.c1(); } if (isTransit()) { return transitCost(costCalculator, slackProvider); @@ -360,11 +357,11 @@ AccessPathLeg createAccessPathLeg( /* Build helper methods, package local */ private static int cost(RaptorCostCalculator costCalculator, RaptorAccessEgress streetPath) { - return costCalculator != null ? streetPath.generalizedCost() : RaptorCostCalculator.ZERO_COST; + return costCalculator != null ? streetPath.c1() : RaptorCostCalculator.ZERO_COST; } private static int cost(RaptorCostCalculator costCalculator, RaptorTransfer transfer) { - return costCalculator != null ? transfer.generalizedCost() : RaptorCostCalculator.ZERO_COST; + return costCalculator != null ? transfer.c1() : RaptorCostCalculator.ZERO_COST; } private void setTime(int fromTime, int toTime) { diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java index 446bca40fc1..b17b3078fc9 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/MultiCriteriaRoutingStrategy.java @@ -32,7 +32,7 @@ public class MultiCriteriaRoutingStrategy patternRideFactory; private final ParetoSet patternRides; private final PassThroughPointsService passThroughPointsService; - private final RaptorCostCalculator generalizedCostCalculator; + private final RaptorCostCalculator c1Calculator; private final SlackProvider slackProvider; public MultiCriteriaRoutingStrategy( @@ -40,7 +40,7 @@ public MultiCriteriaRoutingStrategy( TimeBasedBoardingSupport boardingSupport, PatternRideFactory patternRideFactory, PassThroughPointsService passThroughPointsService, - RaptorCostCalculator generalizedCostCalculator, + RaptorCostCalculator c1Calculator, SlackProvider slackProvider, ParetoSet patternRides ) { @@ -48,7 +48,7 @@ public MultiCriteriaRoutingStrategy( this.boardingSupport = Objects.requireNonNull(boardingSupport); this.patternRideFactory = Objects.requireNonNull(patternRideFactory); this.passThroughPointsService = Objects.requireNonNull(passThroughPointsService); - this.generalizedCostCalculator = Objects.requireNonNull(generalizedCostCalculator); + this.c1Calculator = Objects.requireNonNull(c1Calculator); this.slackProvider = Objects.requireNonNull(slackProvider); this.patternRides = Objects.requireNonNull(patternRides); } @@ -195,7 +195,7 @@ private int calculateCostAtBoardTime( ) { return ( prevArrival.c1() + - generalizedCostCalculator.boardingCost( + c1Calculator.boardingCost( prevArrival.isFirstRound(), prevArrival.arrivalTime(), boardEvent.boardStopIndex(), @@ -214,6 +214,6 @@ private int calculateCostAtBoardTime( * origin in the same iteration, having used the same number-of-rounds to board the same trip. */ private int calculateOnTripRelativeCost(int boardTime, T tripSchedule) { - return generalizedCostCalculator.onTripRelativeRidingCost(boardTime, tripSchedule); + return c1Calculator.onTripRelativeRidingCost(boardTime, tripSchedule); } } diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactory.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactory.java index f7907fa932a..68e103b18db 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactory.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactory.java @@ -8,7 +8,7 @@ public interface ArrivalParetoSetComparatorFactory> { /** * This comparator is used to compare regular stop arrivals. It uses {@code arrivalTime}, - * {@code paretoRound} and {@code generalizedCost} to compare arrivals. It does NOT include + * {@code paretoRound} and {@code c1} to compare arrivals. It does NOT include * {@code arrivedOnBoard}. Normally arriving on-board should give the arrival an advantage * - you can continue on foot, walking to the next stop. But, we only do this if it happens * in the same Raptor iteration and round - if it does it is taken care of by the order diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java index be318be0645..e3787d41f78 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrival.java @@ -23,7 +23,7 @@ final class AccessStopArrival extends McStopArriva access.stop(), departureTime, access.durationInSeconds(), - access.generalizedCost(), + access.c1(), access.numberOfRides() ); this.access = access; @@ -31,7 +31,7 @@ final class AccessStopArrival extends McStopArriva @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return RaptorConstants.NOT_SET; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrival.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrival.java index cbe553f8f8f..05c165a158b 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrival.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrival.java @@ -3,6 +3,7 @@ import static org.opentripplanner.raptor.api.model.PathLegType.TRANSFER; import org.opentripplanner.raptor.api.model.PathLegType; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTransfer; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.model.TransitArrival; @@ -25,14 +26,14 @@ final class TransferStopArrival extends McStopArri 1, transferPath.stop(), arrivalTime, - previousState.c1() + transferPath.generalizedCost() + previousState.c1() + transferPath.c1() ); this.transfer = transferPath; } @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return RaptorConstants.NOT_SET; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrival.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrival.java index 60252a679b1..a30581512a7 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrival.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrival.java @@ -3,6 +3,7 @@ import static org.opentripplanner.raptor.api.model.PathLegType.TRANSIT; import org.opentripplanner.raptor.api.model.PathLegType; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.model.TransitArrival; import org.opentripplanner.raptor.api.view.TransitPathView; @@ -36,7 +37,7 @@ final class TransitStopArrival @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return RaptorConstants.NOT_SET; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AbstractStopArrivalC2.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AbstractStopArrivalC2.java index 33942592466..067772cb014 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AbstractStopArrivalC2.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AbstractStopArrivalC2.java @@ -49,11 +49,6 @@ abstract class AbstractStopArrivalC2 extends McSto this.c2 = c2; } - @Override - public boolean supportsC2() { - return true; - } - public final int c2() { return c2; } diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2.java index 674cb7c6522..ed4d9df1415 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2.java @@ -24,7 +24,7 @@ final class AccessStopArrivalC2 extends AbstractSt departureTime, access.durationInSeconds(), access.numberOfRides(), - access.generalizedCost(), + access.c1(), RaptorCostCalculator.ZERO_COST ); this.access = access; diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2.java index eb245d1fee9..42ee55ff784 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2.java @@ -21,7 +21,7 @@ final class TransferStopArrivalC2 extends Abstract 1, transferPath.stop(), arrivalTime, - previous.c1() + transferPath.generalizedCost(), + previous.c1() + transferPath.c1(), previous.c2() ); this.transfer = transferPath; diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrival.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrival.java index 6133bd03952..351a432cc20 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrival.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrival.java @@ -35,18 +35,21 @@ public class DestinationArrival implements Arrival private final int arrivalTime; private final int numberOfTransfers; private final int c1; + private final int c2; public DestinationArrival( RaptorAccessEgress egress, ArrivalView previous, int arrivalTime, - int additionalCost + int additionalC1, + int c2 ) { this.previous = previous; this.egress = egress; this.arrivalTime = arrivalTime; this.numberOfTransfers = previous.round() - 1; - this.c1 = previous.c1() + additionalCost; + this.c1 = previous.c1() + additionalC1; + this.c2 = c2; } @Override @@ -69,14 +72,9 @@ public int c1() { return c1; } - @Override - public boolean supportsC2() { - return false; - } - @Override public int c2() { - return previous.c2(); + return c2; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalPaths.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalPaths.java index 5f0fa376f74..6ed88da4c89 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalPaths.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalPaths.java @@ -188,7 +188,13 @@ private DestinationArrival createDestinationArrivalView( additionalCost += costCalculator.costEgress(egressPath); } - return new DestinationArrival<>(egressPath, stopArrival, arrivalTime, additionalCost); + return new DestinationArrival<>( + egressPath, + stopArrival, + arrivalTime, + additionalCost, + stopArrival.c2() + ); } /** diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ForwardPathMapper.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ForwardPathMapper.java index 9f7d392c2f0..8e9b77f9cb8 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ForwardPathMapper.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ForwardPathMapper.java @@ -4,7 +4,6 @@ import org.opentripplanner.raptor.api.path.RaptorPath; import org.opentripplanner.raptor.api.path.RaptorStopNameResolver; import org.opentripplanner.raptor.api.view.ArrivalView; -import org.opentripplanner.raptor.path.Path; import org.opentripplanner.raptor.path.PathBuilder; import org.opentripplanner.raptor.rangeraptor.internalapi.WorkerLifeCycle; import org.opentripplanner.raptor.rangeraptor.transit.TripTimesSearch; @@ -70,9 +69,7 @@ public RaptorPath mapToPath(final DestinationArrival destinationArrival) { arrival = arrival.previous(); } - if (destinationArrival.supportsC2()) { - pathBuilder.c2(destinationArrival.c2()); - } + pathBuilder.c2(destinationArrival.c2()); return pathBuilder.build(); } diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ReversePathMapper.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ReversePathMapper.java index 7dd09c2ac92..fde483b4cd8 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ReversePathMapper.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/path/ReversePathMapper.java @@ -65,6 +65,9 @@ public RaptorPath mapToPath(final DestinationArrival destinationArrival) { switch (arrival.arrivedBy()) { case ACCESS: pathBuilder.egress(arrival.accessPath().access()); + + pathBuilder.c2(arrival.c2()); + return pathBuilder.build(); case TRANSIT: var times = tripSearch.find(arrival); diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Access.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Access.java index 6344d6d5c8e..e78b9d0a381 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Access.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Access.java @@ -4,6 +4,7 @@ import org.opentripplanner.raptor.api.model.PathLegType; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.view.AccessPathView; import org.opentripplanner.raptor.api.view.ArrivalView; @@ -29,7 +30,7 @@ public int c1() { @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return RaptorConstants.NOT_SET; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transfer.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transfer.java index a6c1fc7c003..a19a9f1c7e6 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transfer.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transfer.java @@ -3,6 +3,7 @@ import static org.opentripplanner.raptor.api.model.PathLegType.TRANSFER; import org.opentripplanner.raptor.api.model.PathLegType; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTransfer; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.view.ArrivalView; @@ -27,7 +28,7 @@ public int c1() { @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return RaptorConstants.NOT_SET; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transit.java b/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transit.java index 4a967642bf4..e38849f6da7 100644 --- a/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transit.java +++ b/src/main/java/org/opentripplanner/raptor/rangeraptor/standard/stoparrivals/view/Transit.java @@ -3,6 +3,7 @@ import static org.opentripplanner.raptor.api.model.PathLegType.TRANSIT; import org.opentripplanner.raptor.api.model.PathLegType; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.api.view.TransitPathView; @@ -29,7 +30,7 @@ public int c1() { @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return RaptorConstants.NOT_SET; } @Override diff --git a/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java b/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java index bd1b91d46d7..d575a0e4d8c 100644 --- a/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java +++ b/src/main/java/org/opentripplanner/raptor/spi/RaptorCostCalculator.java @@ -12,7 +12,7 @@ */ public interface RaptorCostCalculator { /** - * The cost is zero(0) it it is not calculated or if the cost "element" have no cost associated + * The cost is zero (0) if it's not calculated or if the cost "element" have no cost associated. * with it. */ int ZERO_COST = 0; @@ -63,7 +63,7 @@ int boardingCost( * This method allows the cost calculator to add cost in addition to the generalized-cost of the * given egress itself. For example you might want to add a transfer cost to FLEX egress. * - * @return the {@link RaptorTransfer#generalizedCost()} plus any additional board or transfer + * @return the {@link RaptorTransfer#c1()} plus any additional board or transfer * cost. */ int costEgress(RaptorAccessEgress egress); diff --git a/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java b/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java index f1b0a5e0c25..b95417e86b6 100644 --- a/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java +++ b/src/main/java/org/opentripplanner/raptor/spi/UnknownPath.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.stream.Stream; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.path.AccessPathLeg; import org.opentripplanner.raptor.api.path.EgressPathLeg; @@ -72,7 +73,7 @@ public int c1() { @Override public int c2() { - return RaptorCostCalculator.ZERO_COST; + return RaptorConstants.NOT_SET; } @Override @@ -126,7 +127,7 @@ public String toString() { if (departureTime == 0 && arrivalTime == 0) { pathBuilder.summary(c1()); } else { - pathBuilder.summary(startTime(), endTime(), numberOfTransfers, c1()); + pathBuilder.summary(startTime(), endTime(), numberOfTransfers, c1(), c2()); } return pathBuilder.toString(); } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/RoutingWorker.java b/src/main/java/org/opentripplanner/routing/algorithm/RoutingWorker.java index 24442311617..ad2c4c92639 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/RoutingWorker.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/RoutingWorker.java @@ -16,11 +16,11 @@ import org.opentripplanner.framework.application.OTPRequestTimeoutException; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.plan.Itinerary; -import org.opentripplanner.model.plan.PagingSearchWindowAdjuster; import org.opentripplanner.raptor.api.request.RaptorTuningParameters; import org.opentripplanner.raptor.api.request.SearchParams; import org.opentripplanner.routing.algorithm.filterchain.ItineraryListFilterChain; import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; +import org.opentripplanner.routing.algorithm.mapping.PagingServiceFactory; import org.opentripplanner.routing.algorithm.mapping.RouteRequestToFilterChainMapper; import org.opentripplanner.routing.algorithm.mapping.RoutingResponseMapper; import org.opentripplanner.routing.algorithm.raptoradapter.router.AdditionalSearchDays; @@ -28,13 +28,13 @@ import org.opentripplanner.routing.algorithm.raptoradapter.router.TransitRouter; import org.opentripplanner.routing.algorithm.raptoradapter.router.street.DirectFlexRouter; import org.opentripplanner.routing.algorithm.raptoradapter.router.street.DirectStreetRouter; -import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.response.RoutingError; import org.opentripplanner.routing.api.response.RoutingResponse; import org.opentripplanner.routing.error.RoutingValidationException; import org.opentripplanner.routing.framework.DebugTimingAggregator; +import org.opentripplanner.service.paging.PagingService; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,8 +49,7 @@ public class RoutingWorker { private static final Logger LOG = LoggerFactory.getLogger(RoutingWorker.class); /** An object that accumulates profiling and debugging info for inclusion in the response. */ - public final DebugTimingAggregator debugTimingAggregator; - public final PagingSearchWindowAdjuster pagingSearchWindowAdjuster; + private final DebugTimingAggregator debugTimingAggregator; private final RouteRequest request; private final OtpServerRequestContext serverContext; @@ -78,11 +77,6 @@ public RoutingWorker(OtpServerRequestContext serverContext, RouteRequest request request.preferences().system().tags() ); this.transitSearchTimeZero = ServiceDateUtils.asStartOfService(request.dateTime(), zoneId); - this.pagingSearchWindowAdjuster = - createPagingSearchWindowAdjuster( - serverContext.transitTuningParameters(), - serverContext.raptorTuningParameters() - ); this.additionalSearchDays = createAdditionalSearchDays(serverContext.raptorTuningParameters(), zoneId, request); } @@ -165,18 +159,17 @@ public RoutingResponse route() { // Adjust the search-window for the next search if the current search-window // is off (too few or too many results found). - var searchWindowNextSearch = calculateSearchWindowNextSearch(filteredItineraries); + + var pagingService = createPagingService(itineraries); return RoutingResponseMapper.map( request, - transitSearchTimeZero, raptorSearchParamsUsed, - searchWindowNextSearch, - numItinerariesFilterResults, filteredItineraries, routingErrors, debugTimingAggregator, - serverContext.transitService() + serverContext.transitService(), + pagingService ); } @@ -197,27 +190,6 @@ private static AdditionalSearchDays createAdditionalSearchDays( ); } - /** - * Filter itineraries away that depart after the latest-departure-time for depart after search. - * These itineraries are a result of time-shifting the access leg and is needed for the raptor to - * prune the results. These itineraries are often not ideal, but if they pareto optimal for the - * "next" window, they will appear when a "next" search is performed. - */ - private Instant filterOnLatestDepartureTime() { - if ( - !request.arriveBy() && - raptorSearchParamsUsed != null && - raptorSearchParamsUsed.isSearchWindowSet() && - raptorSearchParamsUsed.isEarliestDepartureTimeSet() - ) { - int ldt = - raptorSearchParamsUsed.earliestDepartureTime() + - raptorSearchParamsUsed.searchWindowInSeconds(); - return transitSearchTimeZero.plusSeconds(ldt).toInstant(); - } - return null; - } - /** * Calculate the earliest-departure-time used in the transit search. * This method returns {@code null} if no transit search is performed. @@ -300,53 +272,19 @@ private Void routeTransit(List itineraries, Collection return null; } - private Duration calculateSearchWindowNextSearch(List itineraries) { - // No transit search performed - if (raptorSearchParamsUsed == null) { - return null; - } - - var sw = Duration.ofSeconds(raptorSearchParamsUsed.searchWindowInSeconds()); - - // SearchWindow cropped -> decrease search-window - if (numItinerariesFilterResults != null) { - Instant swStartTime = searchStartTime() - .plusSeconds(raptorSearchParamsUsed.earliestDepartureTime()); - boolean cropSWHead = request.doCropSearchWindowAtTail(); - Instant rmItineraryStartTime = numItinerariesFilterResults.firstRemovedDepartureTime; - - return pagingSearchWindowAdjuster.decreaseSearchWindow( - sw, - swStartTime, - rmItineraryStartTime, - cropSWHead - ); - } - // (num-of-itineraries found <= numItineraries) -> increase or keep search-window - else { - int nRequested = request.numItineraries(); - int nFound = (int) itineraries - .stream() - .filter(it -> !it.isFlaggedForDeletion() && it.hasTransit()) - .count(); - - return pagingSearchWindowAdjuster.increaseOrKeepSearchWindow(sw, nRequested, nFound); - } - } - private Instant searchStartTime() { return transitSearchTimeZero.toInstant(); } - private PagingSearchWindowAdjuster createPagingSearchWindowAdjuster( - TransitTuningParameters transitTuningParameters, - RaptorTuningParameters raptorTuningParameters - ) { - var c = raptorTuningParameters.dynamicSearchWindowCoefficients(); - return new PagingSearchWindowAdjuster( - c.minWindow(), - c.maxWindow(), - transitTuningParameters.pagingSearchWindowAdjustments() + private PagingService createPagingService(List itineraries) { + return PagingServiceFactory.createPagingService( + searchStartTime(), + serverContext.transitTuningParameters(), + serverContext.raptorTuningParameters(), + request, + raptorSearchParamsUsed, + numItinerariesFilterResults, + itineraries ); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainBuilder.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainBuilder.java index 1c5583ce0bd..872bad6b4ae 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainBuilder.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainBuilder.java @@ -12,12 +12,14 @@ import java.util.function.Function; import javax.annotation.Nullable; import org.opentripplanner.ext.accessibilityscore.AccessibilityScoreFilter; +import org.opentripplanner.framework.collection.ListSection; import org.opentripplanner.framework.lang.Sandbox; import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.ItinerarySortKey; import org.opentripplanner.model.plan.SortOrder; -import org.opentripplanner.model.plan.pagecursor.ItineraryPageCut; import org.opentripplanner.routing.algorithm.filterchain.api.TransitGeneralizedCostFilterParams; import org.opentripplanner.routing.algorithm.filterchain.comparator.SortOrderComparator; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.ItineraryDeletionFlagger; import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.MaxLimitFilter; import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NonTransitGeneralizedCostFilter; import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilter; @@ -59,7 +61,7 @@ public class ItineraryListFilterChainBuilder { private ItineraryFilterDebugProfile debug = ItineraryFilterDebugProfile.OFF; private int maxNumberOfItineraries = NOT_SET; - private ListSection maxNumberOfItinerariesCrop = ListSection.TAIL; + private ListSection maxNumberOfItinerariesCropSection = ListSection.TAIL; private CostLinearFunction removeTransitWithHigherCostThanBestOnStreetOnly; private boolean removeWalkAllTheWayResults; private boolean sameFirstOrLastTripFilter; @@ -77,7 +79,7 @@ public class ItineraryListFilterChainBuilder { private boolean removeItinerariesWithSameRoutesAndStops; private double minBikeParkingDistance; private boolean removeTransitIfWalkingIsBetter = true; - private ItineraryPageCut itineraryPageCut; + private ItinerarySortKey itineraryPageCut; /** * Sandbox filters which decorate the itineraries with extra information. @@ -103,7 +105,7 @@ public ItineraryListFilterChainBuilder(SortOrder sortOrder) { * The maximum number of itineraries returned. This will remove all itineraries at the end of the * list AFTER the final sort of the itineraries. *

- * Se also the {@link #withMaxNumberOfItinerariesCrop(ListSection)} to change which end of the + * Se also the {@link #withMaxNumberOfItinerariesCropSection(ListSection)} to change which end of the * list is cropped. *

* Use {@code -1} to disable. @@ -121,8 +123,10 @@ public ItineraryListFilterChainBuilder withMaxNumberOfItineraries(int value) { * The default is to crop the tail. But, we need to crop the head to be able to paginate in the * opposite direction of the main sort-order of the original search. */ - public ItineraryListFilterChainBuilder withMaxNumberOfItinerariesCrop(ListSection section) { - this.maxNumberOfItinerariesCrop = section; + public ItineraryListFilterChainBuilder withMaxNumberOfItinerariesCropSection( + ListSection section + ) { + this.maxNumberOfItinerariesCropSection = section; return this; } @@ -279,7 +283,7 @@ public ItineraryListFilterChainBuilder withNumItinerariesFilterResultsConsumer( * @param itineraryPageCut contains the parameters to use for deduplication. */ public ItineraryListFilterChainBuilder withPagingDeduplicationFilter( - ItineraryPageCut itineraryPageCut + ItinerarySortKey itineraryPageCut ) { this.itineraryPageCut = itineraryPageCut; return this; @@ -350,10 +354,6 @@ public ItineraryListFilterChainBuilder withStopConsolidationFilter( public ItineraryListFilterChain build() { List filters = new ArrayList<>(); - if (itineraryPageCut != null) { - filters.add(new DeletionFlaggingFilter(new PagingFilter(itineraryPageCut))); - } - filters.addAll(buildGroupByTripIdAndDistanceFilters()); if (removeItinerariesWithSameRoutesAndStops) { @@ -362,7 +362,7 @@ public ItineraryListFilterChain build() { if (sameFirstOrLastTripFilter) { filters.add(new SortingFilter(generalizedCostComparator())); - filters.add(new DeletionFlaggingFilter(new SameFirstOrLastTripFilter())); + addRmFilter(filters, new SameFirstOrLastTripFilter()); } if (minBikeParkingDistance > 0) { @@ -389,23 +389,18 @@ public ItineraryListFilterChain build() { // Filter transit itineraries on generalized-cost if (transitGeneralizedCostFilterParams != null) { - filters.add( - new DeletionFlaggingFilter( - new TransitGeneralizedCostFilter( - transitGeneralizedCostFilterParams.costLimitFunction(), - transitGeneralizedCostFilterParams.intervalRelaxFactor() - ) + addRmFilter( + filters, + new TransitGeneralizedCostFilter( + transitGeneralizedCostFilterParams.costLimitFunction(), + transitGeneralizedCostFilterParams.intervalRelaxFactor() ) ); } // Filter non-transit itineraries on generalized-cost if (nonTransitGeneralizedCostLimit != null) { - filters.add( - new DeletionFlaggingFilter( - new NonTransitGeneralizedCostFilter(nonTransitGeneralizedCostLimit) - ) - ); + addRmFilter(filters, new NonTransitGeneralizedCostFilter(nonTransitGeneralizedCostLimit)); } // Apply all absolute filters AFTER the groupBy filters. Absolute filters are filters that @@ -420,60 +415,61 @@ public ItineraryListFilterChain build() { { // Filter transit itineraries by comparing against non-transit using generalized-cost if (removeTransitWithHigherCostThanBestOnStreetOnly != null) { - filters.add( - new DeletionFlaggingFilter( - new RemoveTransitIfStreetOnlyIsBetterFilter( - removeTransitWithHigherCostThanBestOnStreetOnly - ) + addRmFilter( + filters, + new RemoveTransitIfStreetOnlyIsBetterFilter( + removeTransitWithHigherCostThanBestOnStreetOnly ) ); } if (removeTransitIfWalkingIsBetter) { - filters.add(new DeletionFlaggingFilter(new RemoveTransitIfWalkingIsBetterFilter())); + addRmFilter(filters, new RemoveTransitIfWalkingIsBetterFilter()); } if (removeWalkAllTheWayResults) { - filters.add(new DeletionFlaggingFilter(new RemoveWalkOnlyFilter())); - } - - if (earliestDepartureTime != null) { - filters.add( - new DeletionFlaggingFilter( - new OutsideSearchWindowFilter(earliestDepartureTime, searchWindow) - ) - ); + addRmFilter(filters, new RemoveWalkOnlyFilter()); } if (bikeRentalDistanceRatio > 0) { - filters.add( - new DeletionFlaggingFilter( - new RemoveBikerentalWithMostlyWalkingFilter(bikeRentalDistanceRatio) - ) - ); + addRmFilter(filters, new RemoveBikerentalWithMostlyWalkingFilter(bikeRentalDistanceRatio)); } if (parkAndRideDurationRatio > 0) { - filters.add( - new DeletionFlaggingFilter( - new RemoveParkAndRideWithMostlyWalkingFilter(parkAndRideDurationRatio) - ) + addRmFilter( + filters, + new RemoveParkAndRideWithMostlyWalkingFilter(parkAndRideDurationRatio) ); } } - // Remove itineraries if max limit is set - if (maxNumberOfItineraries > 0) { - filters.add(new SortingFilter(SortOrderComparator.comparator(sortOrder))); - filters.add( - new DeletionFlaggingFilter( + // Paging related filters - these filters are run after group-by filters to allow a result + // outside the page to also take effect inside the window. This is debatable but lead to less + // noise, however it is not deterministic because the result depends on the size of the search-window and + // where the "cut" between each page is located. + { + // Limit to search-window + if (earliestDepartureTime != null) { + addRmFilter(filters, new OutsideSearchWindowFilter(earliestDepartureTime, searchWindow)); + } + + // Remove itineraries present in the page retrieved before this page/search. + if (itineraryPageCut != null) { + addRmFilter(filters, new PagingFilter(sortOrder, deduplicateSection(), itineraryPageCut)); + } + + // Remove itineraries if max limit is set + if (maxNumberOfItineraries > 0) { + filters.add(new SortingFilter(SortOrderComparator.comparator(sortOrder))); + addRmFilter( + filters, new NumItinerariesFilter( maxNumberOfItineraries, - maxNumberOfItinerariesCrop, + maxNumberOfItinerariesCropSection, numItinerariesFilterResultsConsumer ) - ) - ); + ); + } } // Do the final itineraries sort @@ -572,13 +568,12 @@ private List buildGroupByTripIdAndDistanceFilters() { if (group.maxCostOtherLegsFactor > 1.0) { var flagger = new OtherThanSameLegsMaxGeneralizedCostFilter(group.maxCostOtherLegsFactor); sysTags.add(flagger.name()); - nested.add(new DeletionFlaggingFilter(flagger)); + addRmFilter(nested, flagger); } nested.add(new SortingFilter(generalizedCostComparator())); - nested.add( - new DeletionFlaggingFilter(new MaxLimitFilter(tag, group.maxNumOfItinerariesPerGroup)) - ); + + addRmFilter(nested, new MaxLimitFilter(tag, group.maxNumOfItinerariesPerGroup)); nested.add(new RemoveDeletionFlagForLeastTransfersItinerary(sysTags)); @@ -589,4 +584,15 @@ private List buildGroupByTripIdAndDistanceFilters() { return groupByFilters; } + + private ListSection deduplicateSection() { + return maxNumberOfItinerariesCropSection.invert(); + } + + private static void addRmFilter( + List filters, + ItineraryDeletionFlagger removeFilter + ) { + filters.add(new DeletionFlaggingFilter(removeFilter)); + } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/comparator/SortOrderComparator.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/comparator/SortOrderComparator.java index c48b6f0bd5d..e52e53ab1c7 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/comparator/SortOrderComparator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/comparator/SortOrderComparator.java @@ -101,12 +101,9 @@ public static SortOrderComparator numberOfTransfersComparator() { } public static SortOrderComparator comparator(SortOrder sortOrder) { - switch (sortOrder) { - case STREET_AND_ARRIVAL_TIME: - return STREET_AND_ARRIVAL_TIME; - case STREET_AND_DEPARTURE_TIME: - return STREET_AND_DEPARTURE_TIME; - } - throw new IllegalArgumentException(); + return switch (sortOrder) { + case STREET_AND_ARRIVAL_TIME -> STREET_AND_ARRIVAL_TIME; + case STREET_AND_DEPARTURE_TIME -> STREET_AND_DEPARTURE_TIME; + }; } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/ItineraryDeletionFlagger.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/ItineraryDeletionFlagger.java index 3f88179d65c..c6db9c14cf6 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/ItineraryDeletionFlagger.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/ItineraryDeletionFlagger.java @@ -1,5 +1,6 @@ package org.opentripplanner.routing.algorithm.filterchain.deletionflagger; +import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -53,4 +54,16 @@ default List flagForRemoval(List itineraries) { default boolean skipAlreadyFlaggedItineraries() { return true; } + + /** + * Filter given {@code input} and remove itineraries which should be flagged for removal. This + * can be used in unit-tests - either testing the filter or using the filter in a test. + *

+ * This method should be used in unit-tests only. + */ + default List removeMatchesForTest(List input) { + var res = new ArrayList<>(input); + res.removeAll(flagForRemoval(input)); + return res; + } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilter.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilter.java index eb9874ad8ce..b939dd8ca68 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilter.java @@ -2,8 +2,8 @@ import java.util.List; import java.util.function.Consumer; +import org.opentripplanner.framework.collection.ListSection; import org.opentripplanner.model.plan.Itinerary; -import org.opentripplanner.routing.algorithm.filterchain.ListSection; /** * Flag all itineraries after the provided limit. This flags the itineraries at the end of the list diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterResults.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterResults.java index e41ca954fe3..7226c19535b 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterResults.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterResults.java @@ -2,25 +2,19 @@ import java.time.Instant; import java.util.List; +import org.opentripplanner.framework.collection.ListSection; +import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.model.plan.Itinerary; -import org.opentripplanner.model.plan.pagecursor.PageCursorInput; -import org.opentripplanner.model.plan.pagecursor.PagingDeduplicationSection; -import org.opentripplanner.routing.algorithm.filterchain.ListSection; +import org.opentripplanner.model.plan.ItinerarySortKey; +import org.opentripplanner.model.plan.paging.cursor.PageCursorInput; public class NumItinerariesFilterResults implements PageCursorInput { - public final Instant earliestRemovedDeparture; - public final Instant latestRemovedDeparture; - public final Instant earliestRemovedArrival; - public final Instant latestRemovedArrival; - public final Instant earliestKeptArrival; - public final Instant firstRemovedArrivalTime; - public final boolean firstRemovedIsOnStreetAllTheWay; - public final int firstRemovedGeneralizedCost; - public final int firstRemovedNumOfTransfers; - public final Instant firstRemovedDepartureTime; - public final ListSection cropSection; + private final Instant earliestRemovedDeparture; + private final Instant latestRemovedDeparture; + private final ItinerarySortKey pageCut; + private final ListSection cropSection; /** * The NumItinerariesFilter removes itineraries from a list of itineraries based on the number to @@ -38,105 +32,40 @@ public NumItinerariesFilterResults( .stream() .map(it -> it.startTime().toInstant()) .toList(); - List removedArrivals = removedItineraries - .stream() - .map(it -> it.endTime().toInstant()) - .toList(); this.earliestRemovedDeparture = removedDepartures.stream().min(Instant::compareTo).orElse(null); this.latestRemovedDeparture = removedDepartures.stream().max(Instant::compareTo).orElse(null); - this.earliestRemovedArrival = removedArrivals.stream().min(Instant::compareTo).orElse(null); - this.latestRemovedArrival = removedArrivals.stream().max(Instant::compareTo).orElse(null); - - this.earliestKeptArrival = - keptItineraries - .stream() - .map(it -> it.endTime().toInstant()) - .min(Instant::compareTo) - .orElseThrow(); - Itinerary firstRemovedItinerary; if (cropSection == ListSection.HEAD) { - firstRemovedItinerary = removedItineraries.get(removedItineraries.size() - 1); + pageCut = ListUtils.first(keptItineraries); } else { - firstRemovedItinerary = removedItineraries.get(0); + pageCut = ListUtils.last(keptItineraries); } - - this.firstRemovedIsOnStreetAllTheWay = firstRemovedItinerary.isOnStreetAllTheWay(); - this.firstRemovedArrivalTime = firstRemovedItinerary.endTime().toInstant(); - this.firstRemovedGeneralizedCost = firstRemovedItinerary.getGeneralizedCost(); - this.firstRemovedNumOfTransfers = firstRemovedItinerary.getNumberOfTransfers(); - this.firstRemovedDepartureTime = firstRemovedItinerary.startTime().toInstant(); - this.cropSection = cropSection; } - @Override - public String toString() { - return ToStringBuilder - .of(NumItinerariesFilterResults.class) - .addDateTime("earliestRemovedDeparture", earliestRemovedDeparture) - .addDateTime("latestRemovedDeparture", latestRemovedDeparture) - .addDateTime("earliestRemovedArrival", earliestRemovedArrival) - .addDateTime("latestRemovedArrival", latestRemovedArrival) - .addDateTime("earliestKeptArrival", earliestKeptArrival) - .addDateTime("firstRemovedArrivalTime", firstRemovedArrivalTime) - .addNum("firstRemovedGeneralizedCost", firstRemovedGeneralizedCost) - .addNum("firstRemovedNumOfTransfers", firstRemovedNumOfTransfers) - .addDateTime("firstRemovedDepartureTime", firstRemovedDepartureTime) - .addEnum("cropSection", cropSection) - .toString(); - } - @Override public Instant earliestRemovedDeparture() { return earliestRemovedDeparture; } - @Override - public Instant earliestKeptArrival() { - return earliestKeptArrival; - } - @Override public Instant latestRemovedDeparture() { return latestRemovedDeparture; } @Override - public Instant latestRemovedArrival() { - return latestRemovedArrival; - } - - @Override - public Instant firstRemovedArrivalTime() { - return firstRemovedArrivalTime; - } - - @Override - public boolean firstRemovedIsOnStreetAllTheWay() { - return firstRemovedIsOnStreetAllTheWay; - } - - @Override - public int firstRemovedGeneralizedCost() { - return firstRemovedGeneralizedCost; - } - - @Override - public int firstRemovedNumOfTransfers() { - return firstRemovedNumOfTransfers; + public ItinerarySortKey pageCut() { + return pageCut; } @Override - public Instant firstRemovedDepartureTime() { - return firstRemovedDepartureTime; - } - - @Override - public PagingDeduplicationSection deduplicationSection() { - return switch (cropSection) { - case HEAD -> PagingDeduplicationSection.TAIL; - case TAIL -> PagingDeduplicationSection.HEAD; - }; + public String toString() { + return ToStringBuilder + .of(NumItinerariesFilterResults.class) + .addDateTime("earliestRemovedDeparture", earliestRemovedDeparture) + .addDateTime("latestRemovedDeparture", latestRemovedDeparture) + .addObjOp("pageCut", pageCut, ItinerarySortKey::keyAsString) + .addEnum("cropSection", cropSection) + .toString(); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilter.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilter.java index abbcb7a28ee..dc189efbc33 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilter.java @@ -11,8 +11,8 @@ * should appear again when paging to the next page. Hence, this filter will remove * such itineraries. The same is true for when paging to the previous page for arriveBy=true. *

- * Itineraries matching the start(earliest-departure-time) and end(latest-departure-time) - * of the search-window are included [inclusive, inclusive]. + * Itineraries matching the start(earliest-departure-time) are included and itineraries matching + * the end(latest-departure-time) are not. The filter is {@code [inclusive, exclusive]}. */ public class OutsideSearchWindowFilter implements ItineraryDeletionFlagger { @@ -35,7 +35,7 @@ public String name() { public Predicate shouldBeFlaggedForRemoval() { return it -> { var time = it.startTime().toInstant(); - return time.isBefore(earliestDepartureTime) || time.isAfter(latestDepartureTime); + return time.isBefore(earliestDepartureTime) || !time.isBefore(latestDepartureTime); }; } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilter.java b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilter.java index f15e683d4f7..893a239b46b 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilter.java @@ -3,9 +3,10 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import org.opentripplanner.framework.collection.ListSection; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.ItinerarySortKey; -import org.opentripplanner.model.plan.pagecursor.ItineraryPageCut; +import org.opentripplanner.model.plan.SortOrder; import org.opentripplanner.routing.algorithm.filterchain.comparator.SortOrderComparator; /** @@ -22,12 +23,18 @@ public class PagingFilter implements ItineraryDeletionFlagger { public static final String TAG = "paging-filter"; - private final ItineraryPageCut itineraryPageCut; + private final ListSection deduplicateSection; + private final ItinerarySortKey itineraryPageCut; private final Comparator sortOrderComparator; - public PagingFilter(ItineraryPageCut itineraryPageCut) { + public PagingFilter( + SortOrder sortOrder, + ListSection deduplicateSection, + ItinerarySortKey itineraryPageCut + ) { + this.deduplicateSection = deduplicateSection; this.itineraryPageCut = itineraryPageCut; - this.sortOrderComparator = SortOrderComparator.comparator(itineraryPageCut.sortOrder()); + this.sortOrderComparator = SortOrderComparator.comparator(sortOrder); } @Override @@ -36,9 +43,9 @@ public String name() { } private boolean sortsIntoDeduplicationAreaRelativeToRemovedItinerary(Itinerary itinerary) { - return switch (itineraryPageCut.deduplicationSection()) { - case HEAD -> sortOrderComparator.compare(itinerary, itineraryPageCut) < 0; - case TAIL -> sortOrderComparator.compare(itinerary, itineraryPageCut) > 0; + return switch (deduplicateSection) { + case HEAD -> sortOrderComparator.compare(itinerary, itineraryPageCut) <= 0; + case TAIL -> sortOrderComparator.compare(itinerary, itineraryPageCut) >= 0; }; } @@ -46,13 +53,7 @@ private boolean sortsIntoDeduplicationAreaRelativeToRemovedItinerary(Itinerary i public List flagForRemoval(List itineraries) { return itineraries .stream() - .filter(it -> - ( - it.startTime().toInstant().isAfter(itineraryPageCut.windowStart()) && - it.startTime().toInstant().isBefore(itineraryPageCut.windowEnd()) && - sortsIntoDeduplicationAreaRelativeToRemovedItinerary(it) - ) - ) + .filter(this::sortsIntoDeduplicationAreaRelativeToRemovedItinerary) .collect(Collectors.toList()); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/PagingServiceFactory.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/PagingServiceFactory.java new file mode 100644 index 00000000000..8b122e6cf24 --- /dev/null +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/PagingServiceFactory.java @@ -0,0 +1,61 @@ +package org.opentripplanner.routing.algorithm.mapping; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.raptor.api.request.RaptorTuningParameters; +import org.opentripplanner.raptor.api.request.SearchParams; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters; +import org.opentripplanner.routing.api.request.RouteRequest; +import org.opentripplanner.service.paging.PagingService; + +public class PagingServiceFactory { + + public static PagingService createPagingService( + Instant searchStartTime, + TransitTuningParameters transitTuningParameters, + RaptorTuningParameters raptorTuningParameters, + RouteRequest request, + SearchParams raptorSearchParamsUsed, + NumItinerariesFilterResults numItinerariesFilterResults, + List itineraries + ) { + return new PagingService( + transitTuningParameters.pagingSearchWindowAdjustments(), + raptorTuningParameters.dynamicSearchWindowCoefficients().minWindow(), + raptorTuningParameters.dynamicSearchWindowCoefficients().maxWindow(), + searchWindowOf(raptorSearchParamsUsed), + edt(searchStartTime, raptorSearchParamsUsed), + lat(searchStartTime, raptorSearchParamsUsed), + request.itinerariesSortOrder(), + request.arriveBy(), + request.numItineraries(), + request.pageCursor(), + numItinerariesFilterResults, + itineraries + ); + } + + static Duration searchWindowOf(SearchParams searchParamsUsed) { + if (searchParamsUsed == null || !searchParamsUsed.isSearchWindowSet()) { + return null; + } + return Duration.ofSeconds(searchParamsUsed.searchWindowInSeconds()); + } + + static Instant edt(Instant transitSearchStartTime, SearchParams searchParamsUsed) { + if (searchParamsUsed == null || !searchParamsUsed.isEarliestDepartureTimeSet()) { + return null; + } + return transitSearchStartTime.plusSeconds(searchParamsUsed.earliestDepartureTime()); + } + + static Instant lat(Instant transitSearchStartTime, SearchParams searchParamsUsed) { + if (searchParamsUsed == null || !searchParamsUsed.isLatestArrivalTimeSet()) { + return null; + } + return transitSearchStartTime.plusSeconds(searchParamsUsed.latestArrivalTime()); + } +} diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java index 61ac1dd5cc1..a9b042083bf 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapper.java @@ -191,7 +191,7 @@ private Leg mapTransitLeg(Leg prevTransitLeg, TransitPathLeg pathLeg) { int lastLegCost = 0; PathLeg nextLeg = pathLeg.nextLeg(); if (nextLeg.isEgressLeg() && isFree(nextLeg.asEgressLeg())) { - lastLegCost = pathLeg.nextLeg().generalizedCost(); + lastLegCost = pathLeg.nextLeg().c1(); } // Find stop positions in pattern where this leg boards and alights. @@ -221,7 +221,7 @@ private Leg mapTransitLeg(Leg prevTransitLeg, TransitPathLeg pathLeg) { (prevTransitLeg == null ? null : prevTransitLeg.getTransferToNextLeg()) ) .withTransferToNextLeg((ConstrainedTransfer) pathLeg.getConstrainedTransferAfterLeg()) - .withGeneralizedCost(toOtpDomainCost(pathLeg.generalizedCost() + lastLegCost)) + .withGeneralizedCost(toOtpDomainCost(pathLeg.c1() + lastLegCost)) .withFrequencyHeadwayInSeconds(frequencyHeadwayInSeconds) .build(); } @@ -242,7 +242,7 @@ private Leg mapTransitLeg(Leg prevTransitLeg, TransitPathLeg pathLeg) { (prevTransitLeg == null ? null : prevTransitLeg.getTransferToNextLeg()) ) .withTransferToNextLeg((ConstrainedTransfer) pathLeg.getConstrainedTransferAfterLeg()) - .withGeneralizedCost(toOtpDomainCost(pathLeg.generalizedCost() + lastLegCost)) + .withGeneralizedCost(toOtpDomainCost(pathLeg.c1() + lastLegCost)) .build(); } @@ -308,7 +308,7 @@ private List mapNonTransitLeg( .withFrom(from) .withTo(to) .withDistanceMeters(transfer.getDistanceMeters()) - .withGeneralizedCost(toOtpDomainCost(pathLeg.generalizedCost())) + .withGeneralizedCost(toOtpDomainCost(pathLeg.c1())) .withGeometry(GeometryUtils.makeLineString(transfer.getCoordinates())) .withWalkSteps(List.of()) .build() diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RouteRequestToFilterChainMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RouteRequestToFilterChainMapper.java index e86249f6fc8..b379480bc33 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RouteRequestToFilterChainMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RouteRequestToFilterChainMapper.java @@ -12,7 +12,6 @@ import org.opentripplanner.routing.algorithm.filterchain.GroupBySimilarity; import org.opentripplanner.routing.algorithm.filterchain.ItineraryListFilterChain; import org.opentripplanner.routing.algorithm.filterchain.ItineraryListFilterChainBuilder; -import org.opentripplanner.routing.algorithm.filterchain.ListSection; import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.StreetMode; @@ -44,7 +43,7 @@ public static ItineraryListFilterChain createFilterChain( // The page cursor has deduplication information only in certain cases. if (request.pageCursor() != null && request.pageCursor().containsItineraryPageCut()) { - builder = builder.withPagingDeduplicationFilter(request.pageCursor().itineraryPageCut); + builder = builder.withPagingDeduplicationFilter(request.pageCursor().itineraryPageCut()); } ItineraryFilterPreferences params = request.preferences().itineraryFilter(); @@ -66,12 +65,9 @@ public static ItineraryListFilterChain createFilterChain( ); } - if (request.maxNumberOfItinerariesCropHead()) { - builder.withMaxNumberOfItinerariesCrop(ListSection.HEAD); - } - builder .withMaxNumberOfItineraries(Math.min(request.numItineraries(), MAX_NUMBER_OF_ITINERARIES)) + .withMaxNumberOfItinerariesCropSection(request.cropItinerariesAt()) .withTransitGeneralizedCostLimit(params.transitGeneralizedCostLimit()) .withBikeRentalDistanceRatio(params.bikeRentalDistanceRatio()) .withParkAndRideDurationRatio(params.parkAndRideDurationRatio()) diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapper.java index 89263b1b7a4..94b8c792d95 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapper.java @@ -2,26 +2,17 @@ import static org.opentripplanner.ext.realtimeresolver.RealtimeResolver.populateLegsWithRealtime; -import java.time.Duration; -import java.time.Instant; -import java.time.ZonedDateTime; import java.util.List; -import java.util.Objects; import java.util.Set; -import javax.annotation.Nullable; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.model.plan.Itinerary; -import org.opentripplanner.model.plan.SortOrder; -import org.opentripplanner.model.plan.pagecursor.PageCursor; -import org.opentripplanner.model.plan.pagecursor.PageCursorFactory; -import org.opentripplanner.model.plan.pagecursor.PageType; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; import org.opentripplanner.raptor.api.request.SearchParams; -import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.response.RoutingError; import org.opentripplanner.routing.api.response.RoutingResponse; -import org.opentripplanner.routing.api.response.TripSearchMetadata; import org.opentripplanner.routing.framework.DebugTimingAggregator; +import org.opentripplanner.service.paging.PagingService; import org.opentripplanner.transit.service.TransitService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,14 +23,12 @@ public class RoutingResponseMapper { public static RoutingResponse map( RouteRequest request, - ZonedDateTime transitSearchTimeZero, SearchParams raptorSearchParamsUsed, - Duration searchWindowForNextSearch, - NumItinerariesFilterResults numItinerariesFilterResults, List itineraries, Set routingErrors, DebugTimingAggregator debugTimingAggregator, - TransitService transitService + TransitService transitService, + PagingService pagingService ) { // Search is performed without realtime, but we still want to // include realtime information in the result @@ -52,32 +41,15 @@ public static RoutingResponse map( // Create response var tripPlan = TripPlanMapper.mapTripPlan(request, itineraries); - var factory = mapIntoPageCursorFactory( - request.itinerariesSortOrder(), - transitSearchTimeZero, - raptorSearchParamsUsed, - searchWindowForNextSearch, - numItinerariesFilterResults, - request.pageCursor() == null ? null : request.pageCursor().type - ); - - PageCursor nextPageCursor = factory.nextPageCursor(); - PageCursor prevPageCursor = factory.previousPageCursor(); + // Paging + PageCursor nextPageCursor = pagingService.nextPageCursor(); + PageCursor prevPageCursor = pagingService.previousPageCursor(); if (LOG.isDebugEnabled()) { logPagingInformation(request.pageCursor(), prevPageCursor, nextPageCursor, routingErrors); } - var metadata = createTripSearchMetadata( - request, - raptorSearchParamsUsed, - numItinerariesFilterResults == null - ? null - : numItinerariesFilterResults.firstRemovedDepartureTime, - numItinerariesFilterResults == null - ? null - : numItinerariesFilterResults.firstRemovedArrivalTime - ); + var metadata = pagingService.createTripSearchMetadata(); return new RoutingResponse( tripPlan, @@ -89,96 +61,6 @@ public static RoutingResponse map( ); } - public static PageCursorFactory mapIntoPageCursorFactory( - SortOrder sortOrder, - ZonedDateTime transitSearchTimeZero, - SearchParams raptorSearchParamsUsed, - Duration searchWindowNextSearch, - NumItinerariesFilterResults numItinerariesFilterResults, - @Nullable PageType currentPageType - ) { - Objects.requireNonNull(sortOrder); - Objects.requireNonNull(transitSearchTimeZero); - - var factory = new PageCursorFactory(sortOrder, searchWindowNextSearch); - - // No transit search performed - if (raptorSearchParamsUsed == null) { - return factory; - } - - assertRequestPrerequisites(raptorSearchParamsUsed); - - factory = - mapSearchParametersIntoFactory( - factory, - transitSearchTimeZero, - raptorSearchParamsUsed, - currentPageType - ); - - if (numItinerariesFilterResults != null) { - factory = factory.withRemovedItineraries(numItinerariesFilterResults); - } - return factory; - } - - private static PageCursorFactory mapSearchParametersIntoFactory( - PageCursorFactory factory, - ZonedDateTime transitSearchTimeZero, - SearchParams raptorSearchParamsUsed, - PageType currentPageType - ) { - Instant edt = transitSearchTimeZero - .plusSeconds(raptorSearchParamsUsed.earliestDepartureTime()) - .toInstant(); - - Instant lat = raptorSearchParamsUsed.isLatestArrivalTimeSet() - ? transitSearchTimeZero.plusSeconds(raptorSearchParamsUsed.latestArrivalTime()).toInstant() - : null; - - var searchWindowUsed = Duration.ofSeconds(raptorSearchParamsUsed.routerSearchWindowInSeconds()); - - return factory.withOriginalSearch(currentPageType, edt, lat, searchWindowUsed); - } - - @Nullable - private static TripSearchMetadata createTripSearchMetadata( - RouteRequest request, - SearchParams searchParams, - Instant firstRemovedDepartureTime, - Instant firstRemovedArrivalTime - ) { - if (searchParams == null) { - return null; - } - - Instant reqTime = request.dateTime(); - - if (request.arriveBy()) { - return TripSearchMetadata.createForArriveBy( - reqTime, - searchParams.searchWindowInSeconds(), - firstRemovedArrivalTime - ); - } else { - return TripSearchMetadata.createForDepartAfter( - reqTime, - searchParams.searchWindowInSeconds(), - firstRemovedDepartureTime - ); - } - } - - private static void assertRequestPrerequisites(SearchParams raptorSearchParamsUsed) { - if (!raptorSearchParamsUsed.isSearchWindowSet()) { - throw new IllegalStateException("SearchWindow not set"); - } - if (!raptorSearchParamsUsed.isEarliestDepartureTimeSet()) { - throw new IllegalStateException("Earliest departure time not set"); - } - } - private static void logPagingInformation( PageCursor currentPageCursor, PageCursor prevPageCursor, diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgress.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgress.java index 491f68800b8..e0ca070d76f 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgress.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgress.java @@ -37,7 +37,7 @@ protected DefaultAccessEgress(DefaultAccessEgress other, TimeAndCost penalty) { } this.stop = other.stop(); this.durationInSeconds = other.durationInSeconds() + (int) penalty.time().toSeconds(); - this.generalizedCost = other.generalizedCost() + penalty.cost().toCentiSeconds(); + this.generalizedCost = other.c1() + penalty.cost().toCentiSeconds(); this.penalty = penalty; this.lastState = other.getLastState(); } @@ -62,7 +62,7 @@ public int stop() { } @Override - public int generalizedCost() { + public int c1() { return generalizedCost; } @@ -119,7 +119,7 @@ public final boolean equals(Object o) { return ( stop() == that.stop() && durationInSeconds() == that.durationInSeconds() && - generalizedCost() == that.generalizedCost() && + c1() == that.c1() && penalty().equals(that.penalty()) ); } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultRaptorTransfer.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultRaptorTransfer.java index 4914970811a..3547a7ba05b 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultRaptorTransfer.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultRaptorTransfer.java @@ -2,18 +2,13 @@ import org.opentripplanner.raptor.api.model.RaptorTransfer; -public record DefaultRaptorTransfer( - int stop, - int durationInSeconds, - int generalizedCost, - Transfer transfer -) +public record DefaultRaptorTransfer(int stop, int durationInSeconds, int c1, Transfer transfer) implements RaptorTransfer { public static DefaultRaptorTransfer reverseOf(int fromStopIndex, RaptorTransfer transfer) { return new DefaultRaptorTransfer( fromStopIndex, transfer.durationInSeconds(), - transfer.generalizedCost(), + transfer.c1(), transfer instanceof DefaultRaptorTransfer drt ? drt.transfer : null ); } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java index 975526b946e..1d9b804067c 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/RaptorTransferIndex.java @@ -43,11 +43,7 @@ public static RaptorTransferIndex create( .stream() .flatMap(s -> s.asRaptorTransfer(request).stream()) .collect( - toMap( - RaptorTransfer::stop, - Function.identity(), - (a, b) -> a.generalizedCost() < b.generalizedCost() ? a : b - ) + toMap(RaptorTransfer::stop, Function.identity(), (a, b) -> a.c1() < b.c1() ? a : b) ) .values(); diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java index b738d63054e..26a1286d10d 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/DefaultCostCalculator.java @@ -134,15 +134,15 @@ public int calculateMinCost(int minTravelTime, int minNumTransfers) { @Override public int costEgress(RaptorAccessEgress egress) { if (egress.hasRides()) { - return egress.generalizedCost() + transferCostOnly; + return egress.c1() + transferCostOnly; } else if (stopTransferCost != null) { // Remove cost that was added during alighting. // We do not want to add this cost on last alighting since it should only be applied on transfers // It has to be done here because during alighting we do not know yet if it will be // a transfer or not. - return egress.generalizedCost() - stopTransferCost[egress.stop()]; + return egress.c1() - stopTransferCost[egress.stop()]; } else { - return egress.generalizedCost(); + return egress.c1(); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverter.java index 0ee465c2e53..210197f107b 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverter.java @@ -1,7 +1,7 @@ package org.opentripplanner.routing.algorithm.raptoradapter.transit.cost; import java.time.Duration; -import org.opentripplanner.framework.lang.OtpNumberFormat; +import org.opentripplanner.raptor.api.model.RaptorValueFormatter; /** * Convert Raptor internal cost to OTP domain model cost, and back. @@ -47,7 +47,7 @@ public static double toOtpDomainFactor(int raptorFactor) { * Convert Raptor internal cost to a string with format $###.## (in seconds) */ public static String toString(int raptorCost) { - return OtpNumberFormat.formatCostCenti(raptorCost); + return RaptorValueFormatter.formatC1(raptorCost); } /** diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java index 147601cbbae..75c1bcf7214 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java @@ -97,13 +97,13 @@ private RaptorRequest doMap() { } else { var c = request.pageCursor(); - if (c.earliestDepartureTime != null) { - searchParams.earliestDepartureTime(relativeTime(c.earliestDepartureTime)); + if (c.earliestDepartureTime() != null) { + searchParams.earliestDepartureTime(relativeTime(c.earliestDepartureTime())); } - if (c.latestArrivalTime != null) { - searchParams.latestArrivalTime(relativeTime(c.latestArrivalTime)); + if (c.latestArrivalTime() != null) { + searchParams.latestArrivalTime(relativeTime(c.latestArrivalTime())); } - searchParams.searchWindow(c.searchWindow); + searchParams.searchWindow(c.searchWindow()); } if (preferences.transfer().maxTransfers() != null) { diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java index 9564bfa0fd3..ba9af45adba 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java @@ -26,7 +26,6 @@ public class PriorityGroupConfigurator { private static final int BASE_GROUP_ID = TransitPriorityGroup32n.groupId(0); private int groupIndexCounter = 0; private final boolean enabled; - private final PriorityGroupMatcher[] baseMatchers; private final PriorityGroupMatcher[] agencyMatchers; private final PriorityGroupMatcher[] globalMatchers; @@ -36,7 +35,6 @@ public class PriorityGroupConfigurator { private PriorityGroupConfigurator() { this.enabled = false; - this.baseMatchers = null; this.agencyMatchers = null; this.globalMatchers = null; this.agencyMatchersIds = List.of(); @@ -44,15 +42,12 @@ private PriorityGroupConfigurator() { } private PriorityGroupConfigurator( - Collection base, Collection byAgency, Collection global ) { - this.baseMatchers = PriorityGroupMatcher.of(base); this.agencyMatchers = PriorityGroupMatcher.of(byAgency); this.globalMatchers = PriorityGroupMatcher.of(global); - this.enabled = - Stream.of(baseMatchers, agencyMatchers, globalMatchers).anyMatch(ArrayUtils::hasContent); + this.enabled = Stream.of(agencyMatchers, globalMatchers).anyMatch(ArrayUtils::hasContent); this.globalMatchersIds = Arrays.stream(globalMatchers).map(m -> new MatcherAndId(m, nextGroupId())).toList(); // We need to populate this dynamically @@ -64,14 +59,13 @@ public static PriorityGroupConfigurator empty() { } public static PriorityGroupConfigurator of( - Collection base, Collection byAgency, Collection global ) { - if (Stream.of(base, byAgency, global).allMatch(Collection::isEmpty)) { + if (Stream.of(byAgency, global).allMatch(Collection::isEmpty)) { return empty(); } - return new PriorityGroupConfigurator(base, byAgency, global); + return new PriorityGroupConfigurator(byAgency, global); } /** @@ -86,11 +80,6 @@ public int lookupTransitPriorityGroupId(RoutingTripPattern tripPattern) { var p = tripPattern.getPattern(); - for (PriorityGroupMatcher m : baseMatchers) { - if (m.match(p)) { - return BASE_GROUP_ID; - } - } for (var it : agencyMatchersIds) { if (it.matcher().match(p)) { var agencyId = p.getRoute().getAgency().getId(); diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java index b362587c773..f1212b2f545 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitData.java @@ -244,12 +244,11 @@ public RaptorConstrainedBoardingSearch transferConstraintsReverseS } private PriorityGroupConfigurator createTransitPriorityGroupConfigurator(RouteRequest request) { - if (!request.preferences().transit().relaxTransitPriorityGroup().isNormal()) { + if (request.preferences().transit().relaxTransitPriorityGroup().isNormal()) { return PriorityGroupConfigurator.empty(); } var transitRequest = request.journey().transit(); return PriorityGroupConfigurator.of( - transitRequest.priorityGroupsBase(), transitRequest.priorityGroupsByAgency(), transitRequest.priorityGroupsGlobal() ); diff --git a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPath.java b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPath.java index d18da1f0e08..ad4df23a42c 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPath.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPath.java @@ -30,6 +30,7 @@ public OptimizedPath(RaptorPath originalPath) { originalPath.accessLeg(), originalPath.rangeRaptorIterationDepartureTime(), originalPath.c1(), + originalPath.c2(), priorityCost(originalPath), NEUTRAL_COST, NEUTRAL_COST @@ -40,11 +41,12 @@ public OptimizedPath( AccessPathLeg accessPathLeg, int iterationStartTime, int generalizedCost, + int c2, int transferPriorityCost, int waitTimeOptimizedCost, int breakTieCost ) { - super(iterationStartTime, accessPathLeg, generalizedCost); + super(iterationStartTime, accessPathLeg, generalizedCost, c2); this.transferPriorityCost = transferPriorityCost; this.waitTimeOptimizedCost = waitTimeOptimizedCost; this.breakTieCost = breakTieCost; @@ -61,7 +63,7 @@ public static int priorityCost(boolean transferExist, Supplier leg) { } private void appendSummary(PathStringBuilder buf) { - buf.costCentiSec(transferPriorityCost, TransferConstraint.ZERO_COST, "pri"); - buf.costCentiSec(generalizedCostWaitTimeOptimized(), c1(), "wtc"); + buf.transferPriority(transferPriorityCost, TransferConstraint.ZERO_COST); + buf.waitTimeCost(generalizedCostWaitTimeOptimized(), c1()); } } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTail.java b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTail.java index 365ff1ef860..fa74648e8eb 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTail.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTail.java @@ -3,8 +3,10 @@ import javax.annotation.Nullable; import org.opentripplanner.framework.tostring.ValueObjectToStringBuilder; import org.opentripplanner.model.transfer.TransferConstraint; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTransfer; import org.opentripplanner.raptor.api.model.RaptorTripSchedule; +import org.opentripplanner.raptor.api.model.RaptorValueFormatter; import org.opentripplanner.raptor.api.path.RaptorStopNameResolver; import org.opentripplanner.raptor.api.path.TransitPathLeg; import org.opentripplanner.raptor.path.PathBuilder; @@ -130,6 +132,7 @@ public OptimizedPath build() { createPathLegs(costCalculator(), slackProvider()), iterationDepartureTime, generalizedCost, + c2(), transferPriorityCost, waitTimeOptimizedCost, breakTieCost() @@ -138,15 +141,21 @@ public OptimizedPath build() { @Override public String toString() { - return ValueObjectToStringBuilder - .of() - .addObj(super.toString()) - .addText(" [") - .addCostCenti(generalizedCost()) - .addCostCenti(transferPriorityCost, "pri") - .addCostCenti(generalizedCostWaitTimeOptimized(), "wtc") - .addText("]") - .toString(); + var builder = ValueObjectToStringBuilder.of().addObj(super.toString()).addText(" ["); + + if (generalizedCost != RaptorCostCalculator.ZERO_COST) { + builder.addObj(RaptorValueFormatter.formatC1(generalizedCost())); + } + if (c2() != RaptorConstants.NOT_SET) { + builder.addObj(RaptorValueFormatter.formatC2(c2())); + } + if (transferPriorityCost != TransferConstraint.ZERO_COST) { + builder.addObj(RaptorValueFormatter.formatTransferPriority(transferPriorityCost)); + } + if (waitTimeOptimizedCost != TransferWaitTimeCostCalculator.ZERO_COST) { + builder.addObj(RaptorValueFormatter.formatWaitTimeCost(generalizedCostWaitTimeOptimized())); + } + return builder.addText("]").toString(); } @Override @@ -203,7 +212,7 @@ private void updateGeneralizedCost() { return; } this.generalizedCost = - legsAsStream().mapToInt(it -> it.generalizedCost(costCalculator(), slackProvider())).sum(); + legsAsStream().mapToInt(it -> it.c1(costCalculator(), slackProvider())).sum(); } /*private methods */ diff --git a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/TripToTripTransfer.java b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/TripToTripTransfer.java index 5014ae95bcd..0dce8933e3f 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/TripToTripTransfer.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/transferoptimization/model/TripToTripTransfer.java @@ -45,7 +45,7 @@ public int transferDuration() { } public int generalizedCost() { - return sameStop() ? 0 : pathTransfer.generalizedCost(); + return sameStop() ? 0 : pathTransfer.c1(); } public boolean sameStop() { diff --git a/src/main/java/org/opentripplanner/routing/api/request/RouteRequest.java b/src/main/java/org/opentripplanner/routing/api/request/RouteRequest.java index 586b106bc66..ce2fdb31c44 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/RouteRequest.java +++ b/src/main/java/org/opentripplanner/routing/api/request/RouteRequest.java @@ -13,12 +13,12 @@ import java.util.Locale; import java.util.function.Consumer; import javax.annotation.Nullable; +import org.opentripplanner.framework.collection.ListSection; import org.opentripplanner.framework.time.DateUtils; import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.model.GenericLocation; import org.opentripplanner.model.plan.SortOrder; -import org.opentripplanner.model.plan.pagecursor.PageCursor; -import org.opentripplanner.model.plan.pagecursor.PageType; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; import org.opentripplanner.routing.api.request.request.JourneyRequest; import org.opentripplanner.routing.api.response.InputField; @@ -157,7 +157,7 @@ public boolean isTripPlannedForNow() { public SortOrder itinerariesSortOrder() { if (pageCursor != null) { - return pageCursor.originalSortOrder; + return pageCursor.originalSortOrder(); } return arriveBy ? SortOrder.STREET_AND_DEPARTURE_TIME : SortOrder.STREET_AND_ARRIVAL_TIME; } @@ -171,10 +171,11 @@ public void applyPageCursor() { if (pageCursor != null) { // We switch to "depart-after" search when paging next(lat==null). It does not make // sense anymore to keep the latest-arrival-time when going to the "next page". - if (pageCursor.latestArrivalTime == null) { + if (pageCursor.latestArrivalTime() == null) { arriveBy = false; } - this.dateTime = arriveBy ? pageCursor.latestArrivalTime : pageCursor.earliestDepartureTime; + this.dateTime = + arriveBy ? pageCursor.latestArrivalTime() : pageCursor.earliestDepartureTime(); journey.setModes(journey.modes().copyOf().withDirectMode(StreetMode.NOT_SET).build()); LOG.debug("Request dateTime={} set from pageCursor.", dateTime); } @@ -182,35 +183,12 @@ public void applyPageCursor() { /** * When paging we must crop the list of itineraries in the right end according to the sorting of - * the original search and according to the page cursor type (next or previous). - *

- * We need to flip the cropping and crop the head/start of the itineraries when: - *

    - *
  • Paging to the previous page for a {@code depart-after/sort-on-arrival-time} search. - *
  • Paging to the next page for a {@code arrive-by/sort-on-departure-time} search. - *
+ * the original search and according to the paging direction (next or previous). We always + * crop at the end of the initial search. This is a utility function delegating to the + * pageCursor, if available. */ - public boolean maxNumberOfItinerariesCropHead() { - if (pageCursor == null) { - return false; - } - - var previousPage = pageCursor.type == PageType.PREVIOUS_PAGE; - return pageCursor.originalSortOrder.isSortedByArrivalTimeAscending() == previousPage; - } - - /** - * Related to {@link #maxNumberOfItinerariesCropHead()}, but is {@code true} if we should crop the - * search-window head(in the beginning) or tail(in the end). - *

- * For the first search we look if the sort is ascending(crop tail) or descending(crop head), and - * for paged results we look at the paging type: next(tail) and previous(head). - */ - public boolean doCropSearchWindowAtTail() { - if (pageCursor == null) { - return itinerariesSortOrder().isSortedByArrivalTimeAscending(); - } - return pageCursor.type == PageType.NEXT_PAGE; + public ListSection cropItinerariesAt() { + return pageCursor == null ? ListSection.TAIL : pageCursor.cropItinerariesAt(); } /** diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/BikePreferences.java b/src/main/java/org/opentripplanner/routing/api/request/preference/BikePreferences.java index 0985a132dd0..115e1264036 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/preference/BikePreferences.java +++ b/src/main/java/org/opentripplanner/routing/api/request/preference/BikePreferences.java @@ -1,6 +1,7 @@ package org.opentripplanner.routing.api.request.preference; import static org.opentripplanner.framework.lang.DoubleUtils.doubleEquals; +import static org.opentripplanner.framework.lang.ObjectUtils.ifNotNull; import java.io.Serializable; import java.util.Objects; @@ -28,8 +29,7 @@ public final class BikePreferences implements Serializable { private final double walkingReluctance; private final int switchTime; private final Cost switchCost; - private final int parkTime; - private final Cost parkCost; + private final VehicleParkingPreferences parking; private final double stairsReluctance; private final BicycleOptimizeType optimizeType; private final TimeSlopeSafetyTriangle optimizeTriangle; @@ -42,9 +42,7 @@ private BikePreferences() { this.walkingReluctance = 5.0; this.switchTime = 0; this.switchCost = Cost.ZERO; - this.parkTime = 60; - /** Cost of parking a bike. */ - this.parkCost = Cost.costOfSeconds(120); + this.parking = VehicleParkingPreferences.DEFAULT; this.optimizeType = BicycleOptimizeType.SAFE; this.optimizeTriangle = TimeSlopeSafetyTriangle.DEFAULT; // very high reluctance to carry the bike up/down a flight of stairs @@ -59,8 +57,7 @@ private BikePreferences(Builder builder) { this.walkingReluctance = Units.reluctance(builder.walkingReluctance); this.switchTime = Units.duration(builder.switchTime); this.switchCost = builder.switchCost; - this.parkTime = Units.duration(builder.parkTime); - this.parkCost = builder.parkCost; + this.parking = builder.parking; this.optimizeType = Objects.requireNonNull(builder.optimizeType); this.optimizeTriangle = Objects.requireNonNull(builder.optimizeTriangle); this.stairsReluctance = Units.reluctance(builder.stairsReluctance); @@ -124,14 +121,9 @@ public int switchCost() { return switchCost.toSeconds(); } - /** Time to park a bike */ - public int parkTime() { - return parkTime; - } - - /** Cost of parking a bike. */ - public int parkCost() { - return parkCost.toSeconds(); + /** Parking preferences that can be different per request */ + public VehicleParkingPreferences parking() { + return parking; } /** @@ -162,8 +154,7 @@ public boolean equals(Object o) { doubleEquals(that.walkingReluctance, walkingReluctance) && switchTime == that.switchTime && switchCost.equals(that.switchCost) && - parkTime == that.parkTime && - parkCost.equals(that.parkCost) && + parking.equals(that.parking) && optimizeType == that.optimizeType && optimizeTriangle.equals(that.optimizeTriangle) && doubleEquals(stairsReluctance, that.stairsReluctance) @@ -180,8 +171,7 @@ public int hashCode() { walkingReluctance, switchTime, switchCost, - parkTime, - parkCost, + parking, optimizeType, optimizeTriangle, stairsReluctance @@ -199,8 +189,7 @@ public String toString() { .addNum("walkingReluctance", walkingReluctance, DEFAULT.walkingReluctance) .addDurationSec("switchTime", switchTime, DEFAULT.switchTime) .addObj("switchCost", switchCost, DEFAULT.switchCost) - .addDurationSec("parkTime", parkTime, DEFAULT.parkTime) - .addObj("parkCost", parkCost, DEFAULT.parkCost) + .addObj("parking", parking, DEFAULT.parking) .addEnum("optimizeType", optimizeType, DEFAULT.optimizeType) .addObj("optimizeTriangle", optimizeTriangle, DEFAULT.optimizeTriangle) .toString(); @@ -217,8 +206,7 @@ public static class Builder { private double walkingReluctance; private int switchTime; private Cost switchCost; - private int parkTime; - private Cost parkCost; + private VehicleParkingPreferences parking; private BicycleOptimizeType optimizeType; private TimeSlopeSafetyTriangle optimizeTriangle; @@ -233,8 +221,7 @@ public Builder(BikePreferences original) { this.walkingReluctance = original.walkingReluctance; this.switchTime = original.switchTime; this.switchCost = original.switchCost; - this.parkTime = original.parkTime; - this.parkCost = original.parkCost; + this.parking = original.parking; this.optimizeType = original.optimizeType; this.optimizeTriangle = original.optimizeTriangle; this.stairsReluctance = original.stairsReluctance; @@ -307,21 +294,8 @@ public Builder withSwitchCost(int switchCost) { return this; } - public int parkTime() { - return parkTime; - } - - public Builder withParkTime(int parkTime) { - this.parkTime = parkTime; - return this; - } - - public Cost parkCost() { - return parkCost; - } - - public Builder withParkCost(int parkCost) { - this.parkCost = Cost.costOfSeconds(parkCost); + public Builder withParking(Consumer body) { + this.parking = ifNotNull(this.parking, original.parking).copyOf().apply(body).build(); return this; } diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/CarPreferences.java b/src/main/java/org/opentripplanner/routing/api/request/preference/CarPreferences.java index 014b2b0cdec..523e19afb70 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/preference/CarPreferences.java +++ b/src/main/java/org/opentripplanner/routing/api/request/preference/CarPreferences.java @@ -1,5 +1,7 @@ package org.opentripplanner.routing.api.request.preference; +import static org.opentripplanner.framework.lang.ObjectUtils.ifNotNull; + import java.io.Serializable; import java.util.Objects; import java.util.function.Consumer; @@ -21,8 +23,7 @@ public final class CarPreferences implements Serializable { private final double speed; private final double reluctance; - private final int parkTime; - private final Cost parkCost; + private final VehicleParkingPreferences parking; private final int pickupTime; private final Cost pickupCost; private final int dropoffTime; @@ -33,8 +34,7 @@ public final class CarPreferences implements Serializable { private CarPreferences() { this.speed = 40.0; this.reluctance = 2.0; - this.parkTime = 60; - this.parkCost = Cost.costOfMinutes(2); + this.parking = VehicleParkingPreferences.DEFAULT; this.pickupTime = 60; this.pickupCost = Cost.costOfMinutes(2); this.dropoffTime = 120; @@ -45,8 +45,7 @@ private CarPreferences() { private CarPreferences(Builder builder) { this.speed = Units.speed(builder.speed); this.reluctance = Units.reluctance(builder.reluctance); - this.parkTime = Units.duration(builder.parkTime); - this.parkCost = builder.parkCost; + this.parking = builder.parking; this.pickupTime = Units.duration(builder.pickupTime); this.pickupCost = builder.pickupCost; this.dropoffTime = Units.duration(builder.dropoffTime); @@ -75,14 +74,9 @@ public double reluctance() { return reluctance; } - /** Time to park a car. */ - public int parkTime() { - return parkTime; - } - - /** Cost of parking a car. */ - public int parkCost() { - return parkCost.toSeconds(); + /** Parking preferences that can be different per request */ + public VehicleParkingPreferences parking() { + return parking; } /** Time of getting in/out of a carPickup (taxi) */ @@ -127,8 +121,7 @@ public boolean equals(Object o) { return ( DoubleUtils.doubleEquals(that.speed, speed) && DoubleUtils.doubleEquals(that.reluctance, reluctance) && - parkTime == that.parkTime && - parkCost.equals(that.parkCost) && + parking.equals(that.parking) && pickupTime == that.pickupTime && pickupCost.equals(that.pickupCost) && dropoffTime == that.dropoffTime && @@ -142,8 +135,7 @@ public int hashCode() { return Objects.hash( speed, reluctance, - parkTime, - parkCost, + parking, pickupTime, pickupCost, dropoffTime, @@ -158,8 +150,7 @@ public String toString() { .of(CarPreferences.class) .addNum("speed", speed, DEFAULT.speed) .addNum("reluctance", reluctance, DEFAULT.reluctance) - .addNum("parkTime", parkTime, DEFAULT.parkTime) - .addObj("parkCost", parkCost, DEFAULT.parkCost) + .addObj("parking", parking, DEFAULT.parking) .addNum("pickupTime", pickupTime, DEFAULT.pickupTime) .addObj("pickupCost", pickupCost, DEFAULT.pickupCost) .addNum("dropoffTime", dropoffTime, DEFAULT.dropoffTime) @@ -174,8 +165,7 @@ public static class Builder { private final CarPreferences original; private double speed; private double reluctance; - private int parkTime; - private Cost parkCost; + private VehicleParkingPreferences parking; private int pickupTime; private Cost pickupCost; private int dropoffTime; @@ -186,8 +176,7 @@ public Builder(CarPreferences original) { this.original = original; this.speed = original.speed; this.reluctance = original.reluctance; - this.parkTime = original.parkTime; - this.parkCost = original.parkCost; + this.parking = original.parking; this.pickupTime = original.pickupTime; this.pickupCost = original.pickupCost; this.dropoffTime = original.dropoffTime; @@ -209,13 +198,8 @@ public Builder withReluctance(double reluctance) { return this; } - public Builder withParkTime(int parkTime) { - this.parkTime = parkTime; - return this; - } - - public Builder withParkCost(int parkCost) { - this.parkCost = Cost.costOfSeconds(parkCost); + public Builder withParking(Consumer body) { + this.parking = ifNotNull(this.parking, original.parking).copyOf().apply(body).build(); return this; } diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/RoutingPreferences.java b/src/main/java/org/opentripplanner/routing/api/request/preference/RoutingPreferences.java index a4dfcedd0c7..b728b99f8e3 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/preference/RoutingPreferences.java +++ b/src/main/java/org/opentripplanner/routing/api/request/preference/RoutingPreferences.java @@ -96,6 +96,13 @@ public VehicleRentalPreferences rental() { return rental; } + /** + * Get parking preferences for the traverse mode. Note, only car and bike are supported. + */ + public VehicleParkingPreferences parking(TraverseMode mode) { + return mode == TraverseMode.CAR ? car.parking() : bike.parking(); + } + @Nonnull public ItineraryFilterPreferences itineraryFilter() { return itineraryFilter; diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleParkingPreferences.java b/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleParkingPreferences.java new file mode 100644 index 00000000000..c02862c4d79 --- /dev/null +++ b/src/main/java/org/opentripplanner/routing/api/request/preference/VehicleParkingPreferences.java @@ -0,0 +1,208 @@ +package org.opentripplanner.routing.api.request.preference; + +import java.io.Serializable; +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import org.opentripplanner.framework.model.Cost; +import org.opentripplanner.framework.tostring.ToStringBuilder; +import org.opentripplanner.routing.api.request.preference.filter.VehicleParkingFilter; +import org.opentripplanner.routing.api.request.preference.filter.VehicleParkingSelect; + +/** + * The parking preferences contain preferences for car and bicycle parking. These preferences + * include filtering, preference and realtime usage. + *

+ * THIS CLASS IS IMMUTABLE AND THREAD-SAFE. + */ +public final class VehicleParkingPreferences implements Serializable { + + public static final VehicleParkingPreferences DEFAULT = new VehicleParkingPreferences(); + private final Cost unpreferredVehicleParkingTagCost; + private final VehicleParkingFilter filter; + private final VehicleParkingFilter preferred; + private final Duration parkTime; + private final Cost parkCost; + + /** Create a new instance with default values. */ + private VehicleParkingPreferences() { + this.unpreferredVehicleParkingTagCost = Cost.costOfMinutes(5); + this.filter = VehicleParkingFilter.empty(); + this.preferred = VehicleParkingFilter.empty(); + this.parkTime = Duration.ofMinutes(1); + this.parkCost = Cost.costOfMinutes(2); + } + + private VehicleParkingPreferences(Builder builder) { + this.unpreferredVehicleParkingTagCost = builder.unpreferredVehicleParkingTagCost; + this.filter = + new VehicleParkingFilter( + builder.bannedVehicleParkingTags, + builder.requiredVehicleParkingTags + ); + this.preferred = + new VehicleParkingFilter( + builder.notPreferredVehicleParkingTags, + builder.preferredVehicleParkingTags + ); + this.parkTime = builder.parkTime; + this.parkCost = builder.parkCost; + } + + public static VehicleParkingPreferences.Builder of() { + return new Builder(DEFAULT); + } + + public VehicleParkingPreferences.Builder copyOf() { + return new Builder(this); + } + + /** + * What cost is applied to using parking that is not preferred. + */ + public Cost unpreferredVehicleParkingTagCost() { + return unpreferredVehicleParkingTagCost; + } + + /** + * Parking containing select filters must only be usable and parking containing with not filters + * cannot be used. + */ + public VehicleParkingFilter filter() { + return filter; + } + + /** + * Which vehicle parking tags are preferred. Vehicle parking facilities that don't have one of these + * tags receive an extra cost. + *

+ * This is useful if you want to use certain kind of facilities, like lockers for expensive e-bikes. + */ + public VehicleParkingFilter preferred() { + return preferred; + } + + /** Time to park a vehicle */ + public Duration parkTime() { + return parkTime; + } + + /** Cost of parking a bike. */ + public Cost parkCost() { + return parkCost; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VehicleParkingPreferences that = (VehicleParkingPreferences) o; + return ( + Objects.equals(unpreferredVehicleParkingTagCost, that.unpreferredVehicleParkingTagCost) && + Objects.equals(filter, that.filter) && + Objects.equals(preferred, that.preferred) && + Objects.equals(parkCost, that.parkCost) && + Objects.equals(parkTime, that.parkTime) + ); + } + + @Override + public int hashCode() { + return Objects.hash(unpreferredVehicleParkingTagCost, filter, preferred, parkCost, parkTime); + } + + @Override + public String toString() { + return ToStringBuilder + .of(VehicleParkingPreferences.class) + .addObj( + "unpreferredVehicleParkingTagCost", + unpreferredVehicleParkingTagCost, + DEFAULT.unpreferredVehicleParkingTagCost + ) + .addObj("filter", filter, DEFAULT.filter) + .addObj("preferred", preferred, DEFAULT.preferred) + .addObj("parkCost", parkCost, DEFAULT.parkCost) + .addObj("parkTime", parkTime, DEFAULT.parkTime) + .toString(); + } + + public static class Builder { + + private final VehicleParkingPreferences original; + private Cost unpreferredVehicleParkingTagCost; + private List bannedVehicleParkingTags; + private List requiredVehicleParkingTags; + private List preferredVehicleParkingTags; + private List notPreferredVehicleParkingTags; + private Cost parkCost; + private Duration parkTime; + + private Builder(VehicleParkingPreferences original) { + this.original = original; + this.unpreferredVehicleParkingTagCost = original.unpreferredVehicleParkingTagCost; + this.bannedVehicleParkingTags = original.filter.not(); + this.requiredVehicleParkingTags = original.filter.select(); + this.preferredVehicleParkingTags = original.preferred.select(); + this.notPreferredVehicleParkingTags = original.preferred.not(); + this.parkCost = original.parkCost; + this.parkTime = original.parkTime; + } + + public Builder withUnpreferredVehicleParkingTagCost(int cost) { + this.unpreferredVehicleParkingTagCost = Cost.costOfSeconds(cost); + return this; + } + + public Builder withBannedVehicleParkingTags(Set bannedVehicleParkingTags) { + this.bannedVehicleParkingTags = + List.of(new VehicleParkingSelect.TagsSelect(bannedVehicleParkingTags)); + return this; + } + + public Builder withRequiredVehicleParkingTags(Set requiredVehicleParkingTags) { + this.requiredVehicleParkingTags = + List.of(new VehicleParkingSelect.TagsSelect(requiredVehicleParkingTags)); + return this; + } + + public Builder withPreferredVehicleParkingTags(Set preferredVehicleParkingTags) { + this.preferredVehicleParkingTags = + List.of(new VehicleParkingSelect.TagsSelect(preferredVehicleParkingTags)); + return this; + } + + public Builder withNotPreferredVehicleParkingTags(Set notPreferredVehicleParkingTags) { + this.notPreferredVehicleParkingTags = + List.of(new VehicleParkingSelect.TagsSelect(notPreferredVehicleParkingTags)); + return this; + } + + public Builder withParkCost(int cost) { + this.parkCost = Cost.costOfSeconds(cost); + return this; + } + + public Builder withParkTime(int seconds) { + this.parkTime = Duration.ofSeconds(seconds); + return this; + } + + public Builder withParkTime(Duration duration) { + this.parkTime = duration; + return this; + } + + public Builder apply(Consumer body) { + body.accept(this); + return this; + } + + public VehicleParkingPreferences build() { + var newObj = new VehicleParkingPreferences(this); + return original.equals(newObj) ? original : newObj; + } + } +} diff --git a/src/main/java/org/opentripplanner/routing/api/request/preference/filter/VehicleParkingFilter.java b/src/main/java/org/opentripplanner/routing/api/request/preference/filter/VehicleParkingFilter.java new file mode 100644 index 00000000000..c4f5cee422f --- /dev/null +++ b/src/main/java/org/opentripplanner/routing/api/request/preference/filter/VehicleParkingFilter.java @@ -0,0 +1,94 @@ +package org.opentripplanner.routing.api.request.preference.filter; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nonnull; +import org.opentripplanner.framework.tostring.ToStringBuilder; +import org.opentripplanner.routing.vehicle_parking.VehicleParking; + +/** + * A filter class that checks if parking faclities match certain conditions for + * inclusion/exclusion or preference/unpreference. + */ +public class VehicleParkingFilter implements Serializable { + + private final VehicleParkingSelect[] not; + private final VehicleParkingSelect[] select; + + public VehicleParkingFilter( + Collection not, + Collection select + ) { + this.not = makeFilter(not); + this.select = makeFilter(select); + } + + public VehicleParkingFilter(VehicleParkingSelect not, VehicleParkingSelect select) { + this(List.of(not), List.of(select)); + } + + public List not() { + return Arrays.asList(not); + } + + public List select() { + return Arrays.asList(select); + } + + /** + * Create a request with no conditions. + */ + public static VehicleParkingFilter empty() { + return new VehicleParkingFilter(List.of(), List.of()); + } + + /** + * Checks if a parking facility matches the conditions defined in this filter. + */ + public boolean matches(VehicleParking p) { + for (var n : not) { + if (n.matches(p)) { + return false; + } + } + // not doesn't match and no selects means it matches + if (select.length == 0) { + return true; + } + for (var s : select) { + if (s.matches(p)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return ToStringBuilder + .of(this.getClass()) + .addCol("not", Arrays.asList(not)) + .addCol("select", Arrays.asList(select)) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VehicleParkingFilter that = (VehicleParkingFilter) o; + return (Arrays.equals(not, that.not) && Arrays.equals(select, that.select)); + } + + @Override + public int hashCode() { + return Arrays.hashCode(not) + Arrays.hashCode(select); + } + + @Nonnull + private static VehicleParkingSelect[] makeFilter(Collection select) { + return select.stream().filter(f -> !f.isEmpty()).toArray(VehicleParkingSelect[]::new); + } +} diff --git a/src/main/java/org/opentripplanner/routing/api/request/request/filter/VehicleParkingFilter.java b/src/main/java/org/opentripplanner/routing/api/request/preference/filter/VehicleParkingSelect.java similarity index 74% rename from src/main/java/org/opentripplanner/routing/api/request/request/filter/VehicleParkingFilter.java rename to src/main/java/org/opentripplanner/routing/api/request/preference/filter/VehicleParkingSelect.java index a4c240e7160..2d3935461d4 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/request/filter/VehicleParkingFilter.java +++ b/src/main/java/org/opentripplanner/routing/api/request/preference/filter/VehicleParkingSelect.java @@ -1,4 +1,4 @@ -package org.opentripplanner.routing.api.request.request.filter; +package org.opentripplanner.routing.api.request.preference.filter; import java.util.Collections; import java.util.Set; @@ -8,18 +8,18 @@ * A set of conditions that can be used to check if a parking facility should be included/excluded * or preferred/unpreferred. */ -public sealed interface VehicleParkingFilter { +public sealed interface VehicleParkingSelect { /** - * Checks if the parking facilities matches the conditions of the filter. + * Checks if the parking facilities matches the conditions of the select. */ boolean matches(VehicleParking p); /** - * Whether this filter defines any condition. + * Whether this select defines any condition. */ boolean isEmpty(); - record TagsFilter(Set tags) implements VehicleParkingFilter { + record TagsSelect(Set tags) implements VehicleParkingSelect { @Override public boolean matches(VehicleParking p) { return !Collections.disjoint(tags, p.getTags()); diff --git a/src/main/java/org/opentripplanner/routing/api/request/request/JourneyRequest.java b/src/main/java/org/opentripplanner/routing/api/request/request/JourneyRequest.java index b500bdd2398..39a775bf7f5 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/request/JourneyRequest.java +++ b/src/main/java/org/opentripplanner/routing/api/request/request/JourneyRequest.java @@ -8,7 +8,6 @@ public class JourneyRequest implements Cloneable, Serializable { // TODO VIA (Hannes): Move the fields below into StreetRequest private VehicleRentalRequest rental = new VehicleRentalRequest(); - private VehicleParkingRequest parking = new VehicleParkingRequest(); private TransitRequest transit = new TransitRequest(); private StreetRequest access = new StreetRequest(); private StreetRequest egress = new StreetRequest(); @@ -19,10 +18,6 @@ public VehicleRentalRequest rental() { return rental; } - public VehicleParkingRequest parking() { - return parking; - } - public TransitRequest transit() { return transit; } @@ -64,7 +59,6 @@ public JourneyRequest clone() { try { var clone = (JourneyRequest) super.clone(); clone.rental = this.rental.clone(); - clone.parking = this.parking.clone(); clone.transit = this.transit.clone(); clone.access = this.access.clone(); clone.egress = this.egress.clone(); diff --git a/src/main/java/org/opentripplanner/routing/api/request/request/TransitRequest.java b/src/main/java/org/opentripplanner/routing/api/request/request/TransitRequest.java index fcb9b4bdabf..67a56249328 100644 --- a/src/main/java/org/opentripplanner/routing/api/request/request/TransitRequest.java +++ b/src/main/java/org/opentripplanner/routing/api/request/request/TransitRequest.java @@ -31,7 +31,6 @@ public class TransitRequest implements Cloneable, Serializable { private List unpreferredRoutes = List.of(); - private List priorityGroupsBase = new ArrayList<>(); private List priorityGroupsByAgency = new ArrayList<>(); private List priorityGroupsGlobal = new ArrayList<>(); private DebugRaptor raptorDebugging = new DebugRaptor(); @@ -58,27 +57,12 @@ public void setFilters(List filters) { this.filters = filters; } - /** - * All transit patterns matching one of the {@link TransitPriorityGroupSelect}s is assigned the - * BASE-GROUP-ID. This is normally EVERYTHING, including local-traffic, that does not - * need to be treated in a special way. - *

- * Note! Entities that do not mach any of the three sets({@code #priorityGroupsBase()}, - * {@link #priorityGroupsByAgency} and {@link #priorityGroupsGlobal()}) - * will also be put in this group. - */ - public List priorityGroupsBase() { - return priorityGroupsBase; - } - - public void addPriorityGroupsBase(Collection priorityGroupsBase) { - this.priorityGroupsBase.addAll(priorityGroupsBase); - } - /** * A unique group-id is assigned all patterns grouped by matching select and agency. * In other words, two patterns matching the same select and with the same agency-id * will get the same group-id. + *

+ * Note! Entities that are not matched are put in the BASE-GROUP with id 0. */ public List priorityGroupsByAgency() { return priorityGroupsByAgency; @@ -93,6 +77,11 @@ public void addPriorityGroupsByAgency( this.priorityGroupsByAgency.addAll(priorityGroupsByAgency); } + /** + * A unique group-id is assigned all patterns grouped by matching selects. + *

+ * Note! Entities that are not matched are put in the BASE-GROUP with id 0. + */ public List priorityGroupsGlobal() { return priorityGroupsGlobal; } @@ -196,7 +185,6 @@ public TransitRequest clone() { clone.preferredRoutes = List.copyOf(this.preferredRoutes); clone.unpreferredRoutes = List.copyOf(this.unpreferredRoutes); clone.raptorDebugging = new DebugRaptor(this.raptorDebugging); - clone.priorityGroupsBase = new ArrayList<>(this.priorityGroupsBase); clone.priorityGroupsByAgency = new ArrayList<>(this.priorityGroupsByAgency); clone.priorityGroupsGlobal = new ArrayList<>(this.priorityGroupsGlobal); diff --git a/src/main/java/org/opentripplanner/routing/api/request/request/VehicleParkingRequest.java b/src/main/java/org/opentripplanner/routing/api/request/request/VehicleParkingRequest.java deleted file mode 100644 index d63ba79b990..00000000000 --- a/src/main/java/org/opentripplanner/routing/api/request/request/VehicleParkingRequest.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.opentripplanner.routing.api.request.request; - -import java.io.Serializable; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; - -/** - * Class that stores information about what kind of parking lots should be used for Park & Ride - * and Bike & Ride searches. - */ -public class VehicleParkingRequest implements Cloneable, Serializable { - - private VehicleParkingFilterRequest filter = VehicleParkingFilterRequest.empty(); - private VehicleParkingFilterRequest preferred = VehicleParkingFilterRequest.empty(); - private int unpreferredTagCost = 5 * 60; - - private boolean useAvailabilityInformation = false; - - public void setFilter(VehicleParkingFilterRequest filter) { - this.filter = filter; - } - - public void setPreferred(VehicleParkingFilterRequest filter) { - this.preferred = filter; - } - - /** - * Which vehicle parking tags are preferred. Vehicle parking facilities that don't have one of these - * tags receive an extra cost. - *

- * This is useful if you want to use certain kind of facilities, like lockers for expensive e-bikes. - */ - public VehicleParkingFilterRequest preferred() { - return this.preferred; - } - - public void setUnpreferredCost(int cost) { - unpreferredTagCost = cost; - } - - public int unpreferredCost() { - return unpreferredTagCost; - } - - /** - * If realtime availability data should be used when deciding af a parking facility should be - * used. - */ - public void setUseAvailabilityInformation(boolean b) { - useAvailabilityInformation = b; - } - - public boolean useAvailabilityInformation() { - return useAvailabilityInformation; - } - - public VehicleParkingRequest clone() { - try { - return (VehicleParkingRequest) super.clone(); - } catch (CloneNotSupportedException e) { - /* this will never happen since our super is the cloneable object */ - throw new RuntimeException(e); - } - } - - public VehicleParkingFilterRequest filter() { - return filter; - } -} diff --git a/src/main/java/org/opentripplanner/routing/api/request/request/filter/VehicleParkingFilterRequest.java b/src/main/java/org/opentripplanner/routing/api/request/request/filter/VehicleParkingFilterRequest.java deleted file mode 100644 index abe07010bcd..00000000000 --- a/src/main/java/org/opentripplanner/routing/api/request/request/filter/VehicleParkingFilterRequest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.opentripplanner.routing.api.request.request.filter; - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import javax.annotation.Nonnull; -import org.opentripplanner.framework.tostring.ToStringBuilder; -import org.opentripplanner.routing.vehicle_parking.VehicleParking; - -/** - * A request object that checks if parking faclities match certain conditions for - * inclusion/exclusion or preference/unpreference. - */ -public class VehicleParkingFilterRequest { - - private final VehicleParkingFilter[] not; - private final VehicleParkingFilter[] select; - - public VehicleParkingFilterRequest( - Collection not, - Collection select - ) { - this.not = makeFilter(not); - this.select = makeFilter(select); - } - - public VehicleParkingFilterRequest(VehicleParkingFilter not, VehicleParkingFilter select) { - this(List.of(not), List.of(select)); - } - - /** - * Create a request with no conditions. - */ - public static VehicleParkingFilterRequest empty() { - return new VehicleParkingFilterRequest(List.of(), List.of()); - } - - /** - * Checks if a parking facility matches the conditions defined in this filter. - */ - public boolean matches(VehicleParking p) { - for (var n : not) { - if (n.matches(p)) { - return false; - } - } - // not doesn't match and no selects means it matches - if (select.length == 0) { - return true; - } - for (var s : select) { - if (s.matches(p)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return ToStringBuilder - .of(this.getClass()) - .addCol("not", Arrays.asList(not)) - .addCol("select", Arrays.asList(select)) - .toString(); - } - - @Nonnull - private static VehicleParkingFilter[] makeFilter(Collection select) { - return select.stream().filter(f -> !f.isEmpty()).toArray(VehicleParkingFilter[]::new); - } -} diff --git a/src/main/java/org/opentripplanner/routing/api/response/RoutingResponse.java b/src/main/java/org/opentripplanner/routing/api/response/RoutingResponse.java index 85b195943d6..f7bcaca72e2 100644 --- a/src/main/java/org/opentripplanner/routing/api/response/RoutingResponse.java +++ b/src/main/java/org/opentripplanner/routing/api/response/RoutingResponse.java @@ -3,7 +3,7 @@ import java.util.List; import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.model.plan.TripPlan; -import org.opentripplanner.model.plan.pagecursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; import org.opentripplanner.routing.framework.DebugTimingAggregator; public class RoutingResponse { diff --git a/src/main/java/org/opentripplanner/routing/api/response/TripSearchMetadata.java b/src/main/java/org/opentripplanner/routing/api/response/TripSearchMetadata.java index a89b1413189..a5eb5842f23 100644 --- a/src/main/java/org/opentripplanner/routing/api/response/TripSearchMetadata.java +++ b/src/main/java/org/opentripplanner/routing/api/response/TripSearchMetadata.java @@ -17,15 +17,6 @@ public class TripSearchMetadata { */ public Duration searchWindowUsed; - /** - * This is the suggested search time for the "next page" or time window. Insert it together with - * the {@link #searchWindowUsed} in the request to get a new set of trips following in the - * time-window AFTER the current search. No duplicate trips should be returned, unless a trip is - * delayed and new realtime-data is available. - */ - @Deprecated - public Instant nextDateTime; - /** * This is the suggested search time for the "previous page" or time window. Insert it together * with the {@link #searchWindowUsed} in the request to get a new set of trips preceding in the @@ -37,45 +28,56 @@ public class TripSearchMetadata { @Deprecated public Instant prevDateTime; + /** + * This is the suggested search time for the "next page" or time window. Insert it together with + * the {@link #searchWindowUsed} in the request to get a new set of trips following in the + * time-window AFTER the current search. No duplicate trips should be returned, unless a trip is + * delayed and new realtime-data is available. + */ + @Deprecated + public Instant nextDateTime; + private TripSearchMetadata( Duration searchWindowUsed, Instant prevDateTime, Instant nextDateTime ) { this.searchWindowUsed = searchWindowUsed; - this.nextDateTime = nextDateTime; this.prevDateTime = prevDateTime; + this.nextDateTime = nextDateTime; } public static TripSearchMetadata createForArriveBy( - Instant reqTime, - int searchWindowUsed, - @Nullable Instant previousTimeInclusive + Instant earliestDepartureTimeUsed, + Duration searchWindowUsed, + @Nullable Instant firstDepartureTime ) { - Instant prevDateTime = previousTimeInclusive == null - ? reqTime.minusSeconds(searchWindowUsed) - // Round up to closest minute, to meet the _inclusive_ requirement - : previousTimeInclusive.minusSeconds(1).truncatedTo(ChronoUnit.MINUTES).plusSeconds(60); + Instant actualEdt = firstDepartureTime == null + ? earliestDepartureTimeUsed + // Round down to the minute before to avoid duplicates. This may cause missed itineraries. + : firstDepartureTime.minusSeconds(60).truncatedTo(ChronoUnit.MINUTES); return new TripSearchMetadata( - Duration.ofSeconds(searchWindowUsed), - prevDateTime, - reqTime.plusSeconds(searchWindowUsed) + searchWindowUsed, + actualEdt.minus(searchWindowUsed), + earliestDepartureTimeUsed.plus(searchWindowUsed) ); } public static TripSearchMetadata createForDepartAfter( - Instant reqTime, - int searchWindowUsed, - Instant nextDateTimeExcusive + Instant requestDepartureTime, + Duration searchWindowUsed, + Instant lastDepartureTime ) { - Instant nextDateTime = nextDateTimeExcusive == null - ? reqTime.plusSeconds(searchWindowUsed) - : nextDateTimeExcusive.truncatedTo(ChronoUnit.MINUTES); + Instant nextDateTime = lastDepartureTime == null + ? requestDepartureTime.plus(searchWindowUsed) + // There is no way to make this work properly. If we round down we get duplicates, if we + // round up we might skip itineraries. + : lastDepartureTime.plusSeconds(60).truncatedTo(ChronoUnit.MINUTES); return new TripSearchMetadata( - Duration.ofSeconds(searchWindowUsed), - reqTime.minusSeconds(searchWindowUsed), + searchWindowUsed, + requestDepartureTime.minus(searchWindowUsed), nextDateTime ); } diff --git a/src/main/java/org/opentripplanner/routing/graphfinder/DirectGraphFinder.java b/src/main/java/org/opentripplanner/routing/graphfinder/DirectGraphFinder.java index 660d225adbe..5ffa7cd2301 100644 --- a/src/main/java/org/opentripplanner/routing/graphfinder/DirectGraphFinder.java +++ b/src/main/java/org/opentripplanner/routing/graphfinder/DirectGraphFinder.java @@ -60,6 +60,7 @@ public List findClosestPlaces( List filterByModes, List filterByPlaceTypes, List filterByStops, + List filterByStations, List filterByRoutes, List filterByBikeRentalStations, TransitService transitService diff --git a/src/main/java/org/opentripplanner/routing/graphfinder/GraphFinder.java b/src/main/java/org/opentripplanner/routing/graphfinder/GraphFinder.java index 6138138ed45..4c0b0c81144 100644 --- a/src/main/java/org/opentripplanner/routing/graphfinder/GraphFinder.java +++ b/src/main/java/org/opentripplanner/routing/graphfinder/GraphFinder.java @@ -66,6 +66,7 @@ List findClosestPlaces( List filterByModes, List filterByPlaceTypes, List filterByStops, + List filterByStations, List filterByRoutes, List filterByBikeRentalStations, TransitService transitService diff --git a/src/main/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitor.java b/src/main/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitor.java index 49ef39e95ac..e71504d58f3 100644 --- a/src/main/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitor.java +++ b/src/main/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitor.java @@ -29,6 +29,7 @@ public class PlaceFinderTraverseVisitor implements TraverseVisitor private final TransitService transitService; private final Set filterByModes; private final Set filterByStops; + private final Set filterByStations; private final Set filterByRoutes; private final Set filterByVehicleRental; private final Set seenPatternAtStops = new HashSet<>(); @@ -40,6 +41,7 @@ public class PlaceFinderTraverseVisitor implements TraverseVisitor private final boolean includeVehicleRentals; private final boolean includeCarParking; private final boolean includeBikeParking; + private final boolean includeStations; private final int maxResults; private final double radiusMeters; @@ -64,23 +66,31 @@ public PlaceFinderTraverseVisitor( List filterByModes, List filterByPlaceTypes, List filterByStops, + List filterByStations, List filterByRoutes, List filterByBikeRentalStations, int maxResults, double radiusMeters ) { + if (filterByPlaceTypes == null || filterByPlaceTypes.isEmpty()) { + throw new IllegalArgumentException("No place type filter was included in request"); + } this.transitService = transitService; + this.filterByModes = toSet(filterByModes); this.filterByStops = toSet(filterByStops); + this.filterByStations = toSet(filterByStations); this.filterByRoutes = toSet(filterByRoutes); this.filterByVehicleRental = toSet(filterByBikeRentalStations); - includeStops = shouldInclude(filterByPlaceTypes, PlaceType.STOP); + includePatternAtStops = shouldInclude(filterByPlaceTypes, PlaceType.PATTERN_AT_STOP); includeVehicleRentals = shouldInclude(filterByPlaceTypes, PlaceType.VEHICLE_RENT); includeCarParking = shouldInclude(filterByPlaceTypes, PlaceType.CAR_PARK); includeBikeParking = shouldInclude(filterByPlaceTypes, PlaceType.BIKE_PARK); + includeStations = shouldInclude(filterByPlaceTypes, PlaceType.STATION); this.maxResults = maxResults; + this.radiusMeters = radiusMeters; } @@ -134,7 +144,7 @@ public SkipEdgeStrategy getSkipEdgeStrategy() { private static Set toSet(List list) { if (list == null) { - return null; + return Set.of(); } return Set.copyOf(list); } @@ -156,7 +166,7 @@ private void handleParking(VehicleParking parking, double distance) { } private boolean shouldInclude(List filterByPlaceTypes, PlaceType type) { - return filterByPlaceTypes == null || filterByPlaceTypes.contains(type); + return filterByPlaceTypes.contains(type); } private boolean stopHasPatternsWithMode(RegularStop stop, Set modes) { @@ -167,17 +177,54 @@ private boolean stopHasPatternsWithMode(RegularStop stop, Set modes .anyMatch(modes::contains); } + private boolean stopIsIncludedByStopFilter(RegularStop stop) { + return filterByStops.isEmpty() || filterByStops.contains(stop.getId()); + } + + private boolean stopIsIncludedByStationFilter(RegularStop stop) { + return ( + ((filterByStations.isEmpty() || filterByStations.contains(stop.getParentStation().getId()))) + ); + } + + private boolean stopIsIncludedByModeFilter(RegularStop stop) { + return filterByModes.isEmpty() || stopHasPatternsWithMode(stop, filterByModes); + } + + /* Checks whether the stop is included in the stop filter and whether the stop should be considered + * a stop or a station in the search.*/ + private boolean stopShouldNotBeIncludedAsStop(RegularStop stop) { + return ( + (includeStations && !stop.isPartOfStation() && !stopIsIncludedByStopFilter(stop)) || + (!includeStations && !stopIsIncludedByStopFilter(stop)) + ); + } + + /* Checks if the stop is a part of a station and whether that station is + * included in the station filter */ + private boolean stopShouldNotBeIncludedAsStation(RegularStop stop) { + return stop.isPartOfStation() && !stopIsIncludedByStationFilter(stop); + } + private void handleStop(RegularStop stop, double distance) { - if (filterByStops != null && !filterByStops.contains(stop.getId())) { - return; - } + // Do not consider stop if it is not included in the stop or mode filter + // or if it or its parent station has already been seen. if ( - includeStops && - !seenStops.contains(stop.getId()) && - (filterByModes == null || stopHasPatternsWithMode(stop, filterByModes)) + stopShouldNotBeIncludedAsStop(stop) || + stopShouldNotBeIncludedAsStation(stop) || + seenStops.contains(stop.getId()) || + seenStops.contains(stop.getStationOrStopId()) || + !stopIsIncludedByModeFilter(stop) ) { - placesFound.add(new PlaceAtDistance(stop, distance)); + return; + } + + if (includeStations && stop.getParentStation() != null) { + seenStops.add(stop.getParentStation().getId()); + placesFound.add(new PlaceAtDistance(stop.getParentStation(), distance)); + } else if (includeStops) { seenStops.add(stop.getId()); + placesFound.add(new PlaceAtDistance(stop, distance)); } } @@ -186,9 +233,9 @@ private void handlePatternsAtStop(RegularStop stop, double distance) { List patterns = transitService .getPatternsForStop(stop) .stream() - .filter(pattern -> filterByModes == null || filterByModes.contains(pattern.getMode())) + .filter(pattern -> filterByModes.isEmpty() || filterByModes.contains(pattern.getMode())) .filter(pattern -> - filterByRoutes == null || filterByRoutes.contains(pattern.getRoute().getId()) + filterByRoutes.isEmpty() || filterByRoutes.contains(pattern.getRoute().getId()) ) .filter(pattern -> pattern.canBoard(stop)) .toList(); @@ -209,7 +256,9 @@ private void handleVehicleRental(VehicleRentalPlace station, double distance) { if (!includeVehicleRentals) { return; } - if (filterByVehicleRental != null && !filterByVehicleRental.contains(station.getStationId())) { + if ( + !filterByVehicleRental.isEmpty() && !filterByVehicleRental.contains(station.getStationId()) + ) { return; } if (seenVehicleRentalPlaces.contains(station.getId())) { diff --git a/src/main/java/org/opentripplanner/routing/graphfinder/PlaceType.java b/src/main/java/org/opentripplanner/routing/graphfinder/PlaceType.java index 8f9eaaaed6b..6d4edbb00d9 100644 --- a/src/main/java/org/opentripplanner/routing/graphfinder/PlaceType.java +++ b/src/main/java/org/opentripplanner/routing/graphfinder/PlaceType.java @@ -9,4 +9,5 @@ public enum PlaceType { VEHICLE_RENT, BIKE_PARK, CAR_PARK, + STATION, } diff --git a/src/main/java/org/opentripplanner/routing/graphfinder/StreetGraphFinder.java b/src/main/java/org/opentripplanner/routing/graphfinder/StreetGraphFinder.java index 06472c9ad97..1b2b1d8f522 100644 --- a/src/main/java/org/opentripplanner/routing/graphfinder/StreetGraphFinder.java +++ b/src/main/java/org/opentripplanner/routing/graphfinder/StreetGraphFinder.java @@ -53,6 +53,7 @@ public List findClosestPlaces( List filterByModes, List filterByPlaceTypes, List filterByStops, + List filterByStations, List filterByRoutes, List filterByBikeRentalStations, TransitService transitService @@ -62,6 +63,7 @@ public List findClosestPlaces( filterByModes, filterByPlaceTypes, filterByStops, + filterByStations, filterByRoutes, filterByBikeRentalStations, maxResults, diff --git a/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java b/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java index 91398e13c73..320ffb2117d 100644 --- a/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java +++ b/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java @@ -59,9 +59,10 @@ public ViaRoutingResponse route(RouteViaRequest request) { private void logResponse(RoutingResponse response) { if (LOG.isDebugEnabled()) { + var m = response.getMetadata(); var text = MultiLineToStringBuilder .of("Response") - .addDuration("SearchWindowUsed", response.getMetadata().searchWindowUsed) + .addDuration("SearchWindowUsed", m == null ? null : m.searchWindowUsed) .add("NextPage", response.getNextPageCursor()) .add("PreviousPage", response.getPreviousPageCursor()) .addColNl( diff --git a/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java b/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java index 3aadbdcd37c..e5b0fd083dc 100644 --- a/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java +++ b/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java @@ -215,31 +215,15 @@ public boolean hasRealTimeData() { return availability != null; } - public boolean hasSpacesAvailable( - TraverseMode traverseMode, - boolean wheelchairAccessible, - boolean useAvailability - ) { + public boolean hasSpacesAvailable(TraverseMode traverseMode, boolean wheelchairAccessible) { switch (traverseMode) { case BICYCLE: - if (useAvailability && hasRealTimeDataForMode(TraverseMode.BICYCLE, false)) { - return availability.getBicycleSpaces() > 0; - } else { - return bicyclePlaces; - } + return bicyclePlaces; case CAR: if (wheelchairAccessible) { - if (useAvailability && hasRealTimeDataForMode(TraverseMode.CAR, true)) { - return availability.getWheelchairAccessibleCarSpaces() > 0; - } else { - return wheelchairAccessibleCarPlaces; - } + return wheelchairAccessibleCarPlaces; } else { - if (useAvailability && hasRealTimeDataForMode(TraverseMode.CAR, false)) { - return availability.getCarSpaces() > 0; - } else { - return carPlaces; - } + return carPlaces; } default: return false; diff --git a/src/main/java/org/opentripplanner/service/paging/PagingService.java b/src/main/java/org/opentripplanner/service/paging/PagingService.java new file mode 100644 index 00000000000..e8f09acf4d4 --- /dev/null +++ b/src/main/java/org/opentripplanner/service/paging/PagingService.java @@ -0,0 +1,227 @@ +package org.opentripplanner.service.paging; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import javax.annotation.Nullable; +import org.opentripplanner.framework.tostring.ToStringBuilder; +import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.SortOrder; +import org.opentripplanner.model.plan.paging.PagingSearchWindowAdjuster; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageCursorFactory; +import org.opentripplanner.model.plan.paging.cursor.PageType; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; +import org.opentripplanner.routing.api.response.TripSearchMetadata; + +public class PagingService { + + private final Duration searchWindowUsed; + private final Instant earliestDepartureTime; + private final Instant latestArrivalTime; + private final SortOrder itinerariesSortOrder; + private final boolean arriveBy; + private final int numberOfItineraries; + private final PageCursor pageCursor; + private final NumItinerariesFilterResults numItinerariesFilterResults; + private final PagingSearchWindowAdjuster searchWindowAdjuster; + private final List itineraries; + + // Lazy init + private PageCursorFactory pageCursorFactory = null; + + public PagingService( + List pagingSearchWindowAdjustments, + Duration minSearchWindowSize, + Duration maxSearchWindowSize, + @Nullable Duration searchWindowUsed, + @Nullable Instant earliestDepartureTime, + @Nullable Instant latestArrivalTime, + SortOrder itinerariesSortOrder, + boolean arriveBy, + int numberOfItineraries, + @Nullable PageCursor pageCursor, + NumItinerariesFilterResults numItinerariesFilterResults, + List itineraries + ) { + this.searchWindowUsed = searchWindowUsed; + this.earliestDepartureTime = earliestDepartureTime; + this.latestArrivalTime = latestArrivalTime; + this.itinerariesSortOrder = Objects.requireNonNull(itinerariesSortOrder); + this.arriveBy = arriveBy; + this.numberOfItineraries = numberOfItineraries; + this.pageCursor = pageCursor; + + this.numItinerariesFilterResults = numItinerariesFilterResults; + this.itineraries = Objects.requireNonNull(itineraries); + this.searchWindowAdjuster = + createSearchWindowAdjuster( + pagingSearchWindowAdjustments, + minSearchWindowSize, + maxSearchWindowSize + ); + } + + public PageCursor nextPageCursor() { + return pageCursorFactory().nextPageCursor(); + } + + public PageCursor previousPageCursor() { + return pageCursorFactory().previousPageCursor(); + } + + @Nullable + public TripSearchMetadata createTripSearchMetadata() { + if (noSuccessfulTransitSearchPerformed()) { + return null; + } + + if (arriveBy) { + return TripSearchMetadata.createForArriveBy( + earliestDepartureTime, + searchWindowUsed, + firstKeptDepartureTime() + ); + } else { + return TripSearchMetadata.createForDepartAfter( + earliestDepartureTime, + searchWindowUsed, + lastKeptDepartureTime() + ); + } + } + + private Duration calculateSearchWindowNextSearch() { + if (noSuccessfulTransitSearchPerformed()) { + return null; + } + + // SearchWindow cropped -> decrease search-window + if (numItinerariesFilterResults != null) { + boolean cropSWHead = doCropSearchWindowAtTail(); + Instant rmItineraryStartTime = numItinerariesFilterResults.pageCut().startTimeAsInstant(); + + return searchWindowAdjuster.decreaseSearchWindow( + searchWindowUsed, + earliestDepartureTime, + rmItineraryStartTime, + cropSWHead + ); + } + // (num-of-itineraries found <= numItineraries) -> increase or keep search-window + else { + int nFound = (int) itineraries + .stream() + .filter(it -> !it.isFlaggedForDeletion() && it.hasTransit()) + .count(); + + return searchWindowAdjuster.increaseOrKeepSearchWindow( + searchWindowUsed, + numberOfItineraries, + nFound + ); + } + } + + private Instant lastKeptDepartureTime() { + return numItinerariesFilterResults == null + ? null + : numItinerariesFilterResults.pageCut().startTimeAsInstant(); + } + + private Instant firstKeptDepartureTime() { + return numItinerariesFilterResults == null + ? null + : numItinerariesFilterResults.pageCut().startTimeAsInstant(); + } + + private PagingSearchWindowAdjuster createSearchWindowAdjuster( + List pagingSearchWindowAdjustments, + Duration minSearchWindowSize, + Duration maxSearchWindowSize + ) { + return new PagingSearchWindowAdjuster( + minSearchWindowSize, + maxSearchWindowSize, + pagingSearchWindowAdjustments + ); + } + + /** + * Related to {@link org.opentripplanner.routing.api.request.RouteRequest#cropItinerariesAt()}, + * but is {@code true} if we should crop the search-window head(in the beginning) or tail(in the + * end). + *

+ * For the first search we look if the sort is ascending(crop tail) or descending(crop head), and + * for paged results we look at the paging type: next(tail) and previous(head). + */ + private boolean doCropSearchWindowAtTail() { + if (pageCursor == null) { + return itinerariesSortOrder.isSortedByAscendingArrivalTime(); + } + return pageCursor.type().isNext(); + } + + private PageCursorFactory pageCursorFactory() { + if (pageCursorFactory == null) { + this.pageCursorFactory = + mapIntoPageCursorFactory(pageCursor == null ? null : pageCursor.type()); + } + return pageCursorFactory; + } + + private PageCursorFactory mapIntoPageCursorFactory(@Nullable PageType currentPageType) { + var searchWindowNextSearch = calculateSearchWindowNextSearch(); + var factory = new PageCursorFactory(itinerariesSortOrder, searchWindowNextSearch); + + if (noSuccessfulTransitSearchPerformed()) { + return factory; + } + + assertRequestPrerequisites(); + + factory = + factory.withOriginalSearch( + currentPageType, + earliestDepartureTime, + latestArrivalTime, + searchWindowUsed + ); + + if (numItinerariesFilterResults != null) { + factory = factory.withRemovedItineraries(numItinerariesFilterResults); + } + return factory; + } + + private void assertRequestPrerequisites() { + if (noSuccessfulTransitSearchPerformed()) { + throw new IllegalStateException("SearchWindow not set"); + } + if (earliestDepartureTime == null) { + throw new IllegalStateException("Earliest departure time not set"); + } + } + + /** + * Both SW and EDT must be available to compute paging tokens. + */ + private boolean noSuccessfulTransitSearchPerformed() { + return searchWindowUsed == null || earliestDepartureTime == null; + } + + @Override + public String toString() { + return ToStringBuilder + .of(PagingService.class) + .addDuration("searchWindowUsed", searchWindowUsed) + .addDateTime("earliestDepartureTime", earliestDepartureTime) + .addDateTime("latestArrivalTime", latestArrivalTime) + .addEnum("itinerariesSortOrder", itinerariesSortOrder) + .addBoolIfTrue("arriveBy", arriveBy) + .addNum("numberOfItineraries", numberOfItineraries) + .addObj("pageCursor", pageCursor) + .toString(); + } +} diff --git a/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java index 118dca43318..f6a79ea9192 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java @@ -25,10 +25,8 @@ import org.opentripplanner.routing.api.request.preference.StreetPreferences; import org.opentripplanner.routing.api.request.preference.SystemPreferences; import org.opentripplanner.routing.api.request.preference.TransitPreferences; +import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.api.request.preference.WalkPreferences; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter.TagsFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; import org.opentripplanner.standalone.config.sandbox.DataOverlayParametersMapper; import org.opentripplanner.transit.model.basic.TransitMode; @@ -57,7 +55,6 @@ public static RouteRequest mapRouteRequest(NodeAdapter c, RouteRequest dft) { } RouteRequest request = dft.clone(); - VehicleParkingRequest vehicleParking = request.journey().parking(); // Keep this alphabetically sorted so it is easy to check if a parameter is missing from the // mapping or duplicate exist. @@ -123,44 +120,6 @@ latest arrival time (LAT - EAT). .asDuration(dft.searchWindow()) ); - vehicleParking.setUnpreferredCost( - c - .of("unpreferredVehicleParkingTagCost") - .since(V2_3) - .summary("What cost to add if a parking facility doesn't contain a preferred tag.") - .description("See `preferredVehicleParkingTags`.") - .asInt(vehicleParking.unpreferredCost()) - ); - - var bannedTags = c - .of("bannedVehicleParkingTags") - .since(V2_1) - .summary("Tags with which a vehicle parking will not be used. If empty, no tags are banned.") - .asStringSet(List.of()); - - var requiredTags = c - .of("requiredVehicleParkingTags") - .since(V2_1) - .summary( - "Tags without which a vehicle parking will not be used. If empty, no tags are required." - ) - .asStringSet(List.of()); - vehicleParking.setFilter( - new VehicleParkingFilterRequest(new TagsFilter(bannedTags), new TagsFilter(requiredTags)) - ); - - var preferredTags = c - .of("preferredVehicleParkingTags") - .since(V2_3) - .summary( - "Vehicle parking facilities that don't have one of these tags will receive an extra cost and will therefore be penalised." - ) - .asStringSet(List.of()); - - vehicleParking.setPreferred( - new VehicleParkingFilterRequest(List.of(), List.of(new TagsFilter(preferredTags))) - ); - request.setWheelchair(WheelchairConfig.wheelchairEnabled(c, WHEELCHAIR_ACCESSIBILITY)); NodeAdapter unpreferred = c @@ -409,12 +368,6 @@ private static void mapBikePreferences(NodeAdapter c, BikePreferences.Builder bu ) .asInt(dft.boardCost()) ) - .withParkTime( - c.of("bikeParkTime").since(V2_0).summary("Time to park a bike.").asInt(dft.parkTime()) - ) - .withParkCost( - c.of("bikeParkCost").since(V2_0).summary("Cost to park a bike.").asInt(dft.parkCost()) - ) .withWalkingSpeed( c .of("bikeWalkingSpeed") @@ -486,6 +439,75 @@ private static void mapBikePreferences(NodeAdapter c, BikePreferences.Builder bu "How bad is it to walk the bicycle up/down a flight of stairs compared to taking a detour." ) .asDouble(dft.stairsReluctance()) + ) + .withParking(it -> + it + .withUnpreferredVehicleParkingTagCost( + c + .of("unpreferredVehicleParkingTagCost") + .since(V2_3) + .summary("What cost to add if a parking facility doesn't contain a preferred tag.") + .description("See `preferredVehicleParkingTags`.") + .asInt( + VehicleParkingPreferences.DEFAULT.unpreferredVehicleParkingTagCost().toSeconds() + ) + ) + .withBannedVehicleParkingTags( + c + .of("bannedVehicleParkingTags") + .since(V2_1) + .summary( + "Tags with which a vehicle parking will not be used. If empty, no tags are banned." + ) + .description( + """ + Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + """ + ) + .asStringSet(List.of()) + ) + .withRequiredVehicleParkingTags( + c + .of("requiredVehicleParkingTags") + .since(V2_1) + .summary( + "Tags without which a vehicle parking will not be used. If empty, no tags are required." + ) + .description( + """ + Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + """ + ) + .asStringSet(List.of()) + ) + .withParkTime( + c + .of("bikeParkTime") + .since(V2_0) + .summary("Time to park a bike.") + .asDuration(VehicleParkingPreferences.DEFAULT.parkTime()) + ) + .withParkCost( + c + .of("bikeParkCost") + .since(V2_0) + .summary("Cost to park a bike.") + .asInt(VehicleParkingPreferences.DEFAULT.parkCost().toSeconds()) + ) + .withPreferredVehicleParkingTags( + c + .of("preferredVehicleParkingTags") + .since(V2_3) + .summary( + "Vehicle parking facilities that don't have one of these tags will receive an extra cost and will therefore be penalised." + ) + .description( + """ + Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + """ + ) + .asStringSet(List.of()) + ) ); } @@ -703,12 +725,6 @@ private static void mapCarPreferences(NodeAdapter c, CarPreferences.Builder buil ) .asInt(dft.dropoffTime()) ) - .withParkCost( - c.of("carParkCost").since(V2_1).summary("Cost of parking a car.").asInt(dft.parkCost()) - ) - .withParkTime( - c.of("carParkTime").since(V2_1).summary("Time to park a car").asInt(dft.parkTime()) - ) .withPickupCost( c .of("carPickupCost") @@ -736,6 +752,75 @@ private static void mapCarPreferences(NodeAdapter c, CarPreferences.Builder buil .since(V2_0) .summary("The deceleration speed of an automobile, in meters per second per second.") .asDouble(dft.decelerationSpeed()) + ) + .withParking(it -> + it + .withUnpreferredVehicleParkingTagCost( + c + .of("unpreferredVehicleParkingTagCost") + .since(V2_3) + .summary("What cost to add if a parking facility doesn't contain a preferred tag.") + .description("See `preferredVehicleParkingTags`.") + .asInt( + VehicleParkingPreferences.DEFAULT.unpreferredVehicleParkingTagCost().toSeconds() + ) + ) + .withBannedVehicleParkingTags( + c + .of("bannedVehicleParkingTags") + .since(V2_1) + .summary( + "Tags with which a vehicle parking will not be used. If empty, no tags are banned." + ) + .description( + """ + Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + """ + ) + .asStringSet(List.of()) + ) + .withRequiredVehicleParkingTags( + c + .of("requiredVehicleParkingTags") + .since(V2_1) + .summary( + "Tags without which a vehicle parking will not be used. If empty, no tags are required." + ) + .description( + """ + Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + """ + ) + .asStringSet(List.of()) + ) + .withParkCost( + c + .of("carParkCost") + .since(V2_1) + .summary("Cost of parking a car.") + .asInt(VehicleParkingPreferences.DEFAULT.parkCost().toSeconds()) + ) + .withParkTime( + c + .of("carParkTime") + .since(V2_1) + .summary("Time to park a car") + .asDuration(VehicleParkingPreferences.DEFAULT.parkTime()) + ) + .withPreferredVehicleParkingTags( + c + .of("preferredVehicleParkingTags") + .since(V2_3) + .summary( + "Vehicle parking facilities that don't have one of these tags will receive an extra cost and will therefore be penalised." + ) + .description( + """ + Vehicle parking tags can originate from different places depending on the origin of the parking(OSM or RT feed). + """ + ) + .asStringSet(List.of()) + ) ); } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerequest/TransitPriorityGroupConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerequest/TransitPriorityGroupConfig.java index a1f648667ee..51faafc7cbf 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerequest/TransitPriorityGroupConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerequest/TransitPriorityGroupConfig.java @@ -20,23 +20,20 @@ public static void mapTransitRequest(NodeAdapter root, TransitRequest transit) { .summary("Transit priority groups configuration") .description( """ - Use this to separate transit patterns into groups. Each group will be given a priority - when compared with other groups. Hence, two paths with a different set of groups will BOTH - be returned unless the cost is worse then the relaxation specified in the - `relaxTransitPriorityGroup` parameter. This is only available in the TransmodelAPI for now. + Use this to separate transit patterns into groups. Each group will be given a group-id. A + path (multiple legs) will then have a set of group-ids based on the group-id from each leg. + Hence, two paths with a different set of group-ids will BOTH be optimal unless the cost is + worse than the relaxation specified in the `relaxTransitPriorityGroup` parameter. This is + only available in the TransmodelAPI for now. + + Unmatched patterns are put in the BASE priority-group (group id: 0). This group is special. + If a path only have legs in the base group, then that path dominates other paths, but other + paths must be better to make it. """ ) .experimentalFeature() .asObject(); - transit.addPriorityGroupsBase( - TransitPriorityGroupConfig.mapList( - c, - "base", - "All groups in base get the same group-id(GROUP_ZERO). Normally you will put all " + - "local-traffic and other 'non-problematic' services here." - ) - ); transit.addPriorityGroupsByAgency( TransitPriorityGroupConfig.mapList( c, diff --git a/src/main/java/org/opentripplanner/standalone/config/sandbox/TransmodelAPIConfig.java b/src/main/java/org/opentripplanner/standalone/config/sandbox/TransmodelAPIConfig.java index c4261f385c2..c6728f90d63 100644 --- a/src/main/java/org/opentripplanner/standalone/config/sandbox/TransmodelAPIConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/sandbox/TransmodelAPIConfig.java @@ -5,7 +5,7 @@ import java.util.Collection; import java.util.Set; -import org.opentripplanner.ext.transmodelapi.TransmodelAPIParameters; +import org.opentripplanner.apis.transmodel.TransmodelAPIParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; /** diff --git a/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java b/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java index 3191a67aacd..487e8489128 100644 --- a/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java +++ b/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java @@ -2,11 +2,11 @@ import jakarta.ws.rs.core.Application; import javax.annotation.Nullable; +import org.opentripplanner.apis.transmodel.TransmodelAPI; import org.opentripplanner.datastore.api.DataSource; import org.opentripplanner.ext.emissions.EmissionsDataModel; import org.opentripplanner.ext.geocoder.LuceneIndex; import org.opentripplanner.ext.stopconsolidation.StopConsolidationRepository; -import org.opentripplanner.ext.transmodelapi.TransmodelAPI; import org.opentripplanner.framework.application.LogMDCSupport; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.framework.logging.ProgressTracker; @@ -167,7 +167,7 @@ private void setupTransitRoutingServer() { initializeTransferCache(routerConfig().transitTuningConfig(), transitModel()); - if (OTPFeature.SandboxAPITransmodelApi.isOn()) { + if (OTPFeature.TransmodelGraphQlApi.isOn()) { TransmodelAPI.setUp( routerConfig().transmodelApi(), transitModel(), diff --git a/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java b/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java index 460a5e2416a..e682a7bfac1 100644 --- a/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java +++ b/src/main/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLink.java @@ -4,7 +4,7 @@ import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.tostring.ToStringBuilder; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; +import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; @@ -68,8 +68,11 @@ public State[] traverse(State s0) { } var vehicleParking = vehicleParkingEntranceVertex.getVehicleParking(); - final VehicleParkingRequest parkingRequest = s0.getRequest().parking(); - if (traversalBanned(parkingRequest, vehicleParking)) { + final VehicleParkingPreferences parkingPreferences = s0 + .getRequest() + .preferences() + .parking(s0.currentMode()); + if (traversalBanned(parkingPreferences, vehicleParking)) { return State.empty(); } @@ -81,10 +84,10 @@ public State[] traverse(State s0) { } private boolean traversalBanned( - VehicleParkingRequest parkingRequest, + VehicleParkingPreferences parkingPreferences, VehicleParking vehicleParking ) { - return !parkingRequest.filter().matches(vehicleParking); + return !parkingPreferences.filter().matches(vehicleParking); } @Override diff --git a/src/main/java/org/opentripplanner/street/model/edge/VehicleParkingEdge.java b/src/main/java/org/opentripplanner/street/model/edge/VehicleParkingEdge.java index 93a2b9bed0c..be909c1dc4c 100644 --- a/src/main/java/org/opentripplanner/street/model/edge/VehicleParkingEdge.java +++ b/src/main/java/org/opentripplanner/street/model/edge/VehicleParkingEdge.java @@ -1,12 +1,14 @@ package org.opentripplanner.street.model.edge; +import java.time.Duration; import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.framework.model.Cost; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.preference.BikePreferences; import org.opentripplanner.routing.api.request.preference.CarPreferences; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; +import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; import org.opentripplanner.street.search.TraverseMode; @@ -92,33 +94,43 @@ protected State[] traverseUnPark(State s0) { if (streetMode.includesBiking()) { final BikePreferences bike = s0.getPreferences().bike(); - return traverseUnPark(s0, bike.parkCost(), bike.parkTime(), TraverseMode.BICYCLE); + return traverseUnPark( + s0, + bike.parking().parkCost(), + bike.parking().parkTime(), + TraverseMode.BICYCLE + ); } else if (streetMode.includesDriving()) { final CarPreferences car = s0.getPreferences().car(); - return traverseUnPark(s0, car.parkCost(), car.parkTime(), TraverseMode.CAR); + return traverseUnPark( + s0, + car.parking().parkCost(), + car.parking().parkTime(), + TraverseMode.CAR + ); } else { return State.empty(); } } - private State[] traverseUnPark(State s0, int parkingCost, int parkingTime, TraverseMode mode) { + private State[] traverseUnPark( + State s0, + Cost parkingCost, + Duration parkingTime, + TraverseMode mode + ) { final StreetSearchRequest request = s0.getRequest(); - if ( - !vehicleParking.hasSpacesAvailable( - mode, - request.wheelchair(), - request.parking().useAvailabilityInformation() - ) - ) { + if (!vehicleParking.hasSpacesAvailable(mode, request.wheelchair())) { return State.empty(); } StateEditor s0e = s0.edit(this); - s0e.incrementWeight(parkingCost); - s0e.incrementTimeInSeconds(parkingTime); + s0e.incrementWeight(parkingCost.toSeconds()); + s0e.incrementTimeInSeconds((int) parkingTime.toSeconds()); s0e.setVehicleParked(false, mode); - addUnpreferredTagCost(request.parking(), s0e); + var parkingPreferences = s0.getRequest().preferences().parking(s0.currentMode()); + addUnpreferredTagCost(parkingPreferences, s0e); return s0e.makeStateArray(); } @@ -137,38 +149,41 @@ private State[] traversePark(State s0) { return State.empty(); } - return traversePark(s0, preferences.bike().parkCost(), preferences.bike().parkTime()); + return traversePark( + s0, + preferences.bike().parking().parkCost(), + preferences.bike().parking().parkTime() + ); } else if (streetMode.includesDriving()) { - return traversePark(s0, preferences.car().parkCost(), preferences.car().parkTime()); + return traversePark( + s0, + preferences.car().parking().parkCost(), + preferences.car().parking().parkTime() + ); } else { return State.empty(); } } - private State[] traversePark(State s0, int parkingCost, int parkingTime) { - if ( - !vehicleParking.hasSpacesAvailable( - s0.currentMode(), - s0.getRequest().wheelchair(), - s0.getRequest().parking().useAvailabilityInformation() - ) - ) { + private State[] traversePark(State s0, Cost parkingCost, Duration parkingTime) { + if (!vehicleParking.hasSpacesAvailable(s0.currentMode(), s0.getRequest().wheelchair())) { return State.empty(); } StateEditor s0e = s0.edit(this); - s0e.incrementWeight(parkingCost); - s0e.incrementTimeInSeconds(parkingTime); + s0e.incrementWeight(parkingCost.toSeconds()); + s0e.incrementTimeInSeconds((int) parkingTime.toSeconds()); s0e.setVehicleParked(true, TraverseMode.WALK); - addUnpreferredTagCost(s0.getRequest().parking(), s0e); + var parkingPreferences = s0.getRequest().preferences().parking(s0.currentMode()); + addUnpreferredTagCost(parkingPreferences, s0e); return s0e.makeStateArray(); } - private void addUnpreferredTagCost(VehicleParkingRequest req, StateEditor s0e) { - if (!req.preferred().matches(vehicleParking)) { - s0e.incrementWeight(req.unpreferredCost()); + private void addUnpreferredTagCost(VehicleParkingPreferences preferences, StateEditor s0e) { + if (!preferences.preferred().matches(vehicleParking)) { + s0e.incrementWeight(preferences.unpreferredVehicleParkingTagCost().toSeconds()); } } } diff --git a/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequest.java b/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequest.java index 6f44351d27c..6d8bd5783f3 100644 --- a/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequest.java +++ b/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequest.java @@ -12,7 +12,6 @@ import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; import org.opentripplanner.routing.api.request.request.VehicleRentalRequest; import org.opentripplanner.street.model.vertex.Vertex; import org.opentripplanner.street.search.intersection_model.IntersectionTraversalCalculator; @@ -40,7 +39,6 @@ public class StreetSearchRequest implements AStarRequest { private final StreetMode mode; private final boolean arriveBy; private final boolean wheelchair; - private final VehicleParkingRequest parking; private final VehicleRentalRequest rental; private final GenericLocation from; @@ -62,7 +60,6 @@ private StreetSearchRequest() { this.mode = StreetMode.WALK; this.arriveBy = false; this.wheelchair = false; - this.parking = new VehicleParkingRequest(); this.rental = new VehicleRentalRequest(); this.from = null; this.fromEnvelope = null; @@ -76,7 +73,6 @@ private StreetSearchRequest() { this.mode = builder.mode; this.arriveBy = builder.arriveBy; this.wheelchair = builder.wheelchair; - this.parking = builder.parking; this.rental = builder.rental; this.from = builder.from; this.fromEnvelope = createEnvelope(from); @@ -119,10 +115,6 @@ public boolean wheelchair() { return wheelchair; } - public VehicleParkingRequest parking() { - return parking; - } - public VehicleRentalRequest rental() { return rental; } diff --git a/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestBuilder.java b/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestBuilder.java index 1f102c6b45f..439e65a3289 100644 --- a/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestBuilder.java +++ b/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestBuilder.java @@ -5,7 +5,6 @@ import org.opentripplanner.model.GenericLocation; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; import org.opentripplanner.routing.api.request.request.VehicleRentalRequest; public class StreetSearchRequestBuilder { @@ -15,7 +14,6 @@ public class StreetSearchRequestBuilder { RoutingPreferences preferences; boolean arriveBy; boolean wheelchair; - VehicleParkingRequest parking; VehicleRentalRequest rental; GenericLocation from; GenericLocation to; @@ -26,7 +24,6 @@ public class StreetSearchRequestBuilder { this.preferences = original.preferences(); this.arriveBy = original.arriveBy(); this.wheelchair = original.wheelchair(); - this.parking = original.parking().clone(); this.rental = original.rental(); this.from = original.from(); this.to = original.to(); @@ -61,11 +58,6 @@ public StreetSearchRequestBuilder withWheelchair(boolean wheelchair) { return this; } - public StreetSearchRequestBuilder withParking(VehicleParkingRequest parking) { - this.parking = parking; - return this; - } - public StreetSearchRequestBuilder withRental(VehicleRentalRequest rental) { this.rental = rental; return this; diff --git a/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestMapper.java b/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestMapper.java index 902b6d6d92a..9f1f3c567f8 100644 --- a/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestMapper.java +++ b/src/main/java/org/opentripplanner/street/search/request/StreetSearchRequestMapper.java @@ -11,7 +11,6 @@ public static StreetSearchRequestBuilder map(RouteRequest opt) { .withStartTime(opt.dateTime()) .withPreferences(opt.preferences()) .withWheelchair(opt.wheelchair()) - .withParking(opt.journey().parking()) .withRental(opt.journey().rental()) .withFrom(opt.from()) .withTo(opt.to()); @@ -23,7 +22,6 @@ public static StreetSearchRequestBuilder mapToTransferRequest(RouteRequest opt) .withStartTime(Instant.ofEpochSecond(0)) .withPreferences(opt.preferences()) .withWheelchair(opt.wheelchair()) - .withParking(opt.journey().parking()) .withRental(opt.journey().rental()) .withMode(opt.journey().transfer().mode()); } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index d6cc164e3c1..ac2413caeae 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1002,7 +1002,10 @@ enum FeedAlertType { } enum FilterPlaceType { - """Stops""" + """ + Stops. + NOTE: if this is selected at the same time as `STATION`, stops that have a parent station will not be returned but their parent stations will be returned instead. + """ STOP """Departure rows""" @@ -1019,6 +1022,13 @@ enum FilterPlaceType { """Parking lots that contain spaces for cars""" CAR_PARK + + + """ + Stations. + NOTE: if this is selected at the same time as `STOP`, stops that have a parent station will not be returned but their parent stations will be returned instead. + """ + STATION } type Geometry { @@ -1098,6 +1108,9 @@ input InputFilters { """Stops to include by GTFS id.""" stops: [String] + """Stations to include by GTFS id.""" + stations: [String] + """Routes to include by GTFS id.""" routes: [String] @@ -2560,7 +2573,7 @@ type QueryType { filterByModes: [Mode] """Only include places that match one of the given GTFS ids.""" - filterByIds: InputFilters + filterByIds: InputFilters @deprecated(reason: "Not actively maintained") before: String after: String first: Int diff --git a/src/ext/graphql/transmodelapi/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql similarity index 100% rename from src/ext/graphql/transmodelapi/schema.graphql rename to src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql diff --git a/src/test/java/org/opentripplanner/_support/debug/TestDebug.java b/src/test/java/org/opentripplanner/_support/debug/TestDebug.java new file mode 100644 index 00000000000..df08e373ffa --- /dev/null +++ b/src/test/java/org/opentripplanner/_support/debug/TestDebug.java @@ -0,0 +1,57 @@ +package org.opentripplanner._support.debug; + +/** + * Sometimes it is convenient to include debug logging in a unit test. This class uses the + * {@code System.err} for logging - to make sure the output is flushed. Using the standard logging + * framework for this is a bit unnecessary. Use this class instead of System err/out. + *

+ * To turn on debugging set {@code testDebug} as an environment variable or system property - + * if set this class will print debug info to the console. Use: + *

+ * $ export testDebug=true | java ...
+ * or
+ * $ java -DtestDebug ..
+ * 
+ * In IntelliJ it's recommended to add the system property in the JUnit template. In the test + * drop down, choose Edit Configuration... then Edit Configuration Templates.. and + * choose JUnit. + */ +public class TestDebug { + + private static final Boolean ENABLED = enabled(); + + /** This is a utility class - only static methods */ + private TestDebug() {} + + public static boolean on() { + return ENABLED; + } + + public static boolean off() { + return !ENABLED; + } + + public static void print(Object value) { + if (ENABLED) { + System.err.print(value); + } + } + + public static void println() { + if (ENABLED) { + System.err.println(); + } + } + + public static void println(Object value) { + if (ENABLED) { + System.err.println(value); + } + } + + private static boolean enabled() { + boolean sysDebug = System.getProperties().containsKey("testDebug"); + boolean envDebug = System.getenv().containsKey("testDebug"); + return sysDebug || envDebug; + } +} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index a293c940713..a65c46b12fe 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -33,6 +33,7 @@ import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; +import org.locationtech.jts.geom.Coordinate; import org.opentripplanner._support.text.I18NStrings; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.ext.fares.FaresToItineraryMapper; @@ -64,6 +65,9 @@ import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; +import org.opentripplanner.routing.graphfinder.NearbyStop; +import org.opentripplanner.routing.graphfinder.PlaceAtDistance; +import org.opentripplanner.routing.graphfinder.PlaceType; import org.opentripplanner.routing.impl.TransitAlertServiceImpl; import org.opentripplanner.routing.services.TransitAlertService; import org.opentripplanner.routing.vehicle_parking.VehicleParking; @@ -79,12 +83,14 @@ import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.framework.AbstractBuilder; import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.TripTimesFactory; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TransitModel; +import org.opentripplanner.transit.service.TransitService; class GraphQLIntegrationTest { @@ -275,7 +281,7 @@ public TransitAlertService getTransitAlertService() { GRAPH.getVehicleParkingService(), defaultVehicleRentalService, realtimeVehicleService, - GraphFinder.getInstance(GRAPH, transitService::findRegularStop), + finder, new RouteRequest() ); } @@ -375,4 +381,32 @@ private static String responseBody(Response response) { fail("expected an outbound response but got %s".formatted(response.getClass().getSimpleName())); return null; } + + private static final GraphFinder finder = new GraphFinder() { + @Override + public List findClosestStops(Coordinate coordinate, double radiusMeters) { + return null; + } + + @Override + public List findClosestPlaces( + double lat, + double lon, + double radiusMeters, + int maxResults, + List filterByModes, + List filterByPlaceTypes, + List filterByStops, + List filterByStations, + List filterByRoutes, + List filterByBikeRentalStations, + TransitService transitService + ) { + return List + .of(TransitModelForTest.of().stop("A").build()) + .stream() + .map(stop -> new PlaceAtDistance(stop, 0)) + .toList(); + } + }; } diff --git a/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java index af6352839fb..fba953cd93a 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/mapping/RouteRequestMapperTest.java @@ -25,12 +25,13 @@ import org.opentripplanner.model.plan.PlanTestConstants; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.preference.TimeSlopeSafetyTriangle; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; +import org.opentripplanner.routing.api.request.preference.VehicleParkingPreferences; import org.opentripplanner.routing.core.BicycleOptimizeType; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; import org.opentripplanner.service.realtimevehicles.internal.DefaultRealtimeVehicleService; import org.opentripplanner.service.vehiclerental.internal.DefaultVehicleRentalService; +import org.opentripplanner.street.search.TraverseMode; import org.opentripplanner.test.support.VariableSource; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TransitModel; @@ -84,16 +85,8 @@ void parkingFilters() { assertNotNull(routeRequest); - final VehicleParkingRequest parking = routeRequest.journey().parking(); - assertEquals( - "VehicleParkingFilterRequest{not: [tags=[wheelbender]], select: [tags=[locker, roof]]}", - parking.filter().toString() - ); - assertEquals( - "VehicleParkingFilterRequest{select: [tags=[a, b]]}", - parking.preferred().toString() - ); - assertEquals(555, parking.unpreferredCost()); + testParkingFilters(routeRequest.preferences().parking(TraverseMode.CAR)); + testParkingFilters(routeRequest.preferences().parking(TraverseMode.BICYCLE)); } static Stream banningCases = Stream.of( @@ -219,4 +212,16 @@ private DataFetchingEnvironment executionContext(Map arguments) .arguments(arguments) .build(); } + + private void testParkingFilters(VehicleParkingPreferences parkingPreferences) { + assertEquals( + "VehicleParkingFilter{not: [tags=[wheelbender]], select: [tags=[locker, roof]]}", + parkingPreferences.filter().toString() + ); + assertEquals( + "VehicleParkingFilter{select: [tags=[a, b]]}", + parkingPreferences.preferred().toString() + ); + assertEquals(555, parkingPreferences.unpreferredVehicleParkingTagCost().toSeconds()); + } } diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLSchemaTest.java b/src/test/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchemaTest.java similarity index 79% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLSchemaTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchemaTest.java index a5f2d4a50b4..d762d784d3f 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/TransmodelGraphQLSchemaTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchemaTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi; +package org.opentripplanner.apis.transmodel; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; @@ -9,12 +9,14 @@ import java.io.File; import org.junit.jupiter.api.Test; import org.opentripplanner._support.time.ZoneIds; -import org.opentripplanner.ext.transmodelapi.support.GqlUtil; +import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.RouteRequest; class TransmodelGraphQLSchemaTest { - public static final File SCHEMA_FILE = new File("src/ext/graphql/transmodelapi/schema.graphql"); + public static final File SCHEMA_FILE = new File( + "src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql" + ); @Test void testSchemaBuild() { diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/mapping/TransitIdMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapperTest.java similarity index 82% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/mapping/TransitIdMapperTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapperTest.java index df1a00230cb..f0dc8504e93 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/mapping/TransitIdMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapperTest.java @@ -1,11 +1,14 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.List; import java.util.Set; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.opentripplanner.transit.model.framework.FeedScopedId; diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/mapping/TripRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java similarity index 99% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/mapping/TripRequestMapperTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java index e429d59c92c..3058f622281 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/mapping/TripRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping; +package org.opentripplanner.apis.transmodel.mapping; import static graphql.execution.ExecutionContextBuilder.newExecutionContextBuilder; import static java.util.stream.Collectors.toList; @@ -24,9 +24,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.opentripplanner._support.time.ZoneIds; +import org.opentripplanner.apis.transmodel.TransmodelRequestContext; import org.opentripplanner.ext.emissions.DefaultEmissionsService; import org.opentripplanner.ext.emissions.EmissionsDataModel; -import org.opentripplanner.ext.transmodelapi.TransmodelRequestContext; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.model.plan.Itinerary; diff --git a/src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/BikePreferencesMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/BikePreferencesMapperTest.java similarity index 90% rename from src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/BikePreferencesMapperTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/BikePreferencesMapperTest.java index d68c0652862..378571eeea9 100644 --- a/src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/BikePreferencesMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/BikePreferencesMapperTest.java @@ -1,13 +1,13 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.opentripplanner.ext.transmodelapi.mapping.preferences.BikePreferencesMapper.mapBikePreferences; +import static org.opentripplanner.apis.transmodel.mapping.preferences.BikePreferencesMapper.mapBikePreferences; import java.util.List; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.opentripplanner.ext.transmodelapi._support.TestDataFetcherDecorator; +import org.opentripplanner.apis.transmodel._support.TestDataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.BikePreferences; import org.opentripplanner.routing.core.BicycleOptimizeType; diff --git a/src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/CarPreferencesMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/CarPreferencesMapperTest.java similarity index 85% rename from src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/CarPreferencesMapperTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/CarPreferencesMapperTest.java index 96f99220469..08743e32e26 100644 --- a/src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/CarPreferencesMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/CarPreferencesMapperTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -6,7 +6,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.opentripplanner.ext.transmodelapi._support.TestDataFetcherDecorator; +import org.opentripplanner.apis.transmodel._support.TestDataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.CarPreferences; class CarPreferencesMapperTest { diff --git a/src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/WalkPreferencesMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/WalkPreferencesMapperTest.java similarity index 86% rename from src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/WalkPreferencesMapperTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/WalkPreferencesMapperTest.java index d1e9c3fe81d..811c91d0d50 100644 --- a/src/test/java/org/opentripplanner/ext/transmodelapi/mapping/preferences/WalkPreferencesMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/preferences/WalkPreferencesMapperTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.mapping.preferences; +package org.opentripplanner.apis.transmodel.mapping.preferences; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -6,7 +6,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.opentripplanner.ext.transmodelapi._support.TestDataFetcherDecorator; +import org.opentripplanner.apis.transmodel._support.TestDataFetcherDecorator; import org.opentripplanner.routing.api.request.preference.WalkPreferences; class WalkPreferencesMapperTest { diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/EnumTypesTest.java b/src/test/java/org/opentripplanner/apis/transmodel/model/EnumTypesTest.java similarity index 93% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/EnumTypesTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/model/EnumTypesTest.java index 912a727060e..3d834fced58 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/EnumTypesTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/model/EnumTypesTest.java @@ -1,9 +1,9 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.ROUTING_ERROR_CODE; -import static org.opentripplanner.ext.transmodelapi.model.EnumTypes.map; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.ROUTING_ERROR_CODE; +import static org.opentripplanner.apis.transmodel.model.EnumTypes.map; import java.util.EnumSet; import java.util.List; diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/TransportModeSlackTest.java b/src/test/java/org/opentripplanner/apis/transmodel/model/TransportModeSlackTest.java similarity index 97% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/TransportModeSlackTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/model/TransportModeSlackTest.java index 52f4f2f2187..22d998c189b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/TransportModeSlackTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/model/TransportModeSlackTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model; +package org.opentripplanner.apis.transmodel.model; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateTimeScalarFactoryTest.java b/src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java similarity index 96% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateTimeScalarFactoryTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java index 0ab88fb23b4..43b44cbd5a6 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/model/scalars/DateTimeScalarFactoryTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactoryTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.model.scalars; +package org.opentripplanner.apis.transmodel.model.scalars; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/support/ExecutionResultMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java similarity index 97% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/support/ExecutionResultMapperTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java index bf0a6757a72..bce971e9f1e 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/support/ExecutionResultMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/support/ExecutionResultMapperTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.support; +package org.opentripplanner.apis.transmodel.support; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.lang.StringUtils.quoteReplace; diff --git a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/support/GqlUtilTest.java b/src/test/java/org/opentripplanner/apis/transmodel/support/GqlUtilTest.java similarity index 97% rename from src/ext-test/java/org/opentripplanner/ext/transmodelapi/support/GqlUtilTest.java rename to src/test/java/org/opentripplanner/apis/transmodel/support/GqlUtilTest.java index fe61394de1b..d2d15168baf 100644 --- a/src/ext-test/java/org/opentripplanner/ext/transmodelapi/support/GqlUtilTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/support/GqlUtilTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.ext.transmodelapi.support; +package org.opentripplanner.apis.transmodel.support; import static graphql.execution.ExecutionContextBuilder.newExecutionContextBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/org/opentripplanner/ext/transmodelapi/_support/TestDataFetcherDecorator.java b/src/test/java/org/opentripplanner/ext/transmodelapi/_support/TestDataFetcherDecorator.java index b4b2bd9de47..e62b5ceaa1b 100644 --- a/src/test/java/org/opentripplanner/ext/transmodelapi/_support/TestDataFetcherDecorator.java +++ b/src/test/java/org/opentripplanner/ext/transmodelapi/_support/TestDataFetcherDecorator.java @@ -1,8 +1,8 @@ -package org.opentripplanner.ext.transmodelapi._support; +package org.opentripplanner.apis.transmodel._support; import java.util.Map; import java.util.function.Consumer; -import org.opentripplanner.ext.transmodelapi.support.DataFetcherDecorator; +import org.opentripplanner.apis.transmodel.support.DataFetcherDecorator; public class TestDataFetcherDecorator extends DataFetcherDecorator { diff --git a/src/test/java/org/opentripplanner/framework/collection/ListSectionTest.java b/src/test/java/org/opentripplanner/framework/collection/ListSectionTest.java new file mode 100644 index 00000000000..199804e4881 --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/collection/ListSectionTest.java @@ -0,0 +1,22 @@ +package org.opentripplanner.framework.collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class ListSectionTest { + + @Test + void isHead() { + assertTrue(ListSection.HEAD.isHead()); + assertFalse(ListSection.TAIL.isHead()); + } + + @Test + void oppositeEnd() { + assertEquals(ListSection.HEAD, ListSection.TAIL.invert()); + assertEquals(ListSection.TAIL, ListSection.HEAD.invert()); + } +} diff --git a/src/test/java/org/opentripplanner/framework/collection/ListUtilsTest.java b/src/test/java/org/opentripplanner/framework/collection/ListUtilsTest.java index 03d5dcbf8fe..6e72d5626c5 100644 --- a/src/test/java/org/opentripplanner/framework/collection/ListUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/collection/ListUtilsTest.java @@ -1,12 +1,31 @@ package org.opentripplanner.framework.collection; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.opentripplanner.framework.collection.ListUtils.first; +import static org.opentripplanner.framework.collection.ListUtils.last; import java.util.List; import org.junit.jupiter.api.Test; class ListUtilsTest { + @Test + void testFirst() { + assertNull(first(null)); + assertNull(first(List.of())); + assertEquals("A", first(List.of("A"))); + assertEquals("B", first(List.of("B", "C"))); + } + + @Test + void testLast() { + assertNull(last(null)); + assertNull(last(List.of())); + assertEquals("A", last(List.of("A"))); + assertEquals("C", last(List.of("B", "C"))); + } + @Test void combine() { var combined = ListUtils.combine(List.of(1, 2, 3), List.of(5, 6, 7)); diff --git a/src/test/java/org/opentripplanner/framework/lang/BoxTest.java b/src/test/java/org/opentripplanner/framework/lang/BoxTest.java new file mode 100644 index 00000000000..7e072fd2f5a --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/lang/BoxTest.java @@ -0,0 +1,47 @@ +package org.opentripplanner.framework.lang; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class BoxTest { + + public static final String VALUE = "Test"; + + @Test + void getValue() { + assertEquals(VALUE, Box.of(VALUE).get()); + assertNull(Box.empty().get()); + } + + @Test + void setValue() { + Box box = Box.empty(); + box.set(VALUE); + assertEquals(VALUE, box.get()); + } + + @Test + void testIsEmpty() { + assertTrue(Box.empty().isEmpty()); + assertFalse(Box.of("A").isEmpty()); + } + + @Test + void testEquals() { + assertEquals(Box.of(1), Box.of(1)); + assertNotEquals(Box.of(1), Box.of(2)); + + assertEquals(Box.of(1).hashCode(), Box.of(1).hashCode()); + assertNotEquals(Box.of(1).hashCode(), Box.of(2).hashCode()); + } + + @Test + void testToString() { + assertEquals("[Test]", Box.of(VALUE).toString()); + } +} diff --git a/src/test/java/org/opentripplanner/framework/text/CharacterEscapeFormatterTest.java b/src/test/java/org/opentripplanner/framework/text/CharacterEscapeFormatterTest.java new file mode 100644 index 00000000000..b33b06babb6 --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/text/CharacterEscapeFormatterTest.java @@ -0,0 +1,46 @@ +package org.opentripplanner.framework.text; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class CharacterEscapeFormatterTest { + + @ParameterizedTest + @ValueSource( + strings = { + "This;is;a:text", + " ; ", + " ;", + "; ", + ";;;", + "^", + " ^ ", + " ^", + "^ ", + ";^;", + "^;", + ";^", + "%^%", + "^%", + "%^", + ";^;", + "^;", + ";^", + } + ) + public void encodeDecode(String original) { + var subject = new CharacterEscapeFormatter('^', ';', '%'); + + var escapedText = subject.encode(original); + var result = subject.decode(escapedText); + + assertNotEquals(escapedText, original); + + assertEquals(original, result); + assertFalse(escapedText.contains(";"), escapedText); + } +} diff --git a/src/test/java/org/opentripplanner/framework/token/AdvancedTokenSchemaTest.java b/src/test/java/org/opentripplanner/framework/token/AdvancedTokenSchemaTest.java index 263b4bdb844..92fe6ad937e 100644 --- a/src/test/java/org/opentripplanner/framework/token/AdvancedTokenSchemaTest.java +++ b/src/test/java/org/opentripplanner/framework/token/AdvancedTokenSchemaTest.java @@ -12,7 +12,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -class AdvancedTokenSchemaTest implements TokenSchemaConstants { +class AdvancedTokenSchemaTest implements TestTokenSchemaConstants { private static final List TEST_CASES = new ArrayList<>(); diff --git a/src/test/java/org/opentripplanner/framework/token/FieldDefinitionTest.java b/src/test/java/org/opentripplanner/framework/token/FieldDefinitionTest.java new file mode 100644 index 00000000000..3778dbef4f1 --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/token/FieldDefinitionTest.java @@ -0,0 +1,55 @@ +package org.opentripplanner.framework.token; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class FieldDefinitionTest { + + private static final String NAME = "foo"; + public static final TokenType TOKEN_TYPE = TokenType.STRING; + private final FieldDefinition subject = new FieldDefinition(NAME, TOKEN_TYPE); + + @Test + void name() { + assertEquals(NAME, subject.name()); + } + + @Test + void type() { + assertEquals(TOKEN_TYPE, subject.type()); + } + + @Test + void testDeprecate() { + assertFalse(subject.deprecated()); + assertTrue(subject.deprecate().deprecated()); + } + + @Test + void testEqualsAndHashCode() { + var same = new FieldDefinition(NAME, TOKEN_TYPE); + var other1 = new FieldDefinition(NAME, TokenType.INT); + var other2 = new FieldDefinition("Bar", TOKEN_TYPE); + var other3 = subject.deprecate(); + + assertEquals(subject, subject); + assertEquals(same, subject); + assertNotEquals(other1, subject); + assertNotEquals(other2, subject); + assertNotEquals(other3, subject); + + assertEquals(same.hashCode(), subject.hashCode()); + assertNotEquals(other1.hashCode(), subject.hashCode()); + assertNotEquals(other2.hashCode(), subject.hashCode()); + assertNotEquals(other3.hashCode(), subject.hashCode()); + } + + @Test + void testToString() { + assertEquals("foo:STRING", subject.toString()); + } +} diff --git a/src/test/java/org/opentripplanner/framework/token/TokenSchemaConstants.java b/src/test/java/org/opentripplanner/framework/token/TestTokenSchemaConstants.java similarity index 56% rename from src/test/java/org/opentripplanner/framework/token/TokenSchemaConstants.java rename to src/test/java/org/opentripplanner/framework/token/TestTokenSchemaConstants.java index fd6c38461b3..09ac58a0d2d 100644 --- a/src/test/java/org/opentripplanner/framework/token/TokenSchemaConstants.java +++ b/src/test/java/org/opentripplanner/framework/token/TestTokenSchemaConstants.java @@ -2,26 +2,34 @@ import java.time.Duration; import java.time.Instant; +import java.time.Month; import org.opentripplanner.framework.time.DurationUtils; -public interface TokenSchemaConstants { +public interface TestTokenSchemaConstants { // Token field names. These are used to reference a specific field value in theString BYTE_FIELD = "AByte"; // token to avoid index errors. They are not part of the serialized token.String DURATION_FIELD = "ADur"; + String BOOLEAN_TRUE_FIELD = "ABoolTrue"; + String BOOLEAN_FALSE_FIELD = "ABoolFalse"; String BYTE_FIELD = "AByte"; String DURATION_FIELD = "ADur"; + String ENUM_FIELD = "EnField"; String INT_FIELD = "ANum"; String STRING_FIELD = "AStr"; String TIME_INSTANT_FIELD = "ATime"; byte BYTE_VALUE = 17; Duration DURATION_VALUE = DurationUtils.duration("2m13s"); + Month ENUM_VALUE = Month.MAY; + Class ENUM_CLASS = Month.class; int INT_VALUE = 31; String STRING_VALUE = "text"; Instant TIME_INSTANT_VALUE = Instant.parse("2023-10-23T10:00:59Z"); - String BYTE_ENCODED = "rO0ABXcEAAExEQ=="; - String DURATION_ENCODED = "rO0ABXcKAAEyAAUybTEzcw=="; - String INT_ENCODED = "rO0ABXcHAAEzAAIzMQ=="; - String STRING_ENCODED = "rO0ABXcJAAE3AAR0ZXh0"; - String TIME_INSTANT_ENCODED = "rO0ABXcaAAIxMwAUMjAyMy0xMC0yM1QxMDowMDo1OVo="; + String BOOLEAN_ENCODED = "MXx0cnVlfGZhbHNlfA=="; + String BYTE_ENCODED = "MXwxN3w="; + String DURATION_ENCODED = "MnwybTEzc3w="; + String ENUM_ENCODED = "M3xNQVl8"; + String INT_ENCODED = "M3wzMXw="; + String STRING_ENCODED = "N3x0ZXh0fA=="; + String TIME_INSTANT_ENCODED = "MTN8MjAyMy0xMC0yM1QxMDowMDo1OVp8"; } diff --git a/src/test/java/org/opentripplanner/framework/token/TokenSchemaTest.java b/src/test/java/org/opentripplanner/framework/token/TokenSchemaTest.java index 4a6d00c5e68..089aac372cc 100644 --- a/src/test/java/org/opentripplanner/framework/token/TokenSchemaTest.java +++ b/src/test/java/org/opentripplanner/framework/token/TokenSchemaTest.java @@ -1,16 +1,26 @@ package org.opentripplanner.framework.token; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.DayOfWeek; +import java.util.Optional; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -class TokenSchemaTest implements TokenSchemaConstants { +class TokenSchemaTest implements TestTokenSchemaConstants { // Token field names. These are used to reference a specific field value in the // token to avoid index errors. They are not part of the serialized token. + private static final TokenSchema BOOLEAN_SCHEMA = TokenSchema + .ofVersion(1) + .addBoolean(BOOLEAN_TRUE_FIELD) + .addBoolean(BOOLEAN_FALSE_FIELD) + .build(); + private static final TokenSchema BYTE_SCHEMA = TokenSchema .ofVersion(1) .addByte(BYTE_FIELD) @@ -19,6 +29,10 @@ class TokenSchemaTest implements TokenSchemaConstants { .ofVersion(2) .addDuration(DURATION_FIELD) .build(); + private static final TokenSchema ENUM_SCHEMA = TokenSchema + .ofVersion(3) + .addEnum(ENUM_FIELD) + .build(); private static final TokenSchema INT_SCHEMA = TokenSchema.ofVersion(3).addInt(INT_FIELD).build(); private static final TokenSchema STRING_SCHEMA = TokenSchema .ofVersion(7) @@ -29,6 +43,21 @@ class TokenSchemaTest implements TokenSchemaConstants { .addTimeInstant(TIME_INSTANT_FIELD) .build(); + @Test + public void encodeBoolean() { + // Add in opposite order of Schema, test naming fields work + var token = BOOLEAN_SCHEMA + .encode() + .withBoolean(BOOLEAN_FALSE_FIELD, false) + .withBoolean(BOOLEAN_TRUE_FIELD, true) + .build(); + assertEquals(BOOLEAN_ENCODED, token); + assertTrue(BOOLEAN_SCHEMA.decode(token).getBoolean(BOOLEAN_TRUE_FIELD)); + + var tokenResult = BOOLEAN_SCHEMA.decode(token); + assertFalse(tokenResult.getBoolean(BOOLEAN_FALSE_FIELD)); + } + @Test public void encodeByte() { var token = BYTE_SCHEMA.encode().withByte(BYTE_FIELD, (byte) 17).build(); @@ -43,6 +72,14 @@ public void testDuration() { assertEquals(DURATION_VALUE, DURATION_SCHEMA.decode(token).getDuration(DURATION_FIELD)); } + @Test + public void testEnum() { + var token = ENUM_SCHEMA.encode().withEnum(ENUM_FIELD, ENUM_VALUE).build(); + assertEquals(ENUM_ENCODED, token); + assertEquals(ENUM_VALUE, ENUM_SCHEMA.decode(token).getEnum(ENUM_FIELD, ENUM_CLASS).get()); + assertEquals(Optional.empty(), ENUM_SCHEMA.decode(token).getEnum(ENUM_FIELD, DayOfWeek.class)); + } + @Test public void testInt() { var token = INT_SCHEMA.encode().withInt(INT_FIELD, INT_VALUE).build(); diff --git a/src/test/java/org/opentripplanner/framework/token/TokenTypeTest.java b/src/test/java/org/opentripplanner/framework/token/TokenTypeTest.java new file mode 100644 index 00000000000..e4ba897928b --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/token/TokenTypeTest.java @@ -0,0 +1,55 @@ +package org.opentripplanner.framework.token; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Duration; +import java.time.Instant; +import java.time.Month; +import org.junit.jupiter.api.Test; + +class TokenTypeTest { + + @Test + void isNot() { + assertTrue(TokenType.INT.isNot(TokenType.STRING)); + assertFalse(TokenType.INT.isNot(TokenType.INT)); + } + + @Test + void valueToString() { + assertEquals("", TokenType.BYTE.valueToString(null)); + assertEquals("34", TokenType.BYTE.valueToString((byte) 34)); + assertEquals("true", TokenType.BOOLEAN.valueToString(true)); + assertEquals("2m30s", TokenType.DURATION.valueToString(Duration.ofSeconds(150))); + assertEquals("APRIL", TokenType.ENUM.valueToString(Month.APRIL)); + assertEquals("17", TokenType.INT.valueToString(17)); + assertEquals("FG", TokenType.STRING.valueToString("FG")); + assertEquals( + "2023-12-31T17:01:00Z", + TokenType.TIME_INSTANT.valueToString(Instant.parse("2023-12-31T17:01:00Z")) + ); + } + + @Test + void stringToValue() { + assertEquals((byte) 34, TokenType.BYTE.stringToValue("34")); + assertEquals(true, TokenType.BOOLEAN.stringToValue("true")); + assertEquals(Duration.ofSeconds(150), TokenType.DURATION.stringToValue("2m30s")); + assertEquals("APRIL", TokenType.ENUM.stringToValue("APRIL")); + assertEquals(17, TokenType.INT.stringToValue("17")); + assertEquals("FG", TokenType.STRING.stringToValue("FG")); + assertEquals( + Instant.parse("2023-12-31T17:01:00Z"), + TokenType.TIME_INSTANT.stringToValue("2023-12-31T17:01:00Z") + ); + + // Test nullable types with empty string + assertNull(TokenType.DURATION.stringToValue("")); + assertNull(TokenType.ENUM.stringToValue("")); + assertNull(TokenType.STRING.stringToValue("")); + assertNull(TokenType.TIME_INSTANT.stringToValue("")); + } +} diff --git a/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java b/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java index ca35c8272db..3e87006e953 100644 --- a/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java +++ b/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java @@ -20,6 +20,11 @@ public class ToStringBuilderTest { private static final ZoneId TIME_ZONE_ID_PARIS = ZoneIds.PARIS; + @Test + public void ofName() { + assertEquals("Name{}", ToStringBuilder.of("Name").toString()); + } + @Test public void addFieldIfTrue() { assertEquals("ToStringBuilderTest{x}", subject().addBoolIfTrue("x", true).toString()); diff --git a/src/test/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilderTest.java b/src/test/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilderTest.java index fad55e395bc..a59a0bf9b90 100644 --- a/src/test/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilderTest.java +++ b/src/test/java/org/opentripplanner/framework/tostring/ValueObjectToStringBuilderTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.time.Duration; +import java.time.Instant; import org.junit.jupiter.api.Test; public class ValueObjectToStringBuilderTest { @@ -107,6 +108,11 @@ public void addDuration() { assertEquals("", subject().skipNull().addDuration(null).toString()); } + @Test + public void addTime() { + assertEquals("1970-01-01T01:01:01Z", subject().addTime(Instant.ofEpochSecond(3661)).toString()); + } + @Test public void addCost() { assertEquals("null", subject().addCostCenti(null).toString()); diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java similarity index 55% rename from src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java rename to src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java index d0833474adf..6e082d9e98d 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/StopTimesMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java @@ -2,24 +2,35 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; +import org.geojson.LngLatAlt; +import org.geojson.Polygon; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.onebusaway.gtfs.model.AgencyAndId; +import org.onebusaway.gtfs.model.Location; +import org.onebusaway.gtfs.model.LocationGroup; import org.onebusaway.gtfs.model.Stop; import org.onebusaway.gtfs.model.StopTime; import org.onebusaway.gtfs.model.Trip; +import org.opentripplanner._support.geometry.Polygons; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.PickDrop; +import org.opentripplanner.transit.model.site.AreaStop; +import org.opentripplanner.transit.model.site.GroupStop; import org.opentripplanner.transit.service.StopModel; import org.opentripplanner.transit.service.StopModelBuilder; -public class StopTimesMapperTest { +public class StopTimeMapperTest { private static final String FEED_ID = "FEED"; @@ -41,8 +52,6 @@ public class StopTimesMapperTest { private static final double SHAPE_DIST_TRAVELED = 2.5d; - private static final Stop STOP = new Stop(); - private static final String STOP_NAME = "Stop"; private static final String HEAD_SIGN = "Head Sign"; @@ -53,9 +62,11 @@ public class StopTimesMapperTest { private static final Trip TRIP = new GtfsTestData().trip; - private static final StopTime STOP_TIME = new StopTime(); - public static final DataImportIssueStore ISSUE_STORE = DataImportIssueStore.NOOP; + private static final List ZONE_COORDINATES = Arrays + .stream(Polygons.BERLIN.getCoordinates()) + .map(c -> new LngLatAlt(c.x, c.y)) + .toList(); private final StopModelBuilder stopModelBuilder = StopModel.of(); @@ -85,36 +96,60 @@ public class StopTimesMapperTest { new TranslationHelper() ); - static { + /** + * Build a static ("regular") stop. + */ + private static Stop buildStop() { + var stop = new Stop(); + stop.setId(AGENCY_AND_ID); + stop.setName(STOP_NAME); + stop.setLat(53.12); + stop.setLon(12.34); + return stop; + } + + /** + * Builds a stop time with a fixed stop. + */ + static StopTime buildDefaultStopTime() { + var stopTime = buildStopTime(); + var stop = buildStop(); + stopTime.setStop(stop); + return stopTime; + } + + /** + * Builds a stop time without a stop. Useful for testing flex fields. + */ + private static StopTime buildStopTime() { TRIP.setId(AGENCY_AND_ID); - STOP.setId(AGENCY_AND_ID); - STOP.setName(STOP_NAME); - - STOP_TIME.setId(ID); - STOP_TIME.setArrivalTime(ARRIVAL_TIME); - STOP_TIME.setDepartureTime(DEPARTURE_TIME); - STOP_TIME.setDropOffType(DROP_OFF_TYPE); - STOP_TIME.setFarePeriodId(FARE_PERIOD_ID); - STOP_TIME.setPickupType(PICKUP_TYPE); - STOP_TIME.setRouteShortName(ROUTE_SHORT_NAME); - STOP_TIME.setShapeDistTraveled(SHAPE_DIST_TRAVELED); - STOP_TIME.setStop(STOP); - STOP_TIME.setStopHeadsign(HEAD_SIGN); - STOP_TIME.setStopSequence(STOP_SEQUENCE); - STOP_TIME.setTimepoint(TIMEPOINT); - STOP_TIME.setTrip(TRIP); + + var stopTime = new StopTime(); + stopTime.setId(ID); + stopTime.setArrivalTime(ARRIVAL_TIME); + stopTime.setDepartureTime(DEPARTURE_TIME); + stopTime.setDropOffType(DROP_OFF_TYPE); + stopTime.setFarePeriodId(FARE_PERIOD_ID); + stopTime.setPickupType(PICKUP_TYPE); + stopTime.setRouteShortName(ROUTE_SHORT_NAME); + stopTime.setShapeDistTraveled(SHAPE_DIST_TRAVELED); + stopTime.setStopHeadsign(HEAD_SIGN); + stopTime.setStopSequence(STOP_SEQUENCE); + stopTime.setTimepoint(TIMEPOINT); + stopTime.setTrip(TRIP); + return stopTime; } @Test public void testMapCollection() { assertNull(subject.map((Collection) null)); assertTrue(subject.map(Collections.emptyList()).isEmpty()); - assertEquals(1, subject.map(Collections.singleton(STOP_TIME)).size()); + assertEquals(1, subject.map(Collections.singleton(buildDefaultStopTime())).size()); } @Test public void testMap() { - org.opentripplanner.model.StopTime result = subject.map(STOP_TIME); + var result = subject.map(buildDefaultStopTime()); assertEquals(ARRIVAL_TIME, result.getArrivalTime()); assertEquals(DEPARTURE_TIME, result.getDepartureTime()); @@ -132,7 +167,9 @@ public void testMap() { @Test public void testMapWithNulls() { - org.opentripplanner.model.StopTime result = subject.map(new StopTime()); + var st = new StopTime(); + st.setStop(buildStop()); + var result = subject.map(st); assertFalse(result.isArrivalTimeSet()); assertFalse(result.isDepartureTimeSet()); @@ -141,18 +178,56 @@ public void testMapWithNulls() { assertEquals(PickDrop.SCHEDULED, result.getPickupType()); assertNull(result.getRouteShortName()); assertFalse(result.isShapeDistTraveledSet()); - assertNull(result.getStop()); + assertNotNull(result.getStop()); assertNull(result.getStopHeadsign()); assertEquals(0, result.getStopSequence()); assertFalse(result.isTimepointSet()); } - /** Mapping the same object twice, should return the the same instance. */ + /** Mapping the same object twice, should return the same instance. */ @Test public void testMapCache() { - org.opentripplanner.model.StopTime result1 = subject.map(STOP_TIME); - org.opentripplanner.model.StopTime result2 = subject.map(STOP_TIME); - + var st = buildDefaultStopTime(); + var result1 = subject.map(st); + var result2 = subject.map(st); assertSame(result1, result2); } + + @Test + public void testNull() { + var st = buildStopTime(); + Assertions.assertThrows(NullPointerException.class, () -> subject.map(st)); + } + + @Test + public void testFlexLocation() { + var st = buildStopTime(); + var flexLocation = new Location(); + flexLocation.setId(AGENCY_AND_ID); + var polygon = new Polygon(); + polygon.setExteriorRing(ZONE_COORDINATES); + flexLocation.setGeometry(polygon); + st.setStop(flexLocation); + var mapped = subject.map(st); + + assertInstanceOf(AreaStop.class, mapped.getStop()); + var areaStop = (AreaStop) mapped.getStop(); + assertEquals(Polygons.BERLIN, areaStop.getGeometry()); + assertEquals("A:1", areaStop.getId().toString()); + } + + @Test + public void testFlexLocationGroup() { + var st = buildStopTime(); + var locGroup = new LocationGroup(); + locGroup.setName("A location group"); + locGroup.setId(AGENCY_AND_ID); + locGroup.addLocation(buildStop()); + st.setStop(locGroup); + var mapped = subject.map(st); + assertInstanceOf(GroupStop.class, mapped.getStop()); + + var groupStop = (GroupStop) mapped.getStop(); + assertEquals("[RegularStop{A:1 Stop}]", groupStop.getLocations().toString()); + } } diff --git a/src/test/java/org/opentripplanner/mmri/BeneficialChangesTest.java b/src/test/java/org/opentripplanner/mmri/BeneficialChangesTest.java index 5d2bcc7309f..fbef33e50e8 100644 --- a/src/test/java/org/opentripplanner/mmri/BeneficialChangesTest.java +++ b/src/test/java/org/opentripplanner/mmri/BeneficialChangesTest.java @@ -22,6 +22,6 @@ public void test3c1() { validateLeg(leg, 1388531040000L, 1388531100000L, "3c3", "3c2", null); - assertEquals("Stop 3c2 ~ BUS bus 0:04 0:05 ~ Stop 3c3 [$90]", itinerary.toStr()); + assertEquals("Stop 3c2 ~ BUS bus 0:04 0:05 ~ Stop 3c3 [C₁90]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/mmri/ExcludedRoutesTest.java b/src/test/java/org/opentripplanner/mmri/ExcludedRoutesTest.java index 7a47734d294..407c1848529 100644 --- a/src/test/java/org/opentripplanner/mmri/ExcludedRoutesTest.java +++ b/src/test/java/org/opentripplanner/mmri/ExcludedRoutesTest.java @@ -22,6 +22,6 @@ public void test3d1() { validateLeg(leg, 1388530860000L, 1388530980000L, "3d2", "3d1", null); - assertEquals("Stop 3d1 ~ BUS bus 2 0:01 0:03 ~ Stop 3d2 [$150]", itinerary.toStr()); + assertEquals("Stop 3d1 ~ BUS bus 2 0:01 0:03 ~ Stop 3d2 [C₁150]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/mmri/ExcludedTripsTest.java b/src/test/java/org/opentripplanner/mmri/ExcludedTripsTest.java index c0fc04ca62b..e8cf6191c84 100644 --- a/src/test/java/org/opentripplanner/mmri/ExcludedTripsTest.java +++ b/src/test/java/org/opentripplanner/mmri/ExcludedTripsTest.java @@ -22,6 +22,6 @@ public void test3e1() { validateLeg(leg, 1388530980000L, 1388531040000L, "3e2", "3e1", null); - assertEquals("Stop 3e1 ~ BUS bus 0:03 0:04 ~ Stop 3e2 [$90]", itinerary.toStr()); + assertEquals("Stop 3e1 ~ BUS bus 0:03 0:04 ~ Stop 3e2 [C₁90]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/mmri/FirstForbiddenTripToTripTransferTest.java b/src/test/java/org/opentripplanner/mmri/FirstForbiddenTripToTripTransferTest.java index c3ffc9d1956..56c00a76d25 100644 --- a/src/test/java/org/opentripplanner/mmri/FirstForbiddenTripToTripTransferTest.java +++ b/src/test/java/org/opentripplanner/mmri/FirstForbiddenTripToTripTransferTest.java @@ -24,7 +24,7 @@ public void test2e3() { validateLeg(legs[1], 1388531040000L, 1388531100000L, "2e36", "2e34", null); assertEquals( - "Stop 2e31 ~ RAIL train 1 0:01 0:03 ~ Stop 2e34 ~ RAIL train 2 0:04 0:05 ~ Stop 2e36 [$300]", + "Stop 2e31 ~ RAIL train 1 0:01 0:03 ~ Stop 2e34 ~ RAIL train 2 0:04 0:05 ~ Stop 2e36 [C₁300]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/FirstPreferredTripToTripTransferTest.java b/src/test/java/org/opentripplanner/mmri/FirstPreferredTripToTripTransferTest.java index d08fbdddf9c..0f7705e760b 100644 --- a/src/test/java/org/opentripplanner/mmri/FirstPreferredTripToTripTransferTest.java +++ b/src/test/java/org/opentripplanner/mmri/FirstPreferredTripToTripTransferTest.java @@ -24,7 +24,7 @@ public void test2e1() { validateLeg(legs[1], 1388530980000L, 1388531100000L, "2e16", "2e13", null); assertEquals( - "Stop 2e11 ~ RAIL train 1 0:01 0:02 ~ Stop 2e13 ~ RAIL train 2 0:03 0:05 ~ Stop 2e16 [$270]", + "Stop 2e11 ~ RAIL train 1 0:01 0:02 ~ Stop 2e13 ~ RAIL train 2 0:03 0:05 ~ Stop 2e16 [C₁270]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/FirstUnpreferredTransferTest.java b/src/test/java/org/opentripplanner/mmri/FirstUnpreferredTransferTest.java index 039ec7450ed..db938dcaca8 100644 --- a/src/test/java/org/opentripplanner/mmri/FirstUnpreferredTransferTest.java +++ b/src/test/java/org/opentripplanner/mmri/FirstUnpreferredTransferTest.java @@ -24,7 +24,7 @@ public void test3g1() { validateLeg(legs[1], 1388531040000L, 1388531100000L, "3g16", "3g14", null); assertEquals( - "Stop 3g11 ~ RAIL train 1 0:01 0:03 ~ Stop 3g14 ~ RAIL train 2 0:04 0:05 ~ Stop 3g16 [$300]", + "Stop 3g11 ~ RAIL train 1 0:01 0:03 ~ Stop 3g14 ~ RAIL train 2 0:04 0:05 ~ Stop 3g16 [C₁300]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/OptimizationTest.java b/src/test/java/org/opentripplanner/mmri/OptimizationTest.java index 2113a88f06d..1d546663191 100644 --- a/src/test/java/org/opentripplanner/mmri/OptimizationTest.java +++ b/src/test/java/org/opentripplanner/mmri/OptimizationTest.java @@ -22,7 +22,7 @@ public void test2a1() { validateLeg(leg, 1388530860000L, 1388530920000L, "2a2", "2a1", null); - assertEquals("Stop 2a1 ~ BUS short 0:01 0:02 ~ Stop 2a2 [$90]", itinerary.toStr()); + assertEquals("Stop 2a1 ~ BUS short 0:01 0:02 ~ Stop 2a2 [C₁90]", itinerary.toStr()); } @Test @@ -33,6 +33,6 @@ public void test2a2() { validateLeg(leg, 1388531100000L, 1388531160000L, "2a2", "2a1", null); - assertEquals("Stop 2a1 ~ BUS long 0:05 0:06 ~ Stop 2a2 [$90]", itinerary.toStr()); + assertEquals("Stop 2a1 ~ BUS long 0:05 0:06 ~ Stop 2a2 [C₁90]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/mmri/PreferencesTest.java b/src/test/java/org/opentripplanner/mmri/PreferencesTest.java index 0ab71b884af..d3c55097511 100644 --- a/src/test/java/org/opentripplanner/mmri/PreferencesTest.java +++ b/src/test/java/org/opentripplanner/mmri/PreferencesTest.java @@ -26,7 +26,7 @@ public void test2c1() { validateLeg(legs[1], 1388530980000L, 1388531040000L, "2c3", "2c2", null); assertEquals( - "Stop 2c1 ~ RAIL train 1 0:01 0:02 ~ Stop 2c2 ~ RAIL train 2 0:03 0:04 ~ Stop 2c3 [$240]", + "Stop 2c1 ~ RAIL train 1 0:01 0:02 ~ Stop 2c2 ~ RAIL train 2 0:03 0:04 ~ Stop 2c3 [C₁240]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/SecondForbiddenTripToTripTransferTest.java b/src/test/java/org/opentripplanner/mmri/SecondForbiddenTripToTripTransferTest.java index 5bb0d189e4d..335fe4d43d1 100644 --- a/src/test/java/org/opentripplanner/mmri/SecondForbiddenTripToTripTransferTest.java +++ b/src/test/java/org/opentripplanner/mmri/SecondForbiddenTripToTripTransferTest.java @@ -24,7 +24,7 @@ public void test2e4() { validateLeg(legs[1], 1388530980000L, 1388531100000L, "2e46", "2e43", null); assertEquals( - "Stop 2e41 ~ RAIL train 1 0:01 0:02 ~ Stop 2e43 ~ RAIL train 2 0:03 0:05 ~ Stop 2e46 [$300]", + "Stop 2e41 ~ RAIL train 1 0:01 0:02 ~ Stop 2e43 ~ RAIL train 2 0:03 0:05 ~ Stop 2e46 [C₁300]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/SecondPreferredTripToTripTransferTest.java b/src/test/java/org/opentripplanner/mmri/SecondPreferredTripToTripTransferTest.java index c09aeb50612..118dd64472a 100644 --- a/src/test/java/org/opentripplanner/mmri/SecondPreferredTripToTripTransferTest.java +++ b/src/test/java/org/opentripplanner/mmri/SecondPreferredTripToTripTransferTest.java @@ -24,7 +24,7 @@ public void test2e2() { validateLeg(legs[1], 1388531040000L, 1388531100000L, "2e26", "2e24", null); assertEquals( - "Stop 2e21 ~ RAIL train 1 0:01 0:03 ~ Stop 2e24 ~ RAIL train 2 0:04 0:05 ~ Stop 2e26 [$270]", + "Stop 2e21 ~ RAIL train 1 0:01 0:03 ~ Stop 2e24 ~ RAIL train 2 0:04 0:05 ~ Stop 2e26 [C₁270]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/SecondUnpreferredTransferTest.java b/src/test/java/org/opentripplanner/mmri/SecondUnpreferredTransferTest.java index bdd30a65fc0..847bf75e70d 100644 --- a/src/test/java/org/opentripplanner/mmri/SecondUnpreferredTransferTest.java +++ b/src/test/java/org/opentripplanner/mmri/SecondUnpreferredTransferTest.java @@ -24,7 +24,7 @@ public void test3g2() { validateLeg(legs[1], 1388530980000L, 1388531100000L, "3g26", "3g23", null); assertEquals( - "Stop 3g21 ~ RAIL train 1 0:01 0:02 ~ Stop 3g23 ~ RAIL train 2 0:03 0:05 ~ Stop 3g26 [$300]", + "Stop 3g21 ~ RAIL train 1 0:01 0:02 ~ Stop 3g23 ~ RAIL train 2 0:03 0:05 ~ Stop 3g26 [C₁300]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/StopToStopTransfersTest.java b/src/test/java/org/opentripplanner/mmri/StopToStopTransfersTest.java index 7b1a51864d7..6ef244b9d99 100644 --- a/src/test/java/org/opentripplanner/mmri/StopToStopTransfersTest.java +++ b/src/test/java/org/opentripplanner/mmri/StopToStopTransfersTest.java @@ -24,7 +24,7 @@ public void test2d1() { validateLeg(legs[1], 1388530980000L, 1388531040000L, "2d4", "2d3", null); assertEquals( - "Stop 2d1 ~ RAIL train 1 0:01 0:03 ~ Stop 2d3 ~ RAIL train 2 0:03 0:04 ~ Stop 2d4 [$210]", + "Stop 2d1 ~ RAIL train 1 0:01 0:03 ~ Stop 2d3 ~ RAIL train 2 0:03 0:04 ~ Stop 2d4 [C₁210]", itinerary.toStr() ); } diff --git a/src/test/java/org/opentripplanner/mmri/TimeTest.java b/src/test/java/org/opentripplanner/mmri/TimeTest.java index 08c9462ce18..77123d3e656 100644 --- a/src/test/java/org/opentripplanner/mmri/TimeTest.java +++ b/src/test/java/org/opentripplanner/mmri/TimeTest.java @@ -23,7 +23,7 @@ public void test1g1() { validateLeg(leg, 1388530980000L, 1388531040000L, "1g2", "1g1", null); - assertEquals("Stop 1g1 ~ BUS bus 0:03 0:04 ~ Stop 1g2 [$90]", itinerary.toStr()); + assertEquals("Stop 1g1 ~ BUS bus 0:03 0:04 ~ Stop 1g2 [C₁90]", itinerary.toStr()); } @Test @@ -34,7 +34,7 @@ public void test1g2() { validateLeg(leg, 1388530860000L, 1388530920000L, "1g2", "1g1", null); - assertEquals("Stop 1g1 ~ BUS bus 0:01 0:02 ~ Stop 1g2 [$90]", itinerary.toStr()); + assertEquals("Stop 1g1 ~ BUS bus 0:01 0:02 ~ Stop 1g2 [C₁90]", itinerary.toStr()); } @Test @@ -69,7 +69,7 @@ public void test1g5() { validateLeg(leg, 1388703780000L, 1388703840000L, "1g2", "1g1", null); - assertEquals("Stop 1g1 ~ BUS bus 0:03 0:04 ~ Stop 1g2 [$90]", itinerary.toStr()); + assertEquals("Stop 1g1 ~ BUS bus 0:03 0:04 ~ Stop 1g2 [C₁90]", itinerary.toStr()); } @Test @@ -78,8 +78,8 @@ public void test1g6() { Leg leg = itinerary.getLegs().toArray(new Leg[1])[0]; - validateLeg(leg, 1388703780000L, 1388703840000L, "1g2", "1g1", null); + validateLeg(leg, 1388703660000L, 1388703720000L, "1g2", "1g1", null); - assertEquals("Stop 1g1 ~ BUS bus 0:03 0:04 ~ Stop 1g2 [$90]", itinerary.toStr()); + assertEquals("Stop 1g1 ~ BUS bus 0:01 0:02 ~ Stop 1g2 [C₁90]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/mmri/UnplannedChangesTest.java b/src/test/java/org/opentripplanner/mmri/UnplannedChangesTest.java index 78de0af7313..753edd58fa6 100644 --- a/src/test/java/org/opentripplanner/mmri/UnplannedChangesTest.java +++ b/src/test/java/org/opentripplanner/mmri/UnplannedChangesTest.java @@ -22,7 +22,7 @@ public void test3b1() { validateLeg(leg, 1388531460000L, 1388531520000L, "3b2", "3b1", null); - assertEquals("Stop 3b1 ~ BUS bus 0:11 0:12 ~ Stop 3b2 [$90]", itinerary.toStr()); + assertEquals("Stop 3b1 ~ BUS bus 0:11 0:12 ~ Stop 3b2 [C₁90]", itinerary.toStr()); } @Test @@ -33,6 +33,6 @@ public void test3b2() { validateLeg(leg, 1388531460000L, 1388531520000L, "3b2", "3b1", null); - assertEquals("Stop 3b1 ~ BUS bus 0:11 0:12 ~ Stop 3b2 [$90]", itinerary.toStr()); + assertEquals("Stop 3b1 ~ BUS bus 0:11 0:12 ~ Stop 3b2 [C₁90]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/mmri/WheelchairTest.java b/src/test/java/org/opentripplanner/mmri/WheelchairTest.java index 5a3754e491b..c63235b067e 100644 --- a/src/test/java/org/opentripplanner/mmri/WheelchairTest.java +++ b/src/test/java/org/opentripplanner/mmri/WheelchairTest.java @@ -19,6 +19,6 @@ public void test2b1() { validateLeg(itinerary.firstLeg(), 1388530980000L, 1388531040000L, "2b2", "2b1", null); - assertEquals("Stop 2b1 ~ BUS attr 0:03 0:04 ~ Stop 2b2 [$90]", itinerary.toStr()); + assertEquals("Stop 2b1 ~ BUS attr 0:03 0:04 ~ Stop 2b2 [C₁90]", itinerary.toStr()); } } diff --git a/src/test/java/org/opentripplanner/model/plan/ItineraryTest.java b/src/test/java/org/opentripplanner/model/plan/ItineraryTest.java index d65f2057a2e..df67e3c2f44 100644 --- a/src/test/java/org/opentripplanner/model/plan/ItineraryTest.java +++ b/src/test/java/org/opentripplanner/model/plan/ItineraryTest.java @@ -39,7 +39,7 @@ public void testDerivedFieldsWithWalkingOnly() { assertEquals(420.0d, result.firstLeg().getDistanceMeters(), 1E-3); assertSameLocation(B, result.lastLeg().getTo()); - assertEquals("A ~ Walk 5m ~ B [$600]", result.toStr()); + assertEquals("A ~ Walk 5m ~ B [C₁600]", result.toStr()); } @Test @@ -63,7 +63,7 @@ public void testDerivedFieldsWithBusAllTheWay() { assertEquals(TransitModelForTest.id("55"), result.firstLeg().getTrip().getId()); assertEquals(7500, result.firstLeg().getDistanceMeters(), 1E-3); - assertEquals("A ~ BUS 55 11:00 11:10 ~ B [$720]", result.toStr()); + assertEquals("A ~ BUS 55 11:00 11:10 ~ B [C₁720]", result.toStr()); } @Test @@ -87,7 +87,7 @@ public void testDerivedFieldsWithTrainAllTheWay() { assertEquals(TransitModelForTest.id("20"), result.firstLeg().getTrip().getId()); assertEquals(15_000, result.firstLeg().getDistanceMeters(), 1E-3); - assertEquals("A ~ RAIL R2 11:05 11:15 ~ B [$720]", result.toStr()); + assertEquals("A ~ RAIL R2 11:05 11:15 ~ B [C₁720]", result.toStr()); } @Test @@ -129,7 +129,7 @@ public void testDerivedFieldsWithBusAndWalkingAccessAndEgress() { assertEquals(1464, result.getGeneralizedCost()); assertFalse(result.isWalkOnly()); - assertEquals("A ~ Walk 2m ~ B ~ BUS 1 11:10 11:20 ~ C ~ Walk 3m ~ D [$1464]", result.toStr()); + assertEquals("A ~ Walk 2m ~ B ~ BUS 1 11:10 11:20 ~ C ~ Walk 3m ~ D [C₁1_464]", result.toStr()); } @Test @@ -155,7 +155,7 @@ public void walkBusBusWalkTrainWalk() { assertEquals( "A ~ Walk 2m ~ B ~ BUS 55 11:04 11:14 ~ C ~ BUS 21 11:16 11:20 ~ D " + - "~ Walk 3m ~ E ~ RAIL R2 11:30 11:50 ~ F ~ Walk 1m ~ G [$3648]", + "~ Walk 3m ~ E ~ RAIL R2 11:30 11:50 ~ F ~ Walk 1m ~ G [C₁3_648]", result.toStr() ); } diff --git a/src/test/java/org/opentripplanner/model/plan/PlanTestConstants.java b/src/test/java/org/opentripplanner/model/plan/PlanTestConstants.java index 7be75ed1760..edb967b5b16 100644 --- a/src/test/java/org/opentripplanner/model/plan/PlanTestConstants.java +++ b/src/test/java/org/opentripplanner/model/plan/PlanTestConstants.java @@ -22,6 +22,7 @@ public interface PlanTestConstants { int D1m = DurationUtils.durationInSeconds("1m"); int D2m = DurationUtils.durationInSeconds("2m"); int D3m = DurationUtils.durationInSeconds("3m"); + int D4m = DurationUtils.durationInSeconds("4m"); int D5m = DurationUtils.durationInSeconds("5m"); int D10m = DurationUtils.durationInSeconds("10m"); int D12m = DurationUtils.durationInSeconds("12m"); diff --git a/src/test/java/org/opentripplanner/model/plan/PagingSearchWindowAdjusterTest.java b/src/test/java/org/opentripplanner/model/plan/paging/PagingSearchWindowAdjusterTest.java similarity index 98% rename from src/test/java/org/opentripplanner/model/plan/PagingSearchWindowAdjusterTest.java rename to src/test/java/org/opentripplanner/model/plan/paging/PagingSearchWindowAdjusterTest.java index bf4e311f83c..22dcd49e63f 100644 --- a/src/test/java/org/opentripplanner/model/plan/PagingSearchWindowAdjusterTest.java +++ b/src/test/java/org/opentripplanner/model/plan/paging/PagingSearchWindowAdjusterTest.java @@ -1,4 +1,4 @@ -package org.opentripplanner.model.plan; +package org.opentripplanner.model.plan.paging; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.time.DurationUtils.duration; diff --git a/src/test/java/org/opentripplanner/model/plan/paging/cursor/DeduplicationPageCutTest.java b/src/test/java/org/opentripplanner/model/plan/paging/cursor/DeduplicationPageCutTest.java new file mode 100644 index 00000000000..f2b58d6e9c5 --- /dev/null +++ b/src/test/java/org/opentripplanner/model/plan/paging/cursor/DeduplicationPageCutTest.java @@ -0,0 +1,30 @@ +package org.opentripplanner.model.plan.paging.cursor; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Instant; +import org.junit.jupiter.api.Test; + +class DeduplicationPageCutTest { + + public static final Instant DEPARTURE_TIME = Instant.ofEpochSecond(1_000_000); + public static final Instant ARRIVAL_TIME = Instant.ofEpochSecond(2_000_000); + public static final int GENERALIZED_COST = 1700; + public static final int NUM_OF_TRANSFERS = 2; + public static final boolean ON_STREET = false; + + @Test + void testToString() { + assertEquals( + "[1970-01-12T13:46:40Z, 1970-01-24T03:33:20Z, $1700, Tx2, transit]", + new DeduplicationPageCut( + DEPARTURE_TIME, + ARRIVAL_TIME, + GENERALIZED_COST, + NUM_OF_TRANSFERS, + ON_STREET + ) + .toString() + ); + } +} diff --git a/src/test/java/org/opentripplanner/model/plan/pagecursor/PageCursorFactoryTest.java b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorFactoryTest.java similarity index 79% rename from src/test/java/org/opentripplanner/model/plan/pagecursor/PageCursorFactoryTest.java rename to src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorFactoryTest.java index 5e6951ea7cf..7bf54d05bc2 100644 --- a/src/test/java/org/opentripplanner/model/plan/pagecursor/PageCursorFactoryTest.java +++ b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorFactoryTest.java @@ -1,17 +1,18 @@ -package org.opentripplanner.model.plan.pagecursor; +package org.opentripplanner.model.plan.paging.cursor; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.model.plan.SortOrder.STREET_AND_ARRIVAL_TIME; import static org.opentripplanner.model.plan.SortOrder.STREET_AND_DEPARTURE_TIME; import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; -import static org.opentripplanner.model.plan.pagecursor.PageType.NEXT_PAGE; -import static org.opentripplanner.model.plan.pagecursor.PageType.PREVIOUS_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.NEXT_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.PREVIOUS_PAGE; import java.time.Duration; import java.time.Instant; import org.junit.jupiter.api.Test; import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.ItinerarySortKey; import org.opentripplanner.model.plan.PlanTestConstants; @SuppressWarnings("ConstantConditions") @@ -49,8 +50,7 @@ public void sortArrivalAscendingCropSearchWindow() { .withRemovedItineraries( new TestPageCursorInput( newItinerary(A).bus(55, timeAsSeconds(T12_00), timeAsSeconds(T12_10), B).build(), - newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_30), B).build(), - PagingDeduplicationSection.HEAD + newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_30), B).build() ) ); @@ -58,7 +58,7 @@ public void sortArrivalAscendingCropSearchWindow() { assertPageCursor(nextPage, T12_30, null, D90M, NEXT_PAGE, true); var prevPage = factory.previousPageCursor(); - assertPageCursor(prevPage, T10_30, T12_10, D90M, PREVIOUS_PAGE, true); + assertPageCursor(prevPage, T10_30, null, D90M, PREVIOUS_PAGE, true); } @Test @@ -80,8 +80,7 @@ public void sortArrivalAscendingCropSearchWindowPreviousPage() { .withRemovedItineraries( new TestPageCursorInput( newItinerary(A).bus(55, timeAsSeconds(T12_00), timeAsSeconds(T12_10), B).build(), - newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_30), B).build(), - PagingDeduplicationSection.TAIL + newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_30), B).build() ) ); @@ -89,7 +88,7 @@ public void sortArrivalAscendingCropSearchWindowPreviousPage() { assertPageCursor(nextPage, T13_00, null, D90M, NEXT_PAGE, true); var prevPage = factory.previousPageCursor(); - assertPageCursor(prevPage, T11_01, T13_30, D90M, PREVIOUS_PAGE, true); + assertPageCursor(prevPage, T11_01, null, D90M, PREVIOUS_PAGE, true); } @Test @@ -111,8 +110,7 @@ public void sortDepartureDescendingCropSearchWindow() { .withRemovedItineraries( new TestPageCursorInput( newItinerary(A).bus(55, timeAsSeconds(T12_00), timeAsSeconds(T12_30), B).build(), - newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_00), B).build(), - PagingDeduplicationSection.HEAD + newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_00), B).build() ) ); @@ -120,7 +118,7 @@ public void sortDepartureDescendingCropSearchWindow() { assertPageCursor(nextPage, T13_00, null, D90M, NEXT_PAGE, true); var prevPage = factory.previousPageCursor(); - assertPageCursor(prevPage, T11_01, T13_00, D90M, PREVIOUS_PAGE, true); + assertPageCursor(prevPage, T11_01, T13_30, D90M, PREVIOUS_PAGE, true); } @Test @@ -142,8 +140,7 @@ public void sortDepartureDescendingCropSearchWindowNextPage() { .withRemovedItineraries( new TestPageCursorInput( newItinerary(A).bus(55, timeAsSeconds(T12_00), timeAsSeconds(T12_30), B).build(), - newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_00), B).build(), - PagingDeduplicationSection.TAIL + newItinerary(A).bus(65, timeAsSeconds(T12_30), timeAsSeconds(T13_00), B).build() ) ); @@ -170,11 +167,11 @@ private void assertPageCursor( PageType expPageType, Boolean hasDedupeParams ) { - assertEquals(expEdt, pageCursor.earliestDepartureTime); - assertEquals(expLat, pageCursor.latestArrivalTime); - assertEquals(expSearchWindow, pageCursor.searchWindow); - assertEquals(expPageType, pageCursor.type); - assertEquals(hasDedupeParams, pageCursor.itineraryPageCut != null); + assertEquals(expEdt, pageCursor.earliestDepartureTime()); + assertEquals(expLat, pageCursor.latestArrivalTime()); + assertEquals(expSearchWindow, pageCursor.searchWindow()); + assertEquals(expPageType, pageCursor.type()); + assertEquals(hasDedupeParams, pageCursor.itineraryPageCut() != null); } private record TestPageCursorInput( @@ -182,30 +179,16 @@ private record TestPageCursorInput( Instant earliestRemovedDeparture, Instant latestRemovedDeparture, Instant latestRemovedArrival, - Instant firstRemovedArrivalTime, - boolean firstRemovedIsOnStreetAllTheWay, - int firstRemovedGeneralizedCost, - int firstRemovedNumOfTransfers, - Instant firstRemovedDepartureTime, - PagingDeduplicationSection deduplicationSection + ItinerarySortKey pageCut ) implements PageCursorInput { - public TestPageCursorInput( - Itinerary keptItinerary, - Itinerary removedItinerary, - PagingDeduplicationSection deduplicationSection - ) { + public TestPageCursorInput(Itinerary keptItinerary, Itinerary removedItinerary) { this( keptItinerary.endTimeAsInstant(), removedItinerary.startTimeAsInstant(), removedItinerary.startTimeAsInstant(), removedItinerary.endTimeAsInstant(), - removedItinerary.endTimeAsInstant(), - removedItinerary.isOnStreetAllTheWay(), - removedItinerary.getGeneralizedCost(), - removedItinerary.getNumberOfTransfers(), - removedItinerary.startTimeAsInstant(), - deduplicationSection + removedItinerary ); } } diff --git a/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorSerializerTest.java b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorSerializerTest.java new file mode 100644 index 00000000000..20c0230f309 --- /dev/null +++ b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorSerializerTest.java @@ -0,0 +1,77 @@ +package org.opentripplanner.model.plan.paging.cursor; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.opentripplanner.model.plan.SortOrder.STREET_AND_DEPARTURE_TIME; +import static org.opentripplanner.model.plan.paging.cursor.PageType.PREVIOUS_PAGE; + +import java.time.Duration; +import java.time.Instant; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.time.DurationUtils; +import org.opentripplanner.model.plan.ItinerarySortKey; + +class PageCursorSerializerTest { + + private static final Instant EDT = Instant.parse("2023-12-31T23:59:59Z"); + private static final Instant LAT = Instant.parse("2024-01-15T00:00:01Z"); + private static final Duration SW = DurationUtils.duration("5h"); + private static final Instant DT = Instant.parse("2024-01-10T10:00:00Z"); + private static final Instant AT = Instant.parse("2024-01-10T12:00:00Z"); + + public static final String TOKEN_V1 = + "MXxQUkVWSU9VU19QQUdFfDIwMjMtMTItMzFUMjM6NTk6NTlafDIwMjQtMDEtMTVUMDA6MDA6MDFafDVofFNUUkVFVF" + + "9BTkRfREVQQVJUVVJFX1RJTUV8dHJ1ZXwyMDI0LTAxLTEwVDEwOjAwOjAwWnwyMDI0LTAxLTEwVDEyOjAwOjAwWnwz" + + "fDEyMDB8"; + public static final String TOKEN_V1_W_NULLS = + "MXxQUkVWSU9VU19QQUdFfDIwMjMtMTItMzFUMjM6NTk6NTlafHw1aHxTVFJFRVRfQU5EX0RFUEFSVFVSRV9USU1FfH" + + "x8fHx8"; + + private static final ItinerarySortKey CUT = new DeduplicationPageCut(DT, AT, 1200, 3, true); + + private static final PageCursor PAGE_CURSOR_V1 = new PageCursor( + PREVIOUS_PAGE, + STREET_AND_DEPARTURE_TIME, + EDT, + LAT, + SW, + CUT + ); + + private final PageCursor pageCursorV1withNulls = new PageCursor( + PREVIOUS_PAGE, + STREET_AND_DEPARTURE_TIME, + EDT, + null, + SW, + null + ); + + @Test + void encode() { + assertEquals(TOKEN_V1, PageCursorSerializer.encode(PAGE_CURSOR_V1)); + assertEquals(TOKEN_V1_W_NULLS, PageCursorSerializer.encode(pageCursorV1withNulls)); + } + + @Test + void decodeTokenV1() { + PageCursor tokenV1 = PageCursorSerializer.decode(TOKEN_V1); + assertEquals(PREVIOUS_PAGE, tokenV1.type()); + assertEquals(STREET_AND_DEPARTURE_TIME, tokenV1.originalSortOrder()); + assertEquals(EDT, tokenV1.earliestDepartureTime()); + assertEquals(LAT, tokenV1.latestArrivalTime()); + assertEquals(SW, tokenV1.searchWindow()); + assertEquals(CUT, tokenV1.itineraryPageCut()); + } + + @Test + void decodeTokenV1_W_NULLS() { + PageCursor tokenV1 = PageCursorSerializer.decode(TOKEN_V1_W_NULLS); + assertEquals(PREVIOUS_PAGE, tokenV1.type()); + assertEquals(STREET_AND_DEPARTURE_TIME, tokenV1.originalSortOrder()); + assertEquals(EDT, tokenV1.earliestDepartureTime()); + assertNull(tokenV1.latestArrivalTime()); + assertEquals(SW, tokenV1.searchWindow()); + assertNull(tokenV1.itineraryPageCut()); + } +} diff --git a/src/test/java/org/opentripplanner/model/plan/pagecursor/PageCursorTest.java b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorTest.java similarity index 52% rename from src/test/java/org/opentripplanner/model/plan/pagecursor/PageCursorTest.java rename to src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorTest.java index 1b6b452f2a9..10b59007c17 100644 --- a/src/test/java/org/opentripplanner/model/plan/pagecursor/PageCursorTest.java +++ b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageCursorTest.java @@ -1,22 +1,43 @@ -package org.opentripplanner.model.plan.pagecursor; +package org.opentripplanner.model.plan.paging.cursor; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.opentripplanner.framework.collection.ListSection.HEAD; +import static org.opentripplanner.framework.collection.ListSection.TAIL; import static org.opentripplanner.model.plan.SortOrder.STREET_AND_ARRIVAL_TIME; import static org.opentripplanner.model.plan.SortOrder.STREET_AND_DEPARTURE_TIME; -import static org.opentripplanner.model.plan.pagecursor.PageType.NEXT_PAGE; -import static org.opentripplanner.model.plan.pagecursor.PageType.PREVIOUS_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.NEXT_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.PREVIOUS_PAGE; import java.time.Duration; import java.time.Instant; import java.time.ZoneId; +import java.util.List; import java.util.TimeZone; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner._support.time.ZoneIds; +import org.opentripplanner.framework.collection.ListSection; +import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.Place; +import org.opentripplanner.model.plan.PlanTestConstants; +import org.opentripplanner.model.plan.SortOrder; +import org.opentripplanner.model.plan.TestItineraryBuilder; +import org.opentripplanner.transit.model._data.TransitModelForTest; -public class PageCursorTest { +class PageCursorTest implements PlanTestConstants { + + public static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + public static final Place A = Place.forStop( + TEST_MODEL.stop("A").withCoordinate(5.0, 8.0).build() + ); + public static final Place B = Place.forStop( + TEST_MODEL.stop("B").withCoordinate(6.0, 8.5).build() + ); private static final ZoneId ZONE_ID = ZoneIds.GMT; private static final String EDT_STR = "2021-01-31T12:20:00Z"; @@ -24,6 +45,11 @@ public class PageCursorTest { private static final Instant EDT = Instant.parse(EDT_STR); private static final Instant LAT = Instant.parse(LAT_STR); private static final Duration SEARCH_WINDOW = Duration.parse("PT2h"); + private static final Itinerary PAGE_CUT = TestItineraryBuilder + .newItinerary(A, 0) + .walk(20, Place.forStop(TEST_MODEL.stop("1:stop", 1d, 1d).build())) + .bus(23, 0, 50, B) + .build(); private TimeZone originalTimeZone; private PageCursor subjectDepartAfter; @@ -35,9 +61,9 @@ public void setup() { TimeZone.setDefault(TimeZone.getTimeZone(ZONE_ID)); subjectDepartAfter = - new PageCursor(NEXT_PAGE, STREET_AND_ARRIVAL_TIME, EDT, null, SEARCH_WINDOW); + new PageCursor(NEXT_PAGE, STREET_AND_ARRIVAL_TIME, EDT, null, SEARCH_WINDOW, null); subjectArriveBy = - new PageCursor(PREVIOUS_PAGE, STREET_AND_DEPARTURE_TIME, EDT, LAT, SEARCH_WINDOW); + new PageCursor(PREVIOUS_PAGE, STREET_AND_DEPARTURE_TIME, EDT, LAT, SEARCH_WINDOW, PAGE_CUT); } @AfterEach @@ -60,11 +86,30 @@ public void testToString() { EDT_STR + ", lat: " + LAT_STR + - ", searchWindow: 2h}", + ", searchWindow: 2h, " + + "itineraryPageCut: [2020-02-02T00:00:00Z, 2020-02-02T00:00:50Z, $194, Tx0, transit]}", subjectArriveBy.toString() ); } + static List cropItinerariesAtTestCase() { + return List.of( + Arguments.of(NEXT_PAGE, STREET_AND_ARRIVAL_TIME, TAIL), + Arguments.of(NEXT_PAGE, STREET_AND_DEPARTURE_TIME, HEAD), + Arguments.of(PREVIOUS_PAGE, STREET_AND_ARRIVAL_TIME, HEAD), + Arguments.of(PREVIOUS_PAGE, STREET_AND_DEPARTURE_TIME, TAIL) + ); + } + + @ParameterizedTest + @MethodSource("cropItinerariesAtTestCase") + public void cropItinerariesAt(PageType page, SortOrder order, ListSection expSection) { + assertEquals( + expSection, + new PageCursor(page, order, EDT, null, SEARCH_WINDOW, null).cropItinerariesAt() + ); + } + @Test @SuppressWarnings("ConstantConditions") public void encodeAndDecode() { diff --git a/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageTypeTest.java b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageTypeTest.java new file mode 100644 index 00000000000..0e84d0b2e0a --- /dev/null +++ b/src/test/java/org/opentripplanner/model/plan/paging/cursor/PageTypeTest.java @@ -0,0 +1,15 @@ +package org.opentripplanner.model.plan.paging.cursor; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class PageTypeTest { + + @Test + void isNext() { + assertTrue(PageType.NEXT_PAGE.isNext()); + assertFalse(PageType.PREVIOUS_PAGE.isNext()); + } +} diff --git a/src/test/java/org/opentripplanner/model/routing/TripSearchMetadataTest.java b/src/test/java/org/opentripplanner/model/routing/TripSearchMetadataTest.java index 4cfd21ad1e6..fce79cd2d4c 100644 --- a/src/test/java/org/opentripplanner/model/routing/TripSearchMetadataTest.java +++ b/src/test/java/org/opentripplanner/model/routing/TripSearchMetadataTest.java @@ -9,82 +9,81 @@ public class TripSearchMetadataTest { - public static final Duration THIRTY_MINUTES = Duration.ofMinutes(30); - public static final int SEARCH_WINDOW_USED = (int) THIRTY_MINUTES.toSeconds(); + private static final Duration SEARCH_WINDOW_USED = Duration.ofMinutes(30); @Test - public void createMetadataForArriveWithSearchWindowOnly() { + void createMetadataForArriveWithSearchWindowOnly() { TripSearchMetadata subject = TripSearchMetadata.createForArriveBy( Instant.parse("2020-05-17T10:20:00Z"), SEARCH_WINDOW_USED, null ); - assertEquals(THIRTY_MINUTES, subject.searchWindowUsed); + assertEquals(SEARCH_WINDOW_USED, subject.searchWindowUsed); assertEquals("2020-05-17T09:50:00Z", subject.prevDateTime.toString()); assertEquals("2020-05-17T10:50:00Z", subject.nextDateTime.toString()); } @Test - public void createMetadataForArriveByWithTimeGiven() { + void createMetadataForArriveByWithTimeGiven() { TripSearchMetadata subject; - // New arrival-time with seconds, 10:05:15, should be rounded up to 10:06:00 + // New arrival-time with seconds, 10:35:01, should be rounded up to 10:36:00 subject = TripSearchMetadata.createForArriveBy( Instant.parse("2020-05-17T10:20:00Z"), SEARCH_WINDOW_USED, - Instant.parse("2020-05-17T10:05:15Z") + Instant.parse("2020-05-17T10:35:00Z") ); - assertEquals(THIRTY_MINUTES, subject.searchWindowUsed); - assertEquals("2020-05-17T10:06:00Z", subject.prevDateTime.toString()); + assertEquals(SEARCH_WINDOW_USED, subject.searchWindowUsed); + assertEquals("2020-05-17T10:04:00Z", subject.prevDateTime.toString()); assertEquals("2020-05-17T10:50:00Z", subject.nextDateTime.toString()); - // New arrival-time without seconds, 10:05:00, should stay the same: 10:05:00 + // New arrival-time without seconds, 10:36:00, should stay the same: 10:36:00 subject = TripSearchMetadata.createForArriveBy( Instant.parse("2020-05-17T11:20:00Z"), SEARCH_WINDOW_USED, - Instant.parse("2020-05-17T11:05:00Z") + Instant.parse("2020-05-17T11:35:59Z") ); - assertEquals("2020-05-17T11:05:00Z", subject.prevDateTime.toString()); + assertEquals("2020-05-17T11:04:00Z", subject.prevDateTime.toString()); assertEquals("2020-05-17T11:50:00Z", subject.nextDateTime.toString()); } @Test - public void createMetadataForDepartAfterWithSearchWindowOnly() { + void createMetadataForDepartAfterWithSearchWindowOnly() { TripSearchMetadata subject = TripSearchMetadata.createForDepartAfter( Instant.parse("2020-05-17T10:20:00Z"), SEARCH_WINDOW_USED, null ); - assertEquals(THIRTY_MINUTES, subject.searchWindowUsed); + assertEquals(SEARCH_WINDOW_USED, subject.searchWindowUsed); assertEquals("2020-05-17T09:50:00Z", subject.prevDateTime.toString()); assertEquals("2020-05-17T10:50:00Z", subject.nextDateTime.toString()); } @Test - public void createMetadataForDepartAfterWithTimeGiven() { + void createMetadataForDepartAfterWithTimeGiven() { TripSearchMetadata subject; - // New departure-time with seconds, 10:35:15, should be rounded down to 10:35:00 + // New departure-time, 10:35:00, should be rounded up to 10:36:00 subject = TripSearchMetadata.createForDepartAfter( Instant.parse("2020-05-17T10:20:00Z"), SEARCH_WINDOW_USED, - Instant.parse("2020-05-17T10:35:15Z") + Instant.parse("2020-05-17T10:35:00Z") ); - assertEquals(THIRTY_MINUTES, subject.searchWindowUsed); + assertEquals(SEARCH_WINDOW_USED, subject.searchWindowUsed); assertEquals("2020-05-17T09:50:00Z", subject.prevDateTime.toString()); - assertEquals("2020-05-17T10:35:00Z", subject.nextDateTime.toString()); + assertEquals("2020-05-17T10:36:00Z", subject.nextDateTime.toString()); - // New departure-time without seconds, 11:35:00, should stay the same: 11:35:00 + // New departure-time, 11:35:59, should be rounded up to 11:36:00 subject = TripSearchMetadata.createForDepartAfter( Instant.parse("2020-05-17T11:20:00Z"), SEARCH_WINDOW_USED, - Instant.parse("2020-05-17T11:35:00Z") + Instant.parse("2020-05-17T11:35:59Z") ); assertEquals("2020-05-17T10:50:00Z", subject.prevDateTime.toString()); - assertEquals("2020-05-17T11:35:00Z", subject.nextDateTime.toString()); + assertEquals("2020-05-17T11:36:00Z", subject.nextDateTime.toString()); } } diff --git a/src/test/java/org/opentripplanner/raptor/_data/api/PathUtils.java b/src/test/java/org/opentripplanner/raptor/_data/api/PathUtils.java index 1489589561b..9da872adbae 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/api/PathUtils.java +++ b/src/test/java/org/opentripplanner/raptor/_data/api/PathUtils.java @@ -29,7 +29,11 @@ public static String pathsToString(Collection> paths) { } public static String pathsToStringDetailed(RaptorResponse response) { - return pathsToString(response.paths(), p -> p.toStringDetailed(TRANSLATOR::stopIndexToName)); + return pathsToStringDetailed(response.paths()); + } + + public static String pathsToStringDetailed(Collection> paths) { + return pathsToString(paths, p -> p.toStringDetailed(TRANSLATOR::stopIndexToName)); } public static String join(String... paths) { @@ -37,16 +41,14 @@ public static String join(String... paths) { } public static String withoutCost(String path) { - return path.replaceAll(" \\$\\d+", ""); + return path.replaceAll(" C₁[\\d_]+", ""); } public static String[] withoutCost(String... paths) { return Stream.of(paths).map(path -> withoutCost(path)).toList().toArray(new String[0]); } - /* private methods */ - - private static String pathsToString( + public static String pathsToString( Collection> paths, Function, String> mapToStr ) { diff --git a/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilder.java b/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilder.java index da24a375714..19d9904cd5b 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilder.java +++ b/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilder.java @@ -8,6 +8,7 @@ import org.opentripplanner.raptor._data.transit.TestTransfer; import org.opentripplanner.raptor._data.transit.TestTripPattern; import org.opentripplanner.raptor._data.transit.TestTripSchedule; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.path.RaptorPath; import org.opentripplanner.raptor.api.path.RaptorStopNameResolver; import org.opentripplanner.raptor.path.PathBuilder; @@ -31,6 +32,7 @@ public class TestPathBuilder implements RaptorTestConstants { private final RaptorSlackProvider slackProvider; private PathBuilder builder; private int startTime; + private int c2 = RaptorConstants.NOT_SET; public TestPathBuilder( RaptorSlackProvider slackProvider, @@ -47,6 +49,12 @@ public TestPathBuilder(@Nullable RaptorCostCalculator costCalc this(new DefaultSlackProvider(TRANSFER_SLACK, BOARD_SLACK, ALIGHT_SLACK), costCalculator); } + /** Assign c2 value for path. TODO: Add c2 value for each leg. */ + public TestPathBuilder c2(int c2) { + this.c2 = c2; + return this; + } + /** * Create access starting at the fixed given {@code starting}. Opening hours is used to enforce * the access start time and prevent time-shifting it. @@ -116,6 +124,7 @@ public RaptorPath egress(int duration) { public RaptorPath egress(TestAccessEgress transfer) { builder.egress(transfer); + builder.c2(c2); return builder.build(); } diff --git a/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilderTestRaptor.java b/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilderTestRaptor.java index 3ce1e85cb41..bc11f32e4cc 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilderTestRaptor.java +++ b/src/test/java/org/opentripplanner/raptor/_data/api/TestPathBuilderTestRaptor.java @@ -4,7 +4,7 @@ import static org.opentripplanner.framework.time.DurationUtils.durationInSeconds; import static org.opentripplanner.framework.time.TimeUtils.time; import static org.opentripplanner.model.transfer.TransferConstraint.REGULAR_TRANSFER; -import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.COST_CALCULATOR; +import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.C1_CALCULATOR; import static org.opentripplanner.raptor._data.transit.TestAccessEgress.walk; import org.junit.jupiter.api.Assertions; @@ -17,7 +17,7 @@ */ public class TestPathBuilderTestRaptor implements RaptorTestConstants { - private final TestPathBuilder subject = new TestPathBuilder(COST_CALCULATOR); + private final TestPathBuilder subject = new TestPathBuilder(C1_CALCULATOR); @Test public void testSimplePathWithOneTransit() { @@ -29,7 +29,7 @@ public void testSimplePathWithOneTransit() { .egress(D2m); var transitLeg = path.accessLeg().nextLeg().asTransitLeg(); - int boardCost = COST_CALCULATOR.boardingCost( + int boardCost = C1_CALCULATOR.boardingCost( true, path.accessLeg().toTime(), STOP_A, @@ -38,7 +38,7 @@ public void testSimplePathWithOneTransit() { REGULAR_TRANSFER ); - int transitCost = COST_CALCULATOR.transitArrivalCost( + int transitCost = C1_CALCULATOR.transitArrivalCost( boardCost, ALIGHT_SLACK, transitDuration, @@ -46,14 +46,14 @@ public void testSimplePathWithOneTransit() { STOP_B ); - int accessEgressCost = COST_CALCULATOR.costEgress(walk(STOP_B, D2m + D1m)); + int accessEgressCost = C1_CALCULATOR.costEgress(walk(STOP_B, D2m + D1m)); assertEquals(accessEgressCost + transitCost, path.c1()); assertEquals( - "Walk 1m 10:00:15 10:01:15 $120 ~ A 45s " + - "~ BUS L1 10:02 10:07 5m $438 ~ B 15s " + - "~ Walk 2m 10:07:15 10:09:15 $210 " + - "[10:00:15 10:09:15 9m 0tx $768]", + "Walk 1m 10:00:15 10:01:15 C₁120 ~ A 45s " + + "~ BUS L1 10:02 10:07 5m C₁438 ~ B 15s " + + "~ Walk 2m 10:07:15 10:09:15 C₁210 " + + "[10:00:15 10:09:15 9m Tₓ0 C₁768]", path.toStringDetailed(this::stopIndexToName) ); } @@ -61,6 +61,7 @@ public void testSimplePathWithOneTransit() { @Test public void testBasicPath() { var path = subject + .c2(7) .access(BasicPathTestCase.ACCESS_START, STOP_A, BasicPathTestCase.ACCESS_DURATION) .bus( BasicPathTestCase.LINE_11, @@ -68,7 +69,7 @@ public void testBasicPath() { BasicPathTestCase.L11_DURATION, STOP_B ) - .walk(BasicPathTestCase.TX_DURATION, STOP_C, BasicPathTestCase.TX_COST) + .walk(BasicPathTestCase.TX_DURATION, STOP_C, BasicPathTestCase.TX_C1) .bus( BasicPathTestCase.LINE_21, BasicPathTestCase.L21_START, @@ -82,6 +83,7 @@ public void testBasicPath() { STOP_E ) .egress(BasicPathTestCase.EGRESS_DURATION); + Assertions.assertEquals( BasicPathTestCase.BASIC_PATH_AS_STRING, path.toString(this::stopIndexToName) @@ -90,6 +92,6 @@ public void testBasicPath() { BasicPathTestCase.BASIC_PATH_AS_DETAILED_STRING, path.toStringDetailed(this::stopIndexToName) ); - Assertions.assertEquals(BasicPathTestCase.TOTAL_COST, path.c1()); + Assertions.assertEquals(BasicPathTestCase.TOTAL_C1, path.c1()); } } diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/AbstractStopArrival.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/AbstractStopArrival.java index c7edf20b8b9..fbedae88e45 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/AbstractStopArrival.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/AbstractStopArrival.java @@ -3,12 +3,13 @@ import org.opentripplanner.raptor._data.transit.TestTripSchedule; import org.opentripplanner.raptor.api.view.ArrivalView; -public abstract class AbstractStopArrival implements ArrivalView { +abstract class AbstractStopArrival implements ArrivalView { private final int round; private final int stop; private final int arrivalTime; - private final int cost; + private final int c1; + private final int c2; private final ArrivalView previous; AbstractStopArrival( @@ -16,13 +17,30 @@ public abstract class AbstractStopArrival implements ArrivalView previous ) { this.round = round; this.stop = stop; this.arrivalTime = arrivalTime; - this.cost = (previous == null ? 0 : previous.c1()) + extraCost; this.previous = previous; + this.c2 = c2; + + if (previous == null) { + this.c1 = extraCost; + } else { + this.c1 = previous.c1() + extraCost; + } + } + + AbstractStopArrival( + int round, + int stop, + int arrivalTime, + int extraCost, + ArrivalView previous + ) { + this(round, stop, arrivalTime, extraCost, previous.c2(), previous); } @Override @@ -42,12 +60,12 @@ public int arrivalTime() { @Override public int c1() { - return cost; + return c1; } @Override public int c2() { - throw new UnsupportedOperationException("C2 is not available for the C1 implementation"); + return c2; } @Override diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Access.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Access.java index 408e0a4e966..a4ad6d18f38 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Access.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Access.java @@ -2,25 +2,16 @@ import static org.opentripplanner.raptor.api.model.PathLegType.ACCESS; -import org.opentripplanner.raptor._data.transit.TestAccessEgress; import org.opentripplanner.raptor.api.model.PathLegType; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.view.AccessPathView; -public class Access extends AbstractStopArrival { +class Access extends AbstractStopArrival { private final RaptorAccessEgress access; - public Access(int stop, int departureTime, int arrivalTime, int cost) { - this( - stop, - arrivalTime, - TestAccessEgress.walk(stop, Math.abs(arrivalTime - departureTime), cost) - ); - } - - public Access(int stop, int arrivalTime, RaptorAccessEgress path) { - super(0, stop, arrivalTime, path.generalizedCost(), null); + Access(int stop, int arrivalTime, RaptorAccessEgress path, int c2) { + super(0, stop, arrivalTime, path.c1(), c2, null); this.access = path; } diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/BasicPathTestCase.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/BasicPathTestCase.java index 030ae71b4ad..4a92264e87c 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/BasicPathTestCase.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/BasicPathTestCase.java @@ -4,6 +4,10 @@ import static org.opentripplanner.framework.time.DurationUtils.durationToStr; import static org.opentripplanner.framework.time.TimeUtils.time; import static org.opentripplanner.model.transfer.TransferConstraint.REGULAR_TRANSFER; +import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.access; +import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.bus; +import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.egress; +import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.transfer; import static org.opentripplanner.raptor._data.transit.TestAccessEgress.flexWithOnBoard; import static org.opentripplanner.raptor._data.transit.TestTripPattern.pattern; import static org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.RaptorCostConverter.toRaptorCost; @@ -24,6 +28,7 @@ import org.opentripplanner.raptor.api.path.RaptorPath; import org.opentripplanner.raptor.api.path.TransferPathLeg; import org.opentripplanner.raptor.api.path.TransitPathLeg; +import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.path.Path; import org.opentripplanner.raptor.rangeraptor.internalapi.WorkerLifeCycle; import org.opentripplanner.raptor.rangeraptor.lifecycle.LifeCycleSubscriptions; @@ -59,18 +64,18 @@ public class BasicPathTestCase implements RaptorTestConstants { private static final RaptorConstrainedTransfer EMPTY_CONSTRAINTS = null; public static final String BASIC_PATH_AS_DETAILED_STRING = - "Walk 3m 10:00:15 10:03:15 $360 " + + "Walk 3m 10:00:15 10:03:15 C₁360 " + "~ A 45s ~ " + - "BUS L11 10:04 10:35 31m $1998 " + + "BUS L11 10:04 10:35 31m C₁1_998 " + "~ B 15s ~ " + - "Walk 3m45s 10:35:15 10:39 $450 " + + "Walk 3m45s 10:35:15 10:39 C₁450 " + "~ C 21m ~ " + - "BUS L21 11:00 11:23 23m $2640 " + + "BUS L21 11:00 11:23 23m C₁2_640 " + "~ D 17m ~ " + - "BUS L31 11:40 11:52 12m $1776 " + + "BUS L31 11:40 11:52 12m C₁1_776 " + "~ E 15s ~ " + - "Walk 7m45s 11:52:15 12:00 $930 " + - "[10:00:15 12:00 1h59m45s 2tx $8154]"; + "Walk 7m45s 11:52:15 12:00 C₁930 " + + "[10:00:15 12:00 1h59m45s Tₓ2 C₁8_154 C₂7]"; public static final String BASIC_PATH_AS_STRING = "Walk 3m ~ A" + @@ -79,16 +84,17 @@ public class BasicPathTestCase implements RaptorTestConstants { " ~ BUS L21 11:00 11:23 ~ D" + " ~ BUS L31 11:40 11:52 ~ E" + " ~ Walk 7m45s " + - "[10:00:15 12:00 1h59m45s 2tx $8154]"; + "[10:00:15 12:00 1h59m45s Tₓ2 C₁8_154 C₂7]"; - private static final int BOARD_COST_SEC = 60; - private static final int TRANSFER_COST_SEC = 120; + private static final int BOARD_C1_SEC = 60; + private static final int TRANSFER_C1_SEC = 120; private static final double[] TRANSIT_RELUCTANCE = new double[] { 1.0 }; public static final int TRANSIT_RELUCTANCE_INDEX = 0; public static final double WAIT_RELUCTANCE = 0.8; + private static final int C2 = 7; /** Stop cost for stop NA, A, C, E .. H is zero(0), B: 30s, and D: 60s. ?=0, A=1 .. H=8 */ - private static final int[] STOP_COSTS = { 0, 0, 3_000, 0, 6_000, 0, 0, 0, 0, 0 }; + private static final int[] STOP_C1S = { 0, 0, 3_000, 0, 6_000, 0, 0, 0, 0, 0 }; // Some times which should not have eny effect on tests private static final int VERY_EARLY = time("00:00"); @@ -104,48 +110,53 @@ public class BasicPathTestCase implements RaptorTestConstants { STOP_A, ACCESS_DURATION ); - public static final int ACCESS_COST = ACCESS_TRANSFER.generalizedCost(); + public static final int ACCESS_C1 = ACCESS_TRANSFER.c1(); + public static final int ACCESS_C2 = 0; // Trip 1 (A ~ BUS L11 10:04 10:35 ~ B) public static final int L11_START = time("10:04"); private static final int L11_END = time("10:35"); public static final int L11_DURATION = L11_END - L11_START; private static final int L11_WAIT_DURATION = L11_START - ACCESS_END + ALIGHT_SLACK; - public static final int LINE_11_COST = - STOP_COSTS[STOP_A] + - STOP_COSTS[STOP_B] + - toRaptorCost(BOARD_COST_SEC + WAIT_RELUCTANCE * L11_WAIT_DURATION + L11_DURATION); + public static final int LINE_11_C1 = + STOP_C1S[STOP_A] + + STOP_C1S[STOP_B] + + toRaptorCost(BOARD_C1_SEC + WAIT_RELUCTANCE * L11_WAIT_DURATION + L11_DURATION); + public static final int LINE_11_C2 = 2; // Transfers (B ~ Walk 3m45s ~ C) private static final int TX_START = time("10:35:15"); private static final int TX_END = time("10:39:00"); public static final int TX_DURATION = TX_END - TX_START; public static final RaptorTransfer TX_TRANSFER = TestTransfer.transfer(STOP_C, TX_DURATION); - public static final int TX_COST = TX_TRANSFER.generalizedCost(); + public static final int TX_C1 = TX_TRANSFER.c1(); + public static final int TX_C3 = 3; // Trip 2 (C ~ BUS L21 11:00 11:23 ~ D) public static final int L21_START = time("11:00"); private static final int L21_END = time("11:23"); public static final int L21_DURATION = L21_END - L21_START; private static final int L21_WAIT_DURATION = L21_START - TX_END + ALIGHT_SLACK; - public static final int LINE_21_COST = - STOP_COSTS[STOP_C] + - STOP_COSTS[STOP_D] + + public static final int LINE_21_C1 = + STOP_C1S[STOP_C] + + STOP_C1S[STOP_D] + toRaptorCost( - BOARD_COST_SEC + TRANSFER_COST_SEC + WAIT_RELUCTANCE * L21_WAIT_DURATION + L21_DURATION + BOARD_C1_SEC + TRANSFER_C1_SEC + WAIT_RELUCTANCE * L21_WAIT_DURATION + L21_DURATION ); + public static final int LINE_21_C2 = 5; // Trip 3 (D ~ BUS L31 11:40 11:52 ~ E) public static final int L31_START = time("11:40"); private static final int L31_END = time("11:52"); public static final int L31_DURATION = L31_END - L31_START; private static final int L31_WAIT_DURATION = L31_START - (L21_END + ALIGHT_SLACK) + ALIGHT_SLACK; - public static final int LINE_31_COST = - STOP_COSTS[STOP_D] + - STOP_COSTS[STOP_E] + + public static final int LINE_31_C1 = + STOP_C1S[STOP_D] + + STOP_C1S[STOP_E] + toRaptorCost( - BOARD_COST_SEC + TRANSFER_COST_SEC + WAIT_RELUCTANCE * L31_WAIT_DURATION + L31_DURATION + BOARD_C1_SEC + TRANSFER_C1_SEC + WAIT_RELUCTANCE * L31_WAIT_DURATION + L31_DURATION ); + public static final int LINE_31_C2 = 6; // Egress (E ~ Walk 7m45s ~ ) public static final int EGRESS_START = time("11:52:15"); @@ -155,25 +166,26 @@ public class BasicPathTestCase implements RaptorTestConstants { STOP_E, EGRESS_DURATION ); - public static final int EGRESS_COST = EGRESS_TRANSFER.generalizedCost(); + public static final int EGRESS_C1 = EGRESS_TRANSFER.c1(); + public static final int EGRESS_C2 = 7; public static final int TRIP_DURATION = EGRESS_END - ACCESS_START; private static final RaptorAccessEgress ACCESS = TestAccessEgress.walk( STOP_A, ACCESS_DURATION, - ACCESS_COST + ACCESS_C1 ); private static final RaptorAccessEgress EGRESS = TestAccessEgress.walk( STOP_E, EGRESS_DURATION, - EGRESS_COST + EGRESS_C1 ); // this is of course not a real flex egress private static final RaptorAccessEgress FLEX = flexWithOnBoard( STOP_E, EGRESS_DURATION, - EGRESS_COST + EGRESS_C1 ); public static final String LINE_11 = "L11"; @@ -200,16 +212,16 @@ public class BasicPathTestCase implements RaptorTestConstants { .transitReluctanceIndex(TRANSIT_RELUCTANCE_INDEX) .build(); - public static final RaptorCostCalculator COST_CALCULATOR = new DefaultCostCalculator<>( - BOARD_COST_SEC, - TRANSFER_COST_SEC, + public static final RaptorCostCalculator C1_CALCULATOR = new DefaultCostCalculator<>( + BOARD_C1_SEC, + TRANSFER_C1_SEC, WAIT_RELUCTANCE, TRANSIT_RELUCTANCE, - STOP_COSTS + STOP_C1S ); - public static final int TOTAL_COST = - ACCESS_COST + LINE_11_COST + TX_COST + LINE_21_COST + LINE_31_COST + EGRESS_COST; + public static final int TOTAL_C1 = + ACCESS_C1 + LINE_11_C1 + TX_C1 + LINE_21_C1 + LINE_31_C1 + EGRESS_C1; /** Wait time between trip L11 and L21 including slack */ public static final int WAIT_TIME_L11_L21 = L21_START - L11_END - TX_DURATION; @@ -222,18 +234,19 @@ public static WorkerLifeCycle lifeCycle() { } public static DestinationArrival basicTripByForwardSearch() { - AbstractStopArrival prevArrival; - prevArrival = new Access(STOP_A, ACCESS_START, ACCESS_END, ACCESS_COST); - prevArrival = new Bus(1, STOP_B, L11_END, LINE_11_COST, TRIP_1, prevArrival); - prevArrival = new Transfer(1, STOP_C, TX_START, TX_END, TX_COST, prevArrival); - prevArrival = new Bus(2, STOP_D, L21_END, LINE_21_COST, TRIP_2, prevArrival); - prevArrival = new Bus(3, STOP_E, L31_END, LINE_31_COST, TRIP_3, prevArrival); - Egress egress = new Egress(EGRESS_START, EGRESS_END, EGRESS_COST, prevArrival); + ArrivalView prevArrival, egress; + prevArrival = access(STOP_A, ACCESS_START, ACCESS_END, ACCESS_C1, ACCESS_C2); + prevArrival = bus(1, STOP_B, L11_END, LINE_11_C1, LINE_11_C2, TRIP_1, prevArrival); + prevArrival = transfer(1, STOP_C, TX_START, TX_END, TX_C1, prevArrival); + prevArrival = bus(2, STOP_D, L21_END, LINE_21_C1, LINE_21_C2, TRIP_2, prevArrival); + prevArrival = bus(3, STOP_E, L31_END, LINE_31_C1, LINE_31_C2, TRIP_3, prevArrival); + egress = egress(EGRESS_START, EGRESS_END, EGRESS_C1, EGRESS_C2, prevArrival); return new DestinationArrival<>( - TestAccessEgress.walk(egress.previous().stop(), egress.durationInSeconds()), + egress.egressPath().egress(), egress.previous(), egress.arrivalTime(), - egress.additionalCost() + egress.egressPath().egress().c1(), + egress.c2() ); } @@ -242,19 +255,20 @@ public static DestinationArrival basicTripByForwardSearch() { * search: */ public static DestinationArrival basicTripByReverseSearch() { - AbstractStopArrival nextArrival; - nextArrival = new Access(STOP_E, EGRESS_END, EGRESS_START, EGRESS_COST); + ArrivalView nextArrival, egress; + nextArrival = access(STOP_E, EGRESS_END, EGRESS_START, EGRESS_C1, EGRESS_C2); // Board slack is subtracted from the arrival time to get the latest possible - nextArrival = new Bus(1, STOP_D, L31_START, LINE_31_COST, TRIP_3, nextArrival); - nextArrival = new Bus(2, STOP_C, L21_START, LINE_21_COST, TRIP_2, nextArrival); - nextArrival = new Transfer(2, STOP_B, TX_END, TX_START, TX_COST, nextArrival); - nextArrival = new Bus(3, STOP_A, L11_START, LINE_11_COST, TRIP_1, nextArrival); - Egress egress = new Egress(ACCESS_END, ACCESS_START, ACCESS_COST, nextArrival); + nextArrival = bus(1, STOP_D, L31_START, LINE_31_C1, LINE_31_C2, TRIP_3, nextArrival); + nextArrival = bus(2, STOP_C, L21_START, LINE_21_C1, LINE_21_C2, TRIP_2, nextArrival); + nextArrival = transfer(2, STOP_B, TX_END, TX_START, TX_C1, nextArrival); + nextArrival = bus(3, STOP_A, L11_START, LINE_11_C1, LINE_11_C2, TRIP_1, nextArrival); + egress = egress(ACCESS_END, ACCESS_START, ACCESS_C1, ACCESS_C2, nextArrival); return new DestinationArrival<>( - TestAccessEgress.walk(egress.previous().stop(), egress.durationInSeconds()), + egress.egressPath().egress(), egress.previous(), egress.arrivalTime(), - egress.additionalCost() + egress.egressPath().egress().c1(), + egress.c2() ); } @@ -267,7 +281,7 @@ public static RaptorPath basicTripAsPath() { EGRESS, EGRESS_START, EGRESS_END, - EGRESS_COST + EGRESS_C1 ); TransitPathLeg leg5 = new TransitPathLeg<>( TRIP_3, @@ -276,7 +290,7 @@ public static RaptorPath basicTripAsPath() { TRIP_3.findDepartureStopPosition(L31_START, STOP_D), TRIP_3.findArrivalStopPosition(L31_END, STOP_E), EMPTY_CONSTRAINTS, - LINE_31_COST, + LINE_31_C1, leg6 ); TransitPathLeg leg4 = new TransitPathLeg<>( @@ -286,7 +300,7 @@ public static RaptorPath basicTripAsPath() { TRIP_2.findDepartureStopPosition(L21_START, STOP_C), TRIP_2.findArrivalStopPosition(L21_END, STOP_D), EMPTY_CONSTRAINTS, - LINE_21_COST, + LINE_21_C1, leg5 ); var transfer = TestTransfer.transfer(STOP_C, TX_END - TX_START); @@ -294,7 +308,7 @@ public static RaptorPath basicTripAsPath() { STOP_B, TX_START, TX_END, - transfer.generalizedCost(), + transfer.c1(), transfer, leg4.asTransitLeg() ); @@ -305,32 +319,27 @@ public static RaptorPath basicTripAsPath() { TRIP_1.findDepartureStopPosition(L11_START, STOP_A), TRIP_1.findArrivalStopPosition(L11_END, STOP_B), EMPTY_CONSTRAINTS, - LINE_11_COST, + LINE_11_C1, leg3 ); AccessPathLeg leg1 = new AccessPathLeg<>( ACCESS, ACCESS_START, ACCESS_END, - ACCESS_COST, + ACCESS_C1, leg2.asTransitLeg() ); - return new Path<>(RAPTOR_ITERATION_START_TIME, leg1, TOTAL_COST, 0); + return new Path<>(RAPTOR_ITERATION_START_TIME, leg1, TOTAL_C1, 7); } public static RaptorPath flexTripAsPath() { - PathLeg leg6 = new EgressPathLeg<>( - FLEX, - EGRESS_START, - EGRESS_END, - EGRESS_COST - ); + PathLeg leg6 = new EgressPathLeg<>(FLEX, EGRESS_START, EGRESS_END, EGRESS_C1); var transfer = TestTransfer.transfer(STOP_E, TX_END - TX_START); PathLeg leg3 = new TransferPathLeg<>( STOP_B, TX_START, TX_END, - transfer.generalizedCost(), + transfer.c1(), transfer, leg6 ); @@ -341,17 +350,17 @@ public static RaptorPath flexTripAsPath() { TRIP_1.findDepartureStopPosition(L11_START, STOP_A), TRIP_1.findArrivalStopPosition(L11_END, STOP_B), EMPTY_CONSTRAINTS, - LINE_11_COST, + LINE_11_C1, leg3 ); AccessPathLeg leg1 = new AccessPathLeg<>( ACCESS, ACCESS_START, ACCESS_END, - ACCESS_COST, + ACCESS_C1, leg2.asTransitLeg() ); - return new Path<>(RAPTOR_ITERATION_START_TIME, leg1, TOTAL_COST, 0); + return new Path<>(RAPTOR_ITERATION_START_TIME, leg1, TOTAL_C1, C2); } public static List basicTripStops() { @@ -402,15 +411,15 @@ public void testSetup() { // The calculator is not under test here, so we assert everything is as expected assertEquals( - LINE_11_COST, + LINE_11_C1, transitArrivalCost(ACCESS_END, TRIP_1, STOP_A, L11_START, STOP_B, L11_END) ); assertEquals( - LINE_21_COST, + LINE_21_C1, transitArrivalCost(TX_END, TRIP_2, STOP_C, L21_START, STOP_D, L21_END) ); assertEquals( - LINE_31_COST, + LINE_31_C1, transitArrivalCost(L21_END + ALIGHT_SLACK, TRIP_3, STOP_D, L31_START, STOP_E, L31_END) ); @@ -431,7 +440,7 @@ private static int transitArrivalCost( int alightTime ) { boolean firstTransit = TRIP_1 == trip; - int boardCost = COST_CALCULATOR.boardingCost( + int boardCost = C1_CALCULATOR.boardingCost( firstTransit, prevArrivalTime, boardStop, @@ -440,7 +449,7 @@ private static int transitArrivalCost( REGULAR_TRANSFER ); - return COST_CALCULATOR.transitArrivalCost( + return C1_CALCULATOR.transitArrivalCost( boardCost, ALIGHT_SLACK, alightTime - boardTime, diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Egress.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Egress.java index 13ce8398e77..a244acdf720 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Egress.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Egress.java @@ -2,51 +2,48 @@ import org.opentripplanner.framework.time.TimeUtils; import org.opentripplanner.raptor._data.transit.TestTripSchedule; +import org.opentripplanner.raptor.api.model.PathLegType; +import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.view.ArrivalView; +import org.opentripplanner.raptor.api.view.EgressPathView; -public class Egress { +public class Egress extends AbstractStopArrival { - private final int arrivalTime; - private final int durationInSeconds; - private final int cost; - private final ArrivalView previous; + private final RaptorAccessEgress egressPath; public Egress( - int departureTime, int arrivalTime, - int cost, + RaptorAccessEgress egressPath, + int c2, ArrivalView previous ) { - this.arrivalTime = arrivalTime; - this.durationInSeconds = Math.abs(arrivalTime - departureTime); - this.cost = cost; - this.previous = previous; + super(previous.round(), previous.stop(), arrivalTime, egressPath.c1(), c2, previous); + this.egressPath = egressPath; } - public int additionalCost() { - return cost; - } - - public int durationInSeconds() { - return durationInSeconds; - } - - public int arrivalTime() { - return arrivalTime; - } - - public ArrivalView previous() { - return previous; + @Override + public EgressPathView egressPath() { + return () -> egressPath; } @Override public String toString() { return String.format( "Egress { round: %d, stop: %d, arrival-time: %s $%d }", - previous.round(), - previous.stop(), - TimeUtils.timeToStrCompact(arrivalTime), - previous.c1() + additionalCost() + round(), + stop(), + TimeUtils.timeToStrCompact(arrivalTime()), + c1() ); } + + @Override + public PathLegType arrivedBy() { + return PathLegType.EGRESS; + } + + @Override + public boolean arrivedOnBoard() { + return egressPath.stopReachedOnBoard(); + } } diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/FlexAccessAndEgressPathTestCase.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/FlexAccessAndEgressPathTestCase.java index 9291871a555..1e694e3d771 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/FlexAccessAndEgressPathTestCase.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/FlexAccessAndEgressPathTestCase.java @@ -3,6 +3,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.time.DurationUtils.durationInSeconds; import static org.opentripplanner.framework.time.TimeUtils.time; +import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.access; +import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.bus; +import static org.opentripplanner.raptor.api.model.RaptorValueFormatter.formatC1; import static org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.RaptorCostConverter.toRaptorCost; import org.junit.jupiter.api.Test; @@ -13,7 +16,9 @@ import org.opentripplanner.raptor._data.transit.TestTripPattern; import org.opentripplanner.raptor._data.transit.TestTripSchedule; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; +import org.opentripplanner.raptor.api.model.RaptorConstants; import org.opentripplanner.raptor.api.model.RaptorTransfer; +import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.rangeraptor.path.DestinationArrival; import org.opentripplanner.raptor.spi.DefaultSlackProvider; import org.opentripplanner.raptor.spi.RaptorSlackProvider; @@ -46,12 +51,12 @@ public class FlexAccessAndEgressPathTestCase implements RaptorTestConstants { // The transit reluctance is ignored, any value should work private static final int TRANSIT_RELUCTANCE_INDEX = -1; public static final double WAIT_RELUCTANCE = 0.8; - public static final int BOARD_COST_SEC = 60; - public static final int TRANSFER_COST_SEC = 120; - // The COST_CALCULATOR is not under test, so we use it to calculate correct cost values. - public static final DefaultCostCalculator COST_CALCULATOR = new DefaultCostCalculator<>( - BOARD_COST_SEC, - TRANSFER_COST_SEC, + public static final int BOARD_C1_SEC = 60; + public static final int TRANSFER_C1_SEC = 120; + // The C1_CALCULATOR is not under test, so we use it to calculate correct cost values. + public static final DefaultCostCalculator C1_CALCULATOR = new DefaultCostCalculator<>( + BOARD_C1_SEC, + TRANSFER_C1_SEC, WAIT_RELUCTANCE, null, null @@ -65,13 +70,13 @@ public class FlexAccessAndEgressPathTestCase implements RaptorTestConstants { // FLEX Access 5m tx 1 ~ A. Note! The actual times might get time-shifted. public static final int ACCESS_DURATION = durationInSeconds("5m15s"); - public static final int ACCESS_COST = toRaptorCost(600); + public static final int ACCESS_C1 = toRaptorCost(600); // Using transfer reluctance is incorrect, we should use the cost from the access path public static final TestAccessEgress ACCESS = TestAccessEgress.flex( STOP_A, ACCESS_DURATION, ONE_RIDE, - ACCESS_COST + ACCESS_C1 ); // Alternative Flex access with restricted opening hours: 09:00 - 09:50 public static final int ACCESS_OPEN = time("09:00"); @@ -87,7 +92,7 @@ public class FlexAccessAndEgressPathTestCase implements RaptorTestConstants { public static final int TX1_DURATION = TX1_END - TX1_START; public static final RaptorTransfer TX1_TRANSFER = TestTransfer.transfer(STOP_B, TX1_DURATION); public static final RaptorTransfer TX1_TRANSFER_REV = TestTransfer.transfer(STOP_A, TX1_DURATION); - public static final int TX1_COST = TX1_TRANSFER.generalizedCost(); + public static final int TX1_C1 = TX1_TRANSFER.c1(); // Trip A (B ~ BUS L11 10:08 10:20 ~ C) public static final int L1_START = time("10:08"); @@ -105,18 +110,18 @@ public class FlexAccessAndEgressPathTestCase implements RaptorTestConstants { public static final int TX2_DURATION = TX2_END - TX2_START; public static final RaptorTransfer TX2_TRANSFER = TestTransfer.transfer(STOP_D, TX2_DURATION); public static final RaptorTransfer TX2_TRANSFER_REV = TestTransfer.transfer(STOP_C, TX2_DURATION); - public static final int TX2_COST = TX2_TRANSFER.generalizedCost(); + public static final int TX2_C1 = TX2_TRANSFER.c1(); // Wait 15s (ALIGHT_SLACK) // D ~ FLEX Egress 6m tx 1 . Note! The actual times might get time-shifted. public static final int EGRESS_DURATION = durationInSeconds("6m"); - public static final int EGRESS_COST = toRaptorCost(800); + public static final int EGRESS_C1 = toRaptorCost(800); // Using transfer reluctance is incorrect, we should use the cost from the egress path public static final TestAccessEgress EGRESS = TestAccessEgress.flex( STOP_D, EGRESS_DURATION, ONE_RIDE, - EGRESS_COST + EGRESS_C1 ); public static final int EGRESS_OPENING = TimeUtils.time("10:30"); public static final int EGRESS_CLOSING = TimeUtils.time("11:00"); @@ -125,12 +130,12 @@ public class FlexAccessAndEgressPathTestCase implements RaptorTestConstants { EGRESS_CLOSING ); - public static final int EGRESS_COST_W_1M_SLACK = - EGRESS_COST + toRaptorCost(TRANSFER_COST_SEC) + COST_CALCULATOR.waitCost(TRANSFER_SLACK); - public static final int EGRESS_COST_W_7M45S_SLACK = - EGRESS_COST_W_1M_SLACK + COST_CALCULATOR.waitCost(durationInSeconds("6m45s")); - public static final int EGRESS_COST_W_9M45S_SLACK = - EGRESS_COST_W_1M_SLACK + COST_CALCULATOR.waitCost(durationInSeconds("8m45s")); + public static final int EGRESS_C1_W_1M_SLACK = + EGRESS_C1 + toRaptorCost(TRANSFER_C1_SEC) + C1_CALCULATOR.waitCost(TRANSFER_SLACK); + public static final int EGRESS_C1_W_7M45S_SLACK = + EGRESS_C1_W_1M_SLACK + C1_CALCULATOR.waitCost(durationInSeconds("6m45s")); + public static final int EGRESS_C1_W_9M45S_SLACK = + EGRESS_C1_W_1M_SLACK + C1_CALCULATOR.waitCost(durationInSeconds("8m45s")); public static final String LINE_A = "A"; public static final String LINE_B = "B"; @@ -147,23 +152,23 @@ public class FlexAccessAndEgressPathTestCase implements RaptorTestConstants { .transitReluctanceIndex(TRANSIT_RELUCTANCE_INDEX) .build(); - public static final int L1_COST_EX_WAIT = COST_CALCULATOR.transitArrivalCost( - COST_CALCULATOR.boardingCostRegularTransfer(false, L1_START, STOP_B, L1_START), + public static final int L1_C1_EX_WAIT = C1_CALCULATOR.transitArrivalCost( + C1_CALCULATOR.boardingCostRegularTransfer(false, L1_START, STOP_B, L1_START), ZERO, L1_TRANSIT_DURATION, TRIP_A, STOP_C ); - private static final int TOT_COST_A = toRaptorCost(2564); - private static final int TOT_COST_W_OPENING_HOURS_A = toRaptorCost(3512); - private static final int TOT_COST_B = toRaptorCost(2924); - private static final int TOT_COST_W_OPENING_HOURS_B = toRaptorCost(3728); + private static final int TOT_C1_A = toRaptorCost(2564); + private static final int TOT_C1_W_OPENING_HOURS_A = toRaptorCost(3512); + private static final int TOT_C1_B = toRaptorCost(2924); + private static final int TOT_C1_W_OPENING_HOURS_B = toRaptorCost(3728); // Wait before 12m45s + ALIGHT SLACK 15s - private static final int L1_COST_INC_WAIT_W_OPENING_HOURS_A = - L1_COST_EX_WAIT + COST_CALCULATOR.waitCost(durationInSeconds("13m")); - private static final int L1_COST_INC_WAIT_W_OPENING_HOURS_B = - L1_COST_EX_WAIT + COST_CALCULATOR.waitCost(durationInSeconds("12m")); + private static final int L1_C1_INC_WAIT_W_OPENING_HOURS_A = + L1_C1_EX_WAIT + C1_CALCULATOR.waitCost(durationInSeconds("13m")); + private static final int L1_C1_INC_WAIT_W_OPENING_HOURS_B = + L1_C1_EX_WAIT + C1_CALCULATOR.waitCost(durationInSeconds("12m")); /* TEST CASES WITH EXPECTED TO-STRING TEXTS */ @@ -174,12 +179,12 @@ public static DestinationArrival flexCaseAForwardSearch() { public static String flexCaseAText() { return String.format( "Flex 5m15s 1x 10:01 10:06:15 %s ~ A 1m45s ~ " + - "BUS A 10:08 10:20 12m $996 ~ D 1m15s ~ " + + "BUS A 10:08 10:20 12m C₁996 ~ D 1m15s ~ " + "Flex 6m 1x 10:21:15 10:27:15 %s " + - "[10:01 10:27:15 26m15s 2tx %s]", - RaptorCostConverter.toString(ACCESS_COST), - RaptorCostConverter.toString(EGRESS_COST_W_1M_SLACK), - RaptorCostConverter.toString(TOT_COST_A) + "[10:01 10:27:15 26m15s Tₓ2 %s]", + RaptorCostConverter.toString(ACCESS_C1), + RaptorCostConverter.toString(EGRESS_C1_W_1M_SLACK), + RaptorCostConverter.toString(TOT_C1_A) ); } @@ -190,14 +195,14 @@ public static DestinationArrival flexCaseBForwardSearch() { public static String flexCaseBText() { return String.format( "Flex 5m15s 1x 10:00 10:05:15 %s ~ A 0s ~ " + - "Walk 1m 10:05:15 10:06:15 $120 ~ B 1m45s ~ " + - "BUS B 10:08 10:20 12m $996 ~ C 15s ~ " + - "Walk 2m 10:20:15 10:22:15 $240 ~ D 1m ~ " + + "Walk 1m 10:05:15 10:06:15 C₁120 ~ B 1m45s ~ " + + "BUS B 10:08 10:20 12m C₁996 ~ C 15s ~ " + + "Walk 2m 10:20:15 10:22:15 C₁240 ~ D 1m ~ " + "Flex 6m 1x 10:23:15 10:29:15 %s" + - " [10:00 10:29:15 29m15s 2tx %s]", - RaptorCostConverter.toString(ACCESS_COST), - RaptorCostConverter.toString(EGRESS_COST_W_1M_SLACK), - RaptorCostConverter.toString(TOT_COST_B) + " [10:00 10:29:15 29m15s Tₓ2 %s]", + RaptorCostConverter.toString(ACCESS_C1), + RaptorCostConverter.toString(EGRESS_C1_W_1M_SLACK), + RaptorCostConverter.toString(TOT_C1_B) ); } @@ -210,11 +215,11 @@ public static String flexCaseAWithOpeningHoursText() { "Flex 5m15s 1x Open(9:00 9:50) 9:50 9:55:15 %s ~ A 12m45s ~ " + "BUS A 10:08 10:20 12m %s ~ D 10m ~ " + "Flex 6m 1x Open(10:30 11:00) 10:30 10:36 %s " + - "[9:50 10:36 46m 2tx %s]", - RaptorCostConverter.toString(ACCESS_COST), - RaptorCostConverter.toString(L1_COST_INC_WAIT_W_OPENING_HOURS_A), - RaptorCostConverter.toString(EGRESS_COST_W_9M45S_SLACK), - RaptorCostConverter.toString(TOT_COST_W_OPENING_HOURS_A) + "[9:50 10:36 46m Tₓ2 %s]", + formatC1(ACCESS_C1), + formatC1(L1_C1_INC_WAIT_W_OPENING_HOURS_A), + formatC1(EGRESS_C1_W_9M45S_SLACK), + formatC1(TOT_C1_W_OPENING_HOURS_A) ); } @@ -225,15 +230,15 @@ public static DestinationArrival flexCaseBWithOpeningHoursForw public static String flexCaseBWithOpeningHoursText() { return String.format( "Flex 5m15s 1x Open(9:00 9:50) 9:50 9:55:15 %s ~ A 0s ~ " + - "Walk 1m 9:55:15 9:56:15 $120 ~ B 11m45s ~ " + + "Walk 1m 9:55:15 9:56:15 C₁120 ~ B 11m45s ~ " + "BUS B 10:08 10:20 12m %s ~ C 15s ~ " + - "Walk 2m 10:20:15 10:22:15 $240 ~ D 7m45s ~ " + + "Walk 2m 10:20:15 10:22:15 C₁240 ~ D 7m45s ~ " + "Flex 6m 1x Open(10:30 11:00) 10:30 10:36 %s" + - " [9:50 10:36 46m 2tx %s]", - RaptorCostConverter.toString(ACCESS_COST), - RaptorCostConverter.toString(L1_COST_INC_WAIT_W_OPENING_HOURS_B), - RaptorCostConverter.toString(EGRESS_COST_W_7M45S_SLACK), - RaptorCostConverter.toString(TOT_COST_W_OPENING_HOURS_B) + " [9:50 10:36 46m Tₓ2 %s]", + formatC1(ACCESS_C1), + formatC1(L1_C1_INC_WAIT_W_OPENING_HOURS_B), + formatC1(EGRESS_C1_W_7M45S_SLACK), + formatC1(TOT_C1_W_OPENING_HOURS_B) ); } @@ -269,9 +274,9 @@ public void testSetup() { // Assert cost // The calculator is not under test here, so we assert everything is as expected - assertEquals(12000, TX1_COST); - assertEquals(90000, L1_COST_EX_WAIT); - assertEquals(24000, TX2_COST); + assertEquals(12000, TX1_C1); + assertEquals(90000, L1_C1_EX_WAIT); + assertEquals(24000, TX2_C1); } /* PRIVATE METHODS */ @@ -282,24 +287,24 @@ private static DestinationArrival flexForwardSearch( String line ) { int departureTime, arrivalTime, waitTime; - AbstractStopArrival prevArrival; + ArrivalView prevArrival; if (LINE_A.equals(line)) { // The latest time the access can arrive is the same as the TX1 arrival time in case B arrivalTime = accessPath.latestArrivalTime(TX1_END); - prevArrival = new Access(accessPath.stop(), arrivalTime, accessPath); + prevArrival = access(accessPath.stop(), arrivalTime, accessPath); int waitCost = costL1ForwardIncWait(prevArrival.arrivalTime()); - prevArrival = new Bus(2, STOP_D, L1_STOP_ARR_TIME, waitCost, TRIP_A, prevArrival); + prevArrival = bus(2, STOP_D, L1_STOP_ARR_TIME, waitCost, 0, TRIP_A, prevArrival); } else { arrivalTime = accessPath.latestArrivalTime(TX1_START); - prevArrival = new Access(accessPath.stop(), arrivalTime, accessPath); + prevArrival = access(accessPath.stop(), arrivalTime, accessPath); int timeShift = TX1_START - prevArrival.arrivalTime(); prevArrival = new Transfer(1, TX1_END - timeShift, TX1_TRANSFER, prevArrival); int waitCost = costL1ForwardIncWait(prevArrival.arrivalTime()); - prevArrival = new Bus(2, STOP_C, L1_STOP_ARR_TIME, waitCost, TRIP_B, prevArrival); + prevArrival = bus(2, STOP_C, L1_STOP_ARR_TIME, waitCost, 0, TRIP_B, prevArrival); prevArrival = new Transfer(2, TX2_END, TX2_TRANSFER, prevArrival); } @@ -311,9 +316,15 @@ private static DestinationArrival flexForwardSearch( arrivalTime = departureTime + egressPath.durationInSeconds(); waitTime = departureTime - prevArrival.arrivalTime(); int additionalCost = - egressPath.generalizedCost() + toRaptorCost(waitTime * WAIT_RELUCTANCE + TRANSFER_COST_SEC); - - return new DestinationArrival<>(egressPath, prevArrival, arrivalTime, additionalCost); + egressPath.c1() + toRaptorCost(waitTime * WAIT_RELUCTANCE + TRANSFER_C1_SEC); + + return new DestinationArrival<>( + egressPath, + prevArrival, + arrivalTime, + additionalCost, + RaptorConstants.NOT_SET + ); } private static DestinationArrival flexReverseSearch( @@ -322,23 +333,23 @@ private static DestinationArrival flexReverseSearch( String line ) { int departureTime, arrivalTime, cost; - AbstractStopArrival prevArrival; + ArrivalView prevArrival; if (LINE_A.equals(line)) { arrivalTime = L1_END + ALIGHT_SLACK + TRANSFER_SLACK; arrivalTime = egressPath.earliestDepartureTime(arrivalTime); - prevArrival = new Access(egressPath.stop(), arrivalTime, egressPath); + prevArrival = access(egressPath.stop(), arrivalTime, egressPath); cost = costL1ReverseIncWait(prevArrival.arrivalTime()); - prevArrival = new Bus(2, STOP_A, L1_STOP_ARR_TIME_REV, cost, TRIP_A, prevArrival); + prevArrival = bus(2, STOP_A, L1_STOP_ARR_TIME_REV, cost, 0, TRIP_A, prevArrival); } else { arrivalTime = L1_END + ALIGHT_SLACK + TX2_DURATION + TRANSFER_SLACK; arrivalTime = egressPath.earliestDepartureTime(arrivalTime); - prevArrival = new Access(egressPath.stop(), arrivalTime, egressPath); + prevArrival = access(egressPath.stop(), arrivalTime, egressPath); arrivalTime = prevArrival.arrivalTime() - TX2_DURATION; prevArrival = new Transfer(1, arrivalTime, TX2_TRANSFER_REV, prevArrival); cost = costL1ReverseIncWait(prevArrival.arrivalTime()); - prevArrival = new Bus(2, STOP_B, L1_STOP_ARR_TIME_REV, cost, TRIP_B, prevArrival); + prevArrival = bus(2, STOP_B, L1_STOP_ARR_TIME_REV, cost, 0, TRIP_B, prevArrival); arrivalTime = prevArrival.arrivalTime() - TX1_DURATION; prevArrival = new Transfer(2, arrivalTime, TX1_TRANSFER_REV, prevArrival); } @@ -350,18 +361,24 @@ private static DestinationArrival flexReverseSearch( arrivalTime = departureTime - accessPath.durationInSeconds(); int waitTime = prevArrival.arrivalTime() - departureTime; int additionalCost = - accessPath.generalizedCost() + toRaptorCost(waitTime * WAIT_RELUCTANCE + TRANSFER_COST_SEC); - - return new DestinationArrival<>(accessPath, prevArrival, arrivalTime, additionalCost); + accessPath.c1() + toRaptorCost(waitTime * WAIT_RELUCTANCE + TRANSFER_C1_SEC); + + return new DestinationArrival<>( + accessPath, + prevArrival, + arrivalTime, + additionalCost, + RaptorConstants.NOT_SET + ); } private static int costL1ForwardIncWait(int prevArrivalTime) { int waitTime = L1_START - prevArrivalTime + ALIGHT_SLACK; - return toRaptorCost(waitTime * WAIT_RELUCTANCE) + L1_COST_EX_WAIT; + return toRaptorCost(waitTime * WAIT_RELUCTANCE) + L1_C1_EX_WAIT; } private static int costL1ReverseIncWait(int prevArrivalTime) { int waitTime = (prevArrivalTime - L1_END) + BOARD_SLACK; - return toRaptorCost(waitTime * WAIT_RELUCTANCE) + L1_COST_EX_WAIT; + return toRaptorCost(waitTime * WAIT_RELUCTANCE) + L1_C1_EX_WAIT; } } diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/TestArrivals.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/TestArrivals.java new file mode 100644 index 00000000000..a4a042e89c2 --- /dev/null +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/TestArrivals.java @@ -0,0 +1,105 @@ +package org.opentripplanner.raptor._data.stoparrival; + +import org.opentripplanner.raptor._data.transit.TestAccessEgress; +import org.opentripplanner.raptor._data.transit.TestTransfer; +import org.opentripplanner.raptor._data.transit.TestTripSchedule; +import org.opentripplanner.raptor.api.model.RaptorAccessEgress; +import org.opentripplanner.raptor.api.model.RaptorConstants; +import org.opentripplanner.raptor.api.model.RaptorTransfer; +import org.opentripplanner.raptor.api.view.ArrivalView; + +public class TestArrivals { + + public static ArrivalView access( + int stop, + int arrivalTime, + RaptorAccessEgress path, + int c2 + ) { + return new Access(stop, arrivalTime, path, c2); + } + + public static ArrivalView access( + int stop, + int arrivalTime, + RaptorAccessEgress path + ) { + return access(stop, arrivalTime, path, RaptorConstants.NOT_SET); + } + + public static ArrivalView access( + int stop, + int departureTime, + int arrivalTime, + int c1, + int c2 + ) { + return access( + stop, + arrivalTime, + TestAccessEgress.walk(stop, Math.abs(arrivalTime - departureTime), c1), + c2 + ); + } + + public static ArrivalView access( + int stop, + int departureTime, + int arrivalTime, + int c1 + ) { + return access(stop, departureTime, arrivalTime, c1, RaptorConstants.NOT_SET); + } + + public static ArrivalView transfer( + int round, + int arrivalTime, + RaptorTransfer transfer, + ArrivalView previous + ) { + return new Transfer(round, arrivalTime, transfer, previous); + } + + public static ArrivalView transfer( + int round, + int stop, + int departureTime, + int arrivalTime, + int extraCost, + ArrivalView previous + ) { + return transfer( + round, + arrivalTime, + TestTransfer.transfer(stop, Math.abs(arrivalTime - departureTime), extraCost), + previous + ); + } + + public static ArrivalView bus( + int round, + int stop, + int arrivalTime, + int c1, + int c2, + TestTripSchedule trip, + ArrivalView previous + ) { + return new Transit(round, stop, arrivalTime, c1, c2, trip, previous); + } + + public static ArrivalView egress( + int departureTime, + int arrivalTime, + int c1, + int c2, + ArrivalView previous + ) { + return new Egress( + departureTime, + TestAccessEgress.walk(previous.stop(), Math.abs(arrivalTime - departureTime), c1), + c2, + previous + ); + } +} diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transfer.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transfer.java index 99921c6b3e6..e7df3b1f98c 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transfer.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transfer.java @@ -2,37 +2,22 @@ import static org.opentripplanner.raptor.api.model.PathLegType.TRANSFER; -import org.opentripplanner.raptor._data.transit.TestTransfer; import org.opentripplanner.raptor._data.transit.TestTripSchedule; import org.opentripplanner.raptor.api.model.PathLegType; import org.opentripplanner.raptor.api.model.RaptorTransfer; import org.opentripplanner.raptor.api.view.ArrivalView; -public class Transfer extends AbstractStopArrival { +class Transfer extends AbstractStopArrival { private final RaptorTransfer transfer; - public Transfer( - int round, - int stop, - int departureTime, - int arrivalTime, - int extraCost, - ArrivalView previous - ) { - super(round, stop, arrivalTime, extraCost, previous); - // In a reverse search we the arrival is before the departure - int durationInSeconds = Math.abs(arrivalTime - departureTime); - this.transfer = TestTransfer.transfer(stop, durationInSeconds, extraCost); - } - - public Transfer( + Transfer( int round, int arrivalTime, RaptorTransfer transfer, ArrivalView previous ) { - super(round, transfer.stop(), arrivalTime, transfer.generalizedCost(), previous); + super(round, transfer.stop(), arrivalTime, transfer.c1(), previous.c2(), previous); this.transfer = transfer; } diff --git a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Bus.java b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transit.java similarity index 84% rename from src/test/java/org/opentripplanner/raptor/_data/stoparrival/Bus.java rename to src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transit.java index 5362c8aaa35..e2f539bf455 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Bus.java +++ b/src/test/java/org/opentripplanner/raptor/_data/stoparrival/Transit.java @@ -7,19 +7,20 @@ import org.opentripplanner.raptor.api.view.ArrivalView; import org.opentripplanner.raptor.api.view.TransitPathView; -public class Bus extends AbstractStopArrival implements TransitPathView { +class Transit extends AbstractStopArrival implements TransitPathView { private final TestTripSchedule trip; - public Bus( + Transit( int round, int stop, int arrivalTime, - int cost, + int c1, + int c2, TestTripSchedule trip, ArrivalView previous ) { - super(round, stop, arrivalTime, cost, previous); + super(round, stop, arrivalTime, c1, c2, previous); this.trip = trip; } diff --git a/src/test/java/org/opentripplanner/raptor/_data/transit/TestAccessEgress.java b/src/test/java/org/opentripplanner/raptor/_data/transit/TestAccessEgress.java index ecb077b486e..56957e2e33a 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/transit/TestAccessEgress.java +++ b/src/test/java/org/opentripplanner/raptor/_data/transit/TestAccessEgress.java @@ -176,7 +176,7 @@ public int stop() { } @Override - public int generalizedCost() { + public int c1() { return cost; } diff --git a/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransfer.java b/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransfer.java index faae8696fb4..5645f6342d6 100644 --- a/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransfer.java +++ b/src/test/java/org/opentripplanner/raptor/_data/transit/TestTransfer.java @@ -32,7 +32,7 @@ public int stop() { } @Override - public int generalizedCost() { + public int c1() { return cost; } diff --git a/src/test/java/org/opentripplanner/raptor/api/path/PathTest.java b/src/test/java/org/opentripplanner/raptor/api/path/PathTest.java index 3ad076cd04b..de71574a952 100644 --- a/src/test/java/org/opentripplanner/raptor/api/path/PathTest.java +++ b/src/test/java/org/opentripplanner/raptor/api/path/PathTest.java @@ -10,7 +10,7 @@ import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.BASIC_PATH_AS_STRING; import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.EGRESS_END; import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.RAPTOR_ITERATION_START_TIME; -import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.TOTAL_COST; +import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.TOTAL_C1; import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.basicTripStops; import static org.opentripplanner.raptor._data.transit.TestTripPattern.pattern; @@ -99,7 +99,7 @@ public void listStops() { @Test public void cost() { - assertEquals(TOTAL_COST, subject.c1()); + assertEquals(TOTAL_C1, subject.c1()); } @Test @@ -153,7 +153,7 @@ public void testCountTransfersWithStaySeated() { egress, egressStart, egressEnd, - egress.generalizedCost() + egress.c1() ); var trip3 = TestTripSchedule @@ -195,10 +195,10 @@ public void testCountTransfersWithStaySeated() { access, accessStart, accessEnd, - access.generalizedCost(), + access.c1(), leg2.asTransitLeg() ); - RaptorPath path = new Path<>(accessStart, leg1, TOTAL_COST, 0); + RaptorPath path = new Path<>(accessStart, leg1, TOTAL_C1, 0); assertEquals(0, path.numberOfTransfers()); } @@ -211,7 +211,7 @@ public void testCountTransfersWithTransfer() { egress, egressStart, egressEnd, - egress.generalizedCost() + egress.c1() ); var trip3 = TestTripSchedule @@ -252,10 +252,10 @@ public void testCountTransfersWithTransfer() { access, accessStart, accessEnd, - access.generalizedCost(), + access.c1(), leg2.asTransitLeg() ); - RaptorPath path = new Path<>(accessStart, leg1, TOTAL_COST, 0); + RaptorPath path = new Path<>(accessStart, leg1, TOTAL_C1, 0); assertEquals(1, path.numberOfTransfers()); } } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/A01_SingleRouteTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/A01_SingleRouteTest.java index dc6bdfb6616..a28687bdd2b 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/A01_SingleRouteTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/A01_SingleRouteTest.java @@ -68,7 +68,7 @@ void setup() { } static List testCases() { - var path = "Walk 30s ~ B ~ BUS R1 0:01 0:05 ~ D ~ Walk 20s [0:00:30 0:05:20 4m50s 0tx $940]"; + var path = "Walk 30s ~ B ~ BUS R1 0:01 0:05 ~ D ~ Walk 20s [0:00:30 0:05:20 4m50s Tₓ0 C₁940]"; return RaptorModuleTestCase .of() .addMinDuration("4m50s", TX_0, T00_00, T00_10) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/A04_BoardingTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/A04_BoardingTest.java index fabe4db61ec..ff9b81030aa 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/A04_BoardingTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/A04_BoardingTest.java @@ -94,7 +94,7 @@ static List testCases() { "~ BUS L1_1 0:10 0:18 ~ B " + "~ BUS L2 0:20 0:31 ~ F " + "~ BUS L3_2 0:35 0:40 ~ H " + - "~ Walk 1m [0:09 0:41 32m 2tx]" + "~ Walk 1m [0:09 0:41 32m Tₓ2]" ) // A reverse test on the standard profile is included to demonstrate // that the min-travel-duration and the standard give different results @@ -107,7 +107,7 @@ static List testCases() { "~ BUS L1_2 0:14 0:18 ~ C " + "~ BUS L2 0:21 0:32 ~ G " + "~ BUS L3_3 0:35 0:44 ~ H " + - "~ Walk 1m [0:13 0:45 32m 2tx]" + "~ Walk 1m [0:13 0:45 32m Tₓ2]" ) .add( multiCriteria(), @@ -116,7 +116,7 @@ static List testCases() { "~ BUS L1_2 0:14 0:18 ~ C " + "~ BUS L2 0:21 0:31 ~ F " + "~ BUS L3_2 0:35 0:40 ~ H " + - "~ Walk 1m [0:13 0:41 28m 2tx $3600]" + "~ Walk 1m [0:13 0:41 28m Tₓ2 C₁3_600]" ) .build(); } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/B01_AccessTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/B01_AccessTest.java index 026141e82dd..37814d6c6dc 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/B01_AccessTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/B01_AccessTest.java @@ -64,9 +64,9 @@ void setup() { static List testCases() { var expStd = - "Walk 7m 0:11 0:18 ~ D 0s ~ BUS R1 0:18 0:25 7m ~ F 0s ~ Walk 1s 0:25 0:25:01 [0:11 0:25:01 14m1s 0tx]"; + "Walk 7m 0:11 0:18 ~ D 0s ~ BUS R1 0:18 0:25 7m ~ F 0s ~ Walk 1s 0:25 0:25:01 [0:11 0:25:01 14m1s Tₓ0]"; var expStdOne = - "Walk 1s 0:09:59 0:10 ~ B 0s ~ BUS R1 0:10 0:25 15m ~ F 0s ~ Walk 1s 0:25 0:25:01 [0:09:59 0:25:01 15m2s 0tx]"; + "Walk 1s 0:09:59 0:10 ~ B 0s ~ BUS R1 0:10 0:25 15m ~ F 0s ~ Walk 1s 0:25 0:25:01 [0:09:59 0:25:01 15m2s Tₓ0]"; return RaptorModuleTestCase .of() @@ -77,9 +77,9 @@ static List testCases() { .add(TC_STANDARD_ONE, expStdOne) .add( multiCriteria(), - "Walk 7m 0:11 0:18 $840 ~ D 0s ~ BUS R1 0:18 0:25 7m $1020 ~ F 0s ~ Walk 1s 0:25 0:25:01 $2 [0:11 0:25:01 14m1s 0tx $1862]", - "Walk 4m 0:10 0:14 $480 ~ C 0s ~ BUS R1 0:14 0:25 11m $1260 ~ F 0s ~ Walk 1s 0:25 0:25:01 $2 [0:10 0:25:01 15m1s 0tx $1742]", - "Walk 1s 0:09:59 0:10 $2 ~ B 0s ~ BUS R1 0:10 0:25 15m $1500 ~ F 0s ~ Walk 1s 0:25 0:25:01 $2 [0:09:59 0:25:01 15m2s 0tx $1504]" + "Walk 7m 0:11 0:18 C₁840 ~ D 0s ~ BUS R1 0:18 0:25 7m C₁1_020 ~ F 0s ~ Walk 1s 0:25 0:25:01 C₁2 [0:11 0:25:01 14m1s Tₓ0 C₁1_862]", + "Walk 4m 0:10 0:14 C₁480 ~ C 0s ~ BUS R1 0:14 0:25 11m C₁1_260 ~ F 0s ~ Walk 1s 0:25 0:25:01 C₁2 [0:10 0:25:01 15m1s Tₓ0 C₁1_742]", + "Walk 1s 0:09:59 0:10 C₁2 ~ B 0s ~ BUS R1 0:10 0:25 15m C₁1_500 ~ F 0s ~ Walk 1s 0:25 0:25:01 C₁2 [0:09:59 0:25:01 15m2s Tₓ0 C₁1_504]" ) .build(); } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/B02_EgressTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/B02_EgressTest.java index d156c24c128..b32784c0c99 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/B02_EgressTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/B02_EgressTest.java @@ -58,9 +58,9 @@ void setup() { } static List testCases() { - String expStd = "Walk 20s ~ B ~ BUS R1 0:10 0:20 ~ E ~ Walk 7m [0:09:40 0:27 17m20s 0tx]"; + String expStd = "Walk 20s ~ B ~ BUS R1 0:10 0:20 ~ E ~ Walk 7m [0:09:40 0:27 17m20s Tₓ0]"; String expStdRevOne = - "Walk 20s ~ B ~ BUS R1 0:10 0:28 ~ G ~ Walk 1s [0:09:40 0:28:01 18m21s 0tx]"; + "Walk 20s ~ B ~ BUS R1 0:10 0:28 ~ G ~ Walk 1s [0:09:40 0:28:01 18m21s Tₓ0]"; return RaptorModuleTestCase .of() .addMinDuration("17m20s", TX_0, T00_00, T00_30) @@ -70,9 +70,9 @@ static List testCases() { .add(TC_STANDARD_REV_ONE, expStdRevOne) .add( multiCriteria(), - "Walk 20s ~ B ~ BUS R1 0:10 0:20 ~ E ~ Walk 7m [0:09:40 0:27 17m20s 0tx $2080]", - "Walk 20s ~ B ~ BUS R1 0:10 0:24 ~ F ~ Walk 4m [0:09:40 0:28 18m20s 0tx $1960]", - "Walk 20s ~ B ~ BUS R1 0:10 0:28 ~ G ~ Walk 1s [0:09:40 0:28:01 18m21s 0tx $1722]" + "Walk 20s ~ B ~ BUS R1 0:10 0:20 ~ E ~ Walk 7m [0:09:40 0:27 17m20s Tₓ0 C₁2_080]", + "Walk 20s ~ B ~ BUS R1 0:10 0:24 ~ F ~ Walk 4m [0:09:40 0:28 18m20s Tₓ0 C₁1_960]", + "Walk 20s ~ B ~ BUS R1 0:10 0:28 ~ G ~ Walk 1s [0:09:40 0:28:01 18m21s Tₓ0 C₁1_722]" ) .build(); } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/B03_AccessEgressTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/B03_AccessEgressTest.java index 16c3212c549..8cff8320f37 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/B03_AccessEgressTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/B03_AccessEgressTest.java @@ -67,9 +67,9 @@ public void setup() { /** Only the multi-criteria test-cases differ for timetableView on/off */ private static RaptorModuleTestCaseFactory standardTestCases() { - String expStd = "Walk 7m ~ C ~ BUS R1 0:18 0:32 ~ F ~ Walk 7m [0:11 0:39 28m 0tx]"; - String expStdOne = "Walk 1s ~ A ~ BUS R1 0:10 0:32 ~ F ~ Walk 7m [0:09:59 0:39 29m1s 0tx]"; - String expStdRevOne = "Walk 7m ~ C ~ BUS R1 0:18 0:40 ~ H ~ Walk 1s [0:11 0:40:01 29m1s 0tx]"; + String expStd = "Walk 7m ~ C ~ BUS R1 0:18 0:32 ~ F ~ Walk 7m [0:11 0:39 28m Tₓ0]"; + String expStdOne = "Walk 1s ~ A ~ BUS R1 0:10 0:32 ~ F ~ Walk 7m [0:09:59 0:39 29m1s Tₓ0]"; + String expStdRevOne = "Walk 7m ~ C ~ BUS R1 0:18 0:40 ~ H ~ Walk 1s [0:11 0:40:01 29m1s Tₓ0]"; return RaptorModuleTestCase .of() .withRequest(r -> r.searchParams().timetable(true)) @@ -83,15 +83,15 @@ static List testCases() { return standardTestCases() .add( multiCriteria(), - "Walk 7m ~ C ~ BUS R1 0:18 0:32 ~ F ~ Walk 7m [0:11 0:39 28m 0tx $3120]", - "Walk 4m ~ B ~ BUS R1 0:14 0:32 ~ F ~ Walk 7m [0:10 0:39 29m 0tx $3000]", - "Walk 1s ~ A ~ BUS R1 0:10 0:32 ~ F ~ Walk 7m [0:09:59 0:39 29m1s 0tx $2762]", - "Walk 7m ~ C ~ BUS R1 0:18 0:36 ~ G ~ Walk 4m [0:11 0:40 29m 0tx $3000]", - "Walk 4m ~ B ~ BUS R1 0:14 0:36 ~ G ~ Walk 4m [0:10 0:40 30m 0tx $2880]", - "Walk 1s ~ A ~ BUS R1 0:10 0:36 ~ G ~ Walk 4m [0:09:59 0:40 30m1s 0tx $2642]", - "Walk 7m ~ C ~ BUS R1 0:18 0:40 ~ H ~ Walk 1s [0:11 0:40:01 29m1s 0tx $2762]", - "Walk 4m ~ B ~ BUS R1 0:14 0:40 ~ H ~ Walk 1s [0:10 0:40:01 30m1s 0tx $2642]", - "Walk 1s ~ A ~ BUS R1 0:10 0:40 ~ H ~ Walk 1s [0:09:59 0:40:01 30m2s 0tx $2404]" + "Walk 7m ~ C ~ BUS R1 0:18 0:32 ~ F ~ Walk 7m [0:11 0:39 28m Tₓ0 C₁3_120]", + "Walk 4m ~ B ~ BUS R1 0:14 0:32 ~ F ~ Walk 7m [0:10 0:39 29m Tₓ0 C₁3_000]", + "Walk 1s ~ A ~ BUS R1 0:10 0:32 ~ F ~ Walk 7m [0:09:59 0:39 29m1s Tₓ0 C₁2_762]", + "Walk 7m ~ C ~ BUS R1 0:18 0:36 ~ G ~ Walk 4m [0:11 0:40 29m Tₓ0 C₁3_000]", + "Walk 4m ~ B ~ BUS R1 0:14 0:36 ~ G ~ Walk 4m [0:10 0:40 30m Tₓ0 C₁2_880]", + "Walk 1s ~ A ~ BUS R1 0:10 0:36 ~ G ~ Walk 4m [0:09:59 0:40 30m1s Tₓ0 C₁2_642]", + "Walk 7m ~ C ~ BUS R1 0:18 0:40 ~ H ~ Walk 1s [0:11 0:40:01 29m1s Tₓ0 C₁2_762]", + "Walk 4m ~ B ~ BUS R1 0:14 0:40 ~ H ~ Walk 1s [0:10 0:40:01 30m1s Tₓ0 C₁2_642]", + "Walk 1s ~ A ~ BUS R1 0:10 0:40 ~ H ~ Walk 1s [0:09:59 0:40:01 30m2s Tₓ0 C₁2_404]" ) .build(); } @@ -107,11 +107,11 @@ static List testCasesWithoutTimetable() { .withRequest(r -> r.searchParams().timetable(false)) .add( multiCriteria(), - "Walk 7m ~ C ~ BUS R1 0:18 0:32 ~ F ~ Walk 7m [0:11 0:39 28m 0tx $3120]", - "Walk 4m ~ B ~ BUS R1 0:14 0:32 ~ F ~ Walk 7m [0:10 0:39 29m 0tx $3000]", - "Walk 1s ~ A ~ BUS R1 0:10 0:32 ~ F ~ Walk 7m [0:09:59 0:39 29m1s 0tx $2762]", - "Walk 1s ~ A ~ BUS R1 0:10 0:36 ~ G ~ Walk 4m [0:09:59 0:40 30m1s 0tx $2642]", - "Walk 1s ~ A ~ BUS R1 0:10 0:40 ~ H ~ Walk 1s [0:09:59 0:40:01 30m2s 0tx $2404]" + "Walk 7m ~ C ~ BUS R1 0:18 0:32 ~ F ~ Walk 7m [0:11 0:39 28m Tₓ0 C₁3_120]", + "Walk 4m ~ B ~ BUS R1 0:14 0:32 ~ F ~ Walk 7m [0:10 0:39 29m Tₓ0 C₁3_000]", + "Walk 1s ~ A ~ BUS R1 0:10 0:32 ~ F ~ Walk 7m [0:09:59 0:39 29m1s Tₓ0 C₁2_762]", + "Walk 1s ~ A ~ BUS R1 0:10 0:36 ~ G ~ Walk 4m [0:09:59 0:40 30m1s Tₓ0 C₁2_642]", + "Walk 1s ~ A ~ BUS R1 0:10 0:40 ~ H ~ Walk 1s [0:09:59 0:40:01 30m2s Tₓ0 C₁2_404]" ) .build(); } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/B04_AccessEgressBoardingTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/B04_AccessEgressBoardingTest.java index acb3c647a60..6ac5ff4b028 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/B04_AccessEgressBoardingTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/B04_AccessEgressBoardingTest.java @@ -38,14 +38,14 @@ public class B04_AccessEgressBoardingTest implements RaptorTestConstants { /** Board R1 at first possible stop A (not B) and arrive at stop E (the earliest arrival time) */ private static final String EXP_PATH_BEST_ARRIVAL_TIME = - "Walk 1s ~ A ~ BUS R1 0:10 0:34 ~ E ~ Walk 10s [0:09:59 0:34:10 24m11s 0tx]"; + "Walk 1s ~ A ~ BUS R1 0:10 0:34 ~ E ~ Walk 10s [0:09:59 0:34:10 24m11s Tₓ0]"; /** * Searching in REVERSE we will "board" R1 at the first possible stop F and "alight" at the * optimal stop B (the best "arrival-time"). */ private static final String EXP_PATH_BEST_ARRIVAL_TIME_REVERSE = - "Walk 10s ~ B ~ BUS R1 0:14 0:38 ~ F ~ Walk 1s [0:13:50 0:38:01 24m11s 0tx]"; + "Walk 10s ~ B ~ BUS R1 0:14 0:38 ~ F ~ Walk 1s [0:13:50 0:38:01 24m11s Tₓ0]"; private final TestTransitData data = new TestTransitData(); private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); @@ -80,7 +80,7 @@ void setup() { static List testCases() { var expected = - "Walk 10s ~ B ~ BUS R1 0:14 0:34 ~ E ~ Walk 10s [0:13:50 0:34:10 20m20s 0tx $1840]"; + "Walk 10s ~ B ~ BUS R1 0:14 0:34 ~ E ~ Walk 10s [0:13:50 0:34:10 20m20s Tₓ0 C₁1_840]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/C01_TransferBoardAndAlightSlackTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/C01_TransferBoardAndAlightSlackTest.java index 3fea0bcaee6..18d4d7d5024 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/C01_TransferBoardAndAlightSlackTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/C01_TransferBoardAndAlightSlackTest.java @@ -78,7 +78,7 @@ static List testCases() { "~ BUS R1 0:02:11 0:03:01 ~ C " + "~ BUS R2 0:04:41 0:05:01 ~ D " + "~ Walk 20s " + - "[0:01:11 0:05:31 4m20s 1tx $1510]"; + "[0:01:11 0:05:31 4m20s Tₓ1 C₁1_510]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/C02_OnStreetTransfersTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/C02_OnStreetTransfersTest.java index dbf580a4e67..a482a75c1e9 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/C02_OnStreetTransfersTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/C02_OnStreetTransfersTest.java @@ -79,7 +79,7 @@ static List testCases() { "Walk 30s ~ D ~ " + "BUS R2 0:04 0:05 ~ E ~ " + "Walk 20s " + - "[0:01:30 0:05:20 3m50s 1tx $1510]"; + "[0:01:30 0:05:20 3m50s Tₓ1 C₁1_510]"; return RaptorModuleTestCase .of() .addMinDuration("3m50s", TX_1, T00_00, T00_30) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/C03_OnBoardArrivalDominateTransfersTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/C03_OnBoardArrivalDominateTransfersTest.java index 7459c094e28..2bfc2979f6e 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/C03_OnBoardArrivalDominateTransfersTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/C03_OnBoardArrivalDominateTransfersTest.java @@ -68,7 +68,7 @@ static List testCases() { "BUS R1 0:05 0:08 ~ B ~ " + "BUS R2 0:12 0:15 ~ C ~ " + "Walk 1m " + - "[0:04 0:16 12m 1tx $2040]"; + "[0:04 0:16 12m Tₓ1 C₁2_040]"; return RaptorModuleTestCase .of() @@ -81,8 +81,8 @@ static List testCases() { // stops (at least egress stops) or we can compute paths during the search. The last // solution is probably the one which give the best performance, but the first will make // mc-raptor perform better (tighter heuristics). - .add(TC_MIN_DURATION, "[0:00 0:09 9m 0tx]") - .add(TC_MIN_DURATION_REV, "[0:21 0:30 9m 1tx]") + .add(TC_MIN_DURATION, "[0:00 0:09 9m Tₓ0]") + .add(TC_MIN_DURATION_REV, "[0:21 0:30 9m Tₓ1]") .add(standard(), PathUtils.withoutCost(path)) .add(multiCriteria(), path) .build(); diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/D01_SingeRouteBoardAlightRestrictionsTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/D01_SingeRouteBoardAlightRestrictionsTest.java index af84c28e2cf..a63c208cae3 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/D01_SingeRouteBoardAlightRestrictionsTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/D01_SingeRouteBoardAlightRestrictionsTest.java @@ -72,7 +72,7 @@ void setup() { } static List testCases() { - var path = "Walk 30s ~ B ~ BUS R1 0:01 0:05 ~ D ~ Walk 20s [0:00:30 0:05:20 4m50s 0tx $940]"; + var path = "Walk 30s ~ B ~ BUS R1 0:01 0:05 ~ D ~ Walk 20s [0:00:30 0:05:20 4m50s Tₓ0 C₁940]"; return RaptorModuleTestCase .of() .addMinDuration("4m50s", TX_0, T00_00, T00_10) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/D02_TransitModeReluctanceTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/D02_TransitModeReluctanceTest.java index ffa1dd53bd2..970ae42a3ef 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/D02_TransitModeReluctanceTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/D02_TransitModeReluctanceTest.java @@ -73,12 +73,12 @@ static Stream testCases() { Arguments.of( PREFER_R1, config, - "Walk 30s ~ A ~ BUS R1 0:01 0:02:40 ~ B ~ Walk 20s " + "[0:00:30 0:03 2m30s 0tx $799]" + "Walk 30s ~ A ~ BUS R1 0:01 0:02:40 ~ B ~ Walk 20s " + "[0:00:30 0:03 2m30s Tₓ0 C₁799]" ), Arguments.of( PREFER_R2, config, - "Walk 30s ~ A ~ BUS R2 0:01 0:02:40 ~ B ~ Walk 20s " + "[0:00:30 0:03 2m30s 0tx $789]" + "Walk 30s ~ A ~ BUS R2 0:01 0:02:40 ~ B ~ Walk 20s " + "[0:00:30 0:03 2m30s Tₓ0 C₁789]" ) ) ); diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/D03_UnpreferredRouteTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/D03_UnpreferredRouteTest.java index c8aa5eaf7d8..41f2fb2ca12 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/D03_UnpreferredRouteTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/D03_UnpreferredRouteTest.java @@ -31,10 +31,10 @@ public class D03_UnpreferredRouteTest implements RaptorTestConstants { private static final String EXPECTED = - "Walk 30s ~ A ~ BUS %s 0:01 0:02:40 ~ B ~ Walk 20s " + "[0:00:30 0:03 2m30s 0tx $%d]"; + "Walk 30s ~ A ~ BUS %s 0:01 0:02:40 ~ B ~ Walk 20s " + "[0:00:30 0:03 2m30s Tₓ0 C₁%d]"; private static final FeedScopedId ROUTE_ID_1 = TransitModelForTest.id("1"); private static final FeedScopedId ROUTE_ID_2 = TransitModelForTest.id("2"); - private static final CostLinearFunction UNPREFERRED_COST = CostLinearFunction.of("5m + 1t"); + private static final CostLinearFunction UNPREFERRED_C1 = CostLinearFunction.of("5m + 1t"); private final TestTransitData data = new TestTransitData(); private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); private final RaptorService raptorService = new RaptorService<>( @@ -95,7 +95,7 @@ private void unpreferRoute(FeedScopedId routeId) { } } data.mcCostParamsBuilder().unpreferredPatterns(patterns); - data.mcCostParamsBuilder().unpreferredCost(UNPREFERRED_COST); + data.mcCostParamsBuilder().unpreferredCost(UNPREFERRED_C1); } private static String expected(String route, int cost) { diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/E01_StaySeatedTransferTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/E01_StaySeatedTransferTest.java index cb667ca211e..d1d1f2191f5 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/E01_StaySeatedTransferTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/E01_StaySeatedTransferTest.java @@ -87,7 +87,7 @@ static List testCases() { // Note! The number of transfers is zero with stay-seated/interlining var path = "Walk 30s ~ A ~ BUS R1 0:02 0:05 ~ B ~ BUS R2 0:05 0:10 ~ C ~ Walk 30s " + - "[0:01:10 0:10:40 9m30s 0tx $1230]"; + "[0:01:10 0:10:40 9m30s Tₓ0 C₁1_230]"; return RaptorModuleTestCase .of() .addMinDuration("9m30s", TX_1, T00_00, T00_30) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/E02_GuaranteedWalkTransferTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/E02_GuaranteedWalkTransferTest.java index 128d70705bb..c448560c7fb 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/E02_GuaranteedWalkTransferTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/E02_GuaranteedWalkTransferTest.java @@ -83,7 +83,7 @@ public void setup() { static List testCases() { var path = "Walk 30s ~ A ~ BUS R1 0:02 0:05 ~ B ~ Walk 30s ~ C ~ BUS R2 0:05 0:10 ~ D ~ Walk 30s " + - "[0:01:10 0:10:40 9m30s 1tx $1260]"; + "[0:01:10 0:10:40 9m30s Tₓ1 C₁1_260]"; return RaptorModuleTestCase .of() // BUG! 10 minutes is wrong, it should be 9m30s - Raptor may drop optimal paths, diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/E03_NotAllowedConstrainedTransferTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/E03_NotAllowedConstrainedTransferTest.java index ea81abd0f8c..0866042548d 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/E03_NotAllowedConstrainedTransferTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/E03_NotAllowedConstrainedTransferTest.java @@ -82,7 +82,7 @@ public void setup() { static List testCases() { var path = "Walk 30s ~ A ~ BUS R1 0:02 0:05 ~ B ~ BUS R3 0:15 0:20 ~ C ~ Walk 30s " + - "[0:01:30 0:20:30 19m 1tx $2500]"; + "[0:01:30 0:20:30 19m Tₓ1 C₁2_500]"; return RaptorModuleTestCase .of() .addMinDuration("9m", TX_1, T00_00, T00_30) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F01_AccessWithRidesTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F01_AccessWithRidesTest.java index c9b67eb1924..e93f464826c 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F01_AccessWithRidesTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F01_AccessWithRidesTest.java @@ -37,9 +37,9 @@ public class F01_AccessWithRidesTest implements RaptorTestConstants { private static final int TRANSFER_SLACK = 60; - private static final int COST_ONE_STOP = RaptorCostConverter.toRaptorCost(2 * 60); - private static final int COST_TRANSFER_SLACK = RaptorCostConverter.toRaptorCost(TRANSFER_SLACK); - private static final int COST_ONE_SEC = RaptorCostConverter.toRaptorCost(1); + private static final int C1_ONE_STOP = RaptorCostConverter.toRaptorCost(2 * 60); + private static final int C1_TRANSFER_SLACK = RaptorCostConverter.toRaptorCost(TRANSFER_SLACK); + private static final int C1_ONE_SEC = RaptorCostConverter.toRaptorCost(1); private final TestTransitData data = new TestTransitData(); private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); @@ -61,13 +61,13 @@ void setup() { // All access paths are all pareto-optimal (McRaptor). .addAccessPaths( // lowest num-of-transfers (0) - walk(STOP_B, D10m, COST_ONE_STOP + COST_TRANSFER_SLACK), + walk(STOP_B, D10m, C1_ONE_STOP + C1_TRANSFER_SLACK), // lowest cost - flexAndWalk(STOP_C, D2m, TWO_RIDES, 2 * COST_ONE_STOP - COST_ONE_SEC), + flexAndWalk(STOP_C, D2m, TWO_RIDES, 2 * C1_ONE_STOP - C1_ONE_SEC), // latest departure time - flex(STOP_D, D3m, TWO_RIDES, 3 * COST_ONE_STOP), + flex(STOP_D, D3m, TWO_RIDES, 3 * C1_ONE_STOP), // best on combination of transfers and time - flexAndWalk(STOP_E, D7m, ONE_RIDE, 4 * COST_ONE_STOP) + flexAndWalk(STOP_E, D7m, ONE_RIDE, 4 * C1_ONE_STOP) ) .addEgressPaths(walk(STOP_F, D1m)); @@ -77,24 +77,24 @@ void setup() { } static List testCases() { - String expFlexAccess = "Flex 3m 2x ~ D ~ BUS R1 0:14 0:20 ~ F ~ Walk 1m [0:10 0:21 11m 2tx]"; - String expWalkAccess = "Walk 10m ~ B ~ BUS R1 0:10 0:20 ~ F ~ Walk 1m [0:00 0:21 21m 0tx]"; + String expFlexAccess = "Flex 3m 2x ~ D ~ BUS R1 0:14 0:20 ~ F ~ Walk 1m [0:10 0:21 11m Tₓ2]"; + String expWalkAccess = "Walk 10m ~ B ~ BUS R1 0:10 0:20 ~ F ~ Walk 1m [0:00 0:21 21m Tₓ0]"; return RaptorModuleTestCase .of() // TODO - Why do we get only one result here - when there is 3 different pareto-optimal // - paths - .add(TC_MIN_DURATION, "[0:00 0:11 11m 0tx]") + .add(TC_MIN_DURATION, "[0:00 0:11 11m Tₓ0]") // Return pareto optimal paths with 0, 1 and 2 num-of-transfers - .add(TC_MIN_DURATION_REV, "[0:19 0:30 11m 2tx]", "[0:17 0:30 13m 1tx]", "[0:09 0:30 21m 0tx]") + .add(TC_MIN_DURATION_REV, "[0:19 0:30 11m Tₓ2]", "[0:17 0:30 13m Tₓ1]", "[0:09 0:30 21m Tₓ0]") .add(standard().not(TC_STANDARD_ONE), expFlexAccess) // First boarding wins with one-iteration (apply to min-duration and std-one) .add(TC_STANDARD_ONE, expWalkAccess) .add( multiCriteria(), - "Flex 3m 2x ~ D ~ BUS R1 0:14 0:20 ~ F ~ Walk 1m [0:10 0:21 11m 2tx $1500]", // ldt - "Flex+Walk 2m 2x ~ C ~ BUS R1 0:12 0:20 ~ F ~ Walk 1m [0:09 0:21 12m 2tx $1499]", // cost - "Flex+Walk 7m 1x ~ E ~ BUS R1 0:16 0:20 ~ F ~ Walk 1m [0:08 0:21 13m 1tx $1500]", // tx+time - "Walk 10m ~ B ~ BUS R1 0:10 0:20 ~ F ~ Walk 1m [0:00 0:21 21m 0tx $1500]" // tx + "Flex 3m 2x ~ D ~ BUS R1 0:14 0:20 ~ F ~ Walk 1m [0:10 0:21 11m Tₓ2 C₁1_500]", // ldt + "Flex+Walk 2m 2x ~ C ~ BUS R1 0:12 0:20 ~ F ~ Walk 1m [0:09 0:21 12m Tₓ2 C₁1_499]", // cost + "Flex+Walk 7m 1x ~ E ~ BUS R1 0:16 0:20 ~ F ~ Walk 1m [0:08 0:21 13m Tₓ1 C₁1_500]", // tx+time + "Walk 10m ~ B ~ BUS R1 0:10 0:20 ~ F ~ Walk 1m [0:00 0:21 21m Tₓ0 C₁1_500]" // tx ) .build(); } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F02_EgressWithRidesTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F02_EgressWithRidesTest.java index 5e858039897..87b2237fac8 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F02_EgressWithRidesTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F02_EgressWithRidesTest.java @@ -71,15 +71,15 @@ void setup() { static List testCases() { var prefix = "Walk 1m ~ B ~ BUS R1 0:10 "; - var bestArrivalTime = prefix + "0:14 ~ D ~ Flex 3m 2x [0:09 0:18 9m 2tx $1380]"; - var bestNTransfers = prefix + "0:18 ~ F ~ Walk 10m [0:09 0:28 19m 0tx $2400]"; - var bestCost = prefix + "0:16 ~ E ~ Flex+Walk 1m59s 2x [0:09 0:18:59 9m59s 2tx $1378]"; - var bestTxAndTime = prefix + "0:12 ~ C ~ Flex+Walk 7m 1x [0:09 0:20 11m 1tx $1740]"; + var bestArrivalTime = prefix + "0:14 ~ D ~ Flex 3m 2x [0:09 0:18 9m Tₓ2 C₁1_380]"; + var bestNTransfers = prefix + "0:18 ~ F ~ Walk 10m [0:09 0:28 19m Tₓ0 C₁2_400]"; + var bestCost = prefix + "0:16 ~ E ~ Flex+Walk 1m59s 2x [0:09 0:18:59 9m59s Tₓ2 C₁1_378]"; + var bestTxAndTime = prefix + "0:12 ~ C ~ Flex+Walk 7m 1x [0:09 0:20 11m Tₓ1 C₁1_740]"; return RaptorModuleTestCase .of() - .add(TC_MIN_DURATION, "[0:00 0:09 9m 2tx]", "[0:00 0:11 11m 1tx]", "[0:00 0:19 19m 0tx]") - .add(TC_MIN_DURATION_REV, "[0:21 0:30 9m 0tx]") + .add(TC_MIN_DURATION, "[0:00 0:09 9m Tₓ2]", "[0:00 0:11 11m Tₓ1]", "[0:00 0:19 19m Tₓ0]") + .add(TC_MIN_DURATION_REV, "[0:21 0:30 9m Tₓ0]") .add(standard().not(TC_STANDARD_REV_ONE), withoutCost(bestArrivalTime)) // "First" alighting wins for reverse .add(TC_STANDARD_REV_ONE, withoutCost(bestNTransfers)) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F03_AccessEgressWithRidesBoardAndAlightSlackTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F03_AccessEgressWithRidesBoardAndAlightSlackTest.java index 26a769fc2af..0c6895e7e68 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F03_AccessEgressWithRidesBoardAndAlightSlackTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F03_AccessEgressWithRidesBoardAndAlightSlackTest.java @@ -75,7 +75,7 @@ public void setup() { static List testCases() { var path = "Flex+Walk 2m 1x ~ B ~ BUS R1 0:04 0:06 ~ C ~ Flex 2m 1x " + - "[0:00:30 0:09:10 8m40s 2tx $1360]"; + "[0:00:30 0:09:10 8m40s Tₓ2 C₁1_360]"; return RaptorModuleTestCase .of() // TODO - Alight slack is missing diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F04_AccessEgressWithRidesNoTransitTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F04_AccessEgressWithRidesNoTransitTest.java index e3bde4e53a7..0057b8a1d20 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F04_AccessEgressWithRidesNoTransitTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F04_AccessEgressWithRidesNoTransitTest.java @@ -66,8 +66,8 @@ public void setup() { /* Flex ~ B ~ Walk ~ C ~ Flex */ static List flexTransferFlexTestCases() { - var path = "Flex 2m 1x ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:10 0:20 10m 1tx $1140]"; - var stdPathRev = "Flex 2m 1x ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:20 0:30 10m 1tx]"; + var path = "Flex 2m 1x ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:10 0:20 10m Tₓ1 C₁1_140]"; + var stdPathRev = "Flex 2m 1x ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:20 0:30 10m Tₓ1]"; return RaptorModuleTestCase .of() .withRequest(requestBuilder -> @@ -93,9 +93,9 @@ void flexTransferFlexTest(RaptorModuleTestCase testCase) { static List flexOpeningHoursTransferFlexTestCases() { var path = - "Flex 2m 1x Open(0:12 0:16) ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:12 0:22 10m 1tx $1140]"; + "Flex 2m 1x Open(0:12 0:16) ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:12 0:22 10m Tₓ1 C₁1_140]"; var stdPathRev = - "Flex 2m 1x Open(0:12 0:16) ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:16 0:26 10m 1tx]"; + "Flex 2m 1x Open(0:12 0:16) ~ B ~ Walk 5m ~ C ~ Flex 2m 1x [0:16 0:26 10m Tₓ1]"; return RaptorModuleTestCase .of() .withRequest(requestBuilder -> @@ -130,10 +130,10 @@ static List flexTransferFlexOpeningHoursTestCases() { .addEgressPaths(flex(STOP_C, D2m).openingHours("0:22", "0:26")) ) .addMinDuration("10m", TX_1, T00_10, T00_30) - .add(TC_STANDARD, path + "[0:14 0:24 10m 1tx]") - .add(TC_STANDARD_ONE, path + "[0:10 0:24 14m 1tx]") - .add(standard().reverseOnly(), path + "[0:18 0:28 10m 1tx]") - .add(multiCriteria(), path + "[0:14 0:24 10m 1tx $1140]") + .add(TC_STANDARD, path + "[0:14 0:24 10m Tₓ1]") + .add(TC_STANDARD_ONE, path + "[0:10 0:24 14m Tₓ1]") + .add(standard().reverseOnly(), path + "[0:18 0:28 10m Tₓ1]") + .add(multiCriteria(), path + "[0:14 0:24 10m Tₓ1 C₁1_140]") .build(); } @@ -146,8 +146,8 @@ void flexTransferFlexOpeningHoursTest(RaptorModuleTestCase testCase) { /* Flex+Walk ~ C ~ Flex (No transfer) */ static List flexAndWalkToFlexTestCases() { - var path = "Flex+Walk 7m 1x ~ C ~ Flex 2m 1x [0:10 0:20 10m 1tx $1140]"; - var stdPathRev = "Flex+Walk 7m 1x ~ C ~ Flex 2m 1x [0:20 0:30 10m 1tx]"; + var path = "Flex+Walk 7m 1x ~ C ~ Flex 2m 1x [0:10 0:20 10m Tₓ1 C₁1_140]"; + var stdPathRev = "Flex+Walk 7m 1x ~ C ~ Flex 2m 1x [0:20 0:30 10m Tₓ1]"; return RaptorModuleTestCase .of() .withRequest(requestBuilder -> @@ -172,8 +172,8 @@ void flexAndWalkToFlexTest(RaptorModuleTestCase testCase) { /* Flex ~ C ~ Walk+Flex (No transfer) */ static List flexToFlexAndWalkTestCases() { - var path = "Flex 2m 1x ~ C ~ Flex+Walk 7m 1x [0:10 0:20 10m 1tx $1140]"; - var stdPathRev = "Flex 2m 1x ~ C ~ Flex+Walk 7m 1x [0:20 0:30 10m 1tx]"; + var path = "Flex 2m 1x ~ C ~ Flex+Walk 7m 1x [0:10 0:20 10m Tₓ1 C₁1_140]"; + var stdPathRev = "Flex 2m 1x ~ C ~ Flex+Walk 7m 1x [0:20 0:30 10m Tₓ1]"; return RaptorModuleTestCase .of() .withRequest(requestBuilder -> diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F05_OnBoardAccessEgressAndTransfersTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F05_OnBoardAccessEgressAndTransfersTest.java index 72da3f71145..139185c33fc 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F05_OnBoardAccessEgressAndTransfersTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F05_OnBoardAccessEgressAndTransfersTest.java @@ -57,7 +57,7 @@ public void setup() { static List testCases() { var path = - "Flex 5m 1x ~ A ~ Walk 10s ~ B ~ BUS R1 0:10 0:20 ~ C ~ Walk 10s ~ D ~ Flex 5m 1x [0:03:50 0:26:10 22m20s 2tx $2560]"; + "Flex 5m 1x ~ A ~ Walk 10s ~ B ~ BUS R1 0:10 0:20 ~ C ~ Walk 10s ~ D ~ Flex 5m 1x [0:03:50 0:26:10 22m20s Tₓ2 C₁2_560]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F11_AccessWithRidesMultipleOptimalPathsTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F11_AccessWithRidesMultipleOptimalPathsTest.java index 12c849b7349..fdc7c1dadd2 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F11_AccessWithRidesMultipleOptimalPathsTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F11_AccessWithRidesMultipleOptimalPathsTest.java @@ -92,11 +92,11 @@ static List testCase3mWalkAccess() { var endL2AndWalk = "~ BUS L2 0:15 0:20 ~ E ~ Walk 3m "; // Min-Duration 19m - this is - var flexTransferTransit = startFlexAccess + endWalkAndL3 + "[0:02 0:22 20m 1tx $2580]"; + var flexTransferTransit = startFlexAccess + endWalkAndL3 + "[0:02 0:22 20m Tₓ1 C₁2_580]"; // Best duration 18m, - var transitAndTransit = startWalkAndL1 + endL2AndWalk + "[0:02 0:23 21m 1tx]"; + var transitAndTransit = startWalkAndL1 + endL2AndWalk + "[0:02 0:23 21m Tₓ1]"; // Min-Duration 19m - var flexAndTransit = startFlexAccess + endL2AndWalk + "[0:03 0:23 20m 1tx $2640]"; + var flexAndTransit = startFlexAccess + endL2AndWalk + "[0:03 0:23 20m Tₓ1 C₁2_640]"; return RaptorModuleTestCase .of() @@ -125,11 +125,11 @@ static List testCase1mWalkAccess() { var endL2AndWalk = "~ BUS L2 0:15 0:20 ~ E ~ Walk 1m "; // Min-Duration 19m - this is - var flexTransferTransit = startFlexAccess + endWalkAndL3 + "[0:02 0:22 20m 1tx $2580]"; + var flexTransferTransit = startFlexAccess + endWalkAndL3 + "[0:02 0:22 20m Tₓ1 C₁2_580]"; // Best duration 16m, - var transitAndTransit = startWalkAndL1 + endL2AndWalk + "[0:02 0:21 19m 1tx]"; + var transitAndTransit = startWalkAndL1 + endL2AndWalk + "[0:02 0:21 19m Tₓ1]"; // Min-Duration 17m - var flexAndTransit = startFlexAccess + endL2AndWalk + "[0:03 0:21 18m 1tx $2400]"; + var flexAndTransit = startFlexAccess + endL2AndWalk + "[0:03 0:21 18m Tₓ1 C₁2_400]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/F12_EgressWithRidesMultipleOptimalPathsTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/F12_EgressWithRidesMultipleOptimalPathsTest.java index 12d20f51d01..1ec5399a668 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/F12_EgressWithRidesMultipleOptimalPathsTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/F12_EgressWithRidesMultipleOptimalPathsTest.java @@ -57,15 +57,15 @@ public class F12_EgressWithRidesMultipleOptimalPathsTest implements RaptorTestConstants { private static final String EXPECTED_PATH_FLEX_7M = - "A ~ BUS R2 0:05 0:16 ~ B ~ Walk 2m ~ C ~ Flex 7m 1x [0:05 0:26 21m 1tx $2160]"; + "A ~ BUS R2 0:05 0:16 ~ B ~ Walk 2m ~ C ~ Flex 7m 1x [0:05 0:26 21m Tₓ1 C₁2_160]"; private static final String EXPECTED_PATH_WALK_5M = - "A ~ BUS R1 0:04 0:20 ~ C ~ Walk 5m [0:04 0:25 21m 0tx $2160]"; + "A ~ BUS R1 0:04 0:20 ~ C ~ Walk 5m [0:04 0:25 21m Tₓ0 C₁2_160]"; private static final String EXPECTED_PATH_WALK_7M = - "A ~ BUS R1 0:04 0:20 ~ C ~ Walk 7m [0:04 0:27 23m 0tx $2400]"; + "A ~ BUS R1 0:04 0:20 ~ C ~ Walk 7m [0:04 0:27 23m Tₓ0 C₁2_400]"; - private static final int COST_10m = RaptorCostConverter.toRaptorCost(D10m); + private static final int C1_10m = RaptorCostConverter.toRaptorCost(D10m); private final RaptorService raptorService = new RaptorService<>( RaptorConfig.defaultConfigForTest() @@ -102,10 +102,10 @@ static List withFlexAsBestOptionTestCases() { .of() // with Flex egress as the best destination arrival-time .withRequest(r -> - r.searchParams().addEgressPaths(flex(STOP_C, D7m, 1, COST_10m), walk(STOP_C, D7m)) + r.searchParams().addEgressPaths(flex(STOP_C, D7m, 1, C1_10m), walk(STOP_C, D7m)) ) - .add(TC_MIN_DURATION, "[0:00 0:21 21m 1tx]", "[0:00 0:23 23m 0tx]") - .add(TC_MIN_DURATION_REV, "[0:09 0:30 21m 0tx]") + .add(TC_MIN_DURATION, "[0:00 0:21 21m Tₓ1]", "[0:00 0:23 23m Tₓ0]") + .add(TC_MIN_DURATION_REV, "[0:09 0:30 21m Tₓ0]") .add(TC_STANDARD, withoutCost(EXPECTED_PATH_FLEX_7M, EXPECTED_PATH_WALK_7M)) .add(TC_STANDARD_ONE, withoutCost(EXPECTED_PATH_FLEX_7M)) .add(TC_STANDARD_REV, withoutCost(EXPECTED_PATH_FLEX_7M)) @@ -125,7 +125,7 @@ static List withWalkingAsBestOptionTestCase() { .of() // with walk egress as the best destination arrival-time .withRequest(r -> - r.searchParams().addEgressPaths(flex(STOP_C, D7m, 1, COST_10m), walk(STOP_C, D5m)) + r.searchParams().addEgressPaths(flex(STOP_C, D7m, 1, C1_10m), walk(STOP_C, D5m)) ) .addMinDuration("21m", TX_0, T00_00, T00_30) .add(standard().forwardOnly(), withoutCost(EXPECTED_PATH_WALK_5M)) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/G01_AccessWithOpeningHoursTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/G01_AccessWithOpeningHoursTest.java index a266552a3b1..7f5e5421e79 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/G01_AccessWithOpeningHoursTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/G01_AccessWithOpeningHoursTest.java @@ -91,12 +91,12 @@ public void setup() { private static List openInSearchIntervalCases(String access) { var expected = new ExpectedList( - access + EXP_00_15 + "[0:13 0:31 18m 0tx $1860]", - access + EXP_00_20 + "[0:18 0:36 18m 0tx $1860]", - access + EXP_00_25 + "[0:23 0:41 18m 0tx $1860]", - access + EXP_00_30 + "[0:28 0:46 18m 0tx $1860]", - access + EXP_24_15 + "[0:13+1d 0:31+1d 18m 0tx $1860]", - access + EXP_24_20 + "[0:18+1d 0:36+1d 18m 0tx $1860]" + access + EXP_00_15 + "[0:13 0:31 18m Tₓ0 C₁1_860]", + access + EXP_00_20 + "[0:18 0:36 18m Tₓ0 C₁1_860]", + access + EXP_00_25 + "[0:23 0:41 18m Tₓ0 C₁1_860]", + access + EXP_00_30 + "[0:28 0:46 18m Tₓ0 C₁1_860]", + access + EXP_24_15 + "[0:13+1d 0:31+1d 18m Tₓ0 C₁1_860]", + access + EXP_24_20 + "[0:18+1d 0:36+1d 18m Tₓ0 C₁1_860]" ); return tcBuilderWithMinDuration(T00_00, T24_40) @@ -138,8 +138,8 @@ public void openInSearchIntervalTest(RaptorModuleTestCase testCase) { private static List openInSearchIntervalStartSearchNextDayTestCase() { String access = "Walk 2m Open(0:00 1:00)"; var expected = new ExpectedList( - access + EXP_24_15 + "[0:13+1d 0:31+1d 18m 0tx $1860]", - access + EXP_24_20 + "[0:18+1d 0:36+1d 18m 0tx $1860]" + access + EXP_24_15 + "[0:13+1d 0:31+1d 18m Tₓ0 C₁1_860]", + access + EXP_24_20 + "[0:18+1d 0:36+1d 18m Tₓ0 C₁1_860]" ); return tcBuilderWithMinDuration(T24_10, T24_40) @@ -165,10 +165,10 @@ public void openInSearchIntervalStartSearchNextDayTest(RaptorModuleTestCase test private static List openInSecondHalfTodayTestCase() { String access = "Walk 2m Open(0:23 1:00)"; var expected = new ExpectedList( - access + EXP_00_25 + "[0:23 0:41 18m 0tx $1860]", - access + EXP_00_30 + "[0:28 0:46 18m 0tx $1860]", - access + EXP_24_15 + "[1:00 0:31+1d 23h31m 0tx $85440]", - access + EXP_24_20 + "[1:00 0:36+1d 23h36m 0tx $0000]" + access + EXP_00_25 + "[0:23 0:41 18m Tₓ0 C₁1_860]", + access + EXP_00_30 + "[0:28 0:46 18m Tₓ0 C₁1_860]", + access + EXP_24_15 + "[1:00 0:31+1d 23h31m Tₓ0 C₁85_440]", + access + EXP_24_20 + "[1:00 0:36+1d 23h36m Tₓ0 C₁0_000]" ); return tcBuilderWithMinDuration(T00_00, T24_40) @@ -195,12 +195,12 @@ public void openInSecondHalfTodayTest(RaptorModuleTestCase testCase) { private static List openInFirstHalfIntervalTestCase() { String access = "Walk 2m Open(0:00 0:20)"; var expected = new ExpectedList( - access + EXP_00_15 + "[0:13 0:31 18m 0tx $1860]", - access + EXP_00_20 + "[0:18 0:36 18m 0tx $1860]", - access + EXP_00_25 + "[0:20 0:41 21m 0tx $2040]", - access + EXP_00_30 + "[0:20 0:46 26m 0tx $0000]", - access + EXP_24_15 + "[0:13+1d 0:31+1d 18m 0tx $1860]", - access + EXP_24_20 + "[0:18+1d 0:36+1d 18m 0tx $1860]" + access + EXP_00_15 + "[0:13 0:31 18m Tₓ0 C₁1_860]", + access + EXP_00_20 + "[0:18 0:36 18m Tₓ0 C₁1_860]", + access + EXP_00_25 + "[0:20 0:41 21m Tₓ0 C₁2_040]", + access + EXP_00_30 + "[0:20 0:46 26m Tₓ0 C₁0_000]", + access + EXP_24_15 + "[0:13+1d 0:31+1d 18m Tₓ0 C₁1_860]", + access + EXP_24_20 + "[0:18+1d 0:36+1d 18m Tₓ0 C₁1_860]" ); return tcBuilderWithMinDuration(T00_00, T24_40) @@ -231,8 +231,8 @@ public void openInFirstHalfIntervalTest(RaptorModuleTestCase testCase) { private static List partiallyOpenIntervalTestNextDayTestCase() { String access = "Walk 2m Open(0:18 0:20)"; var expected = new ExpectedList( - access + EXP_24_20 + "[0:18+1d 0:36+1d 18m 0tx $1860]", - access + EXP_24_25 + "[0:20+1d 0:41+1d 21m 0tx $2040]" + access + EXP_24_20 + "[0:18+1d 0:36+1d 18m Tₓ0 C₁1_860]", + access + EXP_24_25 + "[0:20+1d 0:41+1d 21m Tₓ0 C₁2_040]" ); return tcBuilderWithMinDuration(T24_10, T25_00) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/G02_EgressWithOpeningHoursTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/G02_EgressWithOpeningHoursTest.java index 6d0eaf4e162..9498f0b0080 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/G02_EgressWithOpeningHoursTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/G02_EgressWithOpeningHoursTest.java @@ -76,10 +76,10 @@ public void setup() { private static List openNoTimeRestrictionTestCase() { var expected = new ExpectedList( - "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m [0:10 0:22 12m 0tx $1440]", - "A ~ BUS R1 0:20 0:30 ~ B ~ Walk 2m [0:20 0:32 12m 0tx $1440]", - "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m [0:30 0:42 12m 0tx $1440]", - "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m [0:20+1d 0:32+1d 12m 0tx]" + "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m [0:10 0:22 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:20 0:30 ~ B ~ Walk 2m [0:20 0:32 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m [0:30 0:42 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m [0:20+1d 0:32+1d 12m Tₓ0]" ); return RaptorModuleTestCase @@ -105,10 +105,10 @@ void openNoTimeRestrictionTest(RaptorModuleTestCase testCase) { private static List openOneHourTestCase() { var expected = new ExpectedList( - "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m Open(0:00 1:00) [0:10 0:22 12m 0tx $1440]", - "A ~ BUS R1 0:20 0:30 ~ B ~ Walk 2m Open(0:00 1:00) [0:20 0:32 12m 0tx $1440]", - "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m Open(0:00 1:00) [0:30 0:42 12m 0tx $1440]", - "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:00 1:00) [0:20+1d 0:32+1d 12m 0tx $1440]" + "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m Open(0:00 1:00) [0:10 0:22 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:20 0:30 ~ B ~ Walk 2m Open(0:00 1:00) [0:20 0:32 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m Open(0:00 1:00) [0:30 0:42 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:00 1:00) [0:20+1d 0:32+1d 12m Tₓ0 C₁1_440]" ); return RaptorModuleTestCase @@ -133,7 +133,7 @@ void openOneHourTest(RaptorModuleTestCase testCase) { private static List openInWholeSearchIntervalTestNextDayTestCase() { var expected = - "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:00 1:00) [0:20+1d 0:32+1d 12m 0tx $1440]"; + "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:00 1:00) [0:20+1d 0:32+1d 12m Tₓ0 C₁1_440]"; return RaptorModuleTestCase .of() @@ -157,8 +157,8 @@ void openInWholeSearchIntervalTestNextDayTest(RaptorModuleTestCase testCase) { private static List openInFirstHalfIntervalTestCase() { var expected = new ExpectedList( - "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m Open(0:00 0:25) [0:10 0:22 12m 0tx $1440]", - "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m Open(0:00 0:25) [0:30 0:02+1d 23h32m 0tx $85440]" + "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m Open(0:00 0:25) [0:10 0:22 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m Open(0:00 0:25) [0:30 0:02+1d 23h32m Tₓ0 C₁85_440]" ); return RaptorModuleTestCase @@ -183,7 +183,7 @@ void openInFirstHalfIntervalTest(RaptorModuleTestCase testCase) { private static List openInFirstHalfIntervalTestNextDayTestCase() { var expected = - "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:25 0:40) [0:20+1d 0:32+1d 12m 0tx $1440]"; + "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:25 0:40) [0:20+1d 0:32+1d 12m Tₓ0 C₁1_440]"; return RaptorModuleTestCase .of() @@ -209,10 +209,10 @@ void openInFirstHalfIntervalTestNextDayTest(RaptorModuleTestCase testCase) { private static List partiallyOpenIntervalTestCase() { var expected = new ExpectedList( - "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m Open(0:25 0:35) [0:10 0:27 17m 0tx $1740]", - "A ~ BUS R1 0:20 0:30 ~ B ~ Walk 2m Open(0:25 0:35) [0:20 0:32 12m 0tx $1440]", - "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m Open(0:25 0:35) [0:30 0:27+1d 23h57m 0tx $86940]", - "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:25 0:35) [0:20+1d 0:32+1d 12m 0tx]" + "A ~ BUS R1 0:10 0:20 ~ B ~ Walk 2m Open(0:25 0:35) [0:10 0:27 17m Tₓ0 C₁1_740]", + "A ~ BUS R1 0:20 0:30 ~ B ~ Walk 2m Open(0:25 0:35) [0:20 0:32 12m Tₓ0 C₁1_440]", + "A ~ BUS R1 0:30 0:40 ~ B ~ Walk 2m Open(0:25 0:35) [0:30 0:27+1d 23h57m Tₓ0 C₁86_940]", + "A ~ BUS R1 0:20+1d 0:30+1d ~ B ~ Walk 2m Open(0:25 0:35) [0:20+1d 0:32+1d 12m Tₓ0]" ); return RaptorModuleTestCase diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/G03_AccessWithOpeningHoursMultipleOptionsTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/G03_AccessWithOpeningHoursMultipleOptionsTest.java index 32d561b3ab8..3d36b813764 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/G03_AccessWithOpeningHoursMultipleOptionsTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/G03_AccessWithOpeningHoursMultipleOptionsTest.java @@ -65,16 +65,16 @@ public void setup() { static List openInWholeSearchIntervalTestCases() { var expA = - "Walk 1m Open(0:05 0:08) 0:08 0:09 $120 ~ B 1m " + - "~ BUS R1 0:10 0:20 10m $1260 ~ C 0s " + - "~ Walk 2m 0:20 0:22 $240 " + - "[0:08 0:22 14m 0tx $1620]"; + "Walk 1m Open(0:05 0:08) 0:08 0:09 C₁120 ~ B 1m " + + "~ BUS R1 0:10 0:20 10m C₁1_260 ~ C 0s " + + "~ Walk 2m 0:20 0:22 C₁240 " + + "[0:08 0:22 14m Tₓ0 C₁1_620]"; var expB = - "Walk 1m Open(0:10 0:13) 0:13 0:14 $120 ~ B 1m " + - "~ BUS R1 0:15 0:25 10m $1260 ~ C 0s " + - "~ Walk 2m 0:25 0:27 $240 " + - "[0:13 0:27 14m 0tx $1620]"; + "Walk 1m Open(0:10 0:13) 0:13 0:14 C₁120 ~ B 1m " + + "~ BUS R1 0:15 0:25 10m C₁1_260 ~ C 0s " + + "~ Walk 2m 0:25 0:27 C₁240 " + + "[0:13 0:27 14m Tₓ0 C₁1_620]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/G04_EgressWithOpeningHoursMultipleOptionsTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/G04_EgressWithOpeningHoursMultipleOptionsTest.java index ac14b461cab..682fff0d16c 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/G04_EgressWithOpeningHoursMultipleOptionsTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/G04_EgressWithOpeningHoursMultipleOptionsTest.java @@ -61,16 +61,16 @@ public void setup() { static List openInWholeSearchIntervalTestCases() { var expA = - "Walk 2m 0:03 0:05 $240 ~ B 0s " + - "~ BUS R1 0:05 0:15 10m $1200 ~ C 2m " + - "~ Walk 1m Open(0:17 0:19) 0:17 0:18 $240 " + - "[0:03 0:18 15m 0tx $1680]"; + "Walk 2m 0:03 0:05 C₁240 ~ B 0s " + + "~ BUS R1 0:05 0:15 10m C₁1_200 ~ C 2m " + + "~ Walk 1m Open(0:17 0:19) 0:17 0:18 C₁240 " + + "[0:03 0:18 15m Tₓ0 C₁1_680]"; var expB = - "Walk 2m 0:08 0:10 $240 ~ B 0s " + - "~ BUS R1 0:10 0:20 10m $1200 ~ C 2m " + - "~ Walk 1m Open(0:22 0:24) 0:22 0:23 $240 " + - "[0:08 0:23 15m 0tx $1680]"; + "Walk 2m 0:08 0:10 C₁240 ~ B 0s " + + "~ BUS R1 0:10 0:20 10m C₁1_200 ~ C 2m " + + "~ Walk 1m Open(0:22 0:24) 0:22 0:23 C₁240 " + + "[0:08 0:23 15m Tₓ0 C₁1_680]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/G05_ClosedAccessOpeningHoursTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/G05_ClosedAccessOpeningHoursTest.java index 9a464b2d1b4..332f49c1f8f 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/G05_ClosedAccessOpeningHoursTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/G05_ClosedAccessOpeningHoursTest.java @@ -53,7 +53,7 @@ public void setup() { } static List testCases() { - var expected = "Walk 7m ~ A ~ BUS R1 0:10 0:20 ~ E [0:03 0:20 17m 0tx $2040]"; + var expected = "Walk 7m ~ A ~ BUS R1 0:10 0:20 ~ E [0:03 0:20 17m Tₓ0 C₁2_040]"; return RaptorModuleTestCase .of() .withRequest(r -> r.searchParams().addAccessPaths(walk(STOP_B, D2m))) diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/G06_ClosedEgressOpeningHoursTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/G06_ClosedEgressOpeningHoursTest.java index 15c1c6c9933..9b828d03de3 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/G06_ClosedEgressOpeningHoursTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/G06_ClosedEgressOpeningHoursTest.java @@ -53,7 +53,7 @@ public void setup() { } static List testCases() { - var expected = "A ~ BUS R1 0:05 0:10 ~ E ~ Walk 5m [0:05 0:15 10m 0tx $1500]"; + var expected = "A ~ BUS R1 0:05 0:10 ~ E ~ Walk 5m [0:05 0:15 10m Tₓ0 C₁1_500]"; return RaptorModuleTestCase .of() diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/H11_GuaranteedTransferWithFlexAccessTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/H11_GuaranteedTransferWithFlexAccessTest.java index 36281346e66..9cf2aaf7b82 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/H11_GuaranteedTransferWithFlexAccessTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/H11_GuaranteedTransferWithFlexAccessTest.java @@ -35,7 +35,7 @@ */ public class H11_GuaranteedTransferWithFlexAccessTest implements RaptorTestConstants { - private static final int COST_ONE_STOP = RaptorCostConverter.toRaptorCost(2 * 60); + private static final int C1_ONE_STOP = RaptorCostConverter.toRaptorCost(2 * 60); private final TestTransitData data = new TestTransitData(); private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); @@ -58,7 +58,7 @@ public void setup() { requestBuilder .searchParams() - .addAccessPaths(flex(STOP_A, D3m, ONE_RIDE, 2 * COST_ONE_STOP)) + .addAccessPaths(flex(STOP_A, D3m, ONE_RIDE, 2 * C1_ONE_STOP)) .addEgressPaths(walk(STOP_D, D1m)); requestBuilder @@ -77,12 +77,12 @@ static List testCases() { "~ BUS R1 0:30 0:45 ~ C " + "~ BUS R2 0:45 0:55 ~ D " + "~ Walk 1m " + - "[0:16 0:56 40m 2tx $3820]"; + "[0:16 0:56 40m Tₓ2 C₁3_820]"; return RaptorModuleTestCase .of() - .add(TC_MIN_DURATION, "[0:00 0:40 40m 2tx]") - .add(TC_MIN_DURATION_REV, "[0:20 1:00 40m 2tx]") + .add(TC_MIN_DURATION, "[0:00 0:40 40m Tₓ2]") + .add(TC_MIN_DURATION_REV, "[0:20 1:00 40m Tₓ2]") .add(standard(), withoutCost(expected)) .add(multiCriteria(), expected) .build(); diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/J01_PassThroughTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/J01_PassThroughTest.java index b15a0a46aaf..d37a1adf61f 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/J01_PassThroughTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/J01_PassThroughTest.java @@ -110,7 +110,7 @@ void passThroughPointOnEgress() { // Verify that only the journey with pass-through stop point is included in response assertEquals( - "Walk 30s ~ A ~ BUS R2 0:02 0:50 ~ D ~ Walk 30s [0:01:30 0:50:30 49m 0tx $3600]", + "Walk 30s ~ A ~ BUS R2 0:02 0:50 ~ D ~ Walk 30s [0:01:30 0:50:30 49m Tₓ0 C₁3_600 C₂1]", pathsToString(raptorService.route(requestBuilder.build(), data)) ); } @@ -144,7 +144,7 @@ void passThroughPointOnAccess() { // Verify that only the journey with pass-through stop point is included in response assertEquals( - "Walk 30s ~ A ~ BUS R2 0:02 0:50 ~ D ~ Walk 30s [0:01:30 0:50:30 49m 0tx $3600]", + "Walk 30s ~ A ~ BUS R2 0:02 0:50 ~ D ~ Walk 30s [0:01:30 0:50:30 49m Tₓ0 C₁3_600 C₂1]", pathsToString(raptorService.route(requestBuilder.build(), data)) ); } @@ -175,7 +175,7 @@ void passThroughPointInTheMiddle() { // Verify that only the journey with pass-through stop point is included in response assertEquals( - "Walk 30s ~ A ~ BUS R2 0:02 0:50 ~ D ~ Walk 30s [0:01:30 0:50:30 49m 0tx $3600]", + "Walk 30s ~ A ~ BUS R2 0:02 0:50 ~ D ~ Walk 30s [0:01:30 0:50:30 49m Tₓ0 C₁3_600 C₂1]", pathsToString(raptorService.route(requestBuilder.build(), data)) ); } @@ -208,7 +208,7 @@ void multiplePassThroughPoints() { // Verify that Raptor generated journey with a transfer to r2 so that both pass-through points // are included assertEquals( - "Walk 30s ~ A ~ BUS R1 0:02 0:10 ~ C ~ BUS R2 0:15 0:50 ~ F ~ Walk 30s [0:01:30 0:50:30 49m 1tx $4300]", + "Walk 30s ~ A ~ BUS R1 0:02 0:10 ~ C ~ BUS R2 0:15 0:50 ~ F ~ Walk 30s [0:01:30 0:50:30 49m Tₓ1 C₁4_300 C₂2]", pathsToString(raptorService.route(requestBuilder.build(), data)) ); } @@ -237,7 +237,7 @@ void passThroughOrder() { // Verify that only route with correct pass-through order is returned assertEquals( - "Walk 30s ~ A ~ BUS R1 0:05 0:20 ~ D ~ Walk 30s [0:04:30 0:20:30 16m 0tx $1620]", + "Walk 30s ~ A ~ BUS R1 0:05 0:20 ~ D ~ Walk 30s [0:04:30 0:20:30 16m Tₓ0 C₁1_620 C₂2]", pathsToString(raptorService.route(requestBuilder.build(), data)) ); } @@ -270,8 +270,9 @@ void passThroughGroup() { // Verify that both routes are included as a valid result assertEquals( """ - Walk 2m ~ B ~ BUS R2 0:05 0:14 ~ E ~ Walk 30s [0:03 0:14:30 11m30s 0tx $1440] - Walk 30s ~ A ~ BUS R1 0:04 0:15 ~ E ~ Walk 30s [0:03:30 0:15:30 12m 0tx $1380]""", + Walk 2m ~ B ~ BUS R2 0:05 0:14 ~ E ~ Walk 30s [0:03 0:14:30 11m30s Tₓ0 C₁1_440 C₂1] + Walk 30s ~ A ~ BUS R1 0:04 0:15 ~ E ~ Walk 30s [0:03:30 0:15:30 12m Tₓ0 C₁1_380 C₂1] + """.trim(), pathsToString(raptorService.route(requestBuilder.build(), data)) ); } diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/J01_SearchWindowAccessSlack.java b/src/test/java/org/opentripplanner/raptor/moduletests/J01_SearchWindowAccessSlack.java index 145119b9cc9..8caa3a862ca 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/J01_SearchWindowAccessSlack.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/J01_SearchWindowAccessSlack.java @@ -65,11 +65,11 @@ void setup() { } static List testCases() { - var path = "Walk 1m ~ A ~ BUS R1 0:10 0:20 ~ B ~ Walk 30s [0:09 0:20:30 11m30s 0tx $1380]"; + var path = "Walk 1m ~ A ~ BUS R1 0:10 0:20 ~ B ~ Walk 30s [0:09 0:20:30 11m30s Tₓ0 C₁1_380]"; return RaptorModuleTestCase .of() - .add(TC_MIN_DURATION, "[0:09 0:20:30 11m30s 0tx]") - .add(TC_MIN_DURATION_REV, "[0:18:30 0:30 11m30s 0tx]") + .add(TC_MIN_DURATION, "[0:09 0:20:30 11m30s Tₓ0]") + .add(TC_MIN_DURATION_REV, "[0:18:30 0:30 11m30s Tₓ0]") .add(standard(), PathUtils.withoutCost(path)) .add(multiCriteria(), path) .build(); diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/K01_TransitPriorityTest.java b/src/test/java/org/opentripplanner/raptor/moduletests/K01_TransitPriorityTest.java index 216b3428f7a..be544f26a11 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/K01_TransitPriorityTest.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/K01_TransitPriorityTest.java @@ -59,7 +59,7 @@ public DominanceFunction dominanceFunction() { GROUP_A, GROUP_C ); - private static final int COST_SLACK_90s = RaptorCostConverter.toRaptorCost(90); + private static final int C1_SLACK_90s = RaptorCostConverter.toRaptorCost(90); private final TestTransitData data = new TestTransitData(); private final RaptorRequestBuilder requestBuilder = new RaptorRequestBuilder<>(); @@ -96,7 +96,7 @@ private void prepareRequest() { requestBuilder.withMultiCriteria(mc -> // Raptor cost 9000 ~= 90 seconds slack mc - .withRelaxC1(value -> value + COST_SLACK_90s) + .withRelaxC1(value -> value + C1_SLACK_90s) .withTransitPriorityCalculator(PRIORITY_GROUP_CALCULATOR) ); // Add 1 second access/egress paths @@ -109,8 +109,8 @@ public void transitPriority() { // We expect L1 & L2 but not L3, since the cost of L3 is > $90.00. assertEquals( """ - Walk 1s ~ B ~ BUS L1 0:02 0:12 ~ C ~ Walk 1s [0:01:59 0:12:01 10m2s 0tx $1204] - Walk 1s ~ B ~ BUS L2 0:02 0:13 ~ C ~ Walk 1s [0:01:59 0:13:01 11m2s 0tx $1264] + Walk 1s ~ B ~ BUS L1 0:02 0:12 ~ C ~ Walk 1s [0:01:59 0:12:01 10m2s Tₓ0 C₁1_204 C₂1] + Walk 1s ~ B ~ BUS L2 0:02 0:13 ~ C ~ Walk 1s [0:01:59 0:13:01 11m2s Tₓ0 C₁1_264 C₂2] """.trim(), pathsToString(raptorService.route(requestBuilder.build(), data)) ); diff --git a/src/test/java/org/opentripplanner/raptor/moduletests/support/ModuleTestDebugLogging.java b/src/test/java/org/opentripplanner/raptor/moduletests/support/ModuleTestDebugLogging.java index 6dac5975d6f..921568e9b0b 100644 --- a/src/test/java/org/opentripplanner/raptor/moduletests/support/ModuleTestDebugLogging.java +++ b/src/test/java/org/opentripplanner/raptor/moduletests/support/ModuleTestDebugLogging.java @@ -14,12 +14,12 @@ *
  * **  RUN RAPTOR FOR MINUTE: 0:09  **
  *
- * ARRIVAL  |   LEG   | RND |  STOP |  ARRIVE  |    COST   | TRIP | DETAILS
+ * ARRIVAL  |   LEG   | RND |  STOP |  ARRIVE  |    C1     | TRIP | DETAILS
  *  Accept  |  Access |   0 |     2 | 00:09:30 |    12 000 |      | Accepted element: Walk 30s ~ 2 (cost: 12000)
  *
  * **  RUN RAPTOR FOR MINUTE: 0:08  **
  *
- * ARRIVAL  |   LEG   | RND |  STOP |  ARRIVE  |    COST   | TRIP | DETAILS
+ * ARRIVAL  |   LEG   | RND |  STOP |  ARRIVE  |    C1     | TRIP | DETAILS
  *   Drop   |  Access |   0 |     2 | 00:09:30 |    12 000 |      | Droped element: Walk 30s ~ 2 (cost: 12000)
  *   ->by   |  Access |   0 |     2 | 00:08:30 |    12 000 |      | ->by element: Walk 30s ~ 2 (cost: 12000)
  *  Accept  |  Access |   0 |     2 | 00:08:30 |    12 000 |      | Accepted element: Walk 30s ~ 2 (cost: 12000)
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/StopArrivalStateParetoSetTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/StopArrivalStateParetoSetTest.java
index 7a07a08c445..e9c39ba6bbf 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/StopArrivalStateParetoSetTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/StopArrivalStateParetoSetTest.java
@@ -44,27 +44,27 @@ public class StopArrivalStateParetoSetTest {
   private static final int STOP_6 = 6;
 
   // Make sure all "base" arrivals have the same cost
-  private static final int BASE_COST = 1;
+  private static final int BASE_C1 = 1;
 
   private static final StopArrivalFactoryC1 STOP_ARRIVAL_FACTORY = new StopArrivalFactoryC1<>();
   private static final McStopArrival ACCESS_ARRIVAL = newAccessStopState(
     999,
     5,
-    BASE_COST
+    BASE_C1
   );
 
   private static final McStopArrival TRANSIT_L1 = newTransitStopState(
     ROUND_1,
     998,
     10,
-    BASE_COST
+    BASE_C1
   );
 
   private static final McStopArrival TRANSIT_L2 = newTransitStopState(
     ROUND_2,
     997,
     20,
-    BASE_COST
+    BASE_C1
   );
   public static final ArrivalParetoSetComparatorFactory> COMPARATOR_FACTORY = ArrivalParetoSetComparatorFactory.factory(
     RelaxFunction.NORMAL,
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactoryTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactoryTest.java
index 55b96421316..9b6311b58bc 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactoryTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/ArrivalParetoSetComparatorFactoryTest.java
@@ -5,7 +5,6 @@
 
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.raptor._data.transit.TestTripSchedule;
-import org.opentripplanner.raptor.api.model.DominanceFunction;
 import org.opentripplanner.raptor.api.model.GeneralizedCostRelaxFunction;
 import org.opentripplanner.raptor.api.model.PathLegType;
 import org.opentripplanner.raptor.api.model.RelaxFunction;
@@ -15,8 +14,8 @@ class ArrivalParetoSetComparatorFactoryTest {
   private static final int STOP = 9;
   private static final boolean ARRIVED_ON_BOARD = true;
   private static final boolean ARRIVED_ON_FOOT = false;
-  private static final int COST_100 = 100;
-  private static final int COST_777 = 777;
+  private static final int C1_100 = 100;
+  private static final int C1_777 = 777;
   private static final int PARETO_ROUND_ONE = 1;
   private static final int PARETO_ROUND_TWO = 2;
   private static final int ARRIVAL_TIME_EARLY = 12;
@@ -39,8 +38,8 @@ void compareArrivalTimeRoundAndCost() {
       comparatorC1
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_777, ARRIVED_ON_FOOT)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_777, ARRIVED_ON_FOOT)
         )
     );
     // Arrival-time is better
@@ -48,8 +47,8 @@ void compareArrivalTimeRoundAndCost() {
       comparatorC1
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_777, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_777, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Pareto-round is better
@@ -57,8 +56,8 @@ void compareArrivalTimeRoundAndCost() {
       comparatorC1
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // C1 is better
@@ -66,8 +65,8 @@ void compareArrivalTimeRoundAndCost() {
       comparatorC1
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_BOARD)
         )
     );
   }
@@ -79,8 +78,8 @@ void compareArrivalTimeRoundAndCostWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_FOOT)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_FOOT)
         )
     );
     // Arrival-time is better
@@ -88,8 +87,8 @@ void compareArrivalTimeRoundAndCostWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_777, COST_100, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_777, C1_100, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Pareto-round is better
@@ -97,8 +96,8 @@ void compareArrivalTimeRoundAndCostWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // C1 is better
@@ -106,8 +105,8 @@ void compareArrivalTimeRoundAndCostWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_BOARD)
         )
     );
 
@@ -116,8 +115,8 @@ void compareArrivalTimeRoundAndCostWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
   }
@@ -129,8 +128,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrivalWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Arrival-time is better
@@ -138,8 +137,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrivalWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_777, COST_100, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_777, C1_100, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Pareto-round is better
@@ -147,8 +146,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrivalWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // C1 is better
@@ -156,8 +155,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrivalWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_100, COST_100, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_100, C1_100, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Arrived on-board is better
@@ -165,8 +164,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrivalWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_777, COST_100, ARRIVED_ON_BOARD),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_FOOT)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_777, C1_100, ARRIVED_ON_BOARD),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_FOOT)
         )
     );
     // C2 is better
@@ -174,8 +173,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrivalWithC2() {
       comparatorC1AndC2
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_100, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_100, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
   }
@@ -187,8 +186,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrival() {
       comparatorC1
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_777, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_777, ARRIVED_ON_BOARD)
         )
     );
     // Arrival-time is better
@@ -196,8 +195,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrival() {
       comparatorC1
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_777, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_777, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Pareto-round is better
@@ -205,8 +204,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrival() {
       comparatorC1
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_777, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_100, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_777, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_100, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // C1 is better
@@ -214,8 +213,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrival() {
       comparatorC1
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_100, COST_777, ARRIVED_ON_FOOT),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_BOARD)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_100, C1_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_BOARD)
         )
     );
     // Arrived on-board is better
@@ -223,8 +222,8 @@ void compareArrivalTimeRoundCostAndOnBoardArrival() {
       comparatorC1
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_777, COST_777, ARRIVED_ON_BOARD),
-          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_FOOT)
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_777, C1_777, ARRIVED_ON_BOARD),
+          new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_FOOT)
         )
     );
   }
@@ -239,7 +238,7 @@ void compareRelaxedC1Test() {
       ARRIVAL_TIME_EARLY,
       PARETO_ROUND_ONE,
       bestC1,
-      COST_100,
+      C1_100,
       ARRIVED_ON_BOARD
     );
 
@@ -249,7 +248,7 @@ void compareRelaxedC1Test() {
       subject
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, rejectC1, COST_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, rejectC1, C1_777, ARRIVED_ON_FOOT),
           referenceArrival
         )
     );
@@ -257,7 +256,7 @@ void compareRelaxedC1Test() {
       subject
         .compareArrivalTimeRoundAndCost()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, okC1, COST_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, okC1, C1_777, ARRIVED_ON_FOOT),
           referenceArrival
         )
     );
@@ -267,7 +266,7 @@ void compareRelaxedC1Test() {
       subject
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, rejectC1, COST_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, rejectC1, C1_777, ARRIVED_ON_FOOT),
           referenceArrival
         )
     );
@@ -275,7 +274,7 @@ void compareRelaxedC1Test() {
       subject
         .compareArrivalTimeRoundCostAndOnBoardArrival()
         .leftDominanceExist(
-          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, okC1, COST_777, ARRIVED_ON_FOOT),
+          new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, okC1, C1_777, ARRIVED_ON_FOOT),
           referenceArrival
         )
     );
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivalTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivalTest.java
index ee74e11ff0f..64593a91b2a 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivalTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/McStopArrivalTest.java
@@ -14,8 +14,8 @@ class McStopArrivalTest {
   private static final int STOP = 9;
   private static final boolean ARRIVED_ON_BOARD = true;
   private static final boolean ARRIVED_ON_FOOT = false;
-  private static final int COST_100 = 100;
-  private static final int COST_777 = 777;
+  private static final int C1_100 = 100;
+  private static final int C1_777 = 777;
   private static final int PARETO_ROUND_ONE = 1;
   private static final int PARETO_ROUND_TWO = 2;
   private static final int ARRIVAL_TIME_EARLY = 12;
@@ -26,29 +26,29 @@ void testCompareBase() {
     // Same values for arrival-time, pareto-round and c1. Ignore c2 and arrivedOnBoard
     assertFalse(
       McStopArrival.compareBase(
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_777, ARRIVED_ON_FOOT)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_777, ARRIVED_ON_FOOT)
       )
     );
     // Arrival-time is better
     assertTrue(
       McStopArrival.compareBase(
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_777, COST_777, ARRIVED_ON_FOOT),
-        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_777, C1_777, ARRIVED_ON_FOOT),
+        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD)
       )
     );
     // Pareto-round is better
     assertTrue(
       McStopArrival.compareBase(
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_777, ARRIVED_ON_FOOT),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, COST_100, COST_100, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_777, ARRIVED_ON_FOOT),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, C1_100, C1_100, ARRIVED_ON_BOARD)
       )
     );
     // C1 is better
     assertTrue(
       McStopArrival.compareBase(
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_777, ARRIVED_ON_FOOT),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_777, COST_100, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_777, ARRIVED_ON_FOOT),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_777, C1_100, ARRIVED_ON_BOARD)
       )
     );
   }
@@ -58,15 +58,15 @@ void testCompareArrivedOnBoard() {
     // Same values for arrivedOnBoard. Ignore arrival-time, pareto-round, c1 and c2
     assertFalse(
       McStopArrival.compareArrivedOnBoard(
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_777, COST_777, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_777, C1_777, ARRIVED_ON_BOARD)
       )
     );
     // Arrived on-board is better
     assertTrue(
       McStopArrival.compareArrivedOnBoard(
-        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, COST_777, COST_777, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, COST_100, COST_100, ARRIVED_ON_FOOT)
+        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_TWO, C1_777, C1_777, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, C1_100, C1_100, ARRIVED_ON_FOOT)
       )
     );
   }
@@ -83,7 +83,7 @@ void testRelaxedCompareBase() {
       ARRIVAL_TIME_EARLY,
       PARETO_ROUND_ONE,
       bestC1,
-      COST_100,
+      C1_100,
       ARRIVED_ON_BOARD
     );
 
@@ -92,8 +92,8 @@ void testRelaxedCompareBase() {
     assertFalse(
       McStopArrival.relaxedCompareBase(
         relaxC1,
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, rejectC1, COST_100, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, bestC1, COST_777, ARRIVED_ON_FOOT)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, rejectC1, C1_100, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, bestC1, C1_777, ARRIVED_ON_FOOT)
       )
     );
 
@@ -101,8 +101,8 @@ void testRelaxedCompareBase() {
     assertTrue(
       McStopArrival.relaxedCompareBase(
         relaxC1,
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, rejectC1, COST_100, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, bestC1, COST_100, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, rejectC1, C1_100, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_LATE, PARETO_ROUND_ONE, bestC1, C1_100, ARRIVED_ON_BOARD)
       )
     );
 
@@ -110,16 +110,16 @@ void testRelaxedCompareBase() {
     assertTrue(
       McStopArrival.relaxedCompareBase(
         relaxC1,
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, rejectC1, COST_100, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, bestC1, COST_100, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, rejectC1, C1_100, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_TWO, bestC1, C1_100, ARRIVED_ON_BOARD)
       )
     );
     // C1 is better, other the same
     assertTrue(
       McStopArrival.relaxedCompareBase(
         relaxC1,
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, okC1, COST_100, ARRIVED_ON_BOARD),
-        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, bestC1, COST_100, ARRIVED_ON_BOARD)
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, okC1, C1_100, ARRIVED_ON_BOARD),
+        new A(ARRIVAL_TIME_EARLY, PARETO_ROUND_ONE, bestC1, C1_100, ARRIVED_ON_BOARD)
       )
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrivalTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrivalTest.java
index 59a9278d638..7abb1910ed9 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrivalTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/AccessStopArrivalTest.java
@@ -11,6 +11,7 @@
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.raptor._data.transit.TestAccessEgress;
 import org.opentripplanner.raptor.api.model.RaptorAccessEgress;
+import org.opentripplanner.raptor.api.model.RaptorConstants;
 import org.opentripplanner.raptor.api.model.RaptorTripSchedule;
 import org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.McStopArrival;
 
@@ -21,7 +22,7 @@ class AccessStopArrivalTest {
   private static final int ACCESS_DURATION = 10 * 60;
   private static final int ALIGHT_TIME = DEPARTURE_TIME + ACCESS_DURATION;
   private static final TestAccessEgress WALK = TestAccessEgress.walk(ALIGHT_STOP, ACCESS_DURATION);
-  private static final int COST = WALK.generalizedCost();
+  private static final int C1 = WALK.c1();
 
   private final AccessStopArrival subject = new AccessStopArrival<>(
     DEPARTURE_TIME,
@@ -46,12 +47,12 @@ public void arrivalTime() {
 
   @Test
   public void c1() {
-    assertEquals(COST, subject.c1());
+    assertEquals(C1, subject.c1());
   }
 
   @Test
   public void c2() {
-    assertThrows(UnsupportedOperationException.class, subject::c2);
+    assertEquals(RaptorConstants.NOT_SET, subject.c2());
   }
 
   @Test
@@ -79,7 +80,7 @@ public void hashCodeThrowsExceptionByDesign() {
   @Test
   public void testToString() {
     assertEquals(
-      "Access { stop: 100, arrival: [8:10 $1200], path: Walk 10m $1200 ~ 100 }",
+      "Access { stop: 100, arrival: [8:10 C₁1_200], path: Walk 10m C₁1_200 ~ 100 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/StopArrivalFactoryC1Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/StopArrivalFactoryC1Test.java
index 00d0ce5b523..d47edf1c58f 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/StopArrivalFactoryC1Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/StopArrivalFactoryC1Test.java
@@ -1,8 +1,6 @@
 package org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.c1;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.framework.time.DurationUtils;
@@ -11,6 +9,7 @@
 import org.opentripplanner.raptor._data.transit.TestTransfer;
 import org.opentripplanner.raptor._data.transit.TestTripPattern;
 import org.opentripplanner.raptor._data.transit.TestTripSchedule;
+import org.opentripplanner.raptor.api.model.RaptorConstants;
 import org.opentripplanner.raptor.api.view.PatternRideView;
 import org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.McStopArrival;
 import org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c1.PatternRideC1;
@@ -78,13 +77,12 @@ public void testCreateAccessStopArrival() {
     var stopArrival = accessArrival();
 
     assertEquals(STOP_A, stopArrival.stop());
-    assertEquals(ACCESS.generalizedCost(), stopArrival.c1());
+    assertEquals(ACCESS.c1(), stopArrival.c1());
     assertEquals(ACCESS_DURATION, stopArrival.travelDuration());
     assertEquals(ORIGIN_DEPARTURE_TIME + ACCESS_DURATION, stopArrival.arrivalTime());
 
     // c2 not supported
-    assertFalse(stopArrival.supportsC2());
-    assertThrows(UnsupportedOperationException.class, stopArrival::c2);
+    assertEquals(RaptorConstants.NOT_SET, stopArrival.c2());
   }
 
   @Test
@@ -97,8 +95,7 @@ public void testCreateTransitStopArrival() {
     assertEquals(STOP_ARRIVAL_TRANSIT_TIME - ORIGIN_DEPARTURE_TIME, stopArrival.travelDuration());
 
     // c2 not supported
-    assertFalse(stopArrival.supportsC2());
-    assertThrows(UnsupportedOperationException.class, stopArrival::c2);
+    assertEquals(RaptorConstants.NOT_SET, stopArrival.c2());
   }
 
   @Test
@@ -107,7 +104,7 @@ public void testCreateTransferStopArrival() {
     var stopArrival = transferArrival(prevArrival);
 
     assertEquals(STOP_C, stopArrival.stop());
-    assertEquals(prevArrival.c1() + TRANSFER.generalizedCost(), stopArrival.c1());
+    assertEquals(prevArrival.c1() + TRANSFER.c1(), stopArrival.c1());
     assertEquals(
       prevArrival.arrivalTime() + TRANSFER.durationInSeconds(),
       stopArrival.arrivalTime()
@@ -115,7 +112,6 @@ public void testCreateTransferStopArrival() {
     assertEquals(DurationUtils.durationInSeconds("11m30s"), stopArrival.travelDuration());
 
     // c2 not supported
-    assertFalse(stopArrival.supportsC2());
-    assertThrows(UnsupportedOperationException.class, stopArrival::c2);
+    assertEquals(RaptorConstants.NOT_SET, stopArrival.c2());
   }
 }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrivalTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrivalTest.java
index 2e5ee35d846..e3baf5e797b 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrivalTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransferStopArrivalTest.java
@@ -3,7 +3,6 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.opentripplanner.raptor.api.model.PathLegType.TRANSFER;
 import static org.opentripplanner.raptor.api.model.PathLegType.TRANSIT;
@@ -11,6 +10,7 @@
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.raptor._data.transit.TestAccessEgress;
 import org.opentripplanner.raptor._data.transit.TestTransfer;
+import org.opentripplanner.raptor.api.model.RaptorConstants;
 import org.opentripplanner.raptor.api.model.RaptorTripSchedule;
 
 class TransferStopArrivalTest {
@@ -24,13 +24,13 @@ class TransferStopArrivalTest {
     ACCESS_TO_STOP,
     ACCESS_DURATION
   );
-  private static final int ACCESS_COST = ACCESS_WALK.generalizedCost();
+  private static final int ACCESS_C1 = ACCESS_WALK.c1();
 
   private static final int TRANSIT_TO_STOP = 101;
   private static final int TRANSIT_BOARD_TIME = 9 * 60 * 60;
   private static final int TRANSIT_LEG_DURATION = 1200;
   private static final int TRANSIT_ALIGHT_TIME = TRANSIT_BOARD_TIME + TRANSIT_LEG_DURATION;
-  private static final int TRANSIT_COST = 128000;
+  private static final int TRANSIT_C1 = 128000;
   private static final RaptorTripSchedule TRANSIT_TRIP = null;
   private static final int ROUND = 1;
 
@@ -41,9 +41,9 @@ class TransferStopArrivalTest {
     TRANSFER_TO_STOP,
     TRANSFER_LEG_DURATION
   );
-  private static final int TRANSFER_COST = TRANSFER_WALK.generalizedCost();
+  private static final int TRANSFER_C1 = TRANSFER_WALK.c1();
 
-  private static final int EXPECTED_COST = ACCESS_COST + TRANSIT_COST + TRANSFER_COST;
+  private static final int EXPECTED_C1 = ACCESS_C1 + TRANSIT_C1 + TRANSFER_C1;
 
   private static final AccessStopArrival ACCESS_ARRIVAL = new AccessStopArrival<>(
     ACCESS_DEPARTURE_TIME,
@@ -54,7 +54,7 @@ class TransferStopArrivalTest {
     ACCESS_ARRIVAL.timeShiftNewArrivalTime(TRANSIT_BOARD_TIME - BOARD_SLACK),
     TRANSIT_TO_STOP,
     TRANSIT_ALIGHT_TIME,
-    ACCESS_ARRIVAL.c1() + TRANSIT_COST,
+    ACCESS_ARRIVAL.c1() + TRANSIT_C1,
     TRANSIT_TRIP
   );
 
@@ -82,12 +82,12 @@ public void arrivalTime() {
 
   @Test
   public void c1() {
-    assertEquals(EXPECTED_COST, subject.c1());
+    assertEquals(EXPECTED_C1, subject.c1());
   }
 
   @Test
   public void c2() {
-    assertThrows(UnsupportedOperationException.class, subject::c2);
+    assertEquals(RaptorConstants.NOT_SET, subject.c2());
   }
 
   @Test
@@ -111,7 +111,7 @@ public void previous() {
   @Test
   public void testToString() {
     assertEquals(
-      "Walk { round: 1, stop: 102, arrival: [9:26 $2600], path: On-Street 6m ~ 102 }",
+      "Walk { round: 1, stop: 102, arrival: [9:26 C₁2_600], path: On-Street 6m ~ 102 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrivalTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrivalTest.java
index b74a78e5659..1bebfc1e798 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrivalTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c1/TransitStopArrivalTest.java
@@ -2,7 +2,6 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.opentripplanner.raptor._data.transit.TestTripPattern.pattern;
 import static org.opentripplanner.raptor.api.model.PathLegType.TRANSIT;
@@ -10,6 +9,7 @@
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.raptor._data.transit.TestAccessEgress;
 import org.opentripplanner.raptor._data.transit.TestTripSchedule;
+import org.opentripplanner.raptor.api.model.RaptorConstants;
 import org.opentripplanner.raptor.api.model.RaptorTripSchedule;
 
 class TransitStopArrivalTest {
@@ -23,7 +23,7 @@ class TransitStopArrivalTest {
     ACCESS_TO_STOP,
     ACCESS_DURATION
   );
-  private static final int ACCESS_COST = ACCESS_WALK.generalizedCost();
+  private static final int ACCESS_C1 = ACCESS_WALK.c1();
   private static final AccessStopArrival ACCESS_ARRIVAL = new AccessStopArrival<>(
     ACCESS_DEPARTURE_TIME,
     ACCESS_WALK
@@ -38,13 +38,13 @@ class TransitStopArrivalTest {
     .build();
   private static final int TRANSIT_TRAVEL_DURATION =
     ACCESS_DURATION + BOARD_SLACK + TRANSIT_LEG_DURATION;
-  private static final int TRANSIT_COST = 128000;
+  private static final int TRANSIT_C1 = 128000;
   private static final int ROUND = 1;
   private final TransitStopArrival subject = new TransitStopArrival<>(
     ACCESS_ARRIVAL.timeShiftNewArrivalTime(TRANSIT_BOARD_TIME - BOARD_SLACK),
     TRANSIT_TO_STOP,
     TRANSIT_ALIGHT_TIME,
-    ACCESS_ARRIVAL.c1() + TRANSIT_COST,
+    ACCESS_ARRIVAL.c1() + TRANSIT_C1,
     TRANSIT_TRIP
   );
 
@@ -76,12 +76,12 @@ public void arrivalTime() {
 
   @Test
   public void c1() {
-    assertEquals(ACCESS_COST + TRANSIT_COST, subject.c1());
+    assertEquals(ACCESS_C1 + TRANSIT_C1, subject.c1());
   }
 
   @Test
   public void c2() {
-    assertThrows(UnsupportedOperationException.class, subject::c2);
+    assertEquals(RaptorConstants.NOT_SET, subject.c2());
   }
 
   @Test
@@ -102,7 +102,7 @@ public void access() {
   @Test
   public void testToString() {
     assertEquals(
-      "Transit { round: 1, stop: 101, arrival: [9:20 $1880], pattern: BUS T1 }",
+      "Transit { round: 1, stop: 101, arrival: [9:20 C₁1_880], pattern: BUS T1 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2Test.java
index 08c6b134dac..371eb2921bc 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/AccessStopArrivalC2Test.java
@@ -20,7 +20,7 @@ class AccessStopArrivalC2Test {
   private static final int ACCESS_DURATION = 10 * 60;
   private static final int ALIGHT_TIME = DEPARTURE_TIME + ACCESS_DURATION;
   private static final TestAccessEgress WALK = TestAccessEgress.walk(ALIGHT_STOP, ACCESS_DURATION);
-  private static final int COST = WALK.generalizedCost();
+  private static final int C1 = WALK.c1();
 
   private final AccessStopArrivalC2 subject = new AccessStopArrivalC2<>(
     DEPARTURE_TIME,
@@ -45,7 +45,7 @@ public void arrivalTime() {
 
   @Test
   public void c1() {
-    assertEquals(COST, subject.c1());
+    assertEquals(C1, subject.c1());
   }
 
   @Test
@@ -79,7 +79,7 @@ public void hashCodeThrowsExceptionByDesign() {
   @Test
   public void testToString() {
     assertEquals(
-      "Access { stop: 100, arrival: [8:10 $1200], path: Walk 10m $1200 ~ 100 }",
+      "Access { stop: 100, arrival: [8:10 C₁1_200 C₂0], path: Walk 10m C₁1_200 ~ 100 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/StopArrivalFactoryC2Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/StopArrivalFactoryC2Test.java
index 3578deb5b2e..4c78461b016 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/StopArrivalFactoryC2Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/StopArrivalFactoryC2Test.java
@@ -1,7 +1,6 @@
 package org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.c2;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.framework.time.DurationUtils;
@@ -80,10 +79,9 @@ public void testCreateAccessStopArrival() {
     var stopArrival = accessArrival();
 
     assertEquals(STOP_A, stopArrival.stop());
-    assertEquals(ACCESS.generalizedCost(), stopArrival.c1());
+    assertEquals(ACCESS.c1(), stopArrival.c1());
     assertEquals(ACCESS_DURATION, stopArrival.travelDuration());
     assertEquals(ORIGIN_DEPARTURE_TIME + ACCESS_DURATION, stopArrival.arrivalTime());
-    assertTrue(stopArrival.supportsC2());
     assertEquals(RaptorCostCalculator.ZERO_COST, stopArrival.c2());
   }
 
@@ -95,7 +93,6 @@ public void testCreateTransitStopArrival() {
     assertEquals(STOP_ARRIVAL_TRANSIT_C1, stopArrival.c1());
     assertEquals(STOP_ARRIVAL_TRANSIT_TIME, stopArrival.arrivalTime());
     assertEquals(STOP_ARRIVAL_TRANSIT_TIME - ORIGIN_DEPARTURE_TIME, stopArrival.travelDuration());
-    assertTrue(stopArrival.supportsC2());
     assertEquals(RIDE_C2, stopArrival.c2());
   }
 
@@ -105,13 +102,12 @@ public void testCreateTransferStopArrival() {
     var stopArrival = transferArrival(prevArrival);
 
     assertEquals(STOP_C, stopArrival.stop());
-    assertEquals(prevArrival.c1() + TRANSFER.generalizedCost(), stopArrival.c1());
+    assertEquals(prevArrival.c1() + TRANSFER.c1(), stopArrival.c1());
     assertEquals(
       prevArrival.arrivalTime() + TRANSFER.durationInSeconds(),
       stopArrival.arrivalTime()
     );
     assertEquals(DurationUtils.durationInSeconds("11m30s"), stopArrival.travelDuration());
-    assertTrue(stopArrival.supportsC2());
     assertEquals(RIDE_C2, stopArrival.c2());
   }
 }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2Test.java
index 55e1d6b6930..a8abe5bdddb 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransferStopArrivalC2Test.java
@@ -1,11 +1,9 @@
 package org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.c2;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.opentripplanner.raptor.api.model.PathLegType.TRANSFER;
-import static org.opentripplanner.raptor.api.model.PathLegType.TRANSIT;
 
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.raptor._data.transit.TestAccessEgress;
@@ -23,13 +21,13 @@ class TransferStopArrivalC2Test {
     ACCESS_TO_STOP,
     ACCESS_DURATION
   );
-  private static final int ACCESS_COST = ACCESS_WALK.generalizedCost();
+  private static final int ACCESS_C1 = ACCESS_WALK.c1();
 
   private static final int TRANSIT_TO_STOP = 101;
   private static final int TRANSIT_BOARD_TIME = 9 * 60 * 60;
   private static final int TRANSIT_LEG_DURATION = 1200;
   private static final int TRANSIT_ALIGHT_TIME = TRANSIT_BOARD_TIME + TRANSIT_LEG_DURATION;
-  private static final int TRANSIT_COST = 128000;
+  private static final int TRANSIT_C1 = 128000;
   private static final RaptorTripSchedule TRANSIT_TRIP = null;
   private static final int ROUND = 1;
 
@@ -40,11 +38,11 @@ class TransferStopArrivalC2Test {
     TRANSFER_TO_STOP,
     TRANSFER_LEG_DURATION
   );
-  private static final int TRANSFER_COST = TRANSFER_WALK.generalizedCost();
+  private static final int TRANSFER_C1 = TRANSFER_WALK.c1();
 
-  private static final int EXPECTED_COST = ACCESS_COST + TRANSIT_COST + TRANSFER_COST;
+  private static final int EXPECTED_C1 = ACCESS_C1 + TRANSIT_C1 + TRANSFER_C1;
 
-  private static final int TRANSIT_C2 = 600;
+  private static final int TRANSIT_C2 = 6;
 
   private static final AccessStopArrivalC2 ACCESS_ARRIVAL = new AccessStopArrivalC2<>(
     ACCESS_DEPARTURE_TIME,
@@ -55,7 +53,7 @@ class TransferStopArrivalC2Test {
     ACCESS_ARRIVAL.timeShiftNewArrivalTime(TRANSIT_BOARD_TIME - BOARD_SLACK),
     TRANSIT_TO_STOP,
     TRANSIT_ALIGHT_TIME,
-    ACCESS_ARRIVAL.c1() + TRANSIT_COST,
+    ACCESS_ARRIVAL.c1() + TRANSIT_C1,
     TRANSIT_C2,
     TRANSIT_TRIP
   );
@@ -84,7 +82,7 @@ public void arrivalTime() {
 
   @Test
   public void c1() {
-    assertEquals(EXPECTED_COST, subject.c1());
+    assertEquals(EXPECTED_C1, subject.c1());
   }
 
   @Test
@@ -114,7 +112,7 @@ public void previous() {
   @Test
   public void testToString() {
     assertEquals(
-      "Walk { round: 1, stop: 102, arrival: [9:26 $2600], path: On-Street 6m ~ 102 }",
+      "Walk { round: 1, stop: 102, arrival: [9:26 C₁2_600 C₂6], path: On-Street 6m ~ 102 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransitStopArrivalC2Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransitStopArrivalC2Test.java
index f25034959a6..8ddf4530c56 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransitStopArrivalC2Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/arrivals/c2/TransitStopArrivalC2Test.java
@@ -1,7 +1,6 @@
 package org.opentripplanner.raptor.rangeraptor.multicriteria.arrivals.c2;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.opentripplanner.raptor._data.transit.TestTripPattern.pattern;
@@ -23,7 +22,7 @@ class TransitStopArrivalC2Test {
     ACCESS_TO_STOP,
     ACCESS_DURATION
   );
-  private static final int ACCESS_COST = ACCESS_WALK.generalizedCost();
+  private static final int ACCESS_C1 = ACCESS_WALK.c1();
   private static final AccessStopArrivalC2 ACCESS_ARRIVAL = new AccessStopArrivalC2<>(
     ACCESS_DEPARTURE_TIME,
     ACCESS_WALK
@@ -78,7 +77,7 @@ public void arrivalTime() {
 
   @Test
   public void c1() {
-    assertEquals(ACCESS_COST + TRANSIT_C1, subject.c1());
+    assertEquals(ACCESS_C1 + TRANSIT_C1, subject.c1());
   }
 
   @Test
@@ -104,7 +103,7 @@ public void access() {
   @Test
   public void testToString() {
     assertEquals(
-      "Transit { round: 1, stop: 101, arrival: [9:20 $1880], pattern: BUS T1 }",
+      "Transit { round: 1, stop: 101, arrival: [9:20 C₁1_880 C₂8000], pattern: BUS T1 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c1/PatternRideC1Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c1/PatternRideC1Test.java
index 24bdba53cd2..02d2a0dd701 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c1/PatternRideC1Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c1/PatternRideC1Test.java
@@ -1,6 +1,5 @@
 package org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c1;
 
-import static org.junit.jupiter.api.Assertions.assertAll;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertSame;
@@ -14,8 +13,8 @@ public class PatternRideC1Test {
 
   @Test
   public void testParetoComparatorRelativeCost() {
-    final var LOW_COST = 100;
-    final var HIGH_COST = 500;
+    final var C1_LOW = 100;
+    final var C1_HIGH = 500;
     final var TRIP_SORT_INDEX_1 = 1;
     final var TRIP_SORT_INDEX_2 = 2;
 
@@ -23,29 +22,29 @@ public void testParetoComparatorRelativeCost() {
 
     assertTrue(
       comparator.leftDominanceExist(
-        new PatternRideC1<>(null, 0, 0, 0, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC1<>(null, 0, 0, 0, LOW_COST, LOW_COST, TRIP_SORT_INDEX_2, null)
+        new PatternRideC1<>(null, 0, 0, 0, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC1<>(null, 0, 0, 0, C1_LOW, C1_LOW, TRIP_SORT_INDEX_2, null)
       )
     );
 
     assertFalse(
       comparator.leftDominanceExist(
-        new PatternRideC1<>(null, 0, 0, 0, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC1<>(null, 0, 0, 0, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC1<>(null, 0, 0, 0, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC1<>(null, 0, 0, 0, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null)
       )
     );
 
     assertTrue(
       comparator.leftDominanceExist(
-        new PatternRideC1<>(null, 0, 0, 0, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC1<>(null, 0, 0, 0, HIGH_COST, HIGH_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC1<>(null, 0, 0, 0, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC1<>(null, 0, 0, 0, C1_HIGH, C1_HIGH, TRIP_SORT_INDEX_1, null)
       )
     );
 
     assertFalse(
       comparator.leftDominanceExist(
-        new PatternRideC1<>(null, 0, 0, 0, HIGH_COST, HIGH_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC1<>(null, 0, 0, 0, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC1<>(null, 0, 0, 0, C1_HIGH, C1_HIGH, TRIP_SORT_INDEX_1, null),
+        new PatternRideC1<>(null, 0, 0, 0, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null)
       )
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/PatternRideC2Test.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/PatternRideC2Test.java
index 731d6843de2..899c4c5ba67 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/PatternRideC2Test.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/multicriteria/ride/c2/PatternRideC2Test.java
@@ -1,6 +1,5 @@
 package org.opentripplanner.raptor.rangeraptor.multicriteria.ride.c2;
 
-import static org.junit.jupiter.api.Assertions.assertAll;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -11,50 +10,50 @@ public class PatternRideC2Test {
 
   @Test
   public void testParetoComparatorRelativeCost() {
-    final var LOW_COST = 100;
-    final var HIGH_COST = 500;
+    final var C1_LOW = 100;
+    final var C1_HIGH = 500;
     final var TRIP_SORT_INDEX_1 = 1;
     final var TRIP_SORT_INDEX_2 = 2;
     var comparator = PatternRideC2.paretoComparatorRelativeCost((l1, l2) -> l1 > l2);
 
     assertTrue(
       comparator.leftDominanceExist(
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_2, null)
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_2, null)
       )
     );
     assertFalse(
       comparator.leftDominanceExist(
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null)
       )
     );
 
     assertTrue(
       comparator.leftDominanceExist(
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC2<>(null, 0, 0, 0, HIGH_COST, HIGH_COST, LOW_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC2<>(null, 0, 0, 0, C1_HIGH, C1_HIGH, C1_LOW, TRIP_SORT_INDEX_1, null)
       )
     );
 
     assertFalse(
       comparator.leftDominanceExist(
-        new PatternRideC2<>(null, 0, 0, 0, HIGH_COST, HIGH_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC2<>(null, 0, 0, 0, C1_HIGH, C1_HIGH, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null)
       )
     );
 
     assertTrue(
       comparator.leftDominanceExist(
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, HIGH_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_HIGH, TRIP_SORT_INDEX_1, null),
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null)
       )
     );
 
     assertFalse(
       comparator.leftDominanceExist(
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, LOW_COST, TRIP_SORT_INDEX_1, null),
-        new PatternRideC2<>(null, 0, 0, 0, LOW_COST, LOW_COST, HIGH_COST, TRIP_SORT_INDEX_1, null)
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_LOW, TRIP_SORT_INDEX_1, null),
+        new PatternRideC2<>(null, 0, 0, 0, C1_LOW, C1_LOW, C1_HIGH, TRIP_SORT_INDEX_1, null)
       )
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalTest.java
index 458e88510d3..af2aa88fb5c 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/path/DestinationArrivalTest.java
@@ -14,7 +14,6 @@
 public class DestinationArrivalTest {
 
   private static final int ANY = 9_999;
-  private static final int BOARD_SLACK = 60;
   private static final int ACCESS_STOP = 100;
   private static final int ACCESS_DEPARTURE_TIME = 8 * 60 * 60;
   private static final int ACCESS_DURATION = 72;
@@ -22,7 +21,7 @@ public class DestinationArrivalTest {
     ACCESS_STOP,
     ACCESS_DURATION
   );
-  private static final int ACCESS_COST = ACCESS_WALK.generalizedCost();
+  private static final int ACCESS_COST = ACCESS_WALK.c1();
 
   private static final int TRANSIT_STOP = 101;
   private static final int TRANSIT_BOARD_TIME = ACCESS_DEPARTURE_TIME + 10 * 60;
@@ -31,10 +30,11 @@ public class DestinationArrivalTest {
   private static final int TRANSIT_COST = 84000;
 
   private static final int DESTINATION_DURATION_TIME = 50;
-  private static final int DESTINATION_COST = 50000;
+  private static final int DESTINATION_C1 = 50000;
+  private static final int DESTINATION_C2 = 5;
 
   private static final int EXPECTED_ARRIVAL_TIME = TRANSIT_ALIGHT_TIME + DESTINATION_DURATION_TIME;
-  private static final int EXPECTED_TOTAL_COST = ACCESS_COST + TRANSIT_COST + DESTINATION_COST;
+  private static final int EXPECTED_TOTAL_COST = ACCESS_COST + TRANSIT_COST + DESTINATION_C1;
 
   private static final StopArrivalFactoryC1 STOP_ARRIVAL_FACTORY = new StopArrivalFactoryC1();
 
@@ -57,7 +57,8 @@ public class DestinationArrivalTest {
     TestAccessEgress.walk(TRANSIT_STOP, DESTINATION_DURATION_TIME),
     TRANSIT_ARRIVAL,
     TRANSIT_ALIGHT_TIME + DESTINATION_DURATION_TIME,
-    DESTINATION_COST
+    DESTINATION_C1,
+    DESTINATION_C2
   );
 
   @Test
@@ -83,7 +84,7 @@ public void previous() {
   @Test
   public void testToString() {
     assertEquals(
-      "Egress { round: 1, from-stop: 101, arrival: [8:14:50 $1484], path: Walk 50s $100 ~ 101 }",
+      "Egress { round: 1, from-stop: 101, arrival: [8:14:50 C₁1_484 C₂5], path: Walk 50s C₁100 ~ 101 }",
       subject.toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/path/PathMapperTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/path/PathMapperTest.java
index cbd2186a2c1..bac2c1b0431 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/path/PathMapperTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/path/PathMapperTest.java
@@ -2,7 +2,7 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.BASIC_PATH_AS_DETAILED_STRING;
-import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.COST_CALCULATOR;
+import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.C1_CALCULATOR;
 import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.basicTripByForwardSearch;
 import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.basicTripByReverseSearch;
 import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.lifeCycle;
@@ -32,7 +32,7 @@ public class PathMapperTest implements RaptorTestConstants {
   private static final RaptorSlackProvider FLEX_SLACK_PROVIDER =
     FlexAccessAndEgressPathTestCase.SLACK_PROVIDER;
   private static final DefaultCostCalculator FLEX_COST_CALCULATOR =
-    FlexAccessAndEgressPathTestCase.COST_CALCULATOR;
+    FlexAccessAndEgressPathTestCase.C1_CALCULATOR;
 
   /* BASIC CASES */
 
@@ -42,7 +42,7 @@ public void mapToPathBasicForwardSearch() {
     var destArrival = basicTripByForwardSearch();
     var mapper = new ForwardPathMapper<>(
       SLACK_PROVIDER,
-      COST_CALCULATOR,
+      C1_CALCULATOR,
       this::stopIndexToName,
       null,
       lifeCycle(),
@@ -62,7 +62,7 @@ public void mapToPathBasicReverseSearch() {
     var destArrival = basicTripByReverseSearch();
     var mapper = new ReversePathMapper<>(
       SLACK_PROVIDER,
-      COST_CALCULATOR,
+      C1_CALCULATOR,
       this::stopIndexToName,
       null,
       lifeCycle(),
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPathsTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPathsTest.java
index 02ba0b22c53..6d3b25c1d31 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPathsTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/EgressPathsTest.java
@@ -51,12 +51,12 @@ class EgressPathsTest {
   @Test
   void byStopStandard() {
     var byStop = subjectStd.byStop();
-    assertEquals("[Walk 1m $120 ~ 2]", byStop.get(STOP_A).toString());
-    assertEquals("[Flex 1m $120 1x ~ 3]", byStop.get(STOP_B).toString());
-    assertEquals("[Flex 1m $120 1x ~ 4]", byStop.get(STOP_C).toString());
-    assertEquals("[Flex 1m $120 2x ~ 5]", byStop.get(STOP_D).toString());
+    assertEquals("[Walk 1m C₁120 ~ 2]", byStop.get(STOP_A).toString());
+    assertEquals("[Flex 1m C₁120 1x ~ 3]", byStop.get(STOP_B).toString());
+    assertEquals("[Flex 1m C₁120 1x ~ 4]", byStop.get(STOP_C).toString());
+    assertEquals("[Flex 1m C₁120 2x ~ 5]", byStop.get(STOP_D).toString());
     assertEquals(
-      "[Walk 2m $240 ~ 6, Walk 1m $120 Open(10:00 11:45) ~ 6, Walk 1m $120 Open(11:30 12:30) ~ 6]",
+      "[Walk 2m C₁240 ~ 6, Walk 1m C₁120 Open(10:00 11:45) ~ 6, Walk 1m C₁120 Open(11:30 12:30) ~ 6]",
       byStop.get(STOP_E).toString()
     );
     // Verify no more stops (A, B, C, D, E)
@@ -73,29 +73,29 @@ void stops() {
   void listAll() {
     assertEquals(
       """
-      Flex 1m $120 1x ~ 3
-      Flex 1m $120 1x ~ 4
-      Flex 1m $120 2x ~ 5
-      Walk 1m $120 Open(10:00 11:45) ~ 6
-      Walk 1m $120 Open(11:30 12:30) ~ 6
-      Walk 1m $120 ~ 2
-      Walk 2m $240 ~ 6
+      Flex 1m C₁120 1x ~ 3
+      Flex 1m C₁120 1x ~ 4
+      Flex 1m C₁120 2x ~ 5
+      Walk 1m C₁120 Open(10:00 11:45) ~ 6
+      Walk 1m C₁120 Open(11:30 12:30) ~ 6
+      Walk 1m C₁120 ~ 2
+      Walk 2m C₁240 ~ 6
       """.strip(),
       subjectStd.listAll().stream().map(Object::toString).sorted().collect(Collectors.joining("\n"))
     );
     assertEquals(
       """
-      Flex 1m $120 1x ~ 3
-      Flex 1m $120 1x ~ 4
-      Flex 1m $120 2x ~ 5
-      Flex 1m $120 3x ~ 5
-      Flex 2m $240 1x ~ 3
-      Flex+Walk 1m $120 1x ~ 4
-      Walk 1m $120 Open(10:00 11:45) ~ 6
-      Walk 1m $120 Open(11:30 12:30) ~ 6
-      Walk 1m $120 ~ 2
-      Walk 2m $240 Open(14:00 14:00) ~ 6
-      Walk 2m $240 ~ 6
+      Flex 1m C₁120 1x ~ 3
+      Flex 1m C₁120 1x ~ 4
+      Flex 1m C₁120 2x ~ 5
+      Flex 1m C₁120 3x ~ 5
+      Flex 2m C₁240 1x ~ 3
+      Flex+Walk 1m C₁120 1x ~ 4
+      Walk 1m C₁120 Open(10:00 11:45) ~ 6
+      Walk 1m C₁120 Open(11:30 12:30) ~ 6
+      Walk 1m C₁120 ~ 2
+      Walk 2m C₁240 Open(14:00 14:00) ~ 6
+      Walk 2m C₁240 ~ 6
       """.strip(),
       subjectMc.listAll().stream().map(Object::toString).sorted().collect(Collectors.joining("\n"))
     );
diff --git a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripTimesSearchTest.java b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripTimesSearchTest.java
index 24d93a74146..50295b0341e 100644
--- a/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripTimesSearchTest.java
+++ b/src/test/java/org/opentripplanner/raptor/rangeraptor/transit/TripTimesSearchTest.java
@@ -3,6 +3,8 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.opentripplanner.framework.time.TimeUtils.timeToStrLong;
+import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.access;
+import static org.opentripplanner.raptor._data.stoparrival.TestArrivals.bus;
 import static org.opentripplanner.raptor._data.transit.TestAccessEgress.free;
 import static org.opentripplanner.raptor._data.transit.TestTripPattern.pattern;
 import static org.opentripplanner.raptor.rangeraptor.transit.TripTimesSearch.findTripForwardSearch;
@@ -13,9 +15,8 @@
 import org.junit.jupiter.api.Test;
 import org.opentripplanner.framework.time.TimeUtils;
 import org.opentripplanner.raptor._data.RaptorTestConstants;
-import org.opentripplanner.raptor._data.stoparrival.Access;
-import org.opentripplanner.raptor._data.stoparrival.Bus;
 import org.opentripplanner.raptor._data.transit.TestTripSchedule;
+import org.opentripplanner.raptor.api.view.ArrivalView;
 import org.opentripplanner.raptor.spi.BoardAndAlightTime;
 
 public class TripTimesSearchTest implements RaptorTestConstants {
@@ -37,12 +38,12 @@ public void findTripWithPlentySlack() {
     BoardAndAlightTime r;
 
     // Search AFTER EDT
-    r = findTripForwardSearch(busFwd(STOP_A, STOP_C, C_ALIGHT_LATE));
+    r = findTripForwardSearch(busFwd(STOP_A, STOP_C, C_ALIGHT_LATE, schedule));
 
     assertTimes(r, A_BOARD_TIME, C_ALIGHT_TIME);
 
     // Search BEFORE LAT
-    r = findTripReverseSearch(busRev(STOP_C, STOP_A, A_BOARD_EARLY));
+    r = findTripReverseSearch(busRev(STOP_C, STOP_A, A_BOARD_EARLY, schedule));
 
     assertTimes(r, A_BOARD_TIME, C_ALIGHT_TIME);
   }
@@ -52,12 +53,12 @@ public void findTripWithApproximateTimes() {
     BoardAndAlightTime r;
 
     // Search AFTER EDT
-    r = findTripForwardSearchApproximateTime(busFwd(STOP_A, STOP_C, C_ALIGHT_LATE));
+    r = findTripForwardSearchApproximateTime(busFwd(STOP_A, STOP_C, C_ALIGHT_LATE, schedule));
 
     assertTimes(r, A_BOARD_TIME, C_ALIGHT_TIME);
 
     // Search BEFORE LAT
-    r = findTripReverseSearchApproximateTime(busRev(STOP_C, STOP_A, A_BOARD_EARLY));
+    r = findTripReverseSearchApproximateTime(busRev(STOP_C, STOP_A, A_BOARD_EARLY, schedule));
 
     assertTimes(r, A_BOARD_TIME, C_ALIGHT_TIME);
   }
@@ -67,12 +68,12 @@ public void findTripWithoutSlack() {
     BoardAndAlightTime r;
 
     // Search AFTER EDT
-    r = findTripForwardSearch(busFwd(STOP_A, STOP_C, C_ALIGHT_TIME));
+    r = findTripForwardSearch(busFwd(STOP_A, STOP_C, C_ALIGHT_TIME, schedule));
 
     assertTimes(r, A_BOARD_TIME, C_ALIGHT_TIME);
 
     // Search BEFORE LAT
-    r = findTripReverseSearch(busRev(STOP_C, STOP_A, A_BOARD_TIME));
+    r = findTripReverseSearch(busRev(STOP_C, STOP_A, A_BOARD_TIME, schedule));
 
     assertTimes(r, A_BOARD_TIME, C_ALIGHT_TIME);
   }
@@ -117,7 +118,7 @@ public void findInLoop() {
   public void noTripFoundWhenArrivalIsToEarly() {
     assertThrows(
       IllegalStateException.class,
-      () -> findTripForwardSearch(busFwd(STOP_A, STOP_C, C_ALIGHT_TIME - 1)),
+      () -> findTripForwardSearch(busFwd(STOP_A, STOP_C, C_ALIGHT_TIME - 1, schedule)),
       "No stops matching 'toStop'."
     );
   }
@@ -126,7 +127,7 @@ public void noTripFoundWhenArrivalIsToEarly() {
   public void noTripFoundWhenReverseArrivalIsToLate() {
     assertThrows(
       IllegalStateException.class,
-      () -> findTripReverseSearch(busRev(STOP_C, STOP_A, A_BOARD_TIME + 1)),
+      () -> findTripReverseSearch(busRev(STOP_C, STOP_A, A_BOARD_TIME + 1, schedule)),
       "No stops matching 'fromStop'."
     );
   }
@@ -135,7 +136,7 @@ public void noTripFoundWhenReverseArrivalIsToLate() {
   public void noTripFoundWhenArrivalIsWayTooEarly() {
     assertThrows(
       IllegalStateException.class,
-      () -> findTripForwardSearch(busFwd(STOP_A, STOP_C, 0)),
+      () -> findTripForwardSearch(busFwd(STOP_A, STOP_C, 0, schedule)),
       "No stops matching 'toStop'."
     );
   }
@@ -144,7 +145,7 @@ public void noTripFoundWhenArrivalIsWayTooEarly() {
   public void noTripFoundWhenReverseArrivalIsWayTooEarly() {
     assertThrows(
       IllegalStateException.class,
-      () -> findTripReverseSearch(busRev(STOP_C, STOP_A, 10_000)),
+      () -> findTripReverseSearch(busRev(STOP_C, STOP_A, 10_000, schedule)),
       "No stops matching 'fromStop'."
     );
   }
@@ -153,7 +154,7 @@ public void noTripFoundWhenReverseArrivalIsWayTooEarly() {
   public void noTripFoundWhenFromStopIsMissing() {
     assertThrows(
       IllegalStateException.class,
-      () -> findTripForwardSearch(busFwd(STOP_A, STOP_A, C_ALIGHT_LATE)),
+      () -> findTripForwardSearch(busFwd(STOP_A, STOP_A, C_ALIGHT_LATE, schedule)),
       "No stops matching 'fromStop'."
     );
   }
@@ -162,7 +163,7 @@ public void noTripFoundWhenFromStopIsMissing() {
   public void noTripFoundWhenToStopIsMissingInReverseSearch() {
     assertThrows(
       IllegalStateException.class,
-      () -> findTripReverseSearch(busRev(STOP_C, STOP_C, A_BOARD_EARLY)),
+      () -> findTripReverseSearch(busRev(STOP_C, STOP_C, A_BOARD_EARLY, schedule)),
       "No stops matching 'toStop'"
     );
   }
@@ -189,17 +190,17 @@ public void findTripWhenScheduleLoops() {
     // TEST FORWARD SEARCH
     {
       // Board in the 2nd loop at stop 2 and get off at stop 3
-      r = findTripForwardSearch(busFwd(122, 133, 800));
+      r = findTripForwardSearch(busFwd(122, 133, 800, schedule));
       assertEquals(710, r.boardTime());
       assertEquals(800, r.alightTime());
 
       // Board in the 1st loop at stop 4 and get off at stop 3
-      r = findTripForwardSearch(busFwd(144, 133, 800));
+      r = findTripForwardSearch(busFwd(144, 133, 800, schedule));
       assertEquals(410, r.boardTime());
       assertEquals(800, r.alightTime());
 
       // Board in the 1st stop, ride the loop twice, alight at the last stop
-      r = findTripForwardSearch(busFwd(1, 1155, 1100));
+      r = findTripForwardSearch(busFwd(1, 1155, 1100, schedule));
       assertEquals(10, r.boardTime());
       assertEquals(1100, r.alightTime());
     }
@@ -207,40 +208,40 @@ public void findTripWhenScheduleLoops() {
     // TEST REVERSE SEARCH
     {
       // Board in the 2nd loop at stop 2 and get off at stop 3
-      r = findTripReverseSearch(busRev(133, 122, 710));
+      r = findTripReverseSearch(busRev(133, 122, 710, schedule));
       assertEquals(710, r.boardTime());
       assertEquals(800, r.alightTime());
 
       // Board in the 1st loop at stop 4 and get off at stop 3
-      r = findTripReverseSearch(busRev(133, 144, 410));
+      r = findTripReverseSearch(busRev(133, 144, 410, schedule));
       assertEquals(410, r.boardTime());
       assertEquals(800, r.alightTime());
 
       // Board in the 1st stop, ride the loop twice, alight at the last stop
-      r = findTripReverseSearch(busRev(1155, 1, 10));
+      r = findTripReverseSearch(busRev(1155, 1, 10, schedule));
       assertEquals(10, r.boardTime());
       assertEquals(1100, r.alightTime());
     }
   }
 
-  private static Bus busFwd(
+  private static ArrivalView busFwd(
     int accessStop,
     int transitToStop,
     int arrivalTime,
     TestTripSchedule trip
   ) {
-    Access access = new Access(accessStop, -9999, free(accessStop));
-    return new Bus(1, transitToStop, arrivalTime, -9999, trip, access);
+    var access = access(accessStop, -9999, free(accessStop));
+    return bus(1, transitToStop, arrivalTime, -9999, -9999, trip, access);
   }
 
-  private static Bus busRev(
+  private static ArrivalView busRev(
     int accessStop,
     int transitToStop,
     int arrivalTime,
     TestTripSchedule trip
   ) {
-    Access access = new Access(accessStop, -9999, free(accessStop));
-    return new Bus(1, transitToStop, arrivalTime, -9999, trip, access);
+    var access = access(accessStop, -9999, free(accessStop));
+    return bus(1, transitToStop, arrivalTime, -9999, -9999, trip, access);
   }
 
   private void assertForwardAppxTime(
@@ -279,12 +280,4 @@ private void assertTimes(BoardAndAlightTime r, int expBoardTime, int expAlightTi
     assertEquals(timeToStrLong(expBoardTime), timeToStrLong(r.boardTime()));
     assertEquals(timeToStrLong(expAlightTime), timeToStrLong(r.alightTime()));
   }
-
-  private Bus busFwd(int accessToStop, int transitToStop, int arrivalTime) {
-    return busFwd(accessToStop, transitToStop, arrivalTime, schedule);
-  }
-
-  private Bus busRev(int accessToStop, int transitToStop, int arrivalTime) {
-    return busRev(accessToStop, transitToStop, arrivalTime, schedule);
-  }
 }
diff --git a/src/test/java/org/opentripplanner/raptor/spi/UnknownPathTest.java b/src/test/java/org/opentripplanner/raptor/spi/UnknownPathTest.java
index ecb5724b9cd..c1eec607877 100644
--- a/src/test/java/org/opentripplanner/raptor/spi/UnknownPathTest.java
+++ b/src/test/java/org/opentripplanner/raptor/spi/UnknownPathTest.java
@@ -14,7 +14,7 @@ void forwardDirectPath() {
     assertEquals(1200, subject.endTime());
     assertEquals(3, subject.numberOfTransfers());
     assertEquals(900, subject.durationInSeconds());
-    assertEquals("[0:05 0:20 15m 3tx]", subject.toString());
+    assertEquals("[0:05 0:20 15m Tₓ3]", subject.toString());
   }
 
   @Test
@@ -25,6 +25,6 @@ void reversDirectPath() {
     assertEquals(1200, subject.endTime());
     assertEquals(2, subject.numberOfTransfers());
     assertEquals(900, subject.durationInSeconds());
-    assertEquals("[0:05 0:20 15m 2tx]", subject.toString());
+    assertEquals("[0:05 0:20 15m Tₓ2]", subject.toString());
   }
 }
diff --git a/src/test/java/org/opentripplanner/raptor/util/PathStringBuilderTest.java b/src/test/java/org/opentripplanner/raptor/util/PathStringBuilderTest.java
index 7e918a71191..d347f3848e4 100644
--- a/src/test/java/org/opentripplanner/raptor/util/PathStringBuilderTest.java
+++ b/src/test/java/org/opentripplanner/raptor/util/PathStringBuilderTest.java
@@ -64,28 +64,28 @@ public void summary() {
     int START_TIME = time(12, 35, 0);
     int END_TIME = time(13, 45, 0);
     assertEquals(
-      "[12:35 13:45 1h10m 1tx $1.23]",
-      subject.summary(START_TIME, END_TIME, 1, 123).toString()
+      "[12:35 13:45 1h10m Tₓ1 C₁1.23 C₂5]",
+      subject.summary(START_TIME, END_TIME, 1, 123, 5).toString()
     );
   }
 
   @Test
   public void summaryGeneralizedCostOnly() {
-    assertEquals("[$0.01]", subject.summary(1).toString());
+    assertEquals("[C₁0.01]", subject.summary(1).toString());
   }
 
   @Test
   public void path() {
     int egressDuration = 3600 + 37 * 60 + 7;
     assertEquals(
-      "Walk 37s ~ 227 ~ BUS 10:46:05 10:55 ~ 112 ~ Walk 1h37m7s [10:44 12:33 1h49m 0tx $567]",
+      "Walk 37s ~ 227 ~ BUS 10:46:05 10:55 ~ 112 ~ Walk 1h37m7s [10:44 12:33 1h49m Tₓ0 C₁567 C₂7]",
       subject
         .walk(37)
         .stop(227)
         .transit(MODE, T_10_46_05, T_10_55)
         .stop(112)
         .walk(egressDuration)
-        .summary(time(10, 44, 0), time(12, 33, 0), 0, 56700)
+        .summary(time(10, 44, 0), time(12, 33, 0), 0, 56700, 7)
         .toString()
     );
   }
@@ -93,14 +93,14 @@ public void path() {
   @Test
   public void pathWithoutAccessAndEgress() {
     assertEquals(
-      "227 ~ BUS 10:46:05 10:55 ~ 112 [10:46:05 10:55 8m55s 0tx $60 3pz]",
+      "227 ~ BUS 10:46:05 10:55 ~ 112 [10:46:05 10:55 8m55s Tₓ0 C₁60 C₂9 3pz]",
       subject
         .accessEgress(free(227))
         .stop(227)
         .transit(MODE, T_10_46_05, T_10_55)
         .stop(112)
         .accessEgress(free(112))
-        .summary(T_10_46_05, T_10_55, 0, 6000, b -> b.text("3pz"))
+        .summary(T_10_46_05, T_10_55, 0, 6000, 9, b -> b.text("3pz"))
         .toString()
     );
   }
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainTest.java
index 3d709a54191..1ce1aec36bd 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/ItineraryListFilterChainTest.java
@@ -26,6 +26,7 @@
 import org.opentripplanner.ext.emissions.EmissionsService;
 import org.opentripplanner.model.SystemNotice;
 import org.opentripplanner.model.plan.Itinerary;
+import org.opentripplanner.model.plan.Place;
 import org.opentripplanner.model.plan.PlanTestConstants;
 import org.opentripplanner.model.plan.TestItineraryBuilder;
 import org.opentripplanner.routing.alertpatch.StopCondition;
@@ -33,6 +34,7 @@
 import org.opentripplanner.routing.api.response.RoutingError;
 import org.opentripplanner.routing.api.response.RoutingErrorCode;
 import org.opentripplanner.routing.services.TransitAlertService;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
 import org.opentripplanner.transit.model.framework.FeedScopedId;
 
 /**
@@ -41,12 +43,19 @@
  */
 public class ItineraryListFilterChainTest implements PlanTestConstants {
 
+  private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of();
+  private static final Place A = Place.forStop(TEST_MODEL.stop("A").build());
+  private static final Place B = Place.forStop(TEST_MODEL.stop("B").build());
+  private static final Place C = Place.forStop(TEST_MODEL.stop("C").build());
+  private static final Place D = Place.forStop(TEST_MODEL.stop("D").build());
+  private static final Place E = Place.forStop(TEST_MODEL.stop("E").build());
+
   private static final int I3_LATE_START_TIME = T11_33;
+  private static final Duration SW_D10m = Duration.ofSeconds(D10m);
 
   private Itinerary i1;
   private Itinerary i2;
   private Itinerary i3;
-  private Itinerary i4;
 
   @BeforeEach
   public void setUpItineraries() {
@@ -59,9 +68,6 @@ public void setUpItineraries() {
 
     // Not optimal, departure is very late
     i3 = newItinerary(A).bus(20, I3_LATE_START_TIME, I3_LATE_START_TIME + D1m, E).build();
-
-    // car itinerary for emissions test
-    i4 = newItinerary(A).drive(T11_30, PlanTestConstants.T11_50, B).build();
   }
 
   @Test
@@ -75,7 +81,7 @@ public void testDefaultFilterChain() {
   @Test
   public void testFilterChainWithSearchWindowFilterSet() {
     ItineraryListFilterChain chain = createBuilder(false, false, 10)
-      .withSearchWindow(TestItineraryBuilder.newTime(T11_00).toInstant(), Duration.ofMinutes(10))
+      .withSearchWindow(TestItineraryBuilder.newTime(T11_00).toInstant(), SW_D10m)
       .build();
     var result = chain.filter(List.of(i1, i2, i3));
     assertEquals(toStr(List.of(i1)), toStr(result));
@@ -101,7 +107,7 @@ public void withMinBikeParkingDistance() {
   public void testDebugFilterChain() {
     // Given a filter-chain with debugging enabled
     ItineraryListFilterChain chain = createBuilder(false, true, 3)
-      .withSearchWindow(newTime(T11_00).toInstant(), Duration.ofMinutes(6))
+      .withSearchWindow(newTime(T11_00).toInstant(), SW_D10m)
       .build();
 
     // Walk first, then transit sorted on arrival-time
@@ -160,7 +166,6 @@ public void testSameFirstOrLastTripFilter() {
     int ID_3 = 3;
 
     Itinerary i1 = newItinerary(A).bus(ID_1, 0, 50, B).bus(ID_2, 52, 100, C).build();
-
     Itinerary i2 = newItinerary(A).bus(ID_1, 0, 50, B).bus(ID_3, 52, 150, C).build();
 
     List input = List.of(i1, i2);
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/DeletionFlaggerTestHelper.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/DeletionFlaggerTestHelper.java
deleted file mode 100644
index 2762f54f9de..00000000000
--- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/DeletionFlaggerTestHelper.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.opentripplanner.routing.algorithm.filterchain.deletionflagger;
-
-import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import org.opentripplanner.model.plan.Itinerary;
-
-public class DeletionFlaggerTestHelper {
-
-  protected static List process(
-    List itineraries,
-    ItineraryDeletionFlagger flagger
-  ) {
-    List filtered = flagger.flagForRemoval(itineraries);
-    return itineraries
-      .stream()
-      .filter(Predicate.not(filtered::contains))
-      .collect(Collectors.toList());
-  }
-}
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/MaxLimitFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/MaxLimitFilterTest.java
index 78c85b6bdb0..b4418de6c68 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/MaxLimitFilterTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/MaxLimitFilterTest.java
@@ -25,27 +25,21 @@ public void name() {
   public void testNormalFilterMaxLimit3() {
     MaxLimitFilter subject = new MaxLimitFilter("Test", 3);
     List itineraries = List.of(i1, i2, i3);
-    assertEquals(
-      toStr(itineraries),
-      toStr(DeletionFlaggerTestHelper.process(itineraries, subject))
-    );
+    assertEquals(toStr(itineraries), toStr(subject.removeMatchesForTest(itineraries)));
   }
 
   @Test
   public void testNormalFilterMaxLimit1() {
     MaxLimitFilter subject = new MaxLimitFilter("Test", 1);
     List itineraries = List.of(i1, i2, i3);
-    assertEquals(
-      toStr(List.of(i1)),
-      toStr(DeletionFlaggerTestHelper.process(itineraries, subject))
-    );
+    assertEquals(toStr(List.of(i1)), toStr(subject.removeMatchesForTest(itineraries)));
   }
 
   @Test
   public void testNormalFilterMaxLimit0() {
     MaxLimitFilter subject = new MaxLimitFilter("Test", 0);
     List itineraries = List.of(i1, i2, i3);
-    var result = DeletionFlaggerTestHelper.process(itineraries, subject);
+    var result = subject.removeMatchesForTest(itineraries);
     assertEquals(toStr(List.of()), toStr(result));
   }
 }
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterTest.java
index ead30cfe38c..879edd784b0 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/NumItinerariesFilterTest.java
@@ -8,8 +8,8 @@
 
 import java.util.List;
 import org.junit.jupiter.api.Test;
+import org.opentripplanner.framework.collection.ListSection;
 import org.opentripplanner.model.plan.Itinerary;
-import org.opentripplanner.routing.algorithm.filterchain.ListSection;
 
 public class NumItinerariesFilterTest {
 
@@ -29,7 +29,7 @@ public void name() {
   public void testCropHead() {
     NumItinerariesFilter subject = new NumItinerariesFilter(1, ListSection.HEAD, null);
     List itineraries = List.of(i1, i2, i3);
-    var result = DeletionFlaggerTestHelper.process(itineraries, subject);
+    var result = subject.removeMatchesForTest(itineraries);
     assertEquals(toStr(List.of(i3)), toStr(result));
   }
 
@@ -38,35 +38,19 @@ public void testCropTailAndSubscribe() {
     var subject = new NumItinerariesFilter(2, ListSection.TAIL, it -> subscribeResult = it);
     var itineraries = List.of(i1, i2, i3);
 
-    var processedList = DeletionFlaggerTestHelper.process(itineraries, subject);
+    var processedList = subject.removeMatchesForTest(itineraries);
 
     assertEquals(
       i3.startTime().toInstant().toString(),
-      subscribeResult.earliestRemovedDeparture.toString()
-    );
-    assertEquals(
-      i3.endTime().toInstant().toString(),
-      subscribeResult.earliestRemovedArrival.toString()
-    );
-
-    assertEquals(
-      i3.startTime().toInstant().toString(),
-      subscribeResult.latestRemovedDeparture.toString()
-    );
-    assertEquals(
-      i3.endTime().toInstant().toString(),
-      subscribeResult.latestRemovedArrival.toString()
+      subscribeResult.earliestRemovedDeparture().toString()
     );
 
     assertEquals(
       i3.startTime().toInstant().toString(),
-      subscribeResult.firstRemovedDepartureTime.toString()
+      subscribeResult.latestRemovedDeparture().toString()
     );
 
-    assertEquals(
-      i1.endTime().toInstant().toString(),
-      subscribeResult.earliestKeptArrival.toString()
-    );
+    assertEquals(i2.keyAsString(), subscribeResult.pageCut().keyAsString());
 
     assertEquals(toStr(List.of(i1, i2)), toStr(processedList));
   }
@@ -76,35 +60,19 @@ public void testCropHeadAndSubscribe() {
     var subject = new NumItinerariesFilter(1, ListSection.HEAD, it -> subscribeResult = it);
     var itineraries = List.of(i1, i2, i3);
 
-    var processedList = DeletionFlaggerTestHelper.process(itineraries, subject);
+    var processedList = subject.removeMatchesForTest(itineraries);
 
     assertEquals(
       i2.startTime().toInstant().toString(),
-      subscribeResult.earliestRemovedDeparture.toString()
-    );
-    assertEquals(
-      i1.endTime().toInstant().toString(),
-      subscribeResult.earliestRemovedArrival.toString()
-    );
-
-    assertEquals(
-      i2.startTime().toInstant().toString(),
-      subscribeResult.latestRemovedDeparture.toString()
-    );
-    assertEquals(
-      i2.endTime().toInstant().toString(),
-      subscribeResult.latestRemovedArrival.toString()
+      subscribeResult.earliestRemovedDeparture().toString()
     );
 
     assertEquals(
       i2.startTime().toInstant().toString(),
-      subscribeResult.firstRemovedDepartureTime.toString()
+      subscribeResult.latestRemovedDeparture().toString()
     );
 
-    assertEquals(
-      i3.endTime().toInstant().toString(),
-      subscribeResult.earliestKeptArrival.toString()
-    );
+    assertEquals(i3.keyAsString(), subscribeResult.pageCut().keyAsString());
 
     assertEquals(toStr(List.of(i3)), toStr(processedList));
   }
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilterTest.java
index f4983e1ddbc..207210092b7 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilterTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/OutsideSearchWindowFilterTest.java
@@ -29,9 +29,9 @@ public class OutsideSearchWindowFilterTest implements PlanTestConstants {
   static List filterOnSearchWindowTestCases() {
     return List.of(
       Arguments.of("Departure time(09:30) matches earliest-departure-time", "09:30", false),
-      Arguments.of("Departure time(09:30) matches latest-departure-time", "09:20", false),
+      Arguments.of("Departure time(09:30) matches latest-departure-time", "09:20:01", false),
       Arguments.of("Departure time(09:30) is before earliest-departure-time", "09:30:01", true),
-      Arguments.of("Departure time(09:30) is after latest-departure-time", "09:19:59", true)
+      Arguments.of("Departure time(09:30) is after latest-departure-time", "09:20", true)
     );
   }
 
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilterTest.java
index 3766f7a6766..965889bdefc 100644
--- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilterTest.java
+++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/PagingFilterTest.java
@@ -1,49 +1,70 @@
 package org.opentripplanner.routing.algorithm.filterchain.deletionflagger;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.opentripplanner.framework.collection.ListUtils.first;
+import static org.opentripplanner.framework.collection.ListUtils.last;
 import static org.opentripplanner.model.plan.Itinerary.toStr;
 import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;
-import static org.opentripplanner.model.plan.TestItineraryBuilder.newTime;
 
-import java.time.Instant;
+import java.util.ArrayList;
 import java.util.List;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.opentripplanner._support.debug.TestDebug;
+import org.opentripplanner.framework.collection.ListSection;
+import org.opentripplanner.framework.time.TimeUtils;
 import org.opentripplanner.model.plan.Itinerary;
+import org.opentripplanner.model.plan.Place;
 import org.opentripplanner.model.plan.PlanTestConstants;
 import org.opentripplanner.model.plan.SortOrder;
-import org.opentripplanner.model.plan.pagecursor.ItineraryPageCut;
-import org.opentripplanner.model.plan.pagecursor.PagingDeduplicationSection;
+import org.opentripplanner.routing.algorithm.filterchain.comparator.SortOrderComparator;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
 
 public class PagingFilterTest implements PlanTestConstants {
 
-  private static final Itinerary early = newItinerary(A).bus(1, T11_04, T11_07, B).build();
+  private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of();
 
-  private static final Itinerary middle = newItinerary(A)
-    .bus(2, T11_03, T11_05, B)
-    .bus(21, T11_07, T11_10, C)
-    .build();
-  private static final Itinerary late = newItinerary(A).bus(3, T11_00, T11_12, B).build();
-  private static final Instant oldSearchWindowEndTime = newTime(T11_05).toInstant();
+  private static final Place A = TEST_MODEL.place("A", 10, 11);
+  private static final Place B = TEST_MODEL.place("B", 10, 13);
+  private static final Place C = TEST_MODEL.place("C", 10, 14);
+  private static final Place D = TEST_MODEL.place("D", 10, 15);
+
+  private static final int EARLY_START = T11_04;
+  private static final int EARLY_END = T11_07;
+  private static final int MIDDLE_START = T11_03;
+  private static final int MIDDLE_END = T11_10;
+  private static final int LATE_START = T11_00;
+  private static final int LATE_END = T11_12;
+
+  /** [11:04, 11:07, $300, Tx0, transit] */
+  private static final Itinerary early = newItinerary(A).bus(1, EARLY_START, EARLY_END, D).build();
+
+  /**  [11:03, 11:10, $636, Tx1, transit] */
+  private static final Itinerary middle = createMiddle();
+
+  /** [11:00, 11:12, $840, Tx0, transit] */
+  private static final Itinerary late = newItinerary(A).bus(3, LATE_START, LATE_END, D).build();
 
   private static PagingFilter pagingFilter;
 
+  /**
+   * This set of itineraries contains all combinations of itineraries with the following values:
+   * 
    + *
  1. departure-time: 10:00 and 10:01
  2. + *
  3. arrival-time: 11:00 and 11:01
  4. + *
  5. number of transfers: zero or one
  6. + *
  7. cost: 5 or 7
  8. + *
  9. mode: car or transit
  10. + *
+ * There are 8 car itineraries and 16 transit (car do not have transfers) = 24 itineraries + */ + private final List allItineraries = allPossibleSortingCombinationsOfItineraries(); + @BeforeEach public void setup() { - pagingFilter = - new PagingFilter( - new ItineraryPageCut( - late.startTime().toInstant(), - oldSearchWindowEndTime, - SortOrder.STREET_AND_ARRIVAL_TIME, - PagingDeduplicationSection.HEAD, - middle.endTime().toInstant(), - middle.startTime().toInstant(), - middle.getGeneralizedCost(), - middle.getNumberOfTransfers(), - false - ) - ); + pagingFilter = new PagingFilter(SortOrder.STREET_AND_ARRIVAL_TIME, ListSection.HEAD, middle); } @Test @@ -55,57 +76,203 @@ public void testName() { public void testPotentialDuplicateMarkedForDeletionWithEarlierArrival() { List itineraries = List.of(early, middle, late); - assertEquals( - toStr(List.of(middle, late)), - toStr(DeletionFlaggerTestHelper.process(itineraries, pagingFilter)) - ); + itineraries.forEach(it -> TestDebug.println(it.keyAsString())); + assertEquals(toStr(List.of(late)), toStr(pagingFilter.removeMatchesForTest(itineraries))); } @Test public void testPotentialDuplicateMarkedForDeletionWithLowerGeneralizedCost() { - Itinerary middleLowCost = newItinerary(A) - .bus(2, T11_03, T11_05, B) - .bus(21, T11_07, T11_10, C) - .build(); - - middleLowCost.setGeneralizedCost(1); + Itinerary middleHighCost = createMiddle(); + middleHighCost.setGeneralizedCost(middle.getGeneralizedCost() + 1); - List itineraries = List.of(middleLowCost, middle, late); + List itineraries = List.of(middleHighCost, middle, late); assertEquals( - toStr(List.of(middle, late)), - toStr(DeletionFlaggerTestHelper.process(itineraries, pagingFilter)) + toStr(List.of(middleHighCost, late)), + toStr(pagingFilter.removeMatchesForTest(itineraries)) ); } @Test public void testPotentialDuplicateMarkedForDeletionWithFewerNumberOfTransfers() { - Itinerary middleNumberOfTransfers = newItinerary(A).bus(21, T11_03, T11_10, C).build(); + int t0 = MIDDLE_START; - middleNumberOfTransfers.setGeneralizedCost(middle.getGeneralizedCost()); + Itinerary middleHighNumberOfTransfers = newItinerary(A) + .bus(21, t0, t0 + D1m, B) + .bus(22, t0 + D2m, t0 + D3m, C) + .bus(23, t0 + D4m, MIDDLE_END, D) + .build(); + + middleHighNumberOfTransfers.setGeneralizedCost(middle.getGeneralizedCost()); - List itineraries = List.of(middleNumberOfTransfers, middle, late); + List itineraries = List.of(middleHighNumberOfTransfers, middle, late); assertEquals( - toStr(List.of(middle, late)), - toStr(DeletionFlaggerTestHelper.process(itineraries, pagingFilter)) + toStr(List.of(middleHighNumberOfTransfers, late)), + toStr(pagingFilter.removeMatchesForTest(itineraries)) ); } @Test public void testPotentialDuplicateMarkedForDeletionWithLaterDepartureTime() { - Itinerary middleLaterDepartureTime = newItinerary(A) - .bus(2, T11_04, T11_05, B) - .bus(21, T11_07, T11_10, C) + int t0 = MIDDLE_START; + Itinerary middleEarlierDepartureTime = newItinerary(A) + .bus(2, t0 - D1m, t0 + D3m, B) + .bus(21, t0 + D4m, MIDDLE_END, C) .build(); - middleLaterDepartureTime.setGeneralizedCost(middle.getGeneralizedCost()); + middleEarlierDepartureTime.setGeneralizedCost(middle.getGeneralizedCost()); - List itineraries = List.of(middleLaterDepartureTime, middle, late); + List itineraries = List.of(middleEarlierDepartureTime, middle, late); assertEquals( - toStr(List.of(middle, late)), - toStr(DeletionFlaggerTestHelper.process(itineraries, pagingFilter)) + toStr(List.of(middleEarlierDepartureTime, late)), + toStr(pagingFilter.removeMatchesForTest(itineraries)) ); } + + @ParameterizedTest + @ValueSource( + ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 } + ) + public void testDepartAfterSearchHeadFilter(int index) { + allItineraries.sort(SortOrderComparator.defaultComparatorDepartAfter()); + + // Crop at top of list + var itinerary = allItineraries.get(index); + var f = new PagingFilter(SortOrder.STREET_AND_ARRIVAL_TIME, ListSection.HEAD, itinerary); + + var result = f.removeMatchesForTest(allItineraries); + + result.forEach(it -> TestDebug.println(it.toStr())); + + if (index == 23) { + assertEquals("", toStr(result)); + } else { + assertItineraryEq(allItineraries.get(index + 1), first(result)); + } + } + + @ParameterizedTest + @ValueSource( + ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 } + ) + public void testDepartAfterSearchTailFilter(int index) { + allItineraries.sort(SortOrderComparator.defaultComparatorDepartAfter()); + + // Crop at top of list + var itinerary = allItineraries.get(index); + var f = new PagingFilter(SortOrder.STREET_AND_ARRIVAL_TIME, ListSection.TAIL, itinerary); + + var result = f.removeMatchesForTest(allItineraries); + + result.forEach(it -> TestDebug.println(it.toStr())); + + if (index == 0) { + assertEquals("", toStr(result)); + } else { + assertItineraryEq(allItineraries.get(index - 1), last(result)); + } + } + + @ParameterizedTest + @ValueSource( + ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 } + ) + public void testArriveBySearchHeadFilter(int index) { + allItineraries.sort(SortOrderComparator.defaultComparatorArriveBy()); + + // Crop at top of list + var itinerary = allItineraries.get(index); + var f = new PagingFilter(SortOrder.STREET_AND_DEPARTURE_TIME, ListSection.HEAD, itinerary); + + var result = f.removeMatchesForTest(allItineraries); + + result.forEach(it -> TestDebug.println(it.toStr())); + + if (index == 23) { + assertEquals("", toStr(result)); + } else { + assertItineraryEq(allItineraries.get(index + 1), first(result)); + } + } + + @ParameterizedTest + @ValueSource( + ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 } + ) + public void testArriveBySearchTailFilter(int index) { + allItineraries.sort(SortOrderComparator.defaultComparatorArriveBy()); + + // Crop at top of list + var pageCut = allItineraries.get(index); + var f = new PagingFilter(SortOrder.STREET_AND_DEPARTURE_TIME, ListSection.TAIL, pageCut); + + var result = f.removeMatchesForTest(allItineraries); + + result.forEach(it -> TestDebug.println(it.toStr())); + + if (index == 0) { + assertEquals("", toStr(result)); + } else { + assertItineraryEq(allItineraries.get(index - 1), last(result)); + } + } + + private static List allPossibleSortingCombinationsOfItineraries() { + int tx_0 = 0; + int tx_1 = 1; + boolean car = false; + boolean transit = true; + List itineraries = new ArrayList<>(); + + for (int start : List.of(TimeUtils.time("10:00"), TimeUtils.time("10:01"))) { + for (int end : List.of(TimeUtils.time("11:00"), TimeUtils.time("11:01"))) { + for (int cost : List.of(5, 7)) { + itineraries.add(itinerary(start, end, cost, tx_0, car)); + itineraries.add(itinerary(start, end, cost, tx_0, transit)); + itineraries.add(itinerary(start, end, cost, tx_1, transit)); + } + } + } + return itineraries; + } + + private static Itinerary itinerary( + int departureTime, + int arrivalTime, + int cost, + int nTransfers, + boolean transit + ) { + var builder = newItinerary(A); + + if (transit) { + if (nTransfers == 0) { + builder.bus(10, departureTime, arrivalTime, B); + } else if (nTransfers == 1) { + builder + .bus(20, departureTime, departureTime + 120, B) + .bus(21, departureTime + 240, arrivalTime, B); + } else { + throw new IllegalArgumentException("nTransfers not supported: " + nTransfers); + } + } else { + builder.drive(departureTime, arrivalTime, B); + } + var it = builder.build(); + it.setGeneralizedCost(cost); + return it; + } + + private static Itinerary createMiddle() { + return newItinerary(A) + .bus(2, MIDDLE_START, MIDDLE_START + D2m, B) + .bus(21, MIDDLE_END - D3m, MIDDLE_END, D) + .build(); + } + + private static void assertItineraryEq(Itinerary expected, Itinerary actual) { + assertEquals(expected.keyAsString(), actual.keyAsString()); + } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveBikeRentalWithMostlyWalkingTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveBikeRentalWithMostlyWalkingTest.java index 91e4c1b1454..5fe2bce098b 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveBikeRentalWithMostlyWalkingTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveBikeRentalWithMostlyWalkingTest.java @@ -41,7 +41,7 @@ public void filter() { Assertions.assertEquals( Itinerary.toStr(expected), - Itinerary.toStr(DeletionFlaggerTestHelper.process(input, subject)) + Itinerary.toStr(subject.removeMatchesForTest(input)) ); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveParkAndRideWithMostlyWalkingTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveParkAndRideWithMostlyWalkingTest.java index 1855f8ddb82..2c65f882473 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveParkAndRideWithMostlyWalkingTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveParkAndRideWithMostlyWalkingTest.java @@ -41,7 +41,7 @@ public void filter() { Assertions.assertEquals( Itinerary.toStr(expected), - Itinerary.toStr(DeletionFlaggerTestHelper.process(input, subject)) + Itinerary.toStr(subject.removeMatchesForTest(input)) ); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfStreetOnlyIsBetterFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfStreetOnlyIsBetterFilterTest.java index 931953e013f..9cbba961e71 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfStreetOnlyIsBetterFilterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfStreetOnlyIsBetterFilterTest.java @@ -20,12 +20,10 @@ public void filterAwayNothingIfNoWalking() { Itinerary i2 = newItinerary(A).rail(110, 6, 9, E).build(); // When: - List result = DeletionFlaggerTestHelper.process( - List.of(i1, i2), - new RemoveTransitIfStreetOnlyIsBetterFilter( - CostLinearFunction.of(Duration.ofSeconds(200), 1.2) - ) + ItineraryDeletionFlagger flagger = new RemoveTransitIfStreetOnlyIsBetterFilter( + CostLinearFunction.of(Duration.ofSeconds(200), 1.2) ); + List result = flagger.removeMatchesForTest(List.of(i1, i2)); // Then: assertEquals(toStr(List.of(i1, i2)), toStr(result)); @@ -50,12 +48,10 @@ public void filterAwayLongTravelTimeWithoutWaitTime() { i2.setGeneralizedCost(360); // When: - List result = DeletionFlaggerTestHelper.process( - List.of(i2, bicycle, walk, i1), - new RemoveTransitIfStreetOnlyIsBetterFilter( - CostLinearFunction.of(Duration.ofSeconds(60), 1.2) - ) + ItineraryDeletionFlagger flagger = new RemoveTransitIfStreetOnlyIsBetterFilter( + CostLinearFunction.of(Duration.ofSeconds(60), 1.2) ); + List result = flagger.removeMatchesForTest(List.of(i2, bicycle, walk, i1)); // Then: assertEquals(toStr(List.of(bicycle, walk, i1)), toStr(result)); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfWalkingIsBetterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfWalkingIsBetterTest.java index b68ac9c46a2..9b008993ba3 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfWalkingIsBetterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveTransitIfWalkingIsBetterTest.java @@ -4,7 +4,6 @@ import static org.opentripplanner.model.plan.Itinerary.toStr; import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; -import java.time.Duration; import java.util.List; import org.junit.jupiter.api.Test; import org.opentripplanner.model.plan.Itinerary; @@ -19,10 +18,8 @@ public void filterAwayNothingIfNoWalking() { Itinerary i2 = newItinerary(A).rail(110, 6, 9, E).build(); // When: - List result = DeletionFlaggerTestHelper.process( - List.of(i1, i2), - new RemoveTransitIfWalkingIsBetterFilter() - ); + List result = new RemoveTransitIfWalkingIsBetterFilter() + .removeMatchesForTest(List.of(i1, i2)); // Then: assertEquals(toStr(List.of(i1, i2)), toStr(result)); @@ -42,10 +39,8 @@ public void filterAwayTransitWithLongerWalk() { // transit which has less walking than plain walk should be kept Itinerary i2 = newItinerary(A, 6).walk(D1m, B).bus(2, 7, 10, E).build(); - List result = DeletionFlaggerTestHelper.process( - List.of(i1, i2, bicycle, walk), - new RemoveTransitIfWalkingIsBetterFilter() - ); + List result = new RemoveTransitIfWalkingIsBetterFilter() + .removeMatchesForTest(List.of(i1, i2, bicycle, walk)); assertEquals(toStr(List.of(i2, bicycle, walk)), toStr(result)); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveWalkOnlyFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveWalkOnlyFilterTest.java index 806859b9081..62029ca389f 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveWalkOnlyFilterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/RemoveWalkOnlyFilterTest.java @@ -38,9 +38,6 @@ public void filter() { var input = List.of(t1, w1, t2, w2, t3, t4); var expected = List.of(t1, t2, t3, t4); - assertEquals( - Itinerary.toStr(expected), - Itinerary.toStr(DeletionFlaggerTestHelper.process(input, subject)) - ); + assertEquals(Itinerary.toStr(expected), Itinerary.toStr(subject.removeMatchesForTest(input))); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/TransitGeneralizedCostFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/TransitGeneralizedCostFilterTest.java index 0f93f44cdc3..37faa5f2feb 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/TransitGeneralizedCostFilterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/filterchain/deletionflagger/TransitGeneralizedCostFilterTest.java @@ -38,10 +38,7 @@ public void filterWithoutWaitCost() { var all = List.of(i1, i2, i3, i4); // Expect - i4 to be dropped - assertEquals( - toStr(List.of(i1, i2, i3)), - toStr(DeletionFlaggerTestHelper.process(all, subject)) - ); + assertEquals(toStr(List.of(i1, i2, i3)), toStr(subject.removeMatchesForTest(all))); } @Test @@ -69,10 +66,7 @@ public void filterWithWaitCostSameDepartureTime() { var all = List.of(i1, i2, i3, i4); // Expect - i4 to be dropped - assertEquals( - toStr(List.of(i1, i2, i3)), - toStr(DeletionFlaggerTestHelper.process(all, subject)) - ); + assertEquals(toStr(List.of(i1, i2, i3)), toStr(subject.removeMatchesForTest(all))); } @Test @@ -100,9 +94,6 @@ public void filterWithWaitCostDifferentDepartureTime() { var all = List.of(i1, i2, i3, i4); // Expect - i3 to be dropped - assertEquals( - toStr(List.of(i1, i2, i4)), - toStr(DeletionFlaggerTestHelper.process(all, subject)) - ); + assertEquals(toStr(List.of(i1, i2, i4)), toStr(subject.removeMatchesForTest(all))); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/PagingServiceFactoryTest.java b/src/test/java/org/opentripplanner/routing/algorithm/mapping/PagingServiceFactoryTest.java new file mode 100644 index 00000000000..369f58d6ef1 --- /dev/null +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/PagingServiceFactoryTest.java @@ -0,0 +1,99 @@ +package org.opentripplanner.routing.algorithm.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.time.DurationUtils; +import org.opentripplanner.framework.time.TimeUtils; +import org.opentripplanner.raptor._data.transit.TestAccessEgress; +import org.opentripplanner.raptor.api.request.RaptorRequestBuilder; +import org.opentripplanner.raptor.api.request.RaptorTuningParameters; +import org.opentripplanner.raptor.api.request.SearchParams; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters; +import org.opentripplanner.routing.api.request.RouteRequest; + +class PagingServiceFactoryTest { + + private static final Instant TRANSIT_START_TIME = Instant.parse("2023-11-11T00:00:00Z"); + private static final int EDT = TimeUtils.time("10:00"); + private static final int LAT = TimeUtils.time("11:30"); + + private static final Instant EXP_EDT = Instant.parse("2023-11-11T10:00:00Z"); + private static final Instant EXP_LAT = Instant.parse("2023-11-11T11:30:00Z"); + + private static final Duration SEARCH_WINDOW = DurationUtils.duration("2h30m"); + private static final SearchParams SEARCH_PARAMS_DEPART_AFTER = new RaptorRequestBuilder<>() + .searchParams() + .earliestDepartureTime(EDT) + .addAccessPaths(TestAccessEgress.walk(1, 1)) + .addEgressPaths(TestAccessEgress.walk(1, 1)) + .build() + .searchParams(); + private static final SearchParams SEARCH_PARAMS_ARRIVE_BY = new RaptorRequestBuilder<>() + .searchParams() + .latestArrivalTime(LAT) + .addAccessPaths(TestAccessEgress.walk(1, 1)) + .addEgressPaths(TestAccessEgress.walk(1, 1)) + .build() + .searchParams(); + private static final SearchParams SEARCH_PARAMS_ALL = new RaptorRequestBuilder<>() + .searchParams() + .earliestDepartureTime(EDT) + .latestArrivalTime(LAT) + .searchWindow(SEARCH_WINDOW) + .addAccessPaths(TestAccessEgress.walk(1, 1)) + .addEgressPaths(TestAccessEgress.walk(1, 1)) + .build() + .searchParams(); + + @Test + void createPagingService() { + var subject = PagingServiceFactory.createPagingService( + TRANSIT_START_TIME, + TransitTuningParameters.FOR_TEST, + new RaptorTuningParameters() {}, + new RouteRequest(), + SEARCH_PARAMS_ALL, + null, + List.of() + ); + assertEquals( + "PagingService{" + + "searchWindowUsed: 2h30m, " + + "earliestDepartureTime: 2023-11-11T10:00:00Z, " + + "latestArrivalTime: 2023-11-11T11:30:00Z, " + + "itinerariesSortOrder: STREET_AND_ARRIVAL_TIME, " + + "numberOfItineraries: 50" + + "}", + subject.toString() + ); + } + + @Test + void searchWindowOf() { + assertNull(PagingServiceFactory.searchWindowOf(null)); + assertNull(PagingServiceFactory.searchWindowOf(SEARCH_PARAMS_DEPART_AFTER)); + assertNull(PagingServiceFactory.searchWindowOf(SEARCH_PARAMS_ARRIVE_BY)); + assertEquals(SEARCH_WINDOW, PagingServiceFactory.searchWindowOf(SEARCH_PARAMS_ALL)); + } + + @Test + void testEarliestDepartureTime() { + assertNull(PagingServiceFactory.edt(TRANSIT_START_TIME, null)); + assertNull(PagingServiceFactory.edt(TRANSIT_START_TIME, SEARCH_PARAMS_ARRIVE_BY)); + assertEquals(EXP_EDT, PagingServiceFactory.edt(TRANSIT_START_TIME, SEARCH_PARAMS_DEPART_AFTER)); + assertEquals(EXP_EDT, PagingServiceFactory.edt(TRANSIT_START_TIME, SEARCH_PARAMS_ALL)); + } + + @Test + void testLatestDepartureTime() { + assertNull(PagingServiceFactory.lat(TRANSIT_START_TIME, null)); + assertNull(PagingServiceFactory.lat(TRANSIT_START_TIME, SEARCH_PARAMS_DEPART_AFTER)); + assertEquals(EXP_LAT, PagingServiceFactory.lat(TRANSIT_START_TIME, SEARCH_PARAMS_ARRIVE_BY)); + assertEquals(EXP_LAT, PagingServiceFactory.lat(TRANSIT_START_TIME, SEARCH_PARAMS_ALL)); + } +} diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java b/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java index 06220c22858..ffd2a5f8591 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/RaptorPathToItineraryMapperTest.java @@ -90,8 +90,8 @@ public void createItineraryTestZeroDurationEgress(int LAST_LEG_COST) { RaptorPath path = createTestTripSchedulePath(getTestTripSchedule()) .egress(TestAccessEgress.free(2, RaptorCostConverter.toRaptorCost(LAST_LEG_COST))); - int transitLegCost = path.accessLeg().nextLeg().generalizedCost(); - int egressLegCost = path.accessLeg().nextLeg().nextLeg().generalizedCost(); + int transitLegCost = path.accessLeg().nextLeg().c1(); + int egressLegCost = path.accessLeg().nextLeg().nextLeg().c1(); // Act var itinerary = mapper.createItinerary(path); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapperTest.java b/src/test/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapperTest.java deleted file mode 100644 index 646eedd628a..00000000000 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/RoutingResponseMapperTest.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.opentripplanner.routing.algorithm.mapping; - -import static java.time.ZoneOffset.UTC; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.opentripplanner.model.plan.PlanTestConstants.A; -import static org.opentripplanner.model.plan.PlanTestConstants.B; - -import java.time.Duration; -import java.time.ZonedDateTime; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.opentripplanner.framework.time.TimeUtils; -import org.opentripplanner.model.plan.Itinerary; -import org.opentripplanner.model.plan.SortOrder; -import org.opentripplanner.model.plan.TestItineraryBuilder; -import org.opentripplanner.model.plan.pagecursor.PageType; -import org.opentripplanner.raptor._data.transit.TestTripSchedule; -import org.opentripplanner.raptor.api.request.RaptorRequestBuilder; -import org.opentripplanner.raptor.api.request.SearchParams; -import org.opentripplanner.routing.algorithm.filterchain.ListSection; -import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; - -public class RoutingResponseMapperTest { - - static final ZonedDateTime TRANSIT_TIME_ZERO = TestItineraryBuilder.SERVICE_DAY.atStartOfDay(UTC); - - static final int T12_00 = TimeUtils.hm2time(12, 0); - static final int T12_30 = TimeUtils.hm2time(12, 30); - static final int T13_00 = TimeUtils.hm2time(13, 0); - static final int T13_30 = TimeUtils.hm2time(13, 30); - - static final Duration D1H = Duration.ofHours(1); - static final Duration D90M = Duration.ofMinutes(90); - - private static final SearchParams SEARCH_PARAMS = new RaptorRequestBuilder() - .searchParams() - .earliestDepartureTime(T12_00) - .latestArrivalTime(T13_30) - .searchWindow(D1H) - .buildSearchParam(); - - private static final Itinerary REMOVED_ITINERARY = TestItineraryBuilder - .newItinerary(A, T12_30) - .bus(1, T12_30, T13_00, B) - .build(); - - private static final Itinerary KEPT_ITINERARY = TestItineraryBuilder - .newItinerary(A, T12_00) - .bus(1, T12_00, T12_30, B) - .build(); - - @Test - public void mapIntoPageCursorFactoryNoTransitSearchParams() { - var factory = RoutingResponseMapper.mapIntoPageCursorFactory( - SortOrder.STREET_AND_ARRIVAL_TIME, - TRANSIT_TIME_ZERO, - null, - null, - null, - PageType.NEXT_PAGE - ); - - assertNull(factory.nextPageCursor()); - assertNull(factory.previousPageCursor()); - } - - @Test - void mapIntoPageCursorFactoryWithSearchParamsNoItineraryRemoved() { - var factory = RoutingResponseMapper.mapIntoPageCursorFactory( - SortOrder.STREET_AND_ARRIVAL_TIME, - TRANSIT_TIME_ZERO, - SEARCH_PARAMS, - D90M, - null, - PageType.NEXT_PAGE - ); - - // There is no way to access the internals of the factory, so we use the toString() - assertEquals( - "PageCursorFactory{" + - "sortOrder: STREET_AND_ARRIVAL_TIME, " + - "currentPageType: NEXT_PAGE, " + - "current: SearchTime{edt: 2020-02-02T12:00:00Z, lat: 2020-02-02T13:30:00Z}, " + - "currentSearchWindow: 1h, " + - "newSearchWindow: 1h30m" + - "}", - factory.toString() - ); - } - - @Test - public void testArriveByReversedRemovedInsidePreviousPage() { - var factory = RoutingResponseMapper.mapIntoPageCursorFactory( - SortOrder.STREET_AND_DEPARTURE_TIME, - TRANSIT_TIME_ZERO, - SEARCH_PARAMS, - D90M, - new NumItinerariesFilterResults( - List.of(KEPT_ITINERARY), - List.of(REMOVED_ITINERARY), - ListSection.TAIL - ), - PageType.NEXT_PAGE - ); - - // There is no way to access the internals of the factory, so we use the toString() - assertEquals( - "PageCursorFactory{" + - "sortOrder: STREET_AND_DEPARTURE_TIME, " + - "currentPageType: NEXT_PAGE, " + - "current: SearchTime{edt: 2020-02-02T12:00:00Z, lat: 2020-02-02T13:30:00Z}, " + - "currentSearchWindow: 1h, " + - "newSearchWindow: 1h30m, " + - "searchWindowCropped, " + - "pageCursorFactoryParams: " + - new NumItinerariesFilterResults( - List.of(KEPT_ITINERARY), - List.of(REMOVED_ITINERARY), - ListSection.TAIL - ) + - "}", - factory.toString() - ); - } -} diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressPenaltyDecoratorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressPenaltyDecoratorTest.java index 23dfc03b252..e063ddfbb14 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressPenaltyDecoratorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/router/street/AccessEgressPenaltyDecoratorTest.java @@ -42,9 +42,12 @@ class AccessEgressPenaltyDecoratorTest { @BeforeAll static void verifyTestSetup() { - assertEquals("Walk 15m38s $238035 w/penalty(13m23s $1606) ~ 1", EXP_WALK_W_PENALTY.toString()); assertEquals( - "Walk 11m53s $237887 w/penalty(11m8s $1336) ~ 1", + "Walk 15m38s C₁238_035 w/penalty(13m23s $1606) ~ 1", + EXP_WALK_W_PENALTY.toString() + ); + assertEquals( + "Walk 11m53s C₁237_887 w/penalty(11m8s $1336) ~ 1", EXP_CAR_RENTAL_W_PENALTY.toString() ); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgressTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgressTest.java index f19a19d5060..a9e088a2ad3 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgressTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/DefaultAccessEgressTest.java @@ -46,8 +46,8 @@ void stop() { void generalizedCost() { // TODO - The value is ? int expected = 23642959; - assertEquals(expected, subject.generalizedCost()); - assertEquals(expected + COST_PENALTY.toCentiSeconds(), subjectWithPenalty.generalizedCost()); + assertEquals(expected, subject.c1()); + assertEquals(expected + COST_PENALTY.toCentiSeconds(), subjectWithPenalty.c1()); } @Test @@ -129,8 +129,8 @@ void timeShiftDepartureTimeToActualTime() { @Test void testToString() { - assertEquals("Walk 1d8h50m15s $236429 ~ 5", subject.toString()); - assertEquals("Walk 1d8h50m16s $236440 w/penalty(1s $11) ~ 5", subjectWithPenalty.toString()); + assertEquals("Walk 1d8h50m15s C₁236_429 ~ 5", subject.toString()); + assertEquals("Walk 1d8h50m16s C₁236_440 w/penalty(1s $11) ~ 5", subjectWithPenalty.toString()); } @Test diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java index b1e2b881b1a..dacd0dcac9c 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransferTest.java @@ -22,7 +22,7 @@ class TransferTest { Coordinates.BERLIN_BRANDENBURG_GATE ); private static final IntersectionVertex BOSTON_V = intersectionVertex(Coordinates.BOSTON); - private static final int MAX_RAPTOR_TRANSFER_COST = RaptorCostConverter.toRaptorCost( + private static final int MAX_RAPTOR_TRANSFER_C1 = RaptorCostConverter.toRaptorCost( Transfer.MAX_TRANSFER_COST ); @@ -87,10 +87,10 @@ void allowLowCost() { } private static void assertMaxCost(RaptorTransfer transfer) { - assertEquals(MAX_RAPTOR_TRANSFER_COST, transfer.generalizedCost()); + assertEquals(MAX_RAPTOR_TRANSFER_C1, transfer.c1()); } private static void assertBelowMaxCost(RaptorTransfer transfer) { - assertTrue(MAX_RAPTOR_TRANSFER_COST > transfer.generalizedCost()); + assertTrue(MAX_RAPTOR_TRANSFER_C1 > transfer.c1()); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverterTest.java index cf57617cc6c..3827bdd31b6 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/cost/RaptorCostConverterTest.java @@ -40,6 +40,6 @@ public void toRaptorCosts() { @Test public void testToString() { - assertEquals("$120", RaptorCostConverter.toString(12_000)); + assertEquals("C₁120", RaptorCostConverter.toString(12_000)); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java index 6ca2e999c35..4cd2b65e8c3 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java @@ -45,7 +45,7 @@ class PriorityGroupConfiguratorTest { @Test void emptyConfigurationShouldReturnGroupZero() { - var subject = PriorityGroupConfigurator.of(List.of(), List.of(), List.of()); + var subject = PriorityGroupConfigurator.of(List.of(), List.of()); assertEquals(0, subject.lookupTransitPriorityGroupId(railA)); assertEquals(0, subject.lookupTransitPriorityGroupId(busB)); assertEquals(0, subject.lookupTransitPriorityGroupId(null)); @@ -54,7 +54,6 @@ void emptyConfigurationShouldReturnGroupZero() { @Test void lookupTransitPriorityGroupIdBySameAgency() { var subject = PriorityGroupConfigurator.of( - List.of(), List.of( TransitPriorityGroupSelect.of().addModes(List.of(TransitMode.BUS)).build(), TransitPriorityGroupSelect.of().addModes(List.of(TransitMode.RAIL)).build() @@ -72,7 +71,6 @@ void lookupTransitPriorityGroupIdBySameAgency() { @Test void lookupTransitPriorityGroupIdByGlobalMode() { var subject = PriorityGroupConfigurator.of( - List.of(), List.of(), List.of( TransitPriorityGroupSelect.of().addModes(List.of(TransitMode.BUS)).build(), diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java index a45c3f2b7a6..4823ea84300 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RouteRequestTransitDataProviderFilterTest.java @@ -14,7 +14,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ValueSource; -import org.opentripplanner.ext.transmodelapi.model.TransmodelTransportSubmode; +import org.opentripplanner.apis.transmodel.model.TransmodelTransportSubmode; import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.StopTime; diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPathTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPathTest.java index eb9880996e4..788192c45b5 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPathTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/api/OptimizedPathTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; import org.opentripplanner.raptor._data.RaptorTestConstants; import org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase; +import org.opentripplanner.raptor.api.model.RaptorValueFormatter; class OptimizedPathTest implements RaptorTestConstants { @@ -15,20 +16,20 @@ void copyBasicPath() { var path = new OptimizedPath<>(BasicPathTestCase.basicTripAsPath()); // Verify all costs - assertEquals(BasicPathTestCase.TOTAL_COST, path.c1()); + assertEquals(BasicPathTestCase.TOTAL_C1, path.c1()); assertEquals(0, path.breakTieCost()); - assertEquals(BasicPathTestCase.TOTAL_COST, path.generalizedCostWaitTimeOptimized()); + assertEquals(BasicPathTestCase.TOTAL_C1, path.generalizedCostWaitTimeOptimized()); assertEquals(66_00, path.transferPriorityCost()); // And toString is the same (transfer priority cost added) assertEquals( - BasicPathTestCase.BASIC_PATH_AS_STRING.replace("]", " $66pri]"), + BasicPathTestCase.BASIC_PATH_AS_STRING.replace("]", " Tₚ6_600]"), path.toString(this::stopIndexToName) ); // Verify details assertEquals( - BasicPathTestCase.BASIC_PATH_AS_DETAILED_STRING.replace("]", " $66pri]"), + BasicPathTestCase.BASIC_PATH_AS_DETAILED_STRING.replace("]", " Tₚ6_600]"), path.toStringDetailed(this::stopIndexToName) ); @@ -43,6 +44,7 @@ void copyBasicPathWithCostsAndVerifyCosts() { // Define some constants final int generalizedCost = 881100; + final int c2 = 7; final int transferPriorityCost = 120100; final int waitTimeOptimizedCost = 130200; final int generalizedCostWaitTimeOptimized = generalizedCost + waitTimeOptimizedCost; @@ -52,6 +54,7 @@ void copyBasicPathWithCostsAndVerifyCosts() { accessLeg, orgPath.rangeRaptorIterationDepartureTime(), generalizedCost, + c2, transferPriorityCost, waitTimeOptimizedCost, breakTieCost @@ -63,8 +66,15 @@ void copyBasicPathWithCostsAndVerifyCosts() { assertEquals(transferPriorityCost, path.transferPriorityCost()); var exp = BasicPathTestCase.BASIC_PATH_AS_STRING.replace( - "$8154]", - "$8811 $1201pri " + "$" + (generalizedCostWaitTimeOptimized / 100) + "wtc]" + "C₁8_154 C₂7]", + RaptorValueFormatter.formatC1(generalizedCost) + + " " + + RaptorValueFormatter.formatC2(c2) + + " " + + RaptorValueFormatter.formatTransferPriority(transferPriorityCost) + + " " + + RaptorValueFormatter.formatWaitTimeCost(generalizedCostWaitTimeOptimized) + + "]" ); assertEquals(exp, path.toString(this::stopIndexToName)); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/MinSafeTransferTimeCalculatorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/MinSafeTransferTimeCalculatorTest.java index a1bfba17afb..ae10dd0d03e 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/MinSafeTransferTimeCalculatorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/MinSafeTransferTimeCalculatorTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.time.TimeUtils.time; -import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.COST_CALCULATOR; +import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.C1_CALCULATOR; import static org.opentripplanner.routing.algorithm.transferoptimization.model.MinSafeTransferTimeCalculator.bound; import java.util.List; @@ -18,7 +18,7 @@ public class MinSafeTransferTimeCalculatorTest implements RaptorTestConstants { private static final int D2m = DurationUtils.durationInSeconds("2m"); private static final int TRANSIT_TIME = 2000 - (BOARD_SLACK + ALIGHT_SLACK); - private static final TestPathBuilder PATH_BUILDER = new TestPathBuilder(COST_CALCULATOR); + private static final TestPathBuilder PATH_BUILDER = new TestPathBuilder(C1_CALCULATOR); private final MinSafeTransferTimeCalculator subject = new MinSafeTransferTimeCalculator<>( SLACK_PROVIDER diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTailTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTailTest.java index bd4e5e12c38..f9bdf0df273 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTailTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/OptimizedPathTailTest.java @@ -57,7 +57,7 @@ class OptimizedPathTailTest implements RaptorTestConstants { private final OptimizedPathTail subject = new OptimizedPathTail<>( SLACK_PROVIDER, - BasicPathTestCase.COST_CALCULATOR, + BasicPathTestCase.C1_CALCULATOR, 0, waitTimeCalc, stopBoardAlightCost, @@ -84,7 +84,7 @@ void testToString() { "~ BUS L21 11:00 11:23 ~ D " + "~ BUS L31 11:40 11:52 ~ E " + "~ Walk 7m45s " + - "[$7989 $46pri $-93137wtc]"; + "[C₁7_989 Tₚ4_600 wtC₁-93_137]"; assertEquals(exp, subject.toString()); } @@ -99,7 +99,7 @@ void shouldHandleATransferAfterLastTransit() { "~ BUS L11 10:04 10:35 ~ B " + "~ Walk 3m45s ~ E " + "~ Flex 7m45s 1x " + - "[$3906 $0pri $3966wtc]"; + "[C₁3_906 wtC₁3_966]"; assertEquals(exp, subject.toString()); } @@ -140,13 +140,13 @@ void testBuildingPath() { // We have replaced the first transfer with a 2 minute walk var expPath = - "Walk 3m 10:00:15 10:03:15 $360 ~ A 45s " + - "~ BUS L11 10:04 10:35 31m $1998 ~ B 15s " + - "~ Walk 2m 10:35:15 10:37:15 $240 ~ C 22m45s " + - "~ BUS L21 11:00 11:23 23m $2724 ~ D 17m {staySeated} " + - "~ BUS L31 11:40 11:52 12m $1737 ~ E 15s " + - "~ Walk 7m45s 11:52:15 12:00 $930 " + - "[10:00:15 12:00 1h59m45s 1tx $7989 $46pri $-93137wtc]"; + "Walk 3m 10:00:15 10:03:15 C₁360 ~ A 45s " + + "~ BUS L11 10:04 10:35 31m C₁1_998 ~ B 15s " + + "~ Walk 2m 10:35:15 10:37:15 C₁240 ~ C 22m45s " + + "~ BUS L21 11:00 11:23 23m C₁2_724 ~ D 17m {staySeated} " + + "~ BUS L31 11:40 11:52 12m C₁1_737 ~ E 15s " + + "~ Walk 7m45s 11:52:15 12:00 C₁930 " + + "[10:00:15 12:00 1h59m45s Tₓ1 C₁7_989 Tₚ4_600 wtC₁-93_137]"; assertEquals(expPath, path.toStringDetailed(this::stopIndexToName)); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/costfilter/MinCostPathTailFilterTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/costfilter/MinCostPathTailFilterTest.java index 910789edbd5..8ecf0006e48 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/costfilter/MinCostPathTailFilterTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/costfilter/MinCostPathTailFilterTest.java @@ -1,7 +1,7 @@ package org.opentripplanner.routing.algorithm.transferoptimization.model.costfilter; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.COST_CALCULATOR; +import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.C1_CALCULATOR; import java.util.List; import java.util.Objects; @@ -80,7 +80,7 @@ static class A extends OptimizedPathTail { public final int y; private A(String name, int x, int y) { - super(SLACK_PROVIDER, COST_CALCULATOR, T00_00, WAIT_TIME_CALC, null, 0.0, null); + super(SLACK_PROVIDER, C1_CALCULATOR, T00_00, WAIT_TIME_CALC, null, 0.0, null); this.name = name; this.x = x; this.y = y; diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughNoTransfersTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughNoTransfersTest.java index cc071d91799..926e6ebe15c 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughNoTransfersTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughNoTransfersTest.java @@ -3,9 +3,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.time.TimeUtils.time; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestCase.testCase; +import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.domainService; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.first; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.pathBuilder; -import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.subject; import java.util.List; import org.junit.jupiter.params.ParameterizedTest; @@ -76,11 +76,12 @@ static List tripWithoutTransfersTestCases() { @MethodSource("tripWithoutTransfersTestCases") public void tripWithoutTransfers(TestCase tc) { var originalPath = pathBuilder() + .c2(tc.points().size()) .access(ITERATION_START_TIME, STOP_B, D1s) .bus(trip1, STOP_D) .egress(D1s); - var subject = subject(tc.points()); + var subject = domainService(tc.points()); // When var result = subject.findBestTransitPath(originalPath); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughOneTransferTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughOneTransferTest.java index 054915e84f4..ad41f43a586 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughOneTransferTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughOneTransferTest.java @@ -3,9 +3,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.time.TimeUtils.time; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestCase.testCase; +import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.domainService; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.pathBuilder; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.pathFocus; -import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.subject; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.tx; import java.util.List; @@ -141,6 +141,7 @@ public void tripWithOneTransfer(TestCase tc) { // We need *a* path - the transfer here can be any. var originalPath = pathBuilder() + .c2(tc.points().size()) .access(ITERATION_START_TIME, STOP_B, D1s) .bus(trip1, STOP_D) .walk(txCost.walkDuration(STOP_D, STOP_F), STOP_F) @@ -148,6 +149,7 @@ public void tripWithOneTransfer(TestCase tc) { .egress(D1s); var expectedPath = pathBuilder() + .c2(tc.points().size()) .access(ITERATION_START_TIME, STOP_B, D1s) .bus(trip1, tc.stopIndexA()) .walk(txCost.walkDuration(tc.stopIndexA(), tc.stopIndexB()), tc.stopIndexB()) @@ -157,7 +159,7 @@ public void tripWithOneTransfer(TestCase tc) { // These are illegal transfers for the given path, we add them here to make sure they // do not interfere with the result. For simpler debugging problems try commenting out these // lines, just do not forget to comment them back in when the problem is fixed. - var subject = subject( + var subject = domainService( tc.points(), List.of( tx(trip1, STOP_C, trip2, STOP_G, txCost), diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughTwoTransfersTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughTwoTransfersTest.java index fd2fd827d7c..e92e0ba0b3b 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughTwoTransfersTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/PassThroughTwoTransfersTest.java @@ -3,16 +3,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.framework.time.TimeUtils.time; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestCase.testCase; +import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.domainService; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.pathBuilder; -import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.pathFocus; -import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.subject; import static org.opentripplanner.routing.algorithm.transferoptimization.model.passthrough.TestUtils.tx; import java.util.List; -import java.util.stream.Collectors; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.raptor._data.RaptorTestConstants; +import org.opentripplanner.raptor._data.api.PathUtils; import org.opentripplanner.raptor._data.transit.TestTripSchedule; import org.opentripplanner.raptor.api.path.RaptorPath; @@ -195,7 +194,7 @@ public void tripWithTwoTransfer(TestCase tc) { RaptorPath expectedPath; { - var b = pathBuilder().access(ITERATION_START_TIME, STOP_B, D1s); + var b = pathBuilder().c2(tc.points().size()).access(ITERATION_START_TIME, STOP_B, D1s); if (tc.stopIndexA() == STOP_C) { b.bus(trip1, STOP_C).walk(costCG, STOP_G); @@ -219,21 +218,17 @@ public void tripWithTwoTransfer(TestCase tc) { tx(trip2, STOP_J, trip3, STOP_L, costJL) ); - var subject = subject(tc.points(), firstTransfers, secondTransfers); + var subject = domainService(tc.points(), firstTransfers, secondTransfers); // When var result = subject.findBestTransitPath(originalPath); // Then expect a set containing the expected path only - var resultAsString = result - .stream() - .map(it -> it.toString(this::stopIndexToName)) - .collect(Collectors.joining(", ")); assertEquals( - pathFocus(expectedPath.toString(this::stopIndexToName)), - pathFocus(resultAsString), - resultAsString + expectedPath.toString(this::stopIndexToName), + // Remove transferPriority cost + PathUtils.pathsToString(result).replace(" Tₚ6_600", "") ); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/TestUtils.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/TestUtils.java index 57695d2ac5c..2faf0ee95c1 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/TestUtils.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/model/passthrough/TestUtils.java @@ -54,7 +54,7 @@ static TripToTripTransfer tx( return TestTransferBuilder.tx(fromTrip, fromStop, toTrip, toStop).walk(txCost).build(); } - static OptimizePathDomainService subject( + static OptimizePathDomainService domainService( List passThroughPoints, final List>... transfers ) { @@ -82,6 +82,6 @@ static T first(Collection c) { * Remove stuff we do not care about, like the priority cost and times. */ static String pathFocus(String resultString) { - return resultString.replaceAll(" \\$\\d+pri]", "]").replaceAll(" \\d{2}:\\d{2}", ""); + return resultString.replaceAll(" Tₚ[\\d_]+]", "]").replaceAll(" \\d{2}:\\d{2}", ""); } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceConstrainedTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceConstrainedTest.java index d6725f4a425..a040da1d23f 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceConstrainedTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceConstrainedTest.java @@ -80,7 +80,7 @@ public void testTransferPriorityAllowed() { testPriority( STOP_D, ALLOWED, - "A ~ BUS T1 10:02 10:10 ~ B ~ Walk 1m ~ C ~ BUS T2 10:13 10:18 ~ D [10:01:20 10:18:20 17m 1tx $1120 $33pri]" + "A ~ BUS T1 10:02 10:10 ~ B ~ Walk 1m ~ C ~ BUS T2 10:13 10:18 ~ D [10:01:20 10:18:20 17m Tₓ1 C₁1_120 Tₚ3_300]" ); } @@ -89,7 +89,7 @@ public void testTransferPriorityRecommended() { testPriority( STOP_E, RECOMMENDED, - "A ~ BUS T1 10:02 10:15 ~ C ~ Walk 2m ~ D ~ BUS T2 10:18 10:24 ~ E [10:01:20 10:24:20 23m 1tx $1540 $32pri]" + "A ~ BUS T1 10:02 10:15 ~ C ~ Walk 2m ~ D ~ BUS T2 10:18 10:24 ~ E [10:01:20 10:24:20 23m Tₓ1 C₁1_540 Tₚ3_200]" ); } @@ -98,7 +98,7 @@ public void testTransferPriorityPreferred() { testPriority( STOP_F, PREFERRED, - "A ~ BUS T1 10:02 10:20 ~ D ~ Walk 3m ~ E ~ BUS T2 10:24 10:30 ~ F [10:01:20 10:30:20 29m 1tx $1960 $31pri]" + "A ~ BUS T1 10:02 10:20 ~ D ~ Walk 3m ~ E ~ BUS T2 10:24 10:30 ~ F [10:01:20 10:30:20 29m Tₓ1 C₁1_960 Tₚ3_100]" ); } @@ -106,7 +106,7 @@ public void testTransferPriorityPreferred() { public void testTransferGuaranteed() { testGuaranteed( STOP_G, - "A ~ BUS T1 10:02 10:25 ~ E ~ Walk 4m ~ F ~ BUS T2 10:30 10:36 ~ G [10:01:20 10:36:20 35m 1tx $2350 $23pri]" + "A ~ BUS T1 10:02 10:25 ~ E ~ Walk 4m ~ F ~ BUS T2 10:30 10:36 ~ G [10:01:20 10:36:20 35m Tₓ1 C₁2_350 Tₚ2_300]" ); } @@ -114,7 +114,7 @@ public void testTransferGuaranteed() { public void testTransferStaySeated() { testStaySeated( STOP_H, - "A ~ BUS T1 10:02 10:30 ~ F ~ Walk 5m ~ G ~ BUS T2 10:36 10:40 ~ H [10:01:20 10:40:20 39m 0tx $2650 $13pri]" + "A ~ BUS T1 10:02 10:30 ~ F ~ Walk 5m ~ G ~ BUS T2 10:36 10:40 ~ H [10:01:20 10:40:20 39m Tₓ0 C₁2_650 Tₚ1_300]" ); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java index c15a7b8247a..d05a4090b39 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/OptimizePathDomainServiceTest.java @@ -5,9 +5,7 @@ import static org.opentripplanner.routing.algorithm.transferoptimization.services.TestTransferBuilder.tx; import static org.opentripplanner.routing.algorithm.transferoptimization.services.TransferGeneratorDummy.dummyTransferGenerator; -import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import javax.annotation.Nullable; import org.junit.jupiter.api.Test; import org.opentripplanner.raptor._data.RaptorTestConstants; @@ -86,9 +84,8 @@ public void testTripWithoutTransfers() { // Then expect a set containing the original path assertEquals( original.toStringDetailed(this::stopIndexToName), - first(result).toStringDetailed(this::stopIndexToName) + PathUtils.pathsToStringDetailed(result) ); - assertEquals(1, result.size()); } /** @@ -133,10 +130,9 @@ public void testTripWithOneTransfer() { // Insert wait-time cost summary info var expected = original .toStringDetailed(this::stopIndexToName) - .replace("$2770]", "$2770 $33pri $3103.81wtc]"); + .replace("C₁2_770]", "C₁2_770 Tₚ3_300 wtC₁3_103.81]"); - assertEquals(expected, first(result).toStringDetailed(this::stopIndexToName)); - assertEquals(1, result.size()); + assertEquals(expected, PathUtils.pathsToStringDetailed(result)); } /** @@ -197,7 +193,7 @@ public void testPathWithThreeTripsAndMultiplePlacesToTransfer() { assertEquals( "A ~ BUS T1 10:02 10:10 ~ B ~ BUS T2 10:12 10:35 ~ F ~ BUS T3 10:37 10:49 ~ G " + - "[10:01:20 10:49:20 48m 2tx $2950 $66pri]", + "[10:01:20 10:49:20 48m Tₓ2 C₁2_950 Tₚ6_600]", PathUtils.pathsToString(result) ); @@ -214,7 +210,7 @@ public void testPathWithThreeTripsAndMultiplePlacesToTransfer() { "A ~ BUS T1 10:02 10:10 ~ B ~ Walk 30s ~ C " + "~ BUS T2 10:15 10:35 ~ F " + "~ BUS T3 10:37 10:49 ~ G " + - "[10:01:20 10:49:20 48m 2tx $2980 $66pri $3294.05wtc]", + "[10:01:20 10:49:20 48m Tₓ2 C₁2_980 Tₚ6_600 wtC₁3_294.05]", PathUtils.pathsToString(result) ); } @@ -267,7 +263,7 @@ public void testConstrainedTransferIsPreferred() { var it = result.iterator().next(); assertEquals( - "A ~ BUS T1 10:02 10:15 ~ C ~ BUS T2 10:17 10:30 ~ D [10:01:20 10:30:20 29m 1tx $1750 $23pri]", + "A ~ BUS T1 10:02 10:15 ~ C ~ BUS T2 10:17 10:30 ~ D [10:01:20 10:30:20 29m Tₓ1 C₁1_750 Tₚ2_300]", it.toString(this::stopIndexToName) ); // Verify the attached Transfer is exist and is valid @@ -327,8 +323,8 @@ public void testSameStopTimesInPattern() { var result = subject.findBestTransitPath(original); assertEquals( - "A ~ BUS T1 10:10 10:10 ~ B ~ BUS T2 10:13 10:30 ~ D [10:09:20 10:30:20 21m 1tx $1300 $33pri]", - result.stream().map(it -> it.toString(this::stopIndexToName)).collect(Collectors.joining()) + "A ~ BUS T1 10:10 10:10 ~ B ~ BUS T2 10:13 10:30 ~ D [10:09:20 10:30:20 21m Tₓ1 C₁1_300 Tₚ3_300]", + PathUtils.pathsToString(result) ); } @@ -361,8 +357,4 @@ static OptimizePathDomainService subject( (new RaptorTestConstants() {})::stopIndexToName ); } - - static T first(Collection c) { - return c.stream().findFirst().orElseThrow(); - } } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java index 8a5e15b3ac3..230097ebfc3 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransferGeneratorTest.java @@ -2,7 +2,7 @@ import static java.time.Duration.ofMinutes; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.COST_CALCULATOR; +import static org.opentripplanner.raptor._data.stoparrival.BasicPathTestCase.C1_CALCULATOR; import static org.opentripplanner.raptor._data.transit.TestRoute.route; import static org.opentripplanner.raptor._data.transit.TestTripSchedule.schedule; @@ -46,7 +46,7 @@ public class TransferGeneratorTest implements RaptorTestConstants { ALIGHT_SLACK ); - private final TestPathBuilder pathBuilder = new TestPathBuilder(SLACK_PROVIDER, COST_CALCULATOR); + private final TestPathBuilder pathBuilder = new TestPathBuilder(SLACK_PROVIDER, C1_CALCULATOR); private final TestTransitData data = new TestTransitData().withSlackProvider(SLACK_PROVIDER); diff --git a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransitPathLegSelectorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransitPathLegSelectorTest.java index 5e92adc4d9e..d62f123e7d6 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransitPathLegSelectorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/transferoptimization/services/TransitPathLegSelectorTest.java @@ -117,12 +117,7 @@ private static String firstRide(Collection c) { private TransitPathLeg transitLeg(int egressStop) { TestAccessEgress walk = TestAccessEgress.walk(egressStop, EGRESS_END - EGRESS_START); - var egress = new EgressPathLeg( - walk, - EGRESS_START, - EGRESS_END, - walk.generalizedCost() - ); + var egress = new EgressPathLeg(walk, EGRESS_START, EGRESS_END, walk.c1()); int toTime = TRIP.arrival(TRIP.findArrivalStopPosition(Integer.MAX_VALUE, egressStop)); int cost = 100 * (STOP_TIME_THREE - STOP_TIME_ONE); return new TransitPathLeg<>( diff --git a/src/test/java/org/opentripplanner/routing/api/request/preference/BikePreferencesTest.java b/src/test/java/org/opentripplanner/routing/api/request/preference/BikePreferencesTest.java index c15512c82de..e8e3ff576a9 100644 --- a/src/test/java/org/opentripplanner/routing/api/request/preference/BikePreferencesTest.java +++ b/src/test/java/org/opentripplanner/routing/api/request/preference/BikePreferencesTest.java @@ -16,8 +16,6 @@ class BikePreferencesTest { public static final double WALKING_RELUCTANCE = 1.45; public static final int SWITCH_TIME = 200; public static final int SWITCH_COST = 450; - public static final int PARK_TIME = 330; - public static final int PARK_COST = 950; public static final TimeSlopeSafetyTriangle TRIANGLE = TimeSlopeSafetyTriangle .of() .withSlope(1) @@ -33,8 +31,6 @@ class BikePreferencesTest { .withWalkingReluctance(WALKING_RELUCTANCE) .withSwitchTime(SWITCH_TIME) .withSwitchCost(SWITCH_COST) - .withParkTime(PARK_TIME) - .withParkCost(PARK_COST) .withOptimizeType(OPTIMIZE_TYPE) .withOptimizeTriangle(it -> it.withSlope(1).build()) .build(); @@ -74,16 +70,6 @@ void switchCost() { assertEquals(SWITCH_COST, subject.switchCost()); } - @Test - void parkTime() { - assertEquals(PARK_TIME, subject.parkTime()); - } - - @Test - void parkCost() { - assertEquals(PARK_COST, subject.parkCost()); - } - @Test void optimizeType() { assertEquals(OPTIMIZE_TYPE, subject.optimizeType()); @@ -121,8 +107,6 @@ void testToString() { "walkingReluctance: 1.45, " + "switchTime: 3m20s, " + "switchCost: $450, " + - "parkTime: 5m30s, " + - "parkCost: $950, " + "optimizeType: TRIANGLE, " + "optimizeTriangle: TimeSlopeSafetyTriangle[time=0.0, slope=1.0, safety=0.0]" + "}", diff --git a/src/test/java/org/opentripplanner/routing/api/request/preference/CarPreferencesTest.java b/src/test/java/org/opentripplanner/routing/api/request/preference/CarPreferencesTest.java index d94f21d567b..7bc0a1620ab 100644 --- a/src/test/java/org/opentripplanner/routing/api/request/preference/CarPreferencesTest.java +++ b/src/test/java/org/opentripplanner/routing/api/request/preference/CarPreferencesTest.java @@ -12,8 +12,6 @@ class CarPreferencesTest { private static final double EXPECTED_SPEED = 20.0; private static final double RELUCTANCE = 5.111; private static final double EXPECTED_RELUCTANCE = 5.1; - private static final int PARK_TIME = 300; - private static final int PARK_COST = 250; private static final int PICKUP_TIME = 600; private static final int PICKUP_COST = 500; private static final double ACCELERATION_SPEED = 3.1; @@ -24,8 +22,6 @@ class CarPreferencesTest { .of() .withSpeed(SPEED) .withReluctance(RELUCTANCE) - .withParkTime(PARK_TIME) - .withParkCost(PARK_COST) .withPickupTime(PICKUP_TIME) .withPickupCost(PICKUP_COST) .withDropoffTime(DROPOFF_TIME) @@ -43,16 +39,6 @@ void reluctance() { assertEquals(EXPECTED_RELUCTANCE, subject.reluctance()); } - @Test - void parkTime() { - assertEquals(PARK_TIME, subject.parkTime()); - } - - @Test - void parkCost() { - assertEquals(PARK_COST, subject.parkCost()); - } - @Test void pickupTime() { assertEquals(PICKUP_TIME, subject.pickupTime()); @@ -97,8 +83,6 @@ void testToString() { "CarPreferences{" + "speed: 20.0, " + "reluctance: 5.1, " + - "parkTime: 300, " + - "parkCost: $250, " + "pickupTime: 600, " + "pickupCost: $500, " + "dropoffTime: 450, " + diff --git a/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleParkingPreferencesTest.java b/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleParkingPreferencesTest.java new file mode 100644 index 00000000000..35666b53f9f --- /dev/null +++ b/src/test/java/org/opentripplanner/routing/api/request/preference/VehicleParkingPreferencesTest.java @@ -0,0 +1,88 @@ +package org.opentripplanner.routing.api.request.preference; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.routing.api.request.preference.ImmutablePreferencesAsserts.assertEqualsAndHashCode; + +import java.time.Duration; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.model.Cost; + +class VehicleParkingPreferencesTest { + + private static final Set PREFERRED_TAGS = Set.of("foo"); + private static final Set NOT_PREFERRED_TAGS = Set.of("bar"); + private static final int UNPREFERRED_COST = 360; + private static final Set REQUIRED_TAGS = Set.of("bar"); + private static final Set BANNED_TAGS = Set.of("not"); + private static final Cost PARKING_COST = Cost.costOfMinutes(4); + private static final Duration PARKING_TIME = Duration.ofMinutes(2); + + private final VehicleParkingPreferences subject = createPreferences(); + + @Test + void preferred() { + assertEquals(tagsToString(PREFERRED_TAGS), subject.preferred().select().toString()); + assertEquals(tagsToString(NOT_PREFERRED_TAGS), subject.preferred().not().toString()); + } + + @Test + void filter() { + assertEquals(tagsToString(REQUIRED_TAGS), subject.filter().select().toString()); + assertEquals(tagsToString(BANNED_TAGS), subject.filter().not().toString()); + } + + @Test + void unpreferredCost() { + assertEquals(UNPREFERRED_COST, subject.unpreferredVehicleParkingTagCost().toSeconds()); + } + + @Test + void parkCost() { + assertEquals(PARKING_COST, subject.parkCost()); + } + + @Test + void parkTime() { + assertEquals(PARKING_TIME, subject.parkTime()); + } + + @Test + void testCopyOfEqualsAndHashCode() { + // Create a copy, make a change and set it back again to force creating a new object + var other = subject.copyOf().withParkCost(10).build(); + var same = other.copyOf().withParkCost(PARKING_COST.toSeconds()).build(); + assertEqualsAndHashCode(subject, other, same); + } + + @Test + void testToString() { + assertEquals("VehicleParkingPreferences{}", VehicleParkingPreferences.DEFAULT.toString()); + assertEquals( + "VehicleParkingPreferences{" + + "unpreferredVehicleParkingTagCost: $360, " + + "filter: VehicleParkingFilter{not: [tags=[not]], select: [tags=[bar]]}, " + + "preferred: VehicleParkingFilter{not: [tags=[bar]], select: [tags=[foo]]}, " + + "parkCost: $240, " + + "parkTime: PT2M}", + subject.toString() + ); + } + + private static String tagsToString(Set tags) { + return "[tags=" + tags + "]"; + } + + private VehicleParkingPreferences createPreferences() { + return VehicleParkingPreferences + .of() + .withPreferredVehicleParkingTags(PREFERRED_TAGS) + .withNotPreferredVehicleParkingTags(NOT_PREFERRED_TAGS) + .withUnpreferredVehicleParkingTagCost(UNPREFERRED_COST) + .withRequiredVehicleParkingTags(REQUIRED_TAGS) + .withBannedVehicleParkingTags(BANNED_TAGS) + .withParkCost(PARKING_COST.toSeconds()) + .withParkTime(PARKING_TIME) + .build(); + } +} diff --git a/src/test/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitorTest.java b/src/test/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitorTest.java new file mode 100644 index 00000000000..1ef675c8101 --- /dev/null +++ b/src/test/java/org/opentripplanner/routing/graphfinder/PlaceFinderTraverseVisitorTest.java @@ -0,0 +1,277 @@ +package org.opentripplanner.routing.graphfinder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.model.plan.PlanTestConstants.T11_00; +import static org.opentripplanner.model.plan.PlanTestConstants.T11_05; +import static org.opentripplanner.model.plan.PlanTestConstants.T11_10; +import static org.opentripplanner.transit.model._data.TransitModelForTest.id; +import static org.opentripplanner.transit.model._data.TransitModelForTest.route; +import static org.opentripplanner.transit.model._data.TransitModelForTest.tripPattern; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.geometry.WgsCoordinate; +import org.opentripplanner.framework.i18n.NonLocalizedString; +import org.opentripplanner.model.StopTime; +import org.opentripplanner.street.search.state.TestStateBuilder; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.basic.TransitMode; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.network.StopPattern; +import org.opentripplanner.transit.model.network.TripPatternBuilder; +import org.opentripplanner.transit.model.site.RegularStop; +import org.opentripplanner.transit.model.site.Station; +import org.opentripplanner.transit.service.DefaultTransitService; +import org.opentripplanner.transit.service.TransitModel; + +public class PlaceFinderTraverseVisitorTest { + + static TransitModelForTest model = TransitModelForTest.of(); + static final Station STATION1 = Station + .of(id("S1")) + .withName(new NonLocalizedString("Station 1")) + .withCoordinate(1.1, 1.1) + .build(); + + static final Station STATION2 = Station + .of(id("S2")) + .withName(new NonLocalizedString("Station 2")) + .withCoordinate(1.1, 1.1) + .build(); + static final RegularStop STOP1 = model + .stop("stop-1") + .withCoordinate(new WgsCoordinate(1, 1)) + .withParentStation(STATION1) + .build(); + static final RegularStop STOP2 = model + .stop("stop-2") + .withCoordinate(1.001, 1.001) + .withParentStation(STATION2) + .build(); + + static final RegularStop STOP3 = model.stop("stop-3").withCoordinate(1.002, 1.002).build(); + static final RegularStop STOP4 = model.stop("stop-4").withCoordinate(1.003, 1.003).build(); + + static final Route r = route("r").build(); + + static TransitModel a = new TransitModel(); + + static { + a.addTransitMode(TransitMode.BUS); + TripPatternBuilder t = tripPattern("trip", r); + var st1 = new StopTime(); + st1.setStop(STOP1); + st1.setArrivalTime(T11_00); + + var st2 = new StopTime(); + st2.setStop(STOP2); + st2.setArrivalTime(T11_05); + t.withStopPattern(new StopPattern(List.of(st1, st2))); + a.addTripPattern(id("tp1"), t.build()); + + var st3 = new StopTime(); + st3.setStop(STOP3); + st3.setArrivalTime(T11_10); + t.withStopPattern(new StopPattern(List.of(st3))); + a.addTripPattern(id("tp2"), t.build()); + + var st4 = new StopTime(); + st4.setStop(STOP4); + st4.setArrivalTime(T11_10); + t.withStopPattern(new StopPattern(List.of(st4))); + a.addTripPattern(id("tp3"), t.build()); + + a.index(); + } + + static DefaultTransitService transitService = new DefaultTransitService(a); + + @Test + void stopsOnly() { + var visitor = new PlaceFinderTraverseVisitor( + transitService, + List.of(TransitMode.BUS), + List.of(PlaceType.STOP), + null, + null, + null, + null, + 1, + 500 + ); + + assertEquals(List.of(), visitor.placesFound); + var state1 = TestStateBuilder.ofWalking().streetEdge().stop(STOP1).build(); + + visitor.visitVertex(state1); + + var state2 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP2).build(); + visitor.visitVertex(state2); + var res = visitor.placesFound.stream().map(PlaceAtDistance::place).toList(); + + assertEquals(List.of(STOP1, STOP2), res); + + visitor.visitVertex(state1); + } + + @Test + void stationsOnly() { + var visitor = new PlaceFinderTraverseVisitor( + transitService, + List.of(TransitMode.BUS), + List.of(PlaceType.STATION), + null, + null, + null, + null, + 1, + 500 + ); + + assertEquals(List.of(), visitor.placesFound); + var state1 = TestStateBuilder.ofWalking().streetEdge().stop(STOP1).build(); + + visitor.visitVertex(state1); + + var state2 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP2).build(); + visitor.visitVertex(state2); + var res = visitor.placesFound.stream().map(PlaceAtDistance::place).toList(); + + assertEquals(List.of(STATION1, STATION2), res); + + visitor.visitVertex(state1); + } + + @Test + void stopsAndStations() { + var visitor = new PlaceFinderTraverseVisitor( + transitService, + List.of(TransitMode.BUS), + List.of(PlaceType.STOP, PlaceType.STATION), + null, + null, + null, + null, + 1, + 500 + ); + + assertEquals(List.of(), visitor.placesFound); + var state1 = TestStateBuilder.ofWalking().streetEdge().stop(STOP1).build(); + + visitor.visitVertex(state1); + + var state2 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP3).build(); + visitor.visitVertex(state2); + + // Revisited stop should not be added to found places + visitor.visitVertex(state1); + var res = visitor.placesFound.stream().map(PlaceAtDistance::place).toList(); + + assertEquals(List.of(STATION1, STOP3), res); + + visitor.visitVertex(state1); + } + + @Test + void stopsAndStationsWithStationFilter() { + var visitor = new PlaceFinderTraverseVisitor( + transitService, + List.of(TransitMode.BUS), + List.of(PlaceType.STOP, PlaceType.STATION), + List.of(STOP2.getId(), STOP3.getId()), + List.of(STATION1.getId()), + null, + null, + 1, + 500 + ); + + assertEquals(List.of(), visitor.placesFound); + var state1 = TestStateBuilder.ofWalking().streetEdge().stop(STOP1).build(); + + visitor.visitVertex(state1); + + var state2 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP2).build(); + visitor.visitVertex(state2); + + var state3 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP3).build(); + visitor.visitVertex(state3); + + var res = visitor.placesFound.stream().map(PlaceAtDistance::place).toList(); + + // Stop 3 should be included as it is not part of a station. + // Stop 2 should not be included as its parent station is not included in the station filter. + assertEquals(List.of(STATION1, STOP3), res); + + visitor.visitVertex(state1); + } + + @Test + void stopsAndStationsWithStopFilter() { + var visitor = new PlaceFinderTraverseVisitor( + transitService, + List.of(TransitMode.BUS), + List.of(PlaceType.STOP, PlaceType.STATION), + List.of(STOP2.getId()), + null, + null, + null, + 1, + 500 + ); + + assertEquals(List.of(), visitor.placesFound); + var state1 = TestStateBuilder.ofWalking().streetEdge().stop(STOP1).build(); + + visitor.visitVertex(state1); + + var state2 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP2).build(); + visitor.visitVertex(state2); + + var state3 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP3).build(); + visitor.visitVertex(state3); + + var res = visitor.placesFound.stream().map(PlaceAtDistance::place).toList(); + + // Stop 3 should not be included as it is included in the stop filter + assertEquals(List.of(STATION1, STATION2), res); + + visitor.visitVertex(state1); + } + + @Test + void stopsAndStationsWithStopAndStationFilter() { + var visitor = new PlaceFinderTraverseVisitor( + transitService, + List.of(TransitMode.BUS), + List.of(PlaceType.STOP, PlaceType.STATION), + List.of(STOP4.getId()), + List.of(STATION1.getId()), + null, + null, + 1, + 500 + ); + + assertEquals(List.of(), visitor.placesFound); + var state1 = TestStateBuilder.ofWalking().streetEdge().stop(STOP1).build(); + + visitor.visitVertex(state1); + + var state2 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP2).build(); + visitor.visitVertex(state2); + + var state3 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP3).build(); + visitor.visitVertex(state3); + + var state4 = TestStateBuilder.ofWalking().streetEdge().streetEdge().stop(STOP4).build(); + visitor.visitVertex(state4); + + var res = visitor.placesFound.stream().map(PlaceAtDistance::place).toList(); + + assertEquals(List.of(STATION1, STOP4), res); + + visitor.visitVertex(state1); + } +} diff --git a/src/test/java/org/opentripplanner/routing/graphfinder/StreetGraphFinderTest.java b/src/test/java/org/opentripplanner/routing/graphfinder/StreetGraphFinderTest.java index 7901c06f9f4..3285e27594c 100644 --- a/src/test/java/org/opentripplanner/routing/graphfinder/StreetGraphFinderTest.java +++ b/src/test/java/org/opentripplanner/routing/graphfinder/StreetGraphFinderTest.java @@ -151,6 +151,7 @@ void findClosestPlacesLimiting() { 10.0, 10, null, + List.of(PlaceType.STOP, PlaceType.PATTERN_AT_STOP, PlaceType.VEHICLE_RENT), null, null, null, @@ -167,6 +168,13 @@ void findClosestPlacesLimiting() { 200.0, 100, null, + List.of( + PlaceType.STOP, + PlaceType.PATTERN_AT_STOP, + PlaceType.VEHICLE_RENT, + PlaceType.CAR_PARK, + PlaceType.BIKE_PARK + ), null, null, null, @@ -183,6 +191,7 @@ void findClosestPlacesLimiting() { 200.0, 3, null, + List.of(PlaceType.STOP, PlaceType.PATTERN_AT_STOP, PlaceType.VEHICLE_RENT), null, null, null, @@ -210,6 +219,7 @@ void findClosestPlacesWithAModeFilter() { null, null, null, + null, transitService ) ); @@ -226,6 +236,7 @@ void findClosestPlacesWithAModeFilter() { null, null, null, + null, transitService ) ); @@ -250,6 +261,7 @@ void findClosestPlacesWithAStopFilter() { null, null, null, + null, transitService ) ); @@ -266,6 +278,7 @@ void findClosestPlacesWithAStopFilter() { List.of(S2.getStop().getId()), null, null, + null, transitService ) ); @@ -290,6 +303,7 @@ void findClosestPlacesWithAStopAndRouteFilter() { null, null, null, + null, transitService ) ); @@ -304,6 +318,7 @@ void findClosestPlacesWithAStopAndRouteFilter() { null, List.of(PlaceType.STOP, PlaceType.PATTERN_AT_STOP), List.of(S2.getStop().getId()), + null, List.of(R1.getId()), null, transitService @@ -331,6 +346,7 @@ void findClosestPlacesWithARouteFilter() { null, null, null, + null, transitService ) ); @@ -345,6 +361,7 @@ void findClosestPlacesWithARouteFilter() { null, List.of(PlaceType.STOP, PlaceType.PATTERN_AT_STOP), null, + null, List.of(R2.getId()), null, transitService @@ -369,6 +386,7 @@ void findClosestPlacesWithAVehicleRentalFilter() { null, null, null, + null, transitService ) ); @@ -384,6 +402,7 @@ void findClosestPlacesWithAVehicleRentalFilter() { List.of(PlaceType.VEHICLE_RENT), null, null, + null, List.of("BR2"), transitService ) @@ -406,6 +425,7 @@ void findClosestPlacesWithABikeParkFilter() { null, null, null, + null, transitService ) ); @@ -427,6 +447,7 @@ void findClosestPlacesWithACarParkFilter() { null, null, null, + null, transitService ) ); diff --git a/src/test/java/org/opentripplanner/routing/stoptimes/AlternativeLegsTest.java b/src/test/java/org/opentripplanner/routing/stoptimes/AlternativeLegsTest.java index 96f49bb9c78..fde87776909 100644 --- a/src/test/java/org/opentripplanner/routing/stoptimes/AlternativeLegsTest.java +++ b/src/test/java/org/opentripplanner/routing/stoptimes/AlternativeLegsTest.java @@ -59,16 +59,13 @@ void testPreviousLegs() { alternativeLegs.stream().map(Leg.class::cast).map(List::of).map(Itinerary::new).toList() ); - var expectd = String.join( - ", ", - List.of( - "B ~ BUS 2 0:20 0:30 ~ C [$-1]", - "B ~ BUS 1 0:10 0:20 ~ C [$-1]", - "B ~ BUS 1 8:20 8:30 ~ C [$-1]" // Previous day - ) - ); + var expected = + "B ~ BUS 2 0:20 0:30 ~ C [C₁-1], " + + "B ~ BUS 1 0:10 0:20 ~ C [C₁-1], " + + // Previous day + "B ~ BUS 1 8:20 8:30 ~ C [C₁-1]"; - assertEquals(expectd, legs); + assertEquals(expected, legs); } @Test @@ -98,16 +95,13 @@ void testNextLegs() { alternativeLegs.stream().map(Leg.class::cast).map(List::of).map(Itinerary::new).toList() ); - var expectd = String.join( - ", ", - List.of( - "B ~ BUS 3 1:00 1:10 ~ C [$-1]", - "B ~ BUS 1 8:20 8:30 ~ C [$-1]", - "B ~ BUS 1 0:10 0:20 ~ C [$-1]" // Next day - ) - ); + var expected = + "B ~ BUS 3 1:00 1:10 ~ C [C₁-1], " + + "B ~ BUS 1 8:20 8:30 ~ C [C₁-1], " + + // Next day + "B ~ BUS 1 0:10 0:20 ~ C [C₁-1]"; - assertEquals(expectd, legs); + assertEquals(expected, legs); } @Test @@ -136,12 +130,7 @@ void testCircularRoutes() { alternativeLegs.stream().map(Leg.class::cast).map(List::of).map(Itinerary::new).toList() ); - var expected = String.join( - ", ", - List.of("X ~ BUS 19 10:30 10:40 ~ Y [$-1]", "X ~ BUS 19 10:00 10:10 ~ Y [$-1]") - ); - - assertEquals(expected, legs); + assertEquals("X ~ BUS 19 10:30 10:40 ~ Y [C₁-1], X ~ BUS 19 10:00 10:10 ~ Y [C₁-1]", legs); } @Test @@ -170,7 +159,7 @@ void testComplexCircularRoutes() { alternativeLegs.stream().map(Leg.class::cast).map(List::of).map(Itinerary::new).toList() ); - var expected = String.join(", ", List.of("X ~ BUS 19 10:30 11:00 ~ B [$-1]")); + var expected = String.join(", ", List.of("X ~ BUS 19 10:30 11:00 ~ B [C₁-1]")); assertEquals(expected, legs); } } diff --git a/src/test/java/org/opentripplanner/service/paging/PS1_LegacyMetaDataTest.java b/src/test/java/org/opentripplanner/service/paging/PS1_LegacyMetaDataTest.java new file mode 100644 index 00000000000..609607d84ff --- /dev/null +++ b/src/test/java/org/opentripplanner/service/paging/PS1_LegacyMetaDataTest.java @@ -0,0 +1,101 @@ +package org.opentripplanner.service.paging; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.service.paging.TestPagingModel.D30m; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.time.TimeUtils; + +/** + * This tests the entire paging service module. + *

+ * To debug this test, set either the system property 'testDebug' or the environment variable 'testDebug' to 'true'. + */ +@SuppressWarnings("DataFlowIssue") +class PS1_LegacyMetaDataTest { + + private static final int T08_45 = TimeUtils.time("08:45"); + private static final int T09_15 = TimeUtils.time("09:15"); + + private static final int T12_00 = TimeUtils.time("12:00"); + private static final int T13_00 = TimeUtils.time("13:00"); + + private static final Duration SEARCH_WINDOW_USED = D30m; + + @Test + @SuppressWarnings("deprecation") + void testCreateTripSearchMetadataDepartAfterWithPageCut() { + var model = TestPagingModel.testDataWithManyItinerariesCaseA(); + var testDriver = model.departAfterDriver(T12_00, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + + assertEquals(D30m, subject.createTripSearchMetadata().searchWindowUsed); + assertEquals( + "11:30", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().prevDateTime) + ); + // 12:11 will drop results, the solution is to use the complete sort-vector. + // The cursor implementation does that + assertEquals( + "12:11", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().nextDateTime) + ); + } + + @Test + @SuppressWarnings("deprecation") + void testCreateTripSearchMetadataDepartAfterNormalSearchWindow() { + var model = TestPagingModel.testDataWithFewItinerariesCaseB(); + var testDriver = model.departAfterDriver(T08_45, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + + assertEquals(D30m, subject.createTripSearchMetadata().searchWindowUsed); + assertEquals( + "08:15", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().prevDateTime) + ); + // 12:11 will drop results, the solution is to use the complete sort-vector. + // The cursor implementation does that + assertEquals( + "09:15", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().nextDateTime) + ); + } + + @Test + @SuppressWarnings("deprecation") + void testCreateTripSearchMetadataArriveByWithPageCut() { + var model = TestPagingModel.testDataWithManyItinerariesCaseA(); + var testDriver = model.arriveByDriver(T12_00, T13_00, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + + assertEquals(D30m, subject.createTripSearchMetadata().searchWindowUsed); + assertEquals( + "11:39", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().prevDateTime) + ); + assertEquals( + "12:30", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().nextDateTime) + ); + } + + @Test + @SuppressWarnings("deprecation") + void testCreateTripSearchMetadataArriveByWithNormalSearchWindow() { + var model = TestPagingModel.testDataWithFewItinerariesCaseB(); + var testDriver = model.arriveByDriver(T09_15, T12_00, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + + assertEquals(D30m, subject.createTripSearchMetadata().searchWindowUsed); + assertEquals( + "08:45", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().prevDateTime) + ); + assertEquals( + "09:45", + TestPagingUtils.cleanStr(subject.createTripSearchMetadata().nextDateTime) + ); + } +} diff --git a/src/test/java/org/opentripplanner/service/paging/PS2_ManyParetoOptimalItinerariesTest.java b/src/test/java/org/opentripplanner/service/paging/PS2_ManyParetoOptimalItinerariesTest.java new file mode 100644 index 00000000000..76a1ae0de1b --- /dev/null +++ b/src/test/java/org/opentripplanner/service/paging/PS2_ManyParetoOptimalItinerariesTest.java @@ -0,0 +1,224 @@ +package org.opentripplanner.service.paging; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.service.paging.TestPagingModel.D30m; +import static org.opentripplanner.service.paging.TestPagingModel.T12_00; +import static org.opentripplanner.service.paging.TestPagingModel.T12_30; +import static org.opentripplanner.service.paging.TestPagingModel.T13_00; +import static org.opentripplanner.service.paging.TestPagingModel.T13_30; + +import java.time.Duration; +import org.junit.jupiter.api.Test; +import org.opentripplanner.model.plan.SortOrder; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageType; + +/** + * This test focus on testing the paging with many itineraries which all is pareto-optimal. + *

+ * Each test do a next/prev search followed by another search (both prev/next) and verify + * all properties in the page-token. There are 4 test: + *

+ * - DEPART AFTER search -> verify NEXT -> search next -> verify NEXT & PREVIOUS
+ * - DEPART AFTER search -> verify PREVIOUS -> search next -> verify NEXT & PREVIOUS
+ * - ARRIVE BY search -> verify NEXT -> search previous -> verify NEXT & PREVIOUS
+ * - ARRIVE BY search -> verify PREVIOUS -> search previous -> verify NEXT & PREVIOUS
+ * 
+ * Note! We are not doing the actual search, just emulating the search using the + * {@link TestDriver} mock. + *

+ * All components required to test paging is used including the {@link PagingService} and the + * 3 filters: + *

    + *
  1. PagingFilter
  2. + *
  3. OutsideSearchWindowFilter
  4. + *
  5. NumItinerariesFilter
  6. + *
+ *

+ */ +@SuppressWarnings("DataFlowIssue") +class PS2_ManyParetoOptimalItinerariesTest { + + private static final Duration SEARCH_WINDOW_USED = D30m; + private final TestPagingModel model = TestPagingModel.testDataWithManyItinerariesCaseA(); + + /** + * Test paging DEPART AFTER search with NEXT -> NEXT/PREVIOUS + */ + @Test + void testPagingDepartAfterAndNext() { + var testDriver = model.departAfterDriver(T12_00, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + var nextCursor = subject.nextPageCursor(); + + assertPageCursor( + nextCursor, + PageType.NEXT_PAGE, + SortOrder.STREET_AND_ARRIVAL_TIME, + "12:09", + "" + ); + + // TEST PAGING AFTER NEXT -> NEXT & PREVIOUS + { + var nextDriver = testDriver.newPage(nextCursor); + var nextSubject = nextDriver.pagingService(nextCursor); + + // PREV + assertPageCursor( + nextSubject.previousPageCursor(), + PageType.PREVIOUS_PAGE, + SortOrder.STREET_AND_ARRIVAL_TIME, + "11:39", + "" + ); + // NEXT + assertPageCursor( + nextSubject.nextPageCursor(), + PageType.NEXT_PAGE, + SortOrder.STREET_AND_ARRIVAL_TIME, + "12:29", + "" + ); + } + } + + /** + * Test paging DEPART AFTER search with PREVIOUS -> NEXT/PREVIOUS + */ + @Test + void testPagingDepartAfterAndPrevious() { + var testDriver = model.departAfterDriver(T12_30, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + var prevCursor = subject.previousPageCursor(); + + assertPageCursor( + prevCursor, + PageType.PREVIOUS_PAGE, + SortOrder.STREET_AND_ARRIVAL_TIME, + "12:00", + "" + ); + + // TEST PAGING AFTER PREVIOUS + { + var prevDriver = testDriver.newPage(prevCursor); + var prevSubject = prevDriver.pagingService(prevCursor); + + // PREV + assertPageCursor( + prevSubject.previousPageCursor(), + PageType.PREVIOUS_PAGE, + SortOrder.STREET_AND_ARRIVAL_TIME, + "11:41", + "" + ); + // NEXT + assertPageCursor( + prevSubject.nextPageCursor(), + PageType.NEXT_PAGE, + SortOrder.STREET_AND_ARRIVAL_TIME, + "12:30", + "" + ); + } + } + + /** + * Test paging ARRIVE BY search with NEXT -> NEXT/PREVIOUS + */ + @Test + void testPagingArriveByAndNext() { + var testDriver = model.arriveByDriver(T12_00, T13_00, D30m, 3); + var subject = testDriver.pagingService(); + + var nextCursor = subject.nextPageCursor(); + + assertPageCursor( + nextCursor, + PageType.NEXT_PAGE, + SortOrder.STREET_AND_DEPARTURE_TIME, + "12:30", + "" + ); + + // TEST PAGING AFTER NEXT -> NEXT & PREVIOUS + { + var nextDriver = testDriver.newPage(nextCursor); + var nextSubject = nextDriver.pagingService(nextCursor); + + // PREV + assertPageCursor( + nextSubject.previousPageCursor(), + PageType.PREVIOUS_PAGE, + SortOrder.STREET_AND_DEPARTURE_TIME, + "12:00", + "" + ); + // NEXT + assertPageCursor( + nextSubject.nextPageCursor(), + PageType.NEXT_PAGE, + SortOrder.STREET_AND_DEPARTURE_TIME, + "12:40", + "" + ); + } + } + + /** + * Test paging ARRIVE BY search with PREVIOUS -> NEXT/PREVIOUS + */ + @Test + void testPagingArriveByAndPrevious() { + var testDriver = model.arriveByDriver(T12_30, T13_30, SEARCH_WINDOW_USED, 3); + var subject = testDriver.pagingService(); + + var cursor = subject.previousPageCursor(); + + assertPageCursor( + cursor, + PageType.PREVIOUS_PAGE, + SortOrder.STREET_AND_DEPARTURE_TIME, + "12:11", + "13:30" + ); + + // TEST PAGING AFTER PREVIOUS + { + var prevDriver = testDriver.newPage(cursor); + var prevSubject = prevDriver.pagingService(cursor); + + // PREV + assertPageCursor( + prevSubject.previousPageCursor(), + PageType.PREVIOUS_PAGE, + SortOrder.STREET_AND_DEPARTURE_TIME, + "12:00", + "13:30" + ); + // NEXT + assertPageCursor( + prevSubject.nextPageCursor(), + PageType.NEXT_PAGE, + SortOrder.STREET_AND_DEPARTURE_TIME, + "12:41", + "" + ); + } + } + + private static void assertPageCursor( + PageCursor cursor, + PageType pageType, + SortOrder sortOrder, + String edt, + String lat + ) { + assertEquals(pageType, cursor.type()); + assertEquals(sortOrder, cursor.originalSortOrder()); + assertEquals(D30m, cursor.searchWindow()); + assertEquals(edt, TestPagingUtils.cleanStr(cursor.earliestDepartureTime())); + assertEquals(lat, TestPagingUtils.cleanStr(cursor.latestArrivalTime())); + } +} diff --git a/src/test/java/org/opentripplanner/service/paging/PS3_FewItinerariesOnSearchWindowLimitTest.java b/src/test/java/org/opentripplanner/service/paging/PS3_FewItinerariesOnSearchWindowLimitTest.java new file mode 100644 index 00000000000..4db61579a47 --- /dev/null +++ b/src/test/java/org/opentripplanner/service/paging/PS3_FewItinerariesOnSearchWindowLimitTest.java @@ -0,0 +1,188 @@ +package org.opentripplanner.service.paging; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.model.plan.paging.cursor.PageType.NEXT_PAGE; +import static org.opentripplanner.model.plan.paging.cursor.PageType.PREVIOUS_PAGE; +import static org.opentripplanner.service.paging.TestPagingUtils.cleanStr; + +import java.time.Duration; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.opentripplanner.framework.time.TimeUtils; +import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.ItinerarySortKey; +import org.opentripplanner.model.plan.SortOrder; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; +import org.opentripplanner.model.plan.paging.cursor.PageType; + +/** + * This test focus on testing the paging with few itineraries. There should be no page-cuts. The + * test focus on paging back and forth, matching itineraries with departure time at + * the exact same time as the search-window earliest-departure-time. + *

+ * Note! We are not doing the actual search, just emulating the search using the + * {@link TestDriver} mock. + *

+ * All components required to test paging is used including the {@link PagingService} and the + * 3 filters: + *

    + *
  1. PagingFilter
  2. + *
  3. OutsideSearchWindowFilter
  4. + *
  5. NumItinerariesFilter
  6. + *
+ *

+ */ +@SuppressWarnings("DataFlowIssue") +class PS3_FewItinerariesOnSearchWindowLimitTest { + + private static final Duration SEARCH_WINDOW = Duration.ofHours(6); + private static final int SEARCH_WINDOW_SEC = (int) SEARCH_WINDOW.toSeconds(); + /** We are avoiding the pageCut in this test - hence setting the value high > 2*/ + private static final int NUM_OF_ITINERARIES = 10; + private static final String LATEST_ARRIVAL_TIME_TEXT = "12:00+1d"; + private static final int LATEST_ARRIVAL_TIME = TimeUtils.time(LATEST_ARRIVAL_TIME_TEXT); + private static final boolean DEPART_AFTER = false; + private static final boolean ARRIVE_BY = true; + public static final String EMPTY = ""; + + private final TestPagingModel model = TestPagingModel.testDataWithFewItinerariesCaseB(); + private TestDriver driver; + + /** + * List of test-cases - for example: + *

+   *   Given: "08:00", DEPART_AFTER, "1 N 2 N - P 2 -"
+   *     - "08:00"        : The first search departure time
+   *     - DEPART_AFTER   : If first search is arriveBy or depart after search
+   *     - "1 N 2 N - .." : Paging sequence - N:NEXT or P:PREVIOUS, 0-4 is the expected itinerary
+   *                        index found in the search between paging events, and '-' means no
+   *                        itinerary found.
+   * 
+ */ + static List testCases() { + return List.of( + // Itineraries depart inside search-window, step NEXT 6 times + //Arguments.of("08:00", DEPART_AFTER, "1 N 2 N - N - N 3 N - N"), + // Itineraries depart inside search-window, step PREV 6 times + //Arguments.of("08:00+1d", DEPART_AFTER, "3 P - P - P 2 P 1 P - P"), + // Itineraries depart inside search-window, step BACK and FORTH + //Arguments.of("08:00", DEPART_AFTER, "1 N 2 N - P 2 N - P 2 P 1 N 2 N"), + // Itineraries depart exactly at the start of search-window [inc, exc>, same sequence as + // test above + Arguments.of("09:00", DEPART_AFTER, "1 N 2 N - P 2 N - P 2 P 1 N 2 N"), + // Itineraries depart inside search-window, step NEXT 6 times + Arguments.of("10:00-1d", ARRIVE_BY, "3 N - N - N 2 N 1 N - N"), + // Itineraries depart inside search-window, step PREV 6 times + Arguments.of("08:00+1d", ARRIVE_BY, "0 P - P - P 1 P 2 P - P"), + // Itineraries depart inside search-window, step BACK and FORTH + Arguments.of("08:00", ARRIVE_BY, "2 P - P - P 3 N - N - P - N - N 2 N 1 P 2"), + // Itineraries depart exactly at the start of search-window [inc, exc>, same sequence as + // test above + Arguments.of("09:00", ARRIVE_BY, "2 P - P - P 3 N - N - P - N - N 2 N 1 P 2") + ); + } + + /** + * Test paging DEPART AFTER search with NEXT -> NEXT/PREVIOUS + */ + @ParameterizedTest + @MethodSource("testCases") + void test(String edt, boolean arriveBy, String testCaseTokens) { + PageCursor cursor; + SortOrder expectedSortOrder; + + int currTime = TimeUtils.time(edt); + + if (arriveBy) { + expectedSortOrder = SortOrder.STREET_AND_DEPARTURE_TIME; + driver = + model.arriveByDriver(currTime, LATEST_ARRIVAL_TIME, SEARCH_WINDOW, NUM_OF_ITINERARIES); + } else { + expectedSortOrder = SortOrder.STREET_AND_ARRIVAL_TIME; + driver = model.departAfterDriver(currTime, SEARCH_WINDOW, NUM_OF_ITINERARIES); + } + + var subject = driver.pagingService(); + var testCases = parseTestCases(testCaseTokens); + + for (var tc : testCases) { + if (tc.gotoNewPage()) { + if (tc.gotoPage() == NEXT_PAGE) { + cursor = subject.nextPageCursor(); + currTime += SEARCH_WINDOW_SEC; + } else { + cursor = subject.previousPageCursor(); + currTime -= SEARCH_WINDOW_SEC; + } + String description = tc.testDescription(); + assertEquals(tc.gotoPage(), cursor.type(), description); + assertEquals(expectedSortOrder, cursor.originalSortOrder(), description); + assertEquals(SEARCH_WINDOW, cursor.searchWindow(), description); + assertEquals( + TimeUtils.timeToStrCompact(currTime), + cleanStr(cursor.earliestDepartureTime()), + description + ); + + // Expect initial LAT - could not change to another time - TODO: FIX THIS AND ENABLE TEST + // assertEquals(expLat, cleanStr(cursor.earliestDepartureTime()), description); + driver = driver.newPage(cursor); + subject = driver.pagingService(cursor); + } else { + assertEquals(tc.expItinerary, getResultAsString(driver.kept()), tc.testDescription()); + } + } + } + + private List parseTestCases(String tokens) { + tokens = tokens.replaceAll("\\s+", ""); + var sequence = new StringBuilder(); + return tokens.chars().mapToObj(ch -> parseToken(Character.toString(ch), sequence)).toList(); + } + + private TestCase parseToken(String token, StringBuilder sequence) { + switch (token) { + case "-": + sequence.append(" > -"); + return new TestCase(sequence.substring(3), null, -1, EMPTY); + case "0", "1", "2", "3": + sequence.append(" > ").append(token); + int i = Integer.parseInt(token); + return new TestCase( + sequence.substring(3), + null, + i, + cleanStr(driver.all().get(i).keyAsString()) + ); + case "N": + sequence.append(" > NEXT"); + return new TestCase(sequence.substring(3), NEXT_PAGE, -1, EMPTY); + case "P": + sequence.append(" > PREV"); + return new TestCase(sequence.substring(3), PREVIOUS_PAGE, -1, EMPTY); + default: + throw new IllegalArgumentException(token); + } + } + + private static String getResultAsString(List kept) { + return kept + .stream() + .map(ItinerarySortKey::keyAsString) + .map(TestPagingUtils::cleanStr) + .collect(Collectors.joining()); + } + + record TestCase(String sequence, PageType gotoPage, int expIndex, String expItinerary) { + boolean gotoNewPage() { + return gotoPage != null; + } + + String testDescription() { + return "Failed after paging sequence: ( " + sequence + " )"; + } + } +} diff --git a/src/test/java/org/opentripplanner/service/paging/TestDriver.java b/src/test/java/org/opentripplanner/service/paging/TestDriver.java new file mode 100644 index 00000000000..0b40b140139 --- /dev/null +++ b/src/test/java/org/opentripplanner/service/paging/TestDriver.java @@ -0,0 +1,197 @@ +package org.opentripplanner.service.paging; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import javax.annotation.Nullable; +import org.opentripplanner._support.debug.TestDebug; +import org.opentripplanner.framework.collection.ListSection; +import org.opentripplanner.framework.lang.Box; +import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.ItinerarySortKey; +import org.opentripplanner.model.plan.SortOrder; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilter; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.NumItinerariesFilterResults; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.OutsideSearchWindowFilter; +import org.opentripplanner.routing.algorithm.filterchain.deletionflagger.PagingFilter; + +/** + * This class simulate/mock the context the paging is operating in. + */ +final class TestDriver { + + private final int nResults; + private final Duration searchWindow; + private final List all; + private final List kept; + private final Instant edt; + private final Instant lat; + private final SortOrder sortOrder; + private final ListSection cropSection; + private final NumItinerariesFilterResults results; + + public TestDriver( + int nResults, + Duration searchWindow, + List all, + List kept, + Instant edt, + Instant lat, + SortOrder sortOrder, + ListSection cropSection, + NumItinerariesFilterResults results + ) { + this.nResults = nResults; + this.searchWindow = searchWindow; + this.all = all; + this.kept = kept; + this.edt = edt; + this.lat = lat; + this.sortOrder = sortOrder; + this.cropSection = cropSection; + this.results = results; + debug(); + } + + static TestDriver driver( + int edt, + int lat, + Duration searchWindow, + int nResults, + SortOrder sortOrder, + List all + ) { + return createNewDriver( + TestPagingModel.time(edt), + TestPagingModel.time(lat), + searchWindow, + nResults, + sortOrder, + all, + ListSection.TAIL, + null + ); + } + + int nResults() { + return nResults; + } + + public Duration searchWindow() { + return searchWindow; + } + + List kept() { + return kept; + } + + List all() { + return all; + } + + Instant earliestDepartureTime() { + return edt; + } + + Instant latestArrivalTime() { + return lat; + } + + SortOrder sortOrder() { + return sortOrder; + } + + boolean arrivedBy() { + return !sortOrder.isSortedByAscendingArrivalTime(); + } + + NumItinerariesFilterResults filterResults() { + return results; + } + + ItinerarySortKey expectedCut() { + return results == null ? null : results.pageCut(); + } + + TestDriver newPage(PageCursor cursor) { + return createNewDriver( + cursor.earliestDepartureTime(), + cursor.latestArrivalTime(), + searchWindow, + nResults, + sortOrder, + all, + cursor.cropItinerariesAt(), + cursor.itineraryPageCut() + ); + } + + PagingService pagingService() { + return TestPagingModel.pagingService(this); + } + + PagingService pagingService(PageCursor cursor) { + return TestPagingModel.pagingService(this, cursor); + } + + private static TestDriver createNewDriver( + Instant edt, + Instant lat, + Duration searchWindow, + int nResults, + SortOrder sortOrder, + List all, + ListSection cropItineraries, + @Nullable ItinerarySortKey pageCut + ) { + List kept = all; + + // Filter search-window + var swFilter = new OutsideSearchWindowFilter(edt, searchWindow); + kept = swFilter.removeMatchesForTest(kept); + + // Simulate Raptor - apply LAT filtering done by raptor + if (lat != null) { + kept = kept.stream().filter(it -> !lat.isBefore(it.endTime().toInstant())).toList(); + } + + //Page filter + if (pageCut != null) { + var pageFilter = new PagingFilter(sortOrder, cropItineraries.invert(), pageCut); + kept = pageFilter.removeMatchesForTest(kept); + } + + // Filter nResults + var filterResultBox = new Box(); + var maxNumFilter = new NumItinerariesFilter(nResults, cropItineraries, filterResultBox::set); + kept = maxNumFilter.removeMatchesForTest(kept); + + return new TestDriver( + nResults, + searchWindow, + all, + kept, + edt, + lat, + sortOrder, + ListSection.TAIL, + filterResultBox.get() + ); + } + + private void debug() { + if (TestDebug.off()) { + return; + } + TestDebug.println(); + TestDebug.println("ITINERARIES:"); + all.forEach(it -> { + var value = TestPagingUtils.toString(it); + if (kept.contains(it)) { + value += " *"; + } + TestDebug.println(value); + }); + } +} diff --git a/src/test/java/org/opentripplanner/service/paging/TestPagingModel.java b/src/test/java/org/opentripplanner/service/paging/TestPagingModel.java new file mode 100644 index 00000000000..f47e3444264 --- /dev/null +++ b/src/test/java/org/opentripplanner/service/paging/TestPagingModel.java @@ -0,0 +1,233 @@ +package org.opentripplanner.service.paging; + +import static org.opentripplanner.framework.time.TimeUtils.hm2time; +import static org.opentripplanner.model.plan.SortOrder.STREET_AND_ARRIVAL_TIME; +import static org.opentripplanner.model.plan.SortOrder.STREET_AND_DEPARTURE_TIME; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import org.opentripplanner.framework.time.TimeUtils; +import org.opentripplanner.model.plan.Itinerary; +import org.opentripplanner.model.plan.Place; +import org.opentripplanner.model.plan.SortOrder; +import org.opentripplanner.model.plan.TestItineraryBuilder; +import org.opentripplanner.model.plan.paging.cursor.PageCursor; +import org.opentripplanner.routing.algorithm.filterchain.comparator.SortOrderComparator; +import org.opentripplanner.transit.model._data.TransitModelForTest; + +class TestPagingModel { + + // Times CASE - A + static final int T12_00 = hm2time(12, 0); + static final int T12_09 = hm2time(12, 9); + static final int T12_10 = hm2time(12, 10); + static final int T12_25 = hm2time(12, 25); + static final int T12_29 = hm2time(12, 29); + static final int T12_30 = hm2time(12, 30); + static final int T12_39 = hm2time(12, 39); + static final int T12_40 = hm2time(12, 40); + static final int T12_41 = hm2time(12, 41); + static final int T12_55 = hm2time(12, 55); + static final int T12_59 = hm2time(12, 59); + static final int T13_00 = hm2time(13, 0); + static final int T13_10 = hm2time(13, 10); + static final int T13_11 = hm2time(13, 11); + static final int T13_25 = hm2time(13, 25); + static final int T13_30 = hm2time(13, 30); + static final int TIME_NOT_SET = -9_999_999; + + // Times CASE - B + static final int T15_00_MINUS_1d = TimeUtils.time("15:00:00-1d"); + static final int T15_30_MINUS_1d = TimeUtils.time("15:30:00-1d"); + static final int T09_00 = hm2time(9, 0); + static final int T09_30 = hm2time(9, 30); + static final int T15_00 = hm2time(15, 0); + static final int T15_30 = hm2time(15, 30); + static final int T09_00_PLUS_1d = TimeUtils.time("09:00:00+1d"); + static final int T09_30_PLUS_1d = TimeUtils.time("09:30:00+1d"); + + static final Duration D30m = Duration.ofMinutes(30); + + // The SEARCH-WINDOW is set to "fixed" 30m in this test for simplicity + private static final List SEARCH_WINDOW_ADJUSTMENTS = List.of(); + + private static final Instant TRANSIT_START_TIME = TestItineraryBuilder.newTime(0).toInstant(); + + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final Place A = Place.forStop(TEST_MODEL.stop("A").build()); + private static final Place B = Place.forStop(TEST_MODEL.stop("B").build()); + + static final boolean ON_STREET = false; + static final boolean TRANSIT = true; + static final int COST_HIGH = 10; + static final int COST_LOW = 9; + static final int TX_1 = 1; + static final int TX_0 = 0; + + private static final List ITINERARIES_CASE_A = List.of( + // EDT time-shifted onStreet result (apply to first depart-after search) + itinerary(T12_00, T12_30, COST_HIGH, TX_0, ON_STREET), + // Next itineraries are almost the same - a criterion is better for each + itinerary(T12_10, T12_41, COST_HIGH, TX_1, TRANSIT), + itinerary(T12_10, T12_40, COST_LOW, TX_1, TRANSIT), + itinerary(T12_10, T12_40, COST_HIGH, TX_0, TRANSIT), + itinerary(T12_09, T12_40, COST_HIGH, TX_1, TRANSIT), + itinerary(T12_25, T12_55, COST_HIGH, TX_1, TRANSIT), + // An itinerary with a very long duration + itinerary(T12_29, T13_11, COST_LOW, TX_0, TRANSIT), + // Next itineraries are almost the same - a criterion is better for each + itinerary(T12_40, T13_11, COST_HIGH, TX_1, TRANSIT), + itinerary(T12_40, T13_10, COST_LOW, TX_1, TRANSIT), + itinerary(T12_40, T13_10, COST_HIGH, TX_0, TRANSIT), + itinerary(T12_39, T13_10, COST_HIGH, TX_1, TRANSIT), + itinerary(T12_55, T13_25, COST_HIGH, TX_1, TRANSIT), + // LAT time-shifted onStreet result (apply to first arrive-by search) + itinerary(T12_59, T13_30, COST_HIGH, TX_0, ON_STREET) + ); + static final List ITINERARIES_CASE_A_DEPART_AFTER = ITINERARIES_CASE_A + // Skip last itinerary (onStreet arriveBy) + .subList(0, ITINERARIES_CASE_A.size() - 1) + .stream() + .sorted(SortOrderComparator.comparator(STREET_AND_ARRIVAL_TIME)) + .toList(); + + static final List ITINERARIES_CASE_A_ARRIVE_BY = ITINERARIES_CASE_A + // Skip first itinerary (onStreet departAfter) + .subList(1, ITINERARIES_CASE_A.size()) + .stream() + .sorted(SortOrderComparator.comparator(SortOrder.STREET_AND_DEPARTURE_TIME)) + .toList(); + + /** + * Case B only have 4 itineraries over 3 days: + *
+   *  - 15:00-1d
+   *  - 12:00
+   *  - 15:00
+   *  - 12:00+1d
+   *  
+ */ + private static final List ITINERARIES_CASE_B = List.of( + itinerary(T15_00_MINUS_1d, T15_30_MINUS_1d, COST_HIGH, TX_1, TRANSIT), + itinerary(T09_00, T09_30, COST_HIGH, TX_1, TRANSIT), + itinerary(T15_00, T15_30, COST_HIGH, TX_1, TRANSIT), + itinerary(T09_00_PLUS_1d, T09_30_PLUS_1d, COST_HIGH, TX_1, TRANSIT) + ); + + static final List ITINERARIES_CASE_B_DEPART_AFTER = ITINERARIES_CASE_B + .stream() + .sorted(SortOrderComparator.comparator(STREET_AND_ARRIVAL_TIME)) + .toList(); + + static final List ITINERARIES_CASE_B_ARRIVE_BY = ITINERARIES_CASE_B + .stream() + .sorted(SortOrderComparator.comparator(SortOrder.STREET_AND_DEPARTURE_TIME)) + .toList(); + + private final List itinerariesDepartAfter; + private final List itinerariesArriveBy; + + private TestPagingModel( + List itinerariesDepartAfter, + List itinerariesArriveBy + ) { + this.itinerariesDepartAfter = itinerariesDepartAfter; + this.itinerariesArriveBy = itinerariesArriveBy; + } + + static TestPagingModel testDataWithManyItinerariesCaseA() { + return new TestPagingModel(ITINERARIES_CASE_A_DEPART_AFTER, ITINERARIES_CASE_A_ARRIVE_BY); + } + + static TestPagingModel testDataWithFewItinerariesCaseB() { + return new TestPagingModel(ITINERARIES_CASE_B_DEPART_AFTER, ITINERARIES_CASE_B_ARRIVE_BY); + } + + static PagingService pagingService(TestDriver testDriver) { + return new PagingService( + SEARCH_WINDOW_ADJUSTMENTS, + testDriver.searchWindow(), + testDriver.searchWindow(), + testDriver.searchWindow(), + testDriver.earliestDepartureTime(), + testDriver.latestArrivalTime(), + testDriver.sortOrder(), + testDriver.arrivedBy(), + testDriver.nResults(), + null, + testDriver.filterResults(), + testDriver.kept() + ); + } + + static PagingService pagingService(TestDriver testDriver, PageCursor pageCursor) { + return new PagingService( + SEARCH_WINDOW_ADJUSTMENTS, + testDriver.searchWindow(), + testDriver.searchWindow(), + testDriver.searchWindow(), + pageCursor.earliestDepartureTime(), + pageCursor.latestArrivalTime(), + pageCursor.originalSortOrder(), + testDriver.arrivedBy(), + testDriver.nResults(), + pageCursor, + testDriver.filterResults(), + testDriver.kept() + ); + } + + TestDriver arriveByDriver(int edt, int lat, Duration searchWindow, int nResults) { + return TestDriver.driver( + edt, + lat, + searchWindow, + nResults, + STREET_AND_DEPARTURE_TIME, + itinerariesArriveBy + ); + } + + TestDriver departAfterDriver(int edt, Duration searchWindow, int nResults) { + return TestDriver.driver( + edt, + TIME_NOT_SET, + searchWindow, + nResults, + STREET_AND_ARRIVAL_TIME, + itinerariesDepartAfter + ); + } + + static Instant time(int time) { + return time == TIME_NOT_SET ? null : TRANSIT_START_TIME.plusSeconds(time); + } + + private static Itinerary itinerary( + int departureTime, + int arrivalTime, + int cost, + int nTransfers, + boolean transit + ) { + var builder = TestItineraryBuilder.newItinerary(A); + + if (transit) { + if (nTransfers == 0) { + builder.bus(10, departureTime, arrivalTime, B); + } else if (nTransfers == 1) { + builder + .bus(20, departureTime, departureTime + 120, B) + .bus(21, departureTime + 240, arrivalTime, B); + } else { + throw new IllegalArgumentException("nTransfers not supported: " + nTransfers); + } + } else { + builder.drive(departureTime, arrivalTime, B); + } + var it = builder.build(); + it.setGeneralizedCost(cost); + return it; + } +} diff --git a/src/test/java/org/opentripplanner/service/paging/TestPagingUtils.java b/src/test/java/org/opentripplanner/service/paging/TestPagingUtils.java new file mode 100644 index 00000000000..9533e22ced7 --- /dev/null +++ b/src/test/java/org/opentripplanner/service/paging/TestPagingUtils.java @@ -0,0 +1,28 @@ +package org.opentripplanner.service.paging; + +import org.opentripplanner.model.plan.ItinerarySortKey; + +class TestPagingUtils { + + static String cleanStr(Object value) { + if (value == null) { + return ""; + } + return value + .toString() + .replaceAll("2020-02-01T(\\d\\d:\\d\\d):00Z", "$1-1d") + .replaceAll("2020-02-02T(\\d\\d:\\d\\d):00Z", "$1") + .replaceAll("2020-02-03T(\\d\\d:\\d\\d):00Z", "$1+1d") + .replaceAll("0(\\d:00)", "$1"); + } + + static String toString(ItinerarySortKey it) { + if (it == null) { + return ""; + } + var value = it.keyAsString(); + value = cleanStr(value); + // indent cost with one digit + return value.replaceAll("(\\$\\d,|transit])", " $1"); + } +} diff --git a/src/test/java/org/opentripplanner/street/integration/ParkAndRideTest.java b/src/test/java/org/opentripplanner/street/integration/ParkAndRideTest.java index 10ab2e27232..6dd53ae0c6e 100644 --- a/src/test/java/org/opentripplanner/street/integration/ParkAndRideTest.java +++ b/src/test/java/org/opentripplanner/street/integration/ParkAndRideTest.java @@ -11,8 +11,6 @@ import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.api.request.request.StreetRequest; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter.TagsFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.street.model.vertex.StreetVertex; import org.opentripplanner.street.model.vertex.Vertex; @@ -140,19 +138,24 @@ protected List runStreetSearchAndCreateDescriptor( var request = new RouteRequest(); request.withPreferences(preferences -> preferences - .withBike(b -> b.withParkCost(120).withParkTime(60)) - .withCar(c -> c.withParkCost(240).withParkTime(180)) + .withBike(b -> + b.withParking(parking -> { + parking.withRequiredVehicleParkingTags(requiredTags); + parking.withBannedVehicleParkingTags(bannedTags); + parking.withParkCost(120); + parking.withParkTime(60); + }) + ) + .withCar(c -> + c.withParking(parking -> { + parking.withRequiredVehicleParkingTags(requiredTags); + parking.withBannedVehicleParkingTags(bannedTags); + parking.withParkCost(240); + parking.withParkTime(180); + }) + ) ); request.setWheelchair(requireWheelChairAccessible); - request - .journey() - .parking() - .setFilter( - new VehicleParkingFilterRequest( - List.of(new TagsFilter(bannedTags)), - List.of(new TagsFilter(requiredTags)) - ) - ); request.setArriveBy(arriveBy); var tree = StreetSearchBuilder diff --git a/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java b/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java index ce94cc92a4c..a9932381b40 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/StreetVehicleParkingLinkTest.java @@ -14,9 +14,6 @@ import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.api.request.StreetMode; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingEntrance; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; @@ -59,17 +56,18 @@ void foo(Set parkingTags, Set not, Set select, boolean s .build(); var entranceVertex = new VehicleParkingEntranceVertex(entrance); - var parkingReq = new VehicleParkingRequest(); - - Set notFilter = Set.of(new VehicleParkingFilter.TagsFilter(not)); - Set selectFilter = Set.of(new VehicleParkingFilter.TagsFilter(select)); - - parkingReq.setFilter(new VehicleParkingFilterRequest(notFilter, selectFilter)); var req = StreetSearchRequest.of(); req.withMode(StreetMode.BIKE_TO_PARK); - req.withParking(parkingReq); - req.withPreferences(p -> p.withBike(bike -> bike.withParkCost(0))); + req.withPreferences(p -> + p.withBike(bike -> { + bike.withParking(parkingPreferences -> { + parkingPreferences.withRequiredVehicleParkingTags(select); + parkingPreferences.withBannedVehicleParkingTags(not); + parkingPreferences.withParkCost(0); + }); + }) + ); var edge = StreetVehicleParkingLink.createStreetVehicleParkingLink( streetVertex, diff --git a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java index a39fed89d6f..7dad61fbd6b 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java @@ -8,7 +8,6 @@ import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.api.request.StreetMode; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex; @@ -46,8 +45,7 @@ public void realtimeAvailableCarPlacesTest() { StreetMode.CAR_TO_PARK, false, true, - VehicleParkingSpaces.builder().carSpaces(1).build(), - true + VehicleParkingSpaces.builder().carSpaces(1).build() ); var s1 = traverse(); @@ -57,28 +55,13 @@ public void realtimeAvailableCarPlacesTest() { @Test public void realtimeAvailableCarPlacesFallbackTest() { - initEdgeAndRequest(StreetMode.CAR_TO_PARK, false, true, null, true); + initEdgeAndRequest(StreetMode.CAR_TO_PARK, false, true, null); var s1 = traverse(); assertFalse(State.isEmpty(s1)); } - @Test - public void realtimeNotAvailableCarPlacesTest() { - initEdgeAndRequest( - StreetMode.CAR_TO_PARK, - false, - true, - VehicleParkingSpaces.builder().carSpaces(0).build(), - true - ); - - var s1 = traverse(); - - assertTrue(State.isEmpty(s1)); - } - @Test public void availableBicyclePlacesTest() { initEdgeAndRequest(StreetMode.BIKE_TO_PARK, true, false); @@ -103,8 +86,7 @@ public void realtimeAvailableBicyclePlacesTest() { StreetMode.BIKE_TO_PARK, true, false, - VehicleParkingSpaces.builder().bicycleSpaces(1).build(), - true + VehicleParkingSpaces.builder().bicycleSpaces(1).build() ); var s1 = traverse(); @@ -114,51 +96,33 @@ public void realtimeAvailableBicyclePlacesTest() { @Test public void realtimeAvailableBicyclePlacesFallbackTest() { - initEdgeAndRequest(StreetMode.BIKE_TO_PARK, true, false, null, true); + initEdgeAndRequest(StreetMode.BIKE_TO_PARK, true, false, null); var s1 = traverse(); assertFalse(State.isEmpty(s1)); } - @Test - public void realtimeNotAvailableBicyclePlacesTest() { - initEdgeAndRequest( - StreetMode.BIKE_TO_PARK, - true, - false, - VehicleParkingSpaces.builder().bicycleSpaces(0).build(), - true - ); - - var s1 = traverse(); - - assertTrue(State.isEmpty(s1)); - } - private void initEdgeAndRequest( StreetMode parkingMode, boolean bicyclePlaces, boolean carPlaces ) { - initEdgeAndRequest(parkingMode, bicyclePlaces, carPlaces, null, false); + initEdgeAndRequest(parkingMode, bicyclePlaces, carPlaces, null); } private void initEdgeAndRequest( StreetMode parkingMode, boolean bicyclePlaces, boolean carPlaces, - VehicleParkingSpaces availability, - boolean realtime + VehicleParkingSpaces availability ) { var vehicleParking = createVehicleParking(bicyclePlaces, carPlaces, availability); this.vertex = new VehicleParkingEntranceVertex(vehicleParking.getEntrances().get(0)); vehicleParkingEdge = VehicleParkingEdge.createVehicleParkingEdge(vertex); - var parking = new VehicleParkingRequest(); - parking.setUseAvailabilityInformation(realtime); - this.request = StreetSearchRequest.of().withMode(parkingMode).withParking(parking).build(); + this.request = StreetSearchRequest.of().withMode(parkingMode).build(); } private VehicleParking createVehicleParking( diff --git a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java index 0417aaf717c..41ecbe162bb 100644 --- a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java +++ b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java @@ -3,8 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.params.provider.Arguments.of; -import java.util.Collection; -import java.util.List; import java.util.Set; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; @@ -13,9 +11,6 @@ import org.opentripplanner.framework.geometry.WgsCoordinate; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.routing.api.request.StreetMode; -import org.opentripplanner.routing.api.request.request.VehicleParkingRequest; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilter; -import org.opentripplanner.routing.api.request.request.filter.VehicleParkingFilterRequest; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingEntrance; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; @@ -85,18 +80,18 @@ private void runTest( var fromV = new VehicleParkingEntranceVertex(entrance); var edge = VehicleParkingEdge.createVehicleParkingEdge(fromV); - var parkingReq = new VehicleParkingRequest(); - Collection select = List.of( - new VehicleParkingFilter.TagsFilter(preferredTags) - ); - parkingReq.setPreferred(new VehicleParkingFilterRequest(List.of(), select)); - parkingReq.setUnpreferredCost(EXTRA_COST); - var req = StreetSearchRequest.of(); req.withMode(StreetMode.BIKE_TO_PARK); - req.withParking(parkingReq); req.withArriveBy(arriveBy); - req.withPreferences(p -> p.withBike(bike -> bike.withParkCost(0))); + req.withPreferences(p -> + p.withBike(bike -> { + bike.withParking(parkingPreferences -> { + parkingPreferences.withUnpreferredVehicleParkingTagCost(EXTRA_COST); + parkingPreferences.withPreferredVehicleParkingTags(preferredTags); + parkingPreferences.withParkCost(0); + }); + }) + ); var result = traverse(fromV, edge, req.build()); diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/nearest.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/nearest.json new file mode 100644 index 00000000000..82d929adeb1 --- /dev/null +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/nearest.json @@ -0,0 +1,17 @@ +{ + "data" : { + "nearest" : { + "edges" : [ + { + "node" : { + "place" : { + "id" : "U3RvcDpGOkE", + "gtfsId" : "F:A", + "parentStation" : null + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/nearest.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/nearest.graphql new file mode 100644 index 00000000000..3616ec03ff8 --- /dev/null +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/nearest.graphql @@ -0,0 +1,17 @@ +{ + nearest(lat: 60.19915, lon: 24.94089, maxDistance: 500) { + edges { + node { + place { + ...on Stop { + id + gtfsId + parentStation { + id + } + } + } + } + } + } + } \ No newline at end of file diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json index ebc2e4f7c02..69f859d784d 100644 --- a/src/test/resources/standalone/config/router-config.json +++ b/src/test/resources/standalone/config/router-config.json @@ -34,7 +34,7 @@ "dropOffTime": 30, "dropOffCost": 30 }, - "bikeParkTime": 60, + "bikeParkTime": "1m", "bikeParkCost": 120, "carDropoffTime": 120, "waitReluctance": 1.0,